From fbfa0103091ea06eac5b07d038c7c944e3b7b0ac Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 30 Jul 2026 18:46:44 +0300 Subject: [PATCH 1/2] Expand CLI help reference --- .gitignore | 1 + README.md | 13 +- internal/app/app.go | 98 +++++++++++---- internal/app/app_test.go | 43 ++++++- memory-bank/features/FT-036/README.md | 19 +++ memory-bank/features/FT-036/brief.md | 117 ++++++++++++++++++ memory-bank/features/FT-036/design.md | 73 +++++++++++ .../features/FT-036/implementation-plan.md | 87 +++++++++++++ memory-bank/features/README.md | 1 + 9 files changed, 427 insertions(+), 25 deletions(-) create mode 100644 memory-bank/features/FT-036/README.md create mode 100644 memory-bank/features/FT-036/brief.md create mode 100644 memory-bank/features/FT-036/design.md create mode 100644 memory-bank/features/FT-036/implementation-plan.md diff --git a/.gitignore b/.gitignore index c6b7081..0bb6683 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /code-converge tmp/ .symphony-workspace/ +.start-issue/runs/ diff --git a/README.md b/README.md index d97bc8a..e379bd9 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,21 @@ ## Root help -`code-converge -h` and `code-converge --help` are equivalent, write the following usage line to stdout, and exit `0` without loading configuration or starting an update or review workflow: +`code-converge -h` and `code-converge --help` are equivalent, write a concise command and global-option reference to stdout, and exit `0` without loading configuration or starting an update or review workflow. Root help lists the `config` and `update` commands, all supported global options, and points to this README for the complete configuration reference. Use `code-converge config --help` for the configuration command syntax, and `code-converge update --help` for update syntax including `--yes` / `-y`. ```text usage: code-converge [flags] [config] + +Commands: + config Show effective configuration and its sources. + update [--yes|-y] Check for and install a newer release. + +Global options: + Output: + --log-format Workflow output format: human or kv. + ... + +See README.md for the full configuration reference. ``` ## Workflow diff --git a/internal/app/app.go b/internal/app/app.go index 1bf7867..00173be 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -24,6 +24,37 @@ import ( type optionalFlag struct{ target *config.OptionalString } +type globalFlagSpec struct { + name, group, description string + bind func(*flag.FlagSet, *config.Overrides) +} + +var globalFlagSpecs = []globalFlagSpec{ + {"log-format", "Output", "Workflow output format: human or kv.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "log-format", &o.LogFormat) }}, + {"heartbeat", "Output", "Human-output liveness interval.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "heartbeat", &o.Heartbeat) }}, + {"color", "Output", "Interactive human-output color: auto, always, or never.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "color", &o.Color) }}, + {"mode", "Workflow", "Execution profile: fast or best.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "mode", &o.Mode) }}, + {"max-cycles", "Workflow", "Maximum fix-findings attempts per review phase.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "max-cycles", &o.MaxCycles) }}, + {"max-ci-recoveries", "Workflow", "Maximum CI recovery attempts.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "max-ci-recoveries", &o.MaxCIRecoveries) }}, + {"review-model", "Stage overrides", "Review model.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "review-model", &o.ReviewModel) }}, + {"review-reasoning-effort", "Stage overrides", "Review reasoning effort.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "review-reasoning-effort", &o.ReviewEffort) }}, + {"fix-model", "Stage overrides", "Fix-findings model.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "fix-model", &o.FixModel) }}, + {"fix-reasoning-effort", "Stage overrides", "Fix-findings reasoning effort.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "fix-reasoning-effort", &o.FixEffort) }}, + {"fix-prompt-file", "Stage overrides", "Fix-findings prompt file.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "fix-prompt-file", &o.FixPromptPath) }}, + {"finalize-model", "Stage overrides", "Finalization model.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "finalize-model", &o.FinalizeModel) }}, + {"finalize-reasoning-effort", "Stage overrides", "Finalization reasoning effort.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "finalize-reasoning-effort", &o.FinalizeEffort) }}, + {"finalize-prompt-file", "Stage overrides", "Finalization prompt file.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "finalize-prompt-file", &o.FinalizePromptPath) }}, + {"ci-fix-model", "Stage overrides", "CI-fix model.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "ci-fix-model", &o.CIFixModel) }}, + {"ci-fix-reasoning-effort", "Stage overrides", "CI-fix reasoning effort.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "ci-fix-reasoning-effort", &o.CIFixEffort) }}, + {"ci-fix-prompt-file", "Stage overrides", "CI-fix prompt file.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "ci-fix-prompt-file", &o.CIFixPromptPath) }}, + {"review-base", "Workflow", "Review base override.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "review-base", &o.ReviewBase) }}, + {"session-log-dir", "Diagnostics", "Diagnostic session-log directory.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "session-log-dir", &o.SessionLogDir) }}, + {"session-log-retention", "Diagnostics", "Diagnostic session-log retention.", func(f *flag.FlagSet, o *config.Overrides) { bind(f, "session-log-retention", &o.SessionLogRetention) }}, + {"no-session-log", "Diagnostics", "Disable diagnostic session logging.", func(f *flag.FlagSet, o *config.Overrides) { + f.BoolVar(&o.NoSessionLog, "no-session-log", false, "disable diagnostic session logging") + }}, +} + func (f optionalFlag) String() string { if f.target == nil { return "" @@ -58,8 +89,7 @@ func (a App) Run(ctx context.Context, args []string) int { if stderr == nil { stderr = os.Stderr } - if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") { - rootUsage(stdout) + if helpCommand(stdout, args) { return workflow.ExitSuccess } if len(args) == 1 && args[0] == "--version" { @@ -92,27 +122,9 @@ func (a App) Run(ctx context.Context, args []string) int { configCommand := len(args) > 0 && args[0] == "config" flags := flag.NewFlagSet("code-converge", flag.ContinueOnError) flags.SetOutput(io.Discard) - bind(flags, "log-format", &overrides.LogFormat) - bind(flags, "heartbeat", &overrides.Heartbeat) - bind(flags, "color", &overrides.Color) - bind(flags, "mode", &overrides.Mode) - bind(flags, "max-cycles", &overrides.MaxCycles) - bind(flags, "max-ci-recoveries", &overrides.MaxCIRecoveries) - bind(flags, "review-model", &overrides.ReviewModel) - bind(flags, "review-reasoning-effort", &overrides.ReviewEffort) - bind(flags, "fix-model", &overrides.FixModel) - bind(flags, "fix-reasoning-effort", &overrides.FixEffort) - bind(flags, "fix-prompt-file", &overrides.FixPromptPath) - bind(flags, "finalize-model", &overrides.FinalizeModel) - bind(flags, "finalize-reasoning-effort", &overrides.FinalizeEffort) - bind(flags, "finalize-prompt-file", &overrides.FinalizePromptPath) - bind(flags, "ci-fix-model", &overrides.CIFixModel) - bind(flags, "ci-fix-reasoning-effort", &overrides.CIFixEffort) - bind(flags, "ci-fix-prompt-file", &overrides.CIFixPromptPath) - bind(flags, "review-base", &overrides.ReviewBase) - bind(flags, "session-log-dir", &overrides.SessionLogDir) - bind(flags, "session-log-retention", &overrides.SessionLogRetention) - flags.BoolVar(&overrides.NoSessionLog, "no-session-log", false, "disable diagnostic session logging") + for _, spec := range globalFlagSpecs { + spec.bind(flags, &overrides) + } if len(args) > 0 && args[0] == "config" { args = append(append([]string{}, args[1:]...), "config") @@ -223,6 +235,46 @@ func (a App) Run(ctx context.Context, args []string) int { func rootUsage(out io.Writer) { fmt.Fprintln(out, "usage: code-converge [flags] [config]") + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Commands:") + fmt.Fprintln(out, " config Show effective configuration and its sources.") + fmt.Fprintln(out, " update [--yes|-y] Check for and install a newer release.") + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Global options:") + group := "" + for _, spec := range globalFlagSpecs { + if spec.group != group { + group = spec.group + fmt.Fprintf(out, " %s:\n", group) + } + fmt.Fprintf(out, " --%-25s %s\n", spec.name, spec.description) + } + fmt.Fprintln(out, "") + fmt.Fprintln(out, "See README.md for the full configuration reference.") +} + +func helpCommand(out io.Writer, args []string) bool { + if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") { + rootUsage(out) + return true + } + if len(args) != 2 || (args[1] != "-h" && args[1] != "--help") { + return false + } + switch args[0] { + case "config": + fmt.Fprintln(out, "usage: code-converge config [global options]") + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Show effective configuration values and their sources without starting a workflow.") + return true + case "update": + fmt.Fprintln(out, "usage: code-converge update [--yes|-y]") + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Check for and install a newer release. --yes and -y skip confirmation.") + return true + default: + return false + } } func updateArgs(args []string) (bool, error) { diff --git a/internal/app/app_test.go b/internal/app/app_test.go index 291c73d..30078b3 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -127,7 +127,20 @@ func TestRootHelpAliasesExitBeforeOperationalSetup(t *testing.T) { Runner: fake, Updater: updater, }).Run(context.Background(), args) - if code != workflow.ExitSuccess || stdout.String() != "usage: code-converge [flags] [config]\n" || stderr.Len() != 0 { + for _, want := range []string{ + "usage: code-converge [flags] [config]", + "config Show effective configuration", + "update [--yes|-y]", + "Global options:", + "--log-format", + "--no-session-log", + "See README.md for the full configuration reference.", + } { + if !strings.Contains(stdout.String(), want) { + t.Errorf("missing %q in help:\n%s", want, stdout.String()) + } + } + if code != workflow.ExitSuccess || stderr.Len() != 0 { t.Fatalf("code=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String()) } if len(fake.invocations) != 0 || updater.called { @@ -137,6 +150,34 @@ func TestRootHelpAliasesExitBeforeOperationalSetup(t *testing.T) { } } +func TestSubcommandHelpExitsBeforeOperationalSetup(t *testing.T) { + tests := []struct { + args []string + wants []string + }{ + {[]string{"config", "--help"}, []string{"usage: code-converge config [global options]", "Show effective configuration"}}, + {[]string{"config", "-h"}, []string{"usage: code-converge config [global options]"}}, + {[]string{"update", "--help"}, []string{"usage: code-converge update [--yes|-y]", "--yes and -y skip confirmation"}}, + {[]string{"update", "-h"}, []string{"usage: code-converge update [--yes|-y]"}}, + } + for _, test := range tests { + t.Run(strings.Join(test.args, " "), func(t *testing.T) { + var stdout, stderr bytes.Buffer + fake := &appFakeRunner{t: t} + updater := &appFakeUpdater{code: workflow.ExitOperational} + code := (App{Stdout: &stdout, Stderr: &stderr, Runner: fake, Updater: updater}).Run(context.Background(), test.args) + if code != workflow.ExitSuccess || stderr.Len() != 0 || len(fake.invocations) != 0 || updater.called { + t.Fatalf("code=%d stdout=%q stderr=%q invocations=%#v updater.called=%v", code, stdout.String(), stderr.String(), fake.invocations, updater.called) + } + for _, want := range test.wants { + if !strings.Contains(stdout.String(), want) { + t.Errorf("missing %q in help:\n%s", want, stdout.String()) + } + } + }) + } +} + func TestUpdateCommandDispatchesWithoutStartingWorkflow(t *testing.T) { var stdout, stderr bytes.Buffer updater := &appFakeUpdater{code: 0} diff --git a/memory-bank/features/FT-036/README.md b/memory-bank/features/FT-036/README.md new file mode 100644 index 0000000..a87632e --- /dev/null +++ b/memory-bank/features/FT-036/README.md @@ -0,0 +1,19 @@ +--- +title: "FT-036: Discoverable CLI Help" +doc_kind: feature +doc_function: index +purpose: "Навигация по canonical problem, solution и execution artifacts для discoverable CLI help из issue #36." +derived_from: + - ../../dna/governance.md + - brief.md +status: active +audience: humans_and_agents +--- + +# FT-036: Discoverable CLI Help + +## Аннотированный индекс + +- [`brief.md`](brief.md) — canonical problem space, scope, validation profile и verify contract. +- [`design.md`](design.md) — selected CLI help contract и invariants. +- [`implementation-plan.md`](implementation-plan.md) — grounding и execution sequence. diff --git a/memory-bank/features/FT-036/brief.md b/memory-bank/features/FT-036/brief.md new file mode 100644 index 0000000..c877bae --- /dev/null +++ b/memory-bank/features/FT-036/brief.md @@ -0,0 +1,117 @@ +--- +title: "FT-036: Discoverable CLI Help" +doc_kind: feature +doc_function: canonical +purpose: "Canonical problem, scope, validation profile и verify contract для discoverable CLI help из issue #36." +derived_from: + - ../../flows/feature.md + - ../../engineering/validation-profiles.md + - ../../../README.md +status: active +delivery_status: in_progress +audience: humans_and_agents +must_not_define: + - implementation_sequence + - solution_space +--- + +# FT-036: Discoverable CLI Help + +## What + +### Problem + +Root help currently exposes only a usage line, and `config --help` and `update --help` are treated as invalid invocations. Operators cannot discover commands, flags, configuration entry points, or command-specific syntax without reading the README. + +### Outcome + +| Metric ID | Metric | Baseline | Target | Measurement method | +| --- | --- | --- | --- | --- | +| `MET-01` | Interactive CLI discoverability | Root has one usage line; subcommand help exits 2 | Root and both supported subcommands provide stable successful help | Focused app tests and public README contract | + +### Scope + +- `REQ-01` `-h` and `--help` render concise root help to stdout and exit 0, including usage, `config` and `update` synopses, global options, and a README/configuration pointer. +- `REQ-02` `config --help` and `update --help` render command-specific stdout help and exit 0; update documents `--yes` and `-y`. +- `REQ-03` Every help invocation returns before configuration loading, diagnostic session logging, workflow start, Codex invocation, and self-update. +- `REQ-04` Focused tests and the public CLI contract describe the help text and exit semantics without changing machine-readable workflow output. + +### Non-Scope + +- `NS-01` Changing workflow, configuration-command, update-command, or machine-readable event semantics outside help invocations. +- `NS-02` Adding commands, changing flag values/defaults, loading configuration to build help, or performing a self-update check. + +### Constraints / Assumptions + +- `ASM-01` The existing `flag` definitions are the authoritative inventory of global options. +- `CON-01` Public CLI output must remain concise and stable; README remains the complete configuration reference. + +## Design Requirement Decision + +| Decision | Reason | Downstream owner | +| --- | --- | --- | +| `Design required: yes` | The public CLI/help and stdout contract changes; command dispatch must preserve non-help side-effect boundaries. | `design.md` | + +## Artifact Routing Decision + +| Artifact | Decision | Trigger / reason | Route / owner | +| --- | --- | --- | --- | +| Separate use-case or runtime-surface artifact | omitted | One CLI entrypoint and three help paths are fully traceable in the brief and design. | `none` | + +## Validation Profile Decision + +| Profile | Triggers / rationale | Downgrade approval | +| --- | --- | --- | +| `standard` | Executable public CLI contract and exit semantics change. No security, data, integration, release, or rollout trigger applies. | `none` | + +## Verify + +### Exit Criteria + +- `EC-01` All three help surfaces satisfy their documented output and exit contract without side effects. +- `EC-02` Normal workflow and machine-readable output remain unaffected. + +### Traceability matrix + +| Requirement ID | Problem refs | Acceptance refs | Checks | Evidence IDs | +| --- | --- | --- | --- | --- | +| `REQ-01` | `ASM-01`, `CON-01` | `EC-01`, `SC-01` | `CHK-01`, `CHK-03` | `EVID-01`, `EVID-03` | +| `REQ-02` | `CON-01` | `EC-01`, `SC-02` | `CHK-01`, `CHK-03` | `EVID-01`, `EVID-03` | +| `REQ-03` | `CON-01` | `EC-01`, `SC-03` | `CHK-02` | `EVID-02` | +| `REQ-04` | `CON-01` | `EC-02`, `SC-04` | `CHK-03`, `CHK-04` | `EVID-03`, `EVID-04` | + +### Acceptance Scenarios + +- `SC-01` An operator runs `code-converge --help` or `-h` and receives root usage, command synopses, grouped global options, and a README/configuration pointer with exit 0. +- `SC-02` An operator runs `code-converge config --help` or `code-converge update --help` and receives the valid syntax and purpose; update lists both confirmation aliases, with exit 0. +- `SC-03` A help invocation with fake runner and updater performs neither a runner invocation nor self-update. +- `SC-04` A normal invalid/workflow invocation retains its pre-existing event and exit behavior. + +### Negative Coverage + +- `NEG-01` Invalid `update` arguments still exit operationally and do not become a successful help path. + +### Checks + +| Check ID | Covers | How to check | Expected result | Evidence path | +| --- | --- | --- | --- | --- | +| `CHK-01` | `SC-01`, `SC-02`, `NEG-01` | Focused `internal/app` tests | Exact required help fragments and exit codes pass | `go test ./internal/app` | +| `CHK-02` | `SC-03` | Fake-runner/updater tests | No configuration/workflow/update side effect on help | `go test ./internal/app` | +| `CHK-03` | `SC-01`, `SC-02`, `SC-04` | `go test ./...`, `go vet ./...`, `git diff --check` | All suites pass and diff is valid | command output | +| `CHK-04` | `REQ-04` | `make docs-lint` | Public docs links and governed frontmatter pass | command output | + +### Test matrix + +| Check ID | Evidence IDs | Evidence path | +| --- | --- | --- | +| `CHK-01` | `EVID-01` | `go test ./internal/app` | +| `CHK-02` | `EVID-02` | `go test ./internal/app` | +| `CHK-03` | `EVID-03` | local command output and CI run | +| `CHK-04` | `EVID-04` | `make docs-lint` | + +### Evidence + +- `EVID-01` Focused app-test output covering root and subcommand help. +- `EVID-02` Test assertions showing help bypasses runner/updater. +- `EVID-03` Full local suite, vet, diff-check, and required CI result. +- `EVID-04` Documentation-lint output and README contract review. diff --git a/memory-bank/features/FT-036/design.md b/memory-bank/features/FT-036/design.md new file mode 100644 index 0000000..60dfeb6 --- /dev/null +++ b/memory-bank/features/FT-036/design.md @@ -0,0 +1,73 @@ +--- +title: "FT-036: Discoverable CLI Help Design" +doc_kind: feature +doc_function: canonical +purpose: "Selected solution and public CLI help contract for FT-036." +derived_from: + - brief.md + - ../../flows/feature.md + - ../../../README.md +status: active +audience: humans_and_agents +must_not_define: + - problem_scope + - execution_sequence +--- + +# FT-036: Discoverable CLI Help Design + +## Design Pack + +No separate design-pack artifact is required: the contract is a small, single-process dispatch change. + +## Selected Design + +- `SOL-01` Recognize supported help forms before command dispatch, configuration resolution, session setup, workflow creation, Codex runner use, or update runner use. Root help accepts only `-h` and `--help`; subcommand help accepts `config --help`/`config -h` and `update --help`/`update -h`. +- `SOL-02` Render deterministic human-oriented help from a single in-process command/option reference. Root output contains usage, commands, grouped global options, and a README/configuration pointer; command output contains purpose and syntax. The option reference is shared with flag registration where practical so a renamed or added global flag cannot silently drift from help. +- `SOL-03` Leave all non-help dispatch paths unchanged, including invalid arguments and workflow `kv` output. + +## Design Decisions + +| Decision | Outcome | Traceability | +| --- | --- | --- | +| `SD-01` | Help text is static in-process output and must not resolve effective config. | `REQ-01`, `REQ-03` | +| `SD-02` | The global option inventory is declared once for both flag binding and help rendering; descriptive grouping may remain presentation metadata. | `REQ-01`, `CON-01` | +| `SD-03` | Help is a successful command path only for recognized root/subcommand forms; malformed update syntax keeps the existing operational failure. | `REQ-02`, `NEG-01` | + +## C4 Applicability Decision + +- `C4-00: not required` — the change stays inside the existing `internal/app` CLI-dispatch component and introduces no component, runtime, storage, integration, or deployment boundary. + +## Architecture Coverage Decision + +| Aspect | Decision | Evidence | +| --- | --- | --- | +| Components | covered | `App.Run` dispatch and the existing flag registration are the only changed responsibilities. | +| Connectors | N/A | No inter-process, network, storage, or configuration connector is entered on help paths. | +| Configuration | covered | Help dispatch precedes `config.ResolveLogFormat` and `config.Load`. | +| Behavioral semantics | covered | Recognized help returns 0/stdout; invalid non-help arguments retain existing exit semantics. | +| Quality/evolution | covered | A shared option declaration and focused exact-output tests make the public text stable and reduce drift. | + +## Contracts and Invariants + +- `CTR-01` Root help output is stdout-only, exit 0, and includes root usage, `config` and `update` command synopses, global option groups, and a README/configuration reference. +- `CTR-02` Config help output is stdout-only, exit 0, and states its purpose plus valid invocation; update help additionally lists `--yes` and `-y`. +- `INV-01` A recognized help path never invokes config loading, session logging, workflow/Codex runner, or self-update. +- `INV-02` Machine-readable workflow records are emitted only by workflow paths, never by help. + +## Failure Modes and Backout + +- `FM-01` A future flag change could make help stale; `SD-02` and focused tests detect it before publication. +- `RB-01` The change is an additive local code/docs/test diff and can be reverted as one commit; no runtime state or rollout action exists. + +## Design Verification + +| Analysis class | Required | Method | Result / evidence | +| --- | --- | --- | --- | +| Contract compatibility | yes | Compare README contract, existing app tests, and proposed acceptance cases. | `CTR-01`/`CTR-02` retain existing root syntax and add successful documented paths. | +| State/transition completeness | yes | Enumerate root, config, update, invalid-update, and workflow dispatch paths. | `SOL-01` and `SD-03` cover each path. | +| Failure propagation | yes | Assert side-effecting collaborators are untouched on help. | `INV-01` is testable with fakes. | +| Concurrency/ordering | no | Single synchronous CLI dispatch; no shared state. | N/A. | +| Security boundaries | no | No credential, auth, or trust-boundary change. | N/A. | +| Capacity/latency | no | Rendering a bounded in-process text block has no material performance impact. | N/A. | +| Migration/evolution safety | yes | Share option registration inventory and preserve non-help branches. | `SD-02`, `SD-03`, `FM-01`. | diff --git a/memory-bank/features/FT-036/implementation-plan.md b/memory-bank/features/FT-036/implementation-plan.md new file mode 100644 index 0000000..edd903e --- /dev/null +++ b/memory-bank/features/FT-036/implementation-plan.md @@ -0,0 +1,87 @@ +--- +title: "FT-036: Discoverable CLI Help Implementation Plan" +doc_kind: feature +doc_function: derived +purpose: "Execution sequencing and validation mapping for FT-036." +derived_from: + - brief.md + - design.md + - ../../engineering/testing-policy.md +status: active +audience: humans_and_agents +--- + +# FT-036: Discoverable CLI Help Implementation Plan + +## Discovery Context + +| Area | Result | +| --- | --- | +| Relevant paths | `internal/app/app.go` dispatches root help, update, config, flag parsing, config load, sessions and workflow; `internal/app/app_test.go` already tests root-help side effects; `README.md` owns public CLI contract. | +| Local patterns | `App` accepts fake `Runner` and `Updater`, so deterministic tests can prove help bypasses both. Global flags are bound in one contiguous `flag.FlagSet` block. | +| Unresolved questions | none — issue acceptance and current implementation establish all required help forms and no conflicting command pattern was found. | +| Test surfaces | Focused `internal/app` output/side-effect tests, full Go suite/vet, documentation lint, diff check, and hosted `Verify` CI. | +| Environment | Go 1.21 project; commands are `go test ./internal/app`, `go test ./...`, `go vet ./...`, `make docs-lint`, and `git diff --check`. | + +## Test Strategy + +Validation profile is `standard` in [`brief.md`](brief.md#validation-profile-decision). + +| Test surface | Canonical refs | Planned automated coverage | Required local suites / commands | Required CI suites / jobs | Manual-only gap | +| --- | --- | --- | --- | --- | --- | +| Help dispatch/rendering | `REQ-01`–`REQ-03`, `SOL-01`–`SOL-03`, `CTR-01`, `CTR-02`, `INV-01`, `INV-02` | Table-driven root/config/update help tests with exact required fragments, exit codes, and fake collaborator assertions | `go test ./internal/app` | `Verify` / `make verify` | none | +| Existing behavior | `REQ-04`, `SD-03`, `NEG-01` | Existing invalid/update and workflow tests remain green | `go test ./...`; `go vet ./...` | `Verify` | none | +| Public documentation | `REQ-04`, `CHK-04` | Root help reference updated in README | `make docs-lint` | `Verify` | none | + +## Preconditions + +| Precondition ID | Canonical ref | Required state | Used by steps | Blocks start | +| --- | --- | --- | --- | --- | +| `PRE-01` | `SD-01`–`SD-03` | Solution Ready design is active. | `STEP-01`–`STEP-03` | yes | + +## Design Realization Mapping + +| Canonical solution refs | Owner | Realization target | Steps | Checks | Evidence | +| --- | --- | --- | --- | --- | --- | +| `SOL-01`, `SD-01`, `CTR-01`, `CTR-02`, `INV-01`, `INV-02` | `design.md` | `internal/app/app.go` early dispatch and help renderers | `STEP-01` | `CHK-01`, `CHK-02` | `EVID-01`, `EVID-02` | +| `SOL-02`, `SD-02`, `FM-01` | `design.md` | shared global option declaration and root renderer | `STEP-01`, `STEP-02` | `CHK-01` | `EVID-01` | +| `SOL-03`, `SD-03`, `RB-01` | `design.md` | app regression tests and README | `STEP-02`, `STEP-03` | `CHK-03`, `CHK-04` | `EVID-03`, `EVID-04` | +| `C4-00` | `design.md` | no runtime/topology realization required | `STEP-01` | `CHK-03` | `EVID-03` | + +## Workstreams + +| Workstream | Implements | Result | Owner | Dependencies | +| --- | --- | --- | --- | --- | +| `WS-1` | `REQ-01`–`REQ-03` | Side-effect-free discoverable help implementation and focused tests | agent | `PRE-01` | +| `WS-2` | `REQ-04` | Public contract documentation and complete validation | agent | `WS-1` | + +## Approval Gates + +No approval gate is required: no production, live-data, security, or irreversible operation is in scope. + +## Порядок работ + +| Step ID | Actor | Implements | Goal | Touchpoints | Verifies | Evidence IDs | Check command / procedure | Blocked by | Needs approval | Escalate if | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `STEP-01` | agent | `REQ-01`–`REQ-03`, `SOL-01`, `SOL-02` | Add early help dispatch and deterministic renderers sharing global-option metadata with flags. | `internal/app/app.go` | `CHK-01`, `CHK-02` | `EVID-01`, `EVID-02` | `go test ./internal/app` | `PRE-01` | none | A discovered existing pattern conflicts materially with `SD-02`. | +| `STEP-02` | agent | `REQ-01`–`REQ-04`, `SOL-03` | Add focused contract/side-effect/regression coverage. | `internal/app/app_test.go` | `CHK-01`–`CHK-03` | `EVID-01`–`EVID-03` | `go test ./internal/app`; `go test ./...`; `go vet ./...` | `STEP-01` | none | Behavior outside help needs a contract decision. | +| `STEP-03` | agent | `REQ-04` | Update the README root-help contract, then validate docs and diff. | `README.md` | `CHK-03`, `CHK-04` | `EVID-03`, `EVID-04` | `make docs-lint`; `git diff --check` | `STEP-02` | none | Documentation conflicts with accepted CLI contract. | + +## Checkpoints + +| Checkpoint ID | Refs | Condition | Evidence IDs | +| --- | --- | --- | --- | +| `CP-01` | `STEP-01`, `CHK-01`, `CHK-02` | Focused tests prove all help forms and no side effects. | `EVID-01`, `EVID-02` | +| `CP-02` | `STEP-03`, `CHK-03`, `CHK-04` | Full local validation and docs lint pass before final review. | `EVID-03`, `EVID-04` | + +## Execution Risks + +| Risk ID | Risk | Impact | Mitigation | Trigger | +| --- | --- | --- | --- | --- | +| `ER-01` | Help text drifts from global flags. | Public contract is misleading. | Use one declaration and focused assertions. | A flag changes without help-test coverage. | + +## Stop Conditions / Fallback + +| Stop ID | Related refs | Trigger | Immediate action | Safe fallback state | +| --- | --- | --- | --- | --- | +| `STOP-01` | `SD-02`, `ER-01` | Shared declaration would change flag parsing semantics. | Return to Solution Ready and choose a compatible presentation strategy. | No implementation change beyond current clean checkpoint. | diff --git a/memory-bank/features/README.md b/memory-bank/features/README.md index d2dd125..c045845 100644 --- a/memory-bank/features/README.md +++ b/memory-bank/features/README.md @@ -47,3 +47,4 @@ audience: humans_and_agents - [`FT-022/README.md`](FT-022/README.md) — complete schema-constrained Codex review result channel for issue #22. - [`FT-024/README.md`](FT-024/README.md) — completed local checkpoints for successful findings fixes, with publication deferred to clean-review finalization for issue #24. - [`FT-028/README.md`](FT-028/README.md) — active remediation of stale interactive liveness frames for issue #28 through footprint-aware clearing and deterministic reflow coverage. +- [`FT-036/README.md`](FT-036/README.md) — planned discoverable root and subcommand CLI help for issue #36. From 0a8620ca5e1a324ced41d9282cd1ccbdadc6fce6 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 30 Jul 2026 18:48:49 +0300 Subject: [PATCH 2/2] Close CLI help feature package --- memory-bank/features/FT-036/brief.md | 2 +- memory-bank/features/FT-036/implementation-plan.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/memory-bank/features/FT-036/brief.md b/memory-bank/features/FT-036/brief.md index c877bae..f76d10a 100644 --- a/memory-bank/features/FT-036/brief.md +++ b/memory-bank/features/FT-036/brief.md @@ -8,7 +8,7 @@ derived_from: - ../../engineering/validation-profiles.md - ../../../README.md status: active -delivery_status: in_progress +delivery_status: done audience: humans_and_agents must_not_define: - implementation_sequence diff --git a/memory-bank/features/FT-036/implementation-plan.md b/memory-bank/features/FT-036/implementation-plan.md index edd903e..1556141 100644 --- a/memory-bank/features/FT-036/implementation-plan.md +++ b/memory-bank/features/FT-036/implementation-plan.md @@ -7,7 +7,7 @@ derived_from: - brief.md - design.md - ../../engineering/testing-policy.md -status: active +status: archived audience: humans_and_agents ---