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 new file mode 100644 index 00000000..2e3b197c --- /dev/null +++ b/.planning/phases/19.8-console-commands-overhaul/19.8-VERIFICATION.md @@ -0,0 +1,478 @@ +--- +phase: 19.8-console-commands-overhaul +verified: 2026-10-22T01:32:12Z +status: gaps_found +score: 54/57 must-haves verified +covered_files: + - ".gitignore" + - ".planning/phases/19.8-console-commands-overhaul/19.8-01-PLAN.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-01-SUMMARY.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-02-PLAN.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-02-SUMMARY.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-03-PLAN.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-03-SUMMARY.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-04-PLAN.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-04-SUMMARY.md" + - ".planning/phases/19.8-console-commands-overhaul/19.8-05-PLAN.md" + - ".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" + - "README.md" + - "cmd/summer/commands_documented_test.go" + - "cmd/summer/docs.go" + - "cmd/summer/docs_test.go" + - "cmd/summer/main.go" + - "cmd/summer/parity.go" + - "cmd/summer/runtime.go" + - "cmd/summer/runtime_test.go" + - "docs/console/introduction.md" + - "docs/console/scaffolding.md" + - "docs/console/setup-and-maintenance.md" + - "docs/console/utilities.md" + - "docs/console/writing-commands.md" + - "docs/examples/blog/console/publish.go" + - "docs/examples/blog/console/publish_test.go" + - "docs/services/configuration.md" + - "docs/services/logging.md" + - "docs/setup/configuration.md" + - "docs/setup/installation.md" + - "docs/setup/porting-a-plugin.md" + - "docs/setup/upgrading.md" + - "examples/hello/hello_test.go" + - "examples/hello/main.go" + - "examples/hello/plugins/greeter/plugin.go" + - "go.mod" + - "go.sum" + - "internal/build/artifact.go" + - "internal/build/build.go" + - "internal/build/build_test.go" + - "internal/build/manifest.go" + - "internal/build/new.go" + - "internal/build/new_golden_test.go" + - "internal/build/scaffold.go" + - "internal/build/stubs/new.tmpl" + - "internal/build/testdata/new-no-plugin/CLAUDE.md.golden" + - "internal/build/testdata/new/CLAUDE.md.golden" + - "internal/build/testdata/new/config__log.yaml.golden" + - "internal/build/testdata/new/main.go.golden" + - "internal/dev/watch.go" + - "internal/dev/watch_test.go" + - "internal/docsite/check_commands.go" + - "internal/docsite/check_commands_test.go" + - "internal/docsite/checks_test.go" + - "modules/beachcomber/README.md" + - "modules/beachcomber/beachcomber.go" + - "modules/bonfire/README.md" + - "modules/bonfire/command.go" + - "modules/bonfire/docs.go" + - "modules/bonfire/docs_test.go" + - "modules/bonfire/errors.go" + - "modules/bonfire/errors_test.go" + - "modules/bonfire/example_test.go" + - "modules/bonfire/execute.go" + - "modules/bonfire/globals.go" + - "modules/bonfire/globals_test.go" + - "modules/bonfire/golden_test.go" + - "modules/bonfire/help.go" + - "modules/bonfire/help_smoke_test.go" + - "modules/bonfire/helpers.go" + - "modules/bonfire/list.go" + - "modules/bonfire/list_smoke_test.go" + - "modules/bonfire/live.go" + - "modules/bonfire/live_signal_unix_test.go" + - "modules/bonfire/live_test.go" + - "modules/bonfire/output.go" + - "modules/bonfire/prompts.go" + - "modules/bonfire/root.go" + - "modules/bonfire/root_test.go" + - "modules/bonfire/selector.go" + - "modules/bonfire/styles.go" + - "modules/bonfire/testdata/error_chain_verbose.golden" + - "modules/bonfire/testdata/error_hint.golden" + - "modules/bonfire/testdata/error_unknown_command.golden" + - "modules/bonfire/testdata/help_passthrough.golden" + - "modules/bonfire/testdata/help_token_create.golden" + - "modules/bonfire/testdata/list.golden" + - "modules/bonfire/testdata/list.json.golden" + - "modules/bonfire/testdata/list_all.golden" + - "modules/bonfire/testdata/list_styled.golden" + - "modules/bonfire/version.go" + - "modules/bonfire/version_test.go" + - "modules/bonfire/widgets.go" + - "modules/bonfire/widgets_smoke_test.go" + - "modules/bonfire/widgets_test.go" + - "modules/bonfire/wrongdir_smoke_test.go" + - "modules/bouncer/README.md" + - "modules/bouncer/turnstile.go" + - "modules/cabana/README.md" + - "modules/cabana/account.go" + - "modules/cabana/account_preferences.go" + - "modules/cabana/account_tokens.go" + - "modules/cabana/actions.go" + - "modules/cabana/api_tokens.go" + - "modules/cabana/auth.go" + - "modules/cabana/commands.go" + - "modules/cabana/contracts.go" + - "modules/cabana/crud.go" + - "modules/cabana/field_dependent.go" + - "modules/cabana/field_file.go" + - "modules/cabana/field_type.go" + - "modules/cabana/http.go" + - "modules/cabana/log.go" + - "modules/cabana/partial_render.go" + - "modules/cabana/query.go" + - "modules/cabana/relation_field.go" + - "modules/cabana/reorder.go" + - "modules/cabana/singleton.go" + - "modules/cabana/token_commands.go" + - "modules/cabana/token_guard.go" + - "modules/cabana/token_json_test.go" + - "modules/conga/README.md" + - "modules/conga/client.go" + - "modules/conga/commands.go" + - "modules/conga/commands_test.go" + - "modules/conga/confirm_linux_test.go" + - "modules/conga/conga.go" + - "modules/conga/logger_smoke_test.go" + - "modules/conga/logger_test.go" + - "modules/conga/schedule_test.go" + - "modules/conga/stats_test.go" + - "modules/conga/worker.go" + - "modules/cooler/README.md" + - "modules/cooler/cooler.go" + - "modules/cooler/memory.go" + - "modules/cooler/ratelimit.go" + - "modules/cooler/rediscache.go" + - "modules/cooler/sitecache.go" + - "modules/diary/README.md" + - "modules/diary/channels.go" + - "modules/diary/component.go" + - "modules/diary/config.go" + - "modules/diary/config_smoke_test.go" + - "modules/diary/config_test.go" + - "modules/diary/console.go" + - "modules/diary/console_test.go" + - "modules/diary/daily.go" + - "modules/diary/daily_test.go" + - "modules/diary/diary.go" + - "modules/diary/diary_test.go" + - "modules/diary/example_test.go" + - "modules/diary/retire_internal_test.go" + - "modules/diary/slogtest_test.go" + - "modules/diary/tracer_smoke_test.go" + - "modules/flare/README.md" + - "modules/flare/commands.go" + - "modules/flare/commands_test.go" + - "modules/flare/flare.go" + - "modules/lagoon/README.md" + - "modules/lagoon/attach/bucket.go" + - "modules/lagoon/attach/thumb.go" + - "modules/lagoon/commands.go" + - "modules/lagoon/commands_flags_test.go" + - "modules/lagoon/connection.go" + - "modules/lagoon/encrypted.go" + - "modules/lagoon/fill.go" + - "modules/lagoon/keygen.go" + - "modules/lagoon/logger_smoke_test.go" + - "modules/lagoon/logger_test.go" + - "modules/lagoon/migrations.go" + - "modules/lagoon/pending_test.go" + - "modules/lagoon/pty_linux_test.go" + - "modules/lagoon/purge.go" + - "modules/lagoon/transaction.go" + - "modules/lighthouse/README.md" + - "modules/lighthouse/centrifugo/client.go" + - "modules/lighthouse/centrifugo/commands.go" + - "modules/lighthouse/lighthouse.go" + - "modules/phrasebook/README.md" + - "modules/phrasebook/translator.go" + - "modules/postcard/README.md" + - "modules/postcard/drivers.go" + - "modules/postcard/mailer.go" + - "modules/sunscreen/README.md" + - "modules/sunscreen/sunscreen.go" + - "modules/sunscreen/sunscreen_test.go" + - "modules/surf/README.md" + - "modules/surf/accesslog.go" + - "modules/surf/accesslog_test.go" + - "modules/surf/routelist_command.go" + - "modules/surf/serve.go" + - "modules/surf/serve_lifecycle_test.go" + - "modules/surf/serve_summary_smoke_test.go" + - "modules/surf/serve_test.go" + - "modules/surf/summary.go" + - "modules/surf/summary_test.go" + - "modules/wristband/README.md" + - "modules/wristband/oidc_token.go" + - "scripts/check-phase19.8.sh" +covered_digest: "v2:sha256:8730d7a9b8f0468f2903e7c4b99cae20366899ae4ecc64e569cd608fa636e4de" +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" +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" + why_human: "Visual layout and palette; the goldens were produced with -update from the code itself, so only a person can compare them with the previews" + - test: "On a real terminal, run a command that uses Spinner, Progress, Process, Choice, Ask, Confirm and Secret (or the throwaway pty program from plan 02); press Ctrl+C during a spinner" + expected: "SSU-like animation, arrow-key selector with confirmation screen, huh prompts; diary log lines print above the view; after Ctrl+C the cursor is visible and the shell is usable" + why_human: "Animation, keyboard interaction and terminal restore cannot be asserted by the short suite (plans 01, 02 and 04 recorded human_judgment: true)" + - test: "Run 'bin/ serve' against a real database on a terminal, then with -q, then with -v, then press Ctrl+C; run 'summer dev' and stop it" + 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)" + 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). + +**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. + +## Verdict on the open review findings (asked explicitly) + +The re-review (19.8-REVIEW.md, 0 critical, 6 warnings, 6 info) leaves 12 findings open. The verdict for each: + +| 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` | + +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. + +## Goal Achievement + +### Roadmap Success Criteria + +| # | 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. | + +### 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). | + +**Score:** 54/57 truths verified (5 SC + 52 plan truths; 3 partial failures, all in plan 05; 0 present-but-behavior-unverified) + +### 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/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 | + +### 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 | 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) | +| surf/accesslog.go | diary | `diary.For("http")` | ✓ WIRED | +| surf/serve.go | lagoon | `lagoon.PendingMigrations(` | ✓ WIRED | +| 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) | + +### Data-Flow Trace (Level 4) + +| 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 | +| http request log | method, pattern, status | `recordPattern` in the route mux | yes (TestAccessLog*) | ✓ FLOWING | + +### Behavioral Spot-Checks (verifier-run) + +| 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 | +| 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 | +| 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) | + +### Probe Execution + +No `scripts/*/tests/probe-*.sh` exist. The phase's probe is `scripts/check-phase19.8.sh`: + +| 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. + +### Requirements Coverage + +There are no REQUIREMENTS.md IDs for this phase (none orphaned). The plans' `requirements:` fields cite SC-1..SC-5 and D-01..D-30: + +| 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 | +| 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 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 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` | +| 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 | +| 06 | Changelog token never printed | judgment | LLM-judge: holds per SUMMARY; non-authoritative | + +### Test Quality Audit + +| 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) | + +Disabled tests on requirements: 0. Circular: 0 blocking. Insufficient assertions: 2 warnings, both tied to gaps 1 and 3. + +### 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 | + +No TBD, FIXME or XXX in any file this phase changed. + +### Human Verification Required + +These items stay open even though the status is `gaps_found`. They are visual or terminal checks, not missing code. + +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. +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. + +### 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: + +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. + +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: "" +``` + +--- + +_Verified: 2026-10-22T01:32:12Z_ +_Verifier: Claude (msd-verifier)_