From eaeb2347c0baf09984f0f3dd6a95e8ac6fe7ec9a Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Thu, 22 Oct 2026 04:41:10 +0200 Subject: [PATCH] docs(19.8): re-verification, gaps closed (57/57) --- .../19.8-VERIFICATION.md | 302 +++++++++--------- 1 file changed, 153 insertions(+), 149 deletions(-) diff --git a/.planning/phases/19.8-console-commands-overhaul/19.8-VERIFICATION.md b/.planning/phases/19.8-console-commands-overhaul/19.8-VERIFICATION.md index 2e3b197c..87ff7374 100644 --- a/.planning/phases/19.8-console-commands-overhaul/19.8-VERIFICATION.md +++ b/.planning/phases/19.8-console-commands-overhaul/19.8-VERIFICATION.md @@ -1,8 +1,8 @@ --- phase: 19.8-console-commands-overhaul -verified: 2026-10-22T01:32:12Z -status: gaps_found -score: 54/57 must-haves verified +verified: 2026-10-22T02:37:57Z +status: human_needed +score: 57/57 must-haves verified covered_files: - ".gitignore" - ".planning/phases/19.8-console-commands-overhaul/19.8-01-PLAN.md" @@ -17,6 +17,8 @@ covered_files: - ".planning/phases/19.8-console-commands-overhaul/19.8-05-SUMMARY.md" - ".planning/phases/19.8-console-commands-overhaul/19.8-06-PLAN.md" - ".planning/phases/19.8-console-commands-overhaul/19.8-06-SUMMARY.md" + - ".planning/quick/261022-4z8-fix-the-open-19-8-re-review-findings-wr-/261022-4z8-PLAN.md" + - ".planning/quick/261022-4z8-fix-the-open-19-8-re-review-findings-wr-/261022-4z8-SUMMARY.md" - "README.md" - "cmd/summer/commands_documented_test.go" - "cmd/summer/docs.go" @@ -30,6 +32,7 @@ covered_files: - "docs/console/setup-and-maintenance.md" - "docs/console/utilities.md" - "docs/console/writing-commands.md" + - "docs/database/migrations.md" - "docs/examples/blog/console/publish.go" - "docs/examples/blog/console/publish_test.go" - "docs/services/configuration.md" @@ -43,6 +46,7 @@ covered_files: - "examples/hello/plugins/greeter/plugin.go" - "go.mod" - "go.sum" + - "internal/argmask/argmask.go" - "internal/build/artifact.go" - "internal/build/build.go" - "internal/build/build_test.go" @@ -205,44 +209,18 @@ covered_files: - "modules/wristband/README.md" - "modules/wristband/oidc_token.go" - "scripts/check-phase19.8.sh" -covered_digest: "v2:sha256:8730d7a9b8f0468f2903e7c4b99cae20366899ae4ecc64e569cd608fa636e4de" +covered_digest: "v2:sha256:472046bb65cca6ab5a4a3a8b7f02a7c66f6f385e90fbecc1f4a7baf1b80b9f9d" behavior_unverified: 0 overrides_applied: 0 -gaps: - - truth: "CR-01 (D-03, D-27): lines printed while a Spinner, Progress or Process view runs (Output.Println and Printf, status lines, Progress Fail lines, bonfire.PrintAbove from diary) appear in the order they were printed and none is lost when the view ends" - status: partial - reason: "Holds when the view ends normally (TestPrintAboveOrderedNoLoss passes). It fails once the view's context is cancelled: bubbletea stops, but activeView stays registered until the work function returns, so printAbove sends to a dead program and still returns true. The verifier reproduced this 3 times out of 3 on a pty with a scratch probe: inside a bonfire.Process item, after cancel(), both out.Println(\"after-cancel-line\") and bonfire.PrintAbove(...) were lost, and PrintAbove returned true. This is review finding WR-09. Under D-27, data printed with Println is also lost on this path." - artifacts: - - path: "modules/bonfire/live.go" - issue: "printAbove (around lines 477-487) does not check whether the program has finished. runLive does not clear activeView when the program ends on its own (context cancelled, Run error)." - - path: "modules/bonfire/helpers.go" - issue: "Process passes the caller's cancellable ctx into runLive, so it reaches this path" - missing: - - "printAbove returns false (plain write) once the program has finished; activeView is cleared when the program ends on its own, without waiting for work to return" - - "Pinning test: cancel the context in the middle of an item, then assert that later Println and PrintAbove lines appear and that PrintAbove reports false" - - truth: "WR-08 (D-19): the wrong-directory Try line ... replaces the value of every flag whose name contains password, passwd, secret, token or key with ***, in both the --flag value and --flag=value forms; together with plan 03's prohibition 'The startup summary, hints and logs never print a DSN password, an app key, a token or a secret'" - status: partial - reason: "tryArgs masks the next argument only when it does not start with '-', but pflag still takes such an argument as the value. Reproduced: 'cd plugins; ../bin/hello admin:create --email a@b.c --password -Xk9q' prints 'Try: cd ..; bin/hello admin:create --email a@b.c --password -Xk9q' (WR-11), while the same command with 'hunter2' prints '--password ***'. The same root cause shows on a second path: when an app binary is killed by a signal, cmd/summer/runtime.go runAppCmd returns 'summer: : signal: ...' without masking. RenderError passes it only through sunscreen.Scrub, so a --password value reaches stderr on Ctrl+C or an OOM kill (WR-10, confirmed by reading the code)." - artifacts: - - path: "modules/bonfire/errors.go" - issue: "tryArgs (lines 310-331): the guard !strings.HasPrefix(args[i+1], \"-\") skips masking for a value that starts with a dash" - - path: "cmd/summer/runtime.go" - issue: "runAppCmd (lines 165-178): the error for a signal death or a start failure contains strings.Join(argv, \" \") unmasked" - missing: - - "Mask the argument after a secret-named long flag whatever its first character (except '--')" - - "Mask argv in runAppCmd's non-exit error path with the same helper, or name only the command word" - - "Test cases: a dash-leading secret value in TestWrongDirectoryMasksSecrets, and a signal-killed delegate with --password whose error block does not contain the value" - - truth: "WR-07 (D-21, D-04): Migrate applies exactly the sets migrationSets lists (one list for Migrate, PendingMigrations, --pretend, the production question, the startup summary and migrate:status --json)" - status: partial - reason: "Migrate, PendingMigrations, --pretend, the question and the summary share migrationSets (TestMigrateAppliedLines and TestPendingMigrations pass with Docker). migrate:status --json does not: Status() walks only plugins, and the JSON keeps a pending ref only when ref.Plugin matches a plugin row. So the framework sets (summercms.attach, summercms.cabana, deferred bindings, queue) never appear, neither applied nor pending. Its own example says 'pending migrations included'. Confirmed by reading modules/lagoon/migrations.go:140-170 and commands.go:270-289 (WR-12)." - artifacts: - - path: "modules/lagoon/migrations.go" - issue: "Status iterates plugins only, not migrationSets(gdb, plugins)" - - path: "modules/lagoon/commands.go" - issue: "migrate:status --json filters pending refs to plugin rows" - missing: - - "Build Status (or the JSON) from migrationSets so framework sets appear with their applied and pending IDs" - - "Extend TestMigrateStatusJSON (Docker) to assert that a pending framework-set migration is listed" +re_verification: + previous_status: gaps_found + previous_score: 54/57 + gaps_closed: + - "CR-01 (D-03, D-27): lines printed while a live view runs appear in order and none is lost when the view ends, including after its context is cancelled (WR-09, fix fce232d)" + - "WR-08 (D-19) and the plan 03 secrets prohibition: secret flag values are masked in the wrong-directory Try line whatever their first character (WR-11, fix 707372b) and in summer's delegate error on a signal death or start failure (WR-10, fix 17c722d), through the shared internal/argmask" + - "WR-07 (D-21, D-04): migrate:status (table and --json) lists the same sets migrationSets gives Migrate, framework sets included (WR-12, fix 57a849d, reworked in 139f5e3 so that lagoon.Status stays plugin-only)" + gaps_remaining: [] + regressions: [] human_verification: - test: "On a real terminal, run 'summer', 'bin/', 'bin/ help admin:token:create' and 'bin/ bogus'" expected: "Colors, alignment and sections match the approved D-13 list, D-14 help and D-18 error previews; --no-ansi removes every escape code" @@ -254,35 +232,76 @@ human_verification: expected: "A compact startup block (version, env, URL, DB and migration state, plugins, queue, scheduler, mail, cache, realtime, search), then INFO lines with component prefixes. -q shows only warnings. -v adds per-plugin lines. Ctrl+C prints the shutdown report and exits 0" why_human: "Readability of the styled block is a visual judgment; TestServeLifecycle (Docker) covers the records and exit code" - test: "Resolve the judgment-tier prohibitions listed under 'Prohibitions' below (the LLM-judge verdicts there are non-authoritative)" - expected: "Each prohibition is confirmed, or rejected with a reason. The 'never print a secret' prohibition of plan 03 is already flagged as violated (gap 2)" + expected: "Each prohibition is confirmed, or rejected with a reason. The plan 03 'never print a secret' prohibition is no longer flagged as violated: both known leaks (WR-10, WR-11) are fixed and reproduced as fixed with built binaries" why_human: "Judgment-tier prohibitions need explicit human resolution in interactive verification" --- # Phase 19.8: Console commands overhaul Verification Report **Phase Goal:** Console commands in `summer` and in application binaries reach the bar set by Laravel's Artisan. Logging, the shared console layer in `bonfire`, and every command's help and output change; the command logic stays. A user sees what a command did, can ask for more or less of it, and learns from `--help` how to use it without opening the docs. -**Verified:** 2026-10-22T01:32:12Z -**Status:** gaps_found -**Re-verification:** No. This is the first verification. The phase already ran one review-fix round (plan 05) and was released as v0.4.2 (plan 06). +**Verified:** 2026-10-22T02:37:57Z (initial verification 2026-10-22T01:32:12Z) +**Status:** human_needed +**Re-verification:** Yes, after gap closure (quick task 261022-4z8, commits 7c15095..a48afbd plus follow-ups 139f5e3 and b1fba7e) -**MVP mode note:** ROADMAP marks the phase `mode: mvp`, but the goal is not a user story (`user-story.validate` returns `valid: false`). All six plans recorded the decision not to invent a story. The orchestrator asked for verification, so this report applies the standard goal-backward method to the goal and SC-1..SC-5 and does not include a User Flow Coverage table. Run `/msd mvp-phase 19.8` if the user-flow framing is wanted. +**Plain verdict:** The phase goal is achieved. All 57 must-haves (5 roadmap success criteria and 52 plan truths) are verified in the codebase, and the three gaps of the first report are closed. Nothing is missing in the code. The status is `human_needed`, not `passed`, only because the verifier contract allows `passed` only when the human verification list is empty. That list still holds the four checks of the first report: three visual or terminal checks (palette and layout, live widgets and Ctrl+C on a real terminal, the serve startup block) and the explicit resolution of the judgment-tier prohibitions. No `*-UAT.md` exists for this phase, so none of them is settled by recorded evidence. They are confirmation checks, not suspected defects. Once a person has done them, the phase can be marked passed. -## Verdict on the open review findings (asked explicitly) +**MVP mode note:** ROADMAP marks the phase `mode: mvp`, but the goal is not a user story (`user-story.validate` returns `valid: false`). All six plans recorded the decision not to invent a story. This report applies the standard goal-backward method to the goal and SC-1..SC-5 and does not include a User Flow Coverage table. -The re-review (19.8-REVIEW.md, 0 critical, 6 warnings, 6 info) leaves 12 findings open. The verdict for each: +## Re-verification (2026-10-22, after quick 261022-4z8) -| Finding | Undermines a roadmap SC? | Undermines a plan must_have or prohibition? | Classification | -|---------|--------------------------|---------------------------------------------|----------------| -| WR-09 lines lost after a live view's context is cancelled | No. SC-2/SC-4 hold on normal paths. The goal's "a user sees what a command did" is hurt only on this path | **Yes**: plan 05 CR-01 truth ("none is lost"), reproduced 3 of 3 on a pty | **Gap 1** | -| WR-10 signal-killed delegate prints its full argv including --password, exit 1 | No | **Yes, in part**: the argv leak breaks plan 03's prohibition "hints and logs never print ... a secret". Exit code 1 is what plan 05's CR-02 truth specifies, so that part is a follow-up (130 would be nicer) | **Gap 2** (leak part) | -| WR-11 dash-leading secret values not masked in the wrong-directory hint | No | **Yes**: plan 05 WR-08 truth ("every flag ... in the --flag value form") and the plan 03 prohibition. Reproduced with a built binary | **Gap 2** | -| WR-12 migrate:status --json omits framework sets | No (SC-4 asks for `--json` output, which exists) | **Yes**: plan 05 WR-07 truth names migrate:status --json as a consumer of the one list. Confirmed in the code | **Gap 3** | -| WR-13 migrate exits 1 when the re-read after a successful Migrate fails | No | No. It needs a second database failure; the scenarios the truth names (success, partial failure) hold and are tested with Docker | Follow-up quality item | -| WR-14 Process's plain path prints item names without Sanitize | No | No. The WR-05 truth covers "process-view item names", and the live view sanitizes them. The plain path is the same class of problem but outside the truth's wording | Follow-up quality item (do it together with gap 1) | -| IN-10..IN-15 | No | No | Follow-up quality items | -| IN-01..IN-09 (first review) | No | No | Already deferred to `.planning/todos/pending/2026-10-22-console-review-info-findings.md` | +The SUMMARY claims were not taken as evidence. Each gap was re-checked against the code at HEAD `4141cd9` (the code tree has no uncommitted changes; only foreign planning files are dirty), with the pinning tests run by the verifier and with an independent check using built binaries. -So none of the open findings undermines a roadmap success criterion. Three groups (WR-09; WR-10 with WR-11; WR-12) are reproducible or code-confirmed counterexamples to the exact wording of plan 05 must_haves that the gap-closure round claimed as fixed, and to plan 03's secrets prohibition. By the decision tree that makes the status `gaps_found`. Each fix is a small change (one function each, plus a pinning test). If the user prefers to ship them as follow-ups, the override block at the end accepts them explicitly. +### Commits under review + +| Commit | Finding | Gap | +|--------|---------|-----| +| `fce232d` fix(bonfire): end a live view when its context is cancelled and print later lines plainly | WR-09 | 1 | +| `1ac75ad` fix(bonfire): claim the live view slot before building the program | IN-15 | (1, same code) | +| `48e13f9` fix(bonfire): strip control characters from Process's plain item lines and the view's label | WR-14 | follow-up | +| `707372b` fix(bonfire): mask secret flag values that start with a dash | WR-11 | 2 | +| `17c722d` fix(summer): mask secret flag values in a delegate's error | WR-10 | 2 | +| `57a849d` fix(lagoon): migrate:status reads the sets migrate applies | WR-12 | 3 | +| `139f5e3` fix(lagoon): keep Status plugin-only; migrate:status adds the framework sets itself | WR-12 rework | 3 | +| `0691d26` fix(lagoon): warn instead of failing when the re-read after a successful migrate fails | WR-13 | follow-up | +| `7c15095`, `a48afbd`, `b1fba7e` | IN-14 doc comment; disposition and todo records | records | + +`19.8-REVIEW-DISPOSITION.md` shows `open: 0`, `total: 32`. WR-09..WR-14, IN-14 and IN-15 are fixed with these hashes; IN-10..IN-13 and the exit-130 suggestion are deferred to `.planning/todos/pending/2026-10-22-console-review-info-findings.md`. The commits are local: 20 commits ahead of the local `origin/master` (`ead8e42`), and no tag contains `fce232d`. So the fixes are not in released v0.4.2 yet. That is a release matter, not a goal gap. + +### Gap 1 (WR-09): lines after a cancelled live view. CLOSED + +- **Code:** `modules/bonfire/live.go`. `tea.NewProgram` no longer takes the caller's ctx (no `tea.WithContext`). `runLive` claims the slot under `liveMu` before it builds the program (lines 368-382). `watchContext` (lines 426-448) does the following on `ctx.Done()`, all under `liveMu`: it clears `activeView`, sends `finishMsg{err: ctx.Err()}` and waits for `finished`. When the program ends first, the watcher only clears the view. `liveView.done` is the `finished` channel, and `printAbove` (lines 529-546) returns false through `case <-v.done:` for a program that has stopped, and unregisters it. The deferred cleanup's `prog.Send` after the watcher has finished the program cannot block, because bubbletea's Run cancels its own context on return. diary's console handler writes the line itself when `bonfire.PrintAbove` returns false (`modules/diary/console.go:165`). +- **Pinning test:** `TestPrintAboveAfterCancel` cancels in the middle of an item. It asserts that the view is unregistered, that `Println`, `Info` and `PrintAbove` lines each appear exactly once, and that `PrintAbove` reports false. The verifier ran it with the rest of the live-view set (`TestNestedProcessBuildsNoProgram`, `TestProcessViewStripsControl`, `TestPrintAboveOrderedNoLoss`, `TestPrintlnStaysWithItsConsole`, `TestLiveViewSingleOwner`, `TestLiveViewPanicUnregisters`, `TestLiveViewRestoresTerminalOnSignal`) under `-race -count=3`: all PASS. +- **Independent pty reproduction:** this is the same scenario that failed 3 of 3 in the first verification. A scratch probe was built from a `git archive HEAD` export: inside a `bonfire.Process` item it calls `cancel()`, then `out.Println("after-cancel-line")`, then `bonfire.PrintAbove(...)`. It ran 5 times under `script(1)`. In 5 of 5 runs `after-cancel-line` printed once after the last frame and `\e[?25h` (cursor restored), `PrintAbove` returned **false** (so its caller prints the line), and `Process` returned `context canceled`. Before the fix the line was lost and `PrintAbove` returned true. + +### Gap 2 (WR-11 and WR-10): secret flag values in clear. CLOSED + +- **Code:** `internal/argmask/argmask.go` is the one implementation and imports only `strings`. `Join` masks the argument after a secret-named long flag (`password`, `passwd`, `secret`, `token`, `key`) whatever its first character; only `--` is left alone. It also masks the `--flag=value` form. bonfire's `tryArgs` and the `cd` part of the Try line call `argmask.Join` and `argmask.Quote` (errors.go:288-301); bonfire's old local helpers are gone. `cmd/summer/runtime.go:174` `runAppCmd` builds its error from `argmask.Join(argv)` on every branch, and no `strings.Join(argv` remains. An exit code from the child is still passed through with `Reported(WithExitCode(...))`. +- **Pinning tests (PASS, verifier run):** `TestWrongDirectoryMasksSecrets` (dash-leading cases included); `TestRunAppCmdMasksSecrets/killed_by_a_signal` and `/start_failure`; `TestDelegateExitCodePassthrough/exit_code`, `/killed_by_a_signal`, `/killed_by_a_signal_masks_secrets`. +- **Independent checks with built binaries** (built into the scratchpad from HEAD): + - `cd plugins; ../bin/hello admin:create --email a@b.c --password hunter2` printed `Try: cd ..; bin/hello admin:create --email a@b.c --password ***` (exit 1). + - The same command with `--password -Xk9q` printed `--password ***` (it was in clear text before the fix). + - `summer admin:create --email a@b.c --password hunter2 --api-token=t0k3n --client-secret -Xk9q` was delegated to a fake app binary that kills itself with SIGKILL. It printed `ERROR summer: admin:create --email a@b.c --password *** --api-token=*** --client-secret ***: signal: killed` and exited 1, which is what plan 05's CR-02 truth specifies. With `-v` the chain shows only `signal: killed`. + - A delegate that exits 2 makes summer exit 2 with no second error block, so the CR-02 behavior is unchanged. + +### Gap 3 (WR-12): migrate:status --json omits the framework sets. CLOSED + +- **Code:** `modules/lagoon/migrations.go`. The new unexported `setStatus` (line 160) takes its sets from `migrationSets(gdb, plugins)`, the same list `Migrate` (line 69) and `PendingMigrations` (line 251) use. `migrate:status` reads `setStatus` (commands.go:282), so every `PendingMigrations` ref, whose `Plugin` field is the set id, matches a row, and framework pending migrations appear with `"applied": false`. The exported `lagoon.Status` is back to its pre-task behavior: the verifier compared it with the `a28957f` version. It has the same plugin-only `HasMigrations` iteration and the same empty row for a plugin without a history table; only the row-reading loop moved into the shared unexported `historyRows`. The exported API diff `a28957f..HEAD` over modules, cmd and internal adds only `argmask.Join` and `argmask.Quote`, which are in `internal/`, so they are not framework API. Nothing was removed or changed. +- **Pinning tests (Docker, PASS, verifier run with `TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1`):** `TestMigrateStatusJSON` deletes the newest `summercms.attach` history row and asserts that `--json` (and `--json -q`) lists that migration as pending. It also asserts that the table lists `summercms.attach, summercms.cabana, deferred, queue, demo.alpha, demo.beta` in order. `TestStatusPluginRows` pins the plugin-only `Status`. `TestMigrateRereadFailureWarns`, `TestMigrateAppliedLines`, `TestPendingMigrations`, `TestMigratePretend`, `TestTwoPluginMigrationSetsIsolated` and `TestDocsMigrate` also PASS. +- **Consumer regression check:** `TestRollbackIsolatesFonotekaFullSchema` in `../fonoteka.go/parity` (it calls `lagoon.Status`, `replace => ../summercms.go`) PASSES against HEAD. It failed at `a48afbd`, before the 139f5e3 rework. + +### Regression spot-checks (nothing else regressed) + +| Check | Result | +|-------|--------| +| `go vet ./...` | PASS | +| `go test -short -count=1 ./...` (all packages, live tree) | PASS, every package ok | +| `scripts/check-phase19.8.sh self-test`, `go`, `hello`, `docs` (live tree, now clean of foreign code edits) | all PASS ("phase19.8 go passed", with race on diary, sunscreen, bonfire and docsite; SUMMER list 7 named tests including TestRunAppCmdMasksSecrets) | +| `PHASE198_REQUIRE_DOCKER=1 scripts/check-phase19.8.sh docker` | PASS (8 lagoon tests including TestMigrateRereadFailureWarns and TestStatusPluginRows; 3 cabana token JSON tests) | +| `summer` bare / `summer bogus` / `summer list --format=json` | exit 0 with the grouped list (59 lines) / ERROR block, `Try: summer list`, exit 2 / 35 commands, 0 without examples | +| `summer help make:command`, `bin/hello help migrate:status` | Description, Usage, Arguments, global options, Help, Examples; migrate:status's Long help names the framework sets | +| `bin/hello key:generate -q`, `bin/hello route:list --json` | key printed, exit 0; JSON route list | +| Debt markers (TBD/FIXME/XXX) in files changed `a28957f..HEAD`; TODO/HACK added | none | +| Generated main / internal/build changed since the first verification | no (`git diff 36e2240..HEAD -- cmd/summer/main.go internal/build` is empty) | ## Goal Achievement @@ -290,52 +309,57 @@ So none of the open findings undermines a roadmap success criterion. Three group | # | Success criterion | Status | Evidence | |---|-------------------|--------|----------| -| SC-1 | `diary` module owns logging (Laravel-shaped keys, stderr/stack/daily/console channels, component loggers), sunscreen on every channel, compat shim, daily files on by default, charm stack with a decision note before code | ✓ VERIFIED | `modules/diary` (3,248 lines): `log.default/level/channels/components` constants (config.go:16-24); `DefaultConfig` is a stack of console and daily (`storage/logs/summer.log`, JSON, warn, 14 days); every leaf goes through `sunscreen.Wrap` (channels.go:117-166). README has a `**Name:**` mnemonic; root README row at line 104. The note commit `e6039b4` is an ancestor of the first go.mod lipgloss commit `e903cc3` (merge-base check). go.mod has lipgloss v2.0.6, bubbletea v2.1.0, bubbles v2.2.1, huh v2.0.3, fang v2.0.1, colorprofile v0.4.3. `go list` shows only bonfire and diary import charm. `sunscreen.InstallDefault` keeps its signature. The roadmap's "sunscreen.Install" never existed; plan 01 and the sunscreen README document this. `summer new` writes `config/log.yaml` (golden). | -| SC-2 | Global flags `-v/-vv/-vvv`, `-q`, `--ansi/--no-ansi`, `-n`, `--env`; verbosity sets the diary level at runtime, so River and plugin logs are hidden or consistent at the default level and shown in full at -vv | ✓ VERIFIED | The flags are in the help and list output of both binaries (spot-checks). The generated main does `PeekGlobals`, then `diary.Bootstrap(os.Stderr, diary.FromGlobals(g))`, then `compass.Open(...Env: g.Env)`, then `diary.Setup`, then `bonfire.OnGlobals(diary.ApplyGlobals)` (examples/hello/main.go). `state.floor` lowers every component floor to info at -v and debug at -vv; River defaults to warn. Tests by name: TestVerbosityLevels, TestComponentFloors, TestQuietConsoleOnly, TestRiverLoggerComponent, TestGlobalFlagsAgree, TestCallNoGlobalsHook, all PASS. | -| SC-3 | Every command has a description, long help with examples, documented args and options with defaults; `list` grouped by namespace; `summer help ` and ` help ` work; the coverage check fails for the framework and warns in plugins | ✓ VERIFIED | Spot-checks: bare `summer` and `bin/hello` print the grouped Artisan list (exit 0). `summer help make:command` and `bin/hello help migrate` print Description, Usage, Arguments, Options with defaults, Help and Examples. `summer list --format=json` covers 35 commands, none without examples. `cmd/summer/commands_documented_test.go` calls `t.Error` on every `bonfire.CheckDocs` problem for the tool and application commands (PASS). Plugin tests use `t.Logf` (warn-only, checked in sm-journal-plugin). | -| SC-4 | Sweep of all commands with the Artisan checklist (`--force`, `--pretend`, progress/tables, `--json`) without breaking names or flags; serve and queue:work print a startup summary and a shutdown report; one-shot commands end with a result line and an exit code | ✓ VERIFIED (plan-level gaps 1 and 3 touch edge paths) | `migrate` has `--pretend` and `--force` (help output). `route:list --json` and `key:generate -q` print data (spot-checks). Unknown command exits 2, missing DSN exits 1 with a hint block. surf/summary.go builds the summary and the report; `PendingMigrations` feeds serve.go:111; the http request log is `diary.For("http")` and logs the route pattern only. `internal/dev/watch.go` starts `serve`. `conga.Worker.Stats` exists. The 15 plugin repos each have one sweep commit `feat: console help, examples and named loggers (SummerCMS v0.4.0)` plus `commands_documented_test.go` (verified per repo). Docker: TestServeLifecycle, TestMigratePretend, TestRollbackPretend, TestDeferredPurgePretend, TestMigrateStatusJSON, TestMigrateAppliedLines and the cabana token JSON tests PASS (gate docker stage, run by the verifier). | -| SC-5 | diary and bonfire READMEs, docs console and logging pages, landing site and roadmap deck reflect the new console; unit tests in the last plan | ✓ VERIFIED | `docs/console/*.md` (5 pages), `docs/services/logging.md` (15 mentions of diary), `docs/setup/upgrading.md` "Upgrading to 0.4". The landing en.json has a "Console" card ("Artisan-style help and examples, -v and -q, daily log files."). The sm-demo-app deck has an Artisan-style console row in curated.go:145 and :157 (commit `b325460`). The snapshot matches origin/master (`sync-roadmap: ok`). Plan 04 delivered the unit, golden and slogtest suites. The gate's docs stage PASS at clean HEAD. | +| SC-1 | `diary` module owns logging (Laravel-shaped keys, stderr/stack/daily/console channels, component loggers), sunscreen on every channel, compat shim, daily files on by default, charm stack with a decision note before code | ✓ VERIFIED | `modules/diary` (3,248 lines): `log.default/level/channels/components` constants (config.go:16-24); `DefaultConfig` is a stack of console and daily (`storage/logs/summer.log`, JSON, warn, 14 days); every leaf goes through `sunscreen.Wrap` (channels.go:117-166). README has a `**Name:**` mnemonic; root README row at line 104. The note commit `e6039b4` is an ancestor of the first go.mod lipgloss commit `e903cc3` (merge-base check). go.mod has lipgloss v2.0.6, bubbletea v2.1.0, bubbles v2.2.1, huh v2.0.3, fang v2.0.1, colorprofile v0.4.3. `go list` shows only bonfire and diary import charm. `sunscreen.InstallDefault` keeps its signature. `summer new` writes `config/log.yaml` (golden). Re-verification: unchanged by the gap-closure commits; diary tests PASS under race. | +| SC-2 | Global flags `-v/-vv/-vvv`, `-q`, `--ansi/--no-ansi`, `-n`, `--env`; verbosity sets the diary level at runtime, so River and plugin logs are hidden or consistent at the default level and shown in full at -vv | ✓ VERIFIED | The flags appear in the help output of both binaries (re-checked). The generated main does `PeekGlobals`, `diary.Bootstrap`, `compass.Open(...Env: g.Env)`, `diary.Setup`, `bonfire.OnGlobals(diary.ApplyGlobals)` (examples/hello/main.go, unchanged). TestVerbosityLevels, TestComponentFloors, TestQuietConsoleOnly, TestRiverLoggerComponent, TestGlobalFlagsAgree and TestCallNoGlobalsHook PASS in the gate's go stage. | +| SC-3 | Every command has a description, long help with examples, documented args and options with defaults; `list` grouped by namespace; `summer help ` and ` help ` work; the coverage check fails for the framework and warns in plugins | ✓ VERIFIED | Re-checked: bare `summer` prints the grouped list (exit 0); `summer help make:command` and `bin/hello help migrate:status` print the full help layout; `summer list --format=json` lists 35 commands, none without examples. `cmd/summer/commands_documented_test.go` (`t.Error` per `bonfire.CheckDocs` problem) PASSES in the go stage. | +| SC-4 | Sweep of all commands with the Artisan checklist (`--force`, `--pretend`, progress/tables, `--json`) without breaking names or flags; serve and queue:work print a startup summary and a shutdown report; one-shot commands end with a result line and an exit code | ✓ VERIFIED | As in the first report (migrate `--pretend`/`--force`, `route:list --json`, `key:generate -q`, unknown command exit 2, missing DSN exit 1 with a hint, serve summary and report, 15 plugin repos swept). The edge paths flagged in the first report are now fixed: `migrate:status --json` covers the framework sets, and `migrate` no longer exits 1 after a successful run when only the re-read fails (WR-13). Docker: TestServeLifecycle, TestMigratePretend, TestRollbackPretend, TestDeferredPurgePretend, TestMigrateStatusJSON, TestMigrateAppliedLines, TestMigrateRereadFailureWarns and the cabana token JSON tests PASS. | +| SC-5 | diary and bonfire READMEs, docs console and logging pages, landing site and roadmap deck reflect the new console; unit tests in the last plan | ✓ VERIFIED | As in the first report (5 docs/console pages, the logging page, "Upgrading to 0.4", the landing "Console" card, the deck row in sm-demo-app). The gap-closure commits updated the bonfire and lagoon READMEs, the docs/console pages and docs/database/migrations.md in the same commits (WR-10's README fold-in is recorded as a deviation in the quick SUMMARY). The gate's docs stage PASSES at HEAD (67 files clean, 35 commands with examples). | ### Plan must_haves (merged; 52 truths) | Plan | Truths | Status | Evidence / notes | |------|--------|--------|------------------| -| 01 diary | 8 | 8 ✓ | Decision note order (merge-base), the six versions in go.mod; ParseConfig with env strings (TestConfigEnvSmoke, TestConfigEnvStrings, TestConfigRules); `For` safe before Setup (TestForBeforeSetup); River through `diary.For("river")`, GORM through `NewSlogLogger(diary.For("db"))` with ParameterizedQueries; daily file 0640, lazy, degrades (TestDailyPermissions, TestDailyUnwritable, TestDailyDegradesSmoke); console styled or logfmt (TestConsoleStyledOnlyOnTerminal); redaction on every driver (TestRedactionEveryDriver); palette in bonfire/styles.go; generated main shape (TestGenerateMainInstallsDiary in the internal/build short suite PASS). | -| 02 bonfire | 8 | 8 ✓ | List and header (TestListTracerSmoke, goldens); globals (TestPeekGlobals, TestGlobalFlagsAgree); help, Examples and Hidden appended to the end of Command (diff of the Command struct shows only the two added fields); JSON listing and CheckDocs (TestListJSONGolden, TestCheckDocs); error block, exit codes 0/1/2 and Reported (TestErrorGolden, TestExitCodes, TestReportedSilent, spot-check exit 2); fang with WithoutVersion, WithoutManpage, WithoutCompletions and WithErrorHandler (execute.go:49-53); degradation matrix (TestWidgetMatrix, TestPromptsNoInteraction, TestSecretWithNoInteraction, TestConfirmProceed); duplicate and reserved-flag errors (TestDuplicateNames, TestReservedFlags); the todo is in `todos/done`. | -| 03 sweep | 9 | 9 ✓ | Summary and records (TestServeSummarySmoke, TestServeRecords, the "listening on " prefix); shutdown report with exit 0 (TestShutdownReportSmoke, TestServeGracefulNil, TestServeLifecycle Docker, TestDevGracefulNil); request log (TestAccessLogNeverLogsPath, TestAccessLogRequestIDCap, TestAccessLogDefaultOn, TestAccessLogDisabled, TestAccessLogComponentHTTP); dev runs serve (TestStartBinServe); coverage gate (TestCommandsDocumented); hints (spot-check of the wrong-directory and DSN hints; TestWrongDirectoryHint); -q data and the production question (TestKeyGenerateQuiet, TestConfirmProductionNonTTYProceeds, TestConfirmProductionInteractiveNo, TestForceSkipsConfirm, TestQueueClearConfirm); release order (tags v0.4.0/v0.4.1/v0.4.2 on origin, the replies recorded in the SUMMARYs); D-20 is complete (15 repos, sm-user-plugin included); SC-5 docs. | -| 04 tests | 7 | 7 ✓ | `check-phase19.8.sh` self-test PASS (verifier run). The go stage, with 30 diary, 42 bonfire, 13 surf, 7 lagoon, 5 conga, 4 dev and 6 cmd/summer named tests plus race, PASS at clean HEAD. hello and docs PASS. docker PASS. The plugins, apps and landing stages were not re-run by the verifier (see Probe Execution); plan 06 recorded `--all` green at ead8e42. TestSlogtestConsoleHandler and TestSlogtestPipeline PASS. The post-release fix efb043e shipped in v0.4.1. | -| 05 review fixes | 13 | **10 ✓, 3 ✗ partial** | CR-02, CR-03, WR-01..WR-06 and the commit/RED-replay/disposition truths are verified (the pinning tests are in the go stage and PASS; the disposition marks them fixed; API additions are limited to WithExitCode and Sanitize). **CR-01, WR-08 and WR-07 are partial**: see gaps 1-3. | -| 06 release | 7 | 7 ✓ | `git ls-remote` shows v0.4.2 annotated tag `60b13ae` on `ead8e42` = origin/master. The changelog post at https://summercms.io/changelog/summercms-0-4-2 returns HTTP 200. sm-demo-app `aa4de22` matches origin/master (`sync-roadmap: ok`). The reply "release" is recorded verbatim in the SUMMARY before the tag. No plugin or app commits were needed (Release impact table). | +| 01 diary | 8 | 8 ✓ | Unchanged since the first report; the diary named tests PASS in the gate's go stage at HEAD. | +| 02 bonfire | 8 | 8 ✓ | Unchanged contract; goldens, globals, help, JSON listing, error block and exit codes, degradation matrix all PASS in the go stage. The Output, Input and Progress interfaces and the Command struct are not touched by the gap-closure commits. | +| 03 sweep | 9 | 9 ✓ | As before. The secrets prohibition is no longer violated by a known path (see Prohibitions). | +| 04 tests | 7 | 7 ✓ | `check-phase19.8.sh` self-test, go, hello, docs and docker stages PASS at HEAD (verifier run). The gate now requires TestNestedProcessBuildsNoProgram, TestPrintAboveAfterCancel, TestRunAppCmdMasksSecrets, TestMigrateRereadFailureWarns and TestStatusPluginRows by name. | +| 05 review fixes | 13 | **13 ✓** (was 10 ✓, 3 partial) | **CR-01** ✓: gap 1 closed (TestPrintAboveAfterCancel plus the pty probe, 5/5). **WR-08** ✓: gap 2 closed (dash-leading values and the delegate error path masked; TestWrongDirectoryMasksSecrets, TestRunAppCmdMasksSecrets, built-binary checks). **WR-07** ✓: gap 3 closed (migrate:status reads migrationSets; TestMigrateStatusJSON with a pending framework migration). The API truth still holds: compared with the first report, the gap-closure diff adds no exported identifier under modules/ and changes none. CR-02, CR-03, WR-01..WR-06 and the commit/RED-replay/disposition truths are still verified (pinning tests PASS; disposition `open: 0`). | +| 06 release | 7 | 7 ✓ | Unchanged: v0.4.2 annotated tag on `ead8e42`, changelog post, deck sync. | -**Score:** 54/57 truths verified (5 SC + 52 plan truths; 3 partial failures, all in plan 05; 0 present-but-behavior-unverified) +**Score:** 57/57 truths verified (5 SC + 52 plan truths; 0 failed; 0 present-but-behavior-unverified). The three behavior-dependent truths that had failed (CR-01's cancellation/cleanup invariant, the WR-08 masking, the WR-07 status list) each have a passing behavioral test named above, so they count as verified on behavior, not on presence. ### Required Artifacts | Artifact | Expected | Status | Details | |----------|----------|--------|---------| | `.planning/notes/2026-10-21-console-charm-stack.md` | D-02 decision note | ✓ VERIFIED | Committed before any charm import | -| `modules/diary/{diary,config,component,console,daily,channels}.go` | diary module | ✓ VERIFIED | Substantive and wired: the generated main and every framework module call `diary.For` | -| `modules/bonfire/{globals,execute,list,help,docs,errors,live,helpers,styles,version}.go` | console layer | ✓ VERIFIED | Wired through the generated main and cmd/summer | -| `modules/surf/summary.go`, `accesslog.go` | serve summary, report and request log | ✓ VERIFIED | `diary.For("http")`; summary and report builders called from serve.go | -| `modules/lagoon/migrations.go` | PendingMigrations, migrationSets | ⚠️ PARTIAL | Status() still per-plugin (gap 3) | +| `modules/diary/{diary,config,component,console,daily,channels}.go` | diary module | ✓ VERIFIED | Substantive and wired | +| `modules/bonfire/{globals,execute,list,help,docs,errors,live,helpers,styles,version}.go` | console layer | ✓ VERIFIED | live.go now has the watcher, `liveView.done` and the claim-before-build; helpers.go sanitizes the plain Process path | +| `internal/argmask/argmask.go` | shared secret masking (new) | ✓ VERIFIED | Imported by `modules/bonfire/errors.go` and `cmd/summer/runtime.go`; the only masking implementation | +| `modules/surf/summary.go`, `accesslog.go` | serve summary, report and request log | ✓ VERIFIED | | +| `modules/lagoon/migrations.go` | PendingMigrations, migrationSets, Status | ✓ VERIFIED (was PARTIAL) | `migrationSets(gdb, plugins)` used by Migrate, setStatus and PendingMigrations; exported Status unchanged in behavior | +| `modules/lagoon/commands.go` | migrate, migrate:status | ✓ VERIFIED | `setStatus` for the status command; re-read warning (WR-13) | | `modules/conga/worker.go` | Worker.Stats | ✓ VERIFIED | | -| `internal/dev/watch.go` | dev runs serve | ✓ VERIFIED | `childArgs := append([]string{"serve"}, args...)` | -| `cmd/summer/commands_documented_test.go` | failing coverage gate | ✓ VERIFIED | `t.Error` per CheckDocs problem | -| `cmd/summer/runtime.go` | delegate exit code and streams | ⚠️ PARTIAL | Exit code and streams are fixed; the signal path leaks argv (gap 2) | -| `scripts/check-phase19.8.sh` | fail-closed gate | ✓ VERIFIED | self-test, go, hello, docs and docker run green by the verifier | +| `internal/dev/watch.go` | dev runs serve | ✓ VERIFIED | | +| `cmd/summer/commands_documented_test.go` | failing coverage gate | ✓ VERIFIED | | +| `cmd/summer/runtime.go` | delegate exit code, streams, masked errors | ✓ VERIFIED (was PARTIAL) | `argmask.Join(argv)` on every error branch | +| `scripts/check-phase19.8.sh` | fail-closed gate | ✓ VERIFIED | all local stages green at HEAD | ### Key Link Verification | From | To | Via | Status | |------|----|-----|--------| -| generated main (internal/build) | diary | `diary.Bootstrap` then `diary.Setup(cfg` | ✓ WIRED (examples/hello/main.go) | +| generated main (internal/build) | diary | `diary.Bootstrap` then `diary.Setup(cfg` | ✓ WIRED | | generated main | bonfire.Execute / OnGlobals | `os.Exit(run(...))`, `bonfire.OnGlobals(diary.ApplyGlobals)` | ✓ WIRED | | diary/channels.go | sunscreen | `sunscreen.Wrap(` on every leaf | ✓ WIRED | | conga/client.go | diary | `diary.For("river")` | ✓ WIRED | | lagoon/connection.go | diary | `NewSlogLogger(diary.For("db")` | ✓ WIRED | -| diary/console.go | bonfire | `bonfire.PrintAbove(` (console.go:165) and `bonfire.Sanitize` | ✓ WIRED (the PrintAbove result is wrong after cancellation, gap 1) | +| diary/console.go | bonfire | `bonfire.PrintAbove(` (console.go:165), plain write on false; `bonfire.Sanitize` | ✓ WIRED (PrintAbove now reports false after a cancellation, so the line is written) | | surf/accesslog.go | diary | `diary.For("http")` | ✓ WIRED | | surf/serve.go | lagoon | `lagoon.PendingMigrations(` | ✓ WIRED | +| lagoon/commands.go migrate:status | lagoon/migrations.go migrationSets | `setStatus(gdb, plugins)` | ✓ WIRED (new) | +| modules/bonfire/errors.go | internal/argmask | `argmask.Join` / `argmask.Quote` | ✓ WIRED (new) | +| cmd/summer/runtime.go | internal/argmask | `argmask.Join(argv)` | ✓ WIRED (new) | | cmd/summer tests | bonfire.CheckDocs | `bonfire.CheckDocs(` | ✓ WIRED | | cmd/summer/runtime.go | bonfire/execute.go | `Reported(WithExitCode(...))` | ✓ WIRED | | v0.4.2 tag | changelog | changelog-post.py | ✓ (post id 37, HTTP 200) | @@ -345,24 +369,27 @@ So none of the open findings undermines a roadmap success criterion. Three group | Artifact | Data | Source | Real data | Status | |----------|------|--------|-----------|--------| | serve startup summary | migration state, plugins, drivers | `lagoon.PendingMigrations`, `party` plugins, config lookups | yes (TestServeLifecycle with Postgres) | ✓ FLOWING | -| `migrate:status --json` | applied/pending list | `Status` (plugins only) + `PendingMigrations` filtered by plugin | partial: framework sets missing | ⚠️ PARTIAL (gap 3) | -| `list --format=json` | command catalog | `bonfire.Describe` over registered commands | yes (35 commands in the spot-check) | ✓ FLOWING | +| `migrate:status` / `--json` | applied and pending list per set | `setStatus` over `migrationSets` + `PendingMigrations` | yes, framework sets included (TestMigrateStatusJSON with Postgres) | ✓ FLOWING (was PARTIAL) | +| `list --format=json` | command catalog | `bonfire.Describe` over registered commands | yes (35 commands) | ✓ FLOWING | | http request log | method, pattern, status | `recordPattern` in the route mux | yes (TestAccessLog*) | ✓ FLOWING | -### Behavioral Spot-Checks (verifier-run) +### Behavioral Spot-Checks (verifier-run, re-verification) | Behavior | Command | Result | Status | |----------|---------|--------|--------| -| Bare tool prints the Artisan list | `./summer` | Header, Usage, global options, commands grouped (admin, docs, key, make, migrate, parity, ...), exit 0 | ✓ PASS | -| Per-command help | `./summer help make:command`, `bin/hello help migrate` | Description, Usage, Arguments, Options with defaults, Global options, Help and Examples | ✓ PASS | -| Unknown command is a usage error | `./summer bogus` | ERROR block, `Try: summer list`, exit 2 | ✓ PASS | +| Bare tool prints the Artisan list | `summer --no-ansi` | grouped list, exit 0 | ✓ PASS | +| Per-command help | `summer help make:command`, `bin/hello help migrate:status` | Description, Usage, Arguments, Global options, Help, Examples | ✓ PASS | +| Unknown command is a usage error | `summer bogus` | ERROR block, `Try: summer list`, exit 2 | ✓ PASS | | JSON catalog complete | `summer list --format=json` | 35 commands, 0 without examples | ✓ PASS | -| App failure hint and exit 1 | `bin/hello migrate` (no DSN) | ERROR, explanation, `Try: cp .env.example .env`, exit 1; `-v` shows the chain | ✓ PASS | -| -q keeps data | `bin/hello key:generate -q` | Key printed, exit 0 | ✓ PASS | -| --json for scripts | `bin/hello route:list --json` | JSON with route patterns | ✓ PASS | +| -q keeps data | `bin/hello key:generate -q` | key printed, exit 0 | ✓ PASS | +| --json for scripts | `bin/hello route:list --json` | JSON route list | ✓ PASS | | Wrong-directory hint masks secrets | `cd plugins; ../bin/hello admin:create --email a@b.c --password hunter2` | `--password ***` | ✓ PASS | -| Same with a dash-leading value | `... --password -Xk9q` | `--password -Xk9q` printed in clear | ✗ FAIL (gap 2) | -| Lines after a cancelled Process view | scratch probe under `script(1)`, 3 runs | `after-cancel-line` and PrintAbove line lost in 3/3; PrintAbove returned true | ✗ FAIL (gap 1) | +| Same with a dash-leading value | `... --password -Xk9q` | `--password ***` | ✓ PASS (was FAIL) | +| Signal-killed delegate masks argv | `summer admin:create ... --password hunter2 --api-token=t0k3n --client-secret -Xk9q` (fake app binary that SIGKILLs itself) | `--password *** --api-token=*** --client-secret ***: signal: killed`, exit 1 | ✓ PASS (new) | +| Delegate exit code passthrough | fake app binary exiting 2 | summer exit 2, no second block | ✓ PASS | +| Lines after a cancelled Process view | scratch probe under `script(1)`, 5 runs | `after-cancel-line` printed once after the last frame in 5/5; PrintAbove returned false (caller writes); cursor restored | ✓ PASS (was FAIL) | +| Pending framework migration in `migrate:status --json` | TestMigrateStatusJSON (Docker) | listed with `applied: false`; the table lists the framework sets first | ✓ PASS (was gap) | +| Exported `lagoon.Status` consumer | `../fonoteka.go` `go test -run TestRollbackIsolatesFonotekaFullSchema ./parity/` (Docker) | ok | ✓ PASS | ### Probe Execution @@ -371,13 +398,11 @@ No `scripts/*/tests/probe-*.sh` exist. The phase's probe is `scripts/check-phase | Stage | Command | Result | Status | |-------|---------|--------|--------| | self-test | `bash scripts/check-phase19.8.sh self-test` | "phase19.8 self-test passed" | PASS | -| go | `bash scripts/check-phase19.8.sh go` (on a `git archive HEAD` export) | "phase19.8 go passed" (vet, short, race, named tests) | PASS | -| hello | same export | "phase19.8 hello passed" | PASS | -| docs | same export | "phase19.8 docs passed" | PASS | -| docker | `PHASE198_REQUIRE_DOCKER=1 TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1 bash scripts/check-phase19.8.sh docker` | TestServeLifecycle, 6 lagoon and 3 cabana tests passed | PASS | -| plugins, apps, landing | not re-run | The plugins replace the framework with `../summercms.go`, whose working tree holds another session's uncommitted cabana edits, so a run now would not test 19.8. Plan 06 recorded `--all` green at ead8e42 | NOT RUN by verifier | - -Note: the go stage on the live working tree fails in `cmd/summer` (TestEveryModuleInSidebar, TestDocsAIOutputsInSync, TestPhase11_1Acceptance: `docs/backend/relation-manager.md:58: go code block has no src= reference`). The cause is another session's uncommitted edit to `docs/backend/relation-manager.md` and `modules/cabana/*`, not phase 19.8. The same stage is green on an export of the committed HEAD. +| go | `bash scripts/check-phase19.8.sh go` (live tree; the code tree is clean) | "phase19.8 go passed" (vet, short, race, named tests), exit 0 | PASS | +| hello | `bash scripts/check-phase19.8.sh hello` | "phase19.8 hello passed", exit 0 | PASS | +| docs | `bash scripts/check-phase19.8.sh docs` | "phase19.8 docs passed", exit 0 | PASS | +| docker | `PHASE198_REQUIRE_DOCKER=1 TESTCONTAINERS_HOST_OVERRIDE=127.0.0.1 bash scripts/check-phase19.8.sh docker` | 8 lagoon and 3 cabana tests passed, exit 0 | PASS | +| plugins, apps, landing | not re-run | These stages touch sibling repos, and another session is working in `../sm-demo-app`. The gap-closure commits do not change the generated main or any exported API, so no plugin or app pin is affected. Plan 06 recorded `--all` green at ead8e42 | NOT RUN by verifier | ### Requirements Coverage @@ -385,33 +410,29 @@ There are no REQUIREMENTS.md IDs for this phase (none orphaned). The plans' `req | Source | IDs | Status | |--------|-----|--------| -| CONTEXT decisions | D-01..D-30 | 30/30 honoured (`check.decision-coverage-verify`); D-03, D-19 and D-27 have the plan-05-level partial gaps above | +| CONTEXT decisions | D-01..D-30 | 30/30 honored; D-03, D-19, D-21 and D-27, which the plan 05 gaps touched, are now fully satisfied | | Plan 01 | SC-1, SC-2, D-01, D-02, D-04, D-05, D-08, D-09, D-10, D-12 | ✓ SATISFIED | | Plan 02 | SC-2, SC-3, D-01..D-04, D-13..D-18, D-27, D-28, D-30 | ✓ SATISFIED | -| Plan 03 | SC-3, SC-4, SC-5, D-04..D-07, D-11, D-17..D-29 | ✓ SATISFIED (prohibition flag, gap 2) | +| Plan 03 | SC-3, SC-4, SC-5, D-04..D-07, D-11, D-17..D-29 | ✓ SATISFIED | | Plan 04 | SC-5 and D-03, D-08..D-10, D-12..D-19, D-21, D-23, D-25, D-27..D-29 | ✓ SATISFIED | -| Plan 05 | D-03, D-04, D-10, D-12, D-18, D-19, D-21, D-25, D-27..D-29 | ⚠️ PARTIAL (gaps 1-3) | +| Plan 05 | D-03, D-04, D-10, D-12, D-18, D-19, D-21, D-25, D-27..D-29 | ✓ SATISFIED (was PARTIAL) | | Plan 06 | D-26 | ✓ SATISFIED | -### Decision Coverage - -All trackable CONTEXT.md decisions are honored by shipped artifacts (30/30). - ### Prohibitions | Plan | Prohibition | Tier | Disposition | |------|-------------|------|-------------| -| 01 | Only bonfire and diary import charm modules | judgment (checked mechanically) | Holds: `go list` imports | -| 01 | Nothing imports gopkg.in/yaml.v3 | judgment (checked mechanically) | Holds: grep is empty | -| 01-03 | No consuming application named in framework code and docs | judgment | LLM-judge: holds (gate docs stage, 67 files clean); non-authoritative | -| 01-06 | Nothing pushed or tagged before the go-ahead; no force-push; no deploy | judgment | LLM-judge: holds (replies recorded before the tags; v0.4.2 tags the reply commit itself); non-authoritative | -| 02 | No method added to Output, Input or Progress | judgment (checked mechanically) | Holds: the Output and Input interface blocks are byte-identical at bde7d9f and HEAD; Command gained only `Examples` and `Hidden` | +| 01 | Only bonfire and diary import charm modules | judgment (checked mechanically) | Holds: `internal/argmask` imports only `strings` | +| 01 | Nothing imports gopkg.in/yaml.v3 | judgment (checked mechanically) | Holds | +| 01-03 | No consuming application named in framework code and docs | judgment | LLM-judge: holds (gate docs stage, 67 files clean at HEAD); non-authoritative | +| 01-06 | Nothing pushed or tagged before the go-ahead; no force-push; no deploy | judgment | LLM-judge: holds (the gap-closure commits are local and untagged); non-authoritative | +| 02 | No method added to Output, Input or Progress | judgment (checked mechanically) | Holds: no exported change in the gap-closure diff | | 02 | No prompt blocks a non-TTY, -n or -q run | judgment | Holds per TestPromptsNoInteraction, TestConfirmProceed, TestConfirmProductionNonTTYProceeds | -| 03 | No command name or flag removed or renamed | judgment | LLM-judge: holds (plan 06 gate's additive check); non-authoritative, not re-run | -| 03 | Summary, hints and logs never print a DSN password, key, token or secret | judgment | **Violated (flagged)**: the wrong-directory hint with a dash-leading value, and the delegate signal error block (gap 2) | -| 04 | No test skipped or weakened; goldens free of credentials | judgment | LLM-judge: holds (only conditional skips for root, platform or Docker; the gate fails on a skipped required name); non-authoritative | -| 05 | No exported identifier removed or changed | judgment | LLM-judge: holds (plan 05 API check; only WithExitCode and Sanitize added); non-authoritative | -| 05 | WR-01 fixed inside live views; generated main unchanged | judgment | Holds: generated main has no signal code; internal/build untouched by plan 05 | +| 03 | No command name or flag removed or renamed | judgment | LLM-judge: holds (migrate:status kept its name, flags, Description and Examples; only its Long help changed); non-authoritative | +| 03 | Summary, hints and logs never print a DSN password, key, token or secret | judgment | LLM-judge: **holds for every known path** (was violated). The wrong-directory hint with a dash-leading value and the delegate signal and start-failure errors now mask through `internal/argmask`; reproduced with built binaries. Non-authoritative | +| 04 | No test skipped or weakened; goldens free of credentials | judgment | LLM-judge: holds. The WR-12 rework returned TestTwoPluginMigrationSetsIsolated and TestDocsMigrate to their pre-57a849d form rather than weakening them; non-authoritative | +| 05 | No exported identifier removed or changed | judgment (checked mechanically) | Holds: `git diff a28957f..HEAD` over modules, cmd and internal (non-test) shows only `argmask.Join` and `argmask.Quote` added, both under `internal/`; `lagoon.Status` keeps its signature and its plugin-only result | +| 05 | WR-01 fixed inside live views; generated main unchanged | judgment | Holds: internal/build and cmd/summer/main.go are unchanged since the first verification | | 06 | Changelog token never printed | judgment | LLM-judge: holds per SUMMARY; non-authoritative | ### Test Quality Audit @@ -419,60 +440,43 @@ All trackable CONTEXT.md decisions are honored by shipped artifacts (30/30). | Test area | Linked | Skipped | Circular | Assertion level | Verdict | |-----------|--------|---------|----------|-----------------|---------| | diary (30 named) | SC-1, D-08..D-12 | 1 conditional (root) | no | value/behavioral (slogtest conformance) | OK | -| bonfire goldens | D-13, D-14, D-18 | 0 | partial: created with `-update` from the code, then read against the previews by a person | value | OK, provenance PARTIAL (human item 1) | -| bonfire behavior (live, signals, exit codes) | D-03, D-18, D-27 | 0 | no | behavioral (helper processes, pty) | OK; does not cover cancellation (gap 1) | -| lagoon Docker | D-21, WR-07 | 0 under Docker | no | value | TestMigrateStatusJSON does not assert framework sets (gap 3) | -| cmd/summer runtime | CR-02, CR-03, WR-03 | POSIX-only conditionals | no | behavioral | No signal-death leak case (gap 2) | +| bonfire goldens | D-13, D-14, D-18 | 0 | partial: created with `-update` | value | OK, provenance PARTIAL (human item 1) | +| bonfire behavior (live, signals, exit codes) | D-03, D-18, D-27 | 0 | no | behavioral (helper processes, pty, cancellation) | OK; cancellation now covered by TestPrintAboveAfterCancel | +| lagoon Docker | D-21, WR-07, WR-12, WR-13 | 0 under Docker | no | value | OK; TestMigrateStatusJSON asserts a pending framework migration | +| cmd/summer runtime | CR-02, CR-03, WR-03, WR-10 | POSIX-only conditionals | no | behavioral | OK; signal-death and start-failure leak cases covered | -Disabled tests on requirements: 0. Circular: 0 blocking. Insufficient assertions: 2 warnings, both tied to gaps 1 and 3. +Disabled tests on requirements: 0. Circular: 0 blocking. Insufficient assertions: 0. One small note carried from the quick verification: printAbove's "Run ended on its own" branch (not via cancellation) has no committed pinning test; the cancellation branch it shares code with is pinned. ### Anti-Patterns Found | File | Line | Pattern | Severity | Impact | |------|------|---------|----------|--------| -| internal/build/artifact.go | 182 | `"TODO: describe " + cmdName` | ℹ️ Info | A template string that the scaffolder writes into generated commands (from 2026-09-18, before this phase; the folded todo deliberately leaves the scaffolder unchanged) | -| cmd/summer/main.go, runtime.go, modules/flare/commands.go | n/a | gofmt drift | ℹ️ Info | Pre-existing, recorded in deferred-items.md | +| internal/build/artifact.go | 182 | `"TODO: describe " + cmdName` | ℹ️ Info | A template string the scaffolder writes into generated commands (pre-phase) | +| cmd/summer/main.go, runtime.go, runtime_test.go, modules/flare/commands.go | n/a | gofmt drift | ℹ️ Info | Pre-existing, recorded in deferred-items.md and in the quick SUMMARY | +| modules/lagoon/commands.go | migrate:status Description | "Show per-plugin migration history" / example "Show the applied migrations per plugin" | ℹ️ Info | The command now also lists framework sets; the Long help says so, but the one-line description still says per-plugin. Kept unchanged on purpose (P-06); cosmetic | -No TBD, FIXME or XXX in any file this phase changed. +No TBD, FIXME or XXX in any file this phase or the gap-closure task changed; no TODO or HACK added. ### Human Verification Required -These items stay open even though the status is `gaps_found`. They are visual or terminal checks, not missing code. +The goal is achieved; these are the confirmation checks from the first report. Three are visual or terminal checks the contract always routes to a person, and one is the explicit resolution of judgment-tier prohibitions. None is a suspected defect. 1. **Styled list, help and error on a real terminal.** Run `summer`, `bin/`, `bin/ help admin:token:create` and `bin/ bogus`. Expected: the output matches the D-13, D-14 and D-18 previews in palette and alignment. Why human: the goldens came from the code itself. -2. **Live widgets and prompts.** Run Spinner, Progress, Process, Choice, Ask, Confirm and Secret on a pty, then press Ctrl+C during a spinner. Expected: SSU-like look; log lines print above the view; the cursor comes back. Why human: animation and keyboard input. +2. **Live widgets and prompts.** Run Spinner, Progress, Process, Choice, Ask, Confirm and Secret on a pty, then press Ctrl+C during a spinner. Expected: SSU-like look; log lines print above the view; the cursor comes back. Why human: animation and keyboard input. (The cancellation path of gap 1 is now covered by a test and a pty probe; this item is about look and feel.) 3. **serve on a real application.** Run it at the default verbosity, with `-q` and with `-v`, then stop it with Ctrl+C; also run `summer dev`. Expected: a readable startup block, component-prefixed INFO lines, a shutdown report, exit 0. Why human: readability. -4. **Judgment-tier prohibitions.** Confirm or reject the non-authoritative verdicts in the Prohibitions table. +4. **Judgment-tier prohibitions.** Confirm or reject the non-authoritative verdicts in the Prohibitions table. The secrets prohibition is no longer flagged as violated. ### Gaps Summary -All five roadmap success criteria hold in the codebase. diary, the bonfire console layer, the command sweep across the framework and the 15 plugin repos, the docs, the landing page, the deck and the tests are in place, wired and green: vet, the short suites, the gate's go, hello, docs and docker stages, and the spot-checks with built binaries. The three gaps are all in the gap-closure round's own contract (plan 05), which the re-review reported as partial. Each was reproduced or confirmed in the code: +No gaps remain. All five roadmap success criteria and all 52 plan truths hold in the codebase at HEAD `4141cd9`. The three gaps of the first report were each re-checked in the code, with the named pinning tests, and with an independent run that reproduced the original failure scenario: -1. **Live view lifecycle (WR-09):** after a context cancellation, lines are lost while `PrintAbove` reports success. Root cause: the view stays registered after the program has stopped. Fix it together with WR-14 (sanitize Process's plain path), since both touch `Process`. -2. **Argv masking (WR-11, WR-10):** one rule is applied inconsistently. A dash-leading secret value is not masked, and the delegate signal path echoes the raw argv. A shared masking helper fixes both. -3. **Migration reporting (WR-12):** `migrate:status --json` is still per-plugin, so framework sets are invisible to scripts. WR-13 (exit 1 after a successful migrate when the re-read fails) is in the same file and can be fixed with it. +1. **Live view lifecycle (WR-09):** a cancelled view now ends with its last frame and is unregistered without waiting for the work function. Later lines print plainly, and `PrintAbove` reports false. The pty probe passed 5/5, where the first verification had failed 3/3. +2. **Argv masking (WR-11, WR-10):** one helper (`internal/argmask`) masks dash-leading values and is used by both the wrong-directory hint and summer's delegate errors. Built binaries no longer print `-Xk9q`, `hunter2` or `t0k3n`. +3. **Migration reporting (WR-12):** `migrate:status` (table and `--json`) reads the same `migrationSets` as `migrate`, so framework sets and their pending migrations are listed. The exported `lagoon.Status` keeps its plugin-only contract, and the fonoteka parity consumer passes. -No later phase in the milestone covers these (Phases 20, 30 and 31 are demo, cutover and chat work), so nothing is deferred. The remaining open findings (WR-13, WR-14, the exit-130 suggestion in WR-10, IN-10..IN-15) are follow-up quality items and can go to the same todo as IN-01..IN-09. - -**If the user decides to accept these as follow-ups instead of a third fix round**, add to this file's frontmatter: - -```yaml -overrides: - - must_have: "CR-01 (D-03, D-27): lines printed while a Spinner, Progress or Process view runs appear in the order they were printed and none is lost when the view ends" - reason: "Holds on normal completion; the context-cancellation path (WR-09) is tracked as a follow-up" - accepted_by: "" - accepted_at: "" - - must_have: "WR-08 (D-19): the wrong-directory Try line masks secret flag values in both the --flag value and --flag=value forms" - reason: "Dash-leading values (WR-11) and the delegate signal path (WR-10) are tracked as a follow-up; --password is deprecated and warns that the value is visible" - accepted_by: "" - accepted_at: "" - - must_have: "WR-07 (D-21, D-04): Migrate applies exactly the sets migrationSets lists, including migrate:status --json" - reason: "migrate:status is documented as per-plugin; framework sets in its JSON (WR-12) are tracked as a follow-up" - accepted_by: "" - accepted_at: "" -``` +The follow-up items WR-13, WR-14, IN-14 and IN-15 are fixed too. IN-10..IN-13, IN-01..IN-09 and the exit-130 idea are recorded as deferred in the console review todo. The gap-closure commits are local and unreleased; shipping them needs a v0.4.x tag on the user's go-ahead. --- -_Verified: 2026-10-22T01:32:12Z_ +_Verified: 2026-10-22T02:37:57Z_ _Verifier: Claude (msd-verifier)_