From 49f3aef108e18241f0459d9b94774648078fc935 Mon Sep 17 00:00:00 2001 From: warren-agent Date: Mon, 15 Jun 2026 10:17:26 +0000 Subject: [PATCH 1/3] mulch: canonicalize ml upgrade --json key to up_to_date (mulch-4ca6) ml upgrade --json previously emitted upToDate (camelCase) while ml onboard --json emitted the same up-to-date concept as the snake_case action value up_to_date. Rename upgrade's JSON field to up_to_date to match mulch's snake_case JSON convention (e.g. not_installed, default_mode, extracts_files). The Bun-local upToDate identifier in src/commands/upgrade.ts is unchanged; only the emitted JSON key flips. - src/commands/upgrade.ts: emit up_to_date in all three JSON paths - test/commands/upgrade.test.ts: assert parsed.up_to_date - CHANGELOG.md: Unreleased entry documenting the key rename Closes step 1 of pl-b637 (nightwatch patrol 2026-06-15). --- CHANGELOG.md | 4 ++++ src/commands/upgrade.ts | 6 +++--- test/commands/upgrade.test.ts | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42e5c02..60939e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **`ml upgrade --json` key canonicalized to `up_to_date`** (closes mulch-4ca6): the `upgrade` JSON output previously emitted `upToDate` (camelCase) while `ml onboard --json` emitted the same concept as the snake_case action value `up_to_date`. The `upgrade` payload now uses `up_to_date` to match the rest of mulch's snake_case JSON convention (e.g. `not_installed`, `default_mode`, `extracts_files`). Consumers that read `parsed.upToDate` must switch to `parsed.up_to_date`; the boolean semantics are unchanged. + ## [0.10.7] - 2026-06-02 A targeted bug-fix release. Published consumers of `@os-eco/mulch-cli` running in an interactive TTY hit pino's pretty-transport path even though `pino-pretty` ships only as a devDependency, causing pino to throw `unable to determine transport target for "pino-pretty"`. The diagnostic logger now probes `pino-pretty` resolvability and degrades to JSON-on-stderr when it is absent, honoring the documented JSON-for-consumers promise. No schema, hook-event, config-key, or public CLI-command changes. 1497 tests across 71 files / 3854 expect() calls (up from 1494 / 71 / 3849 in 0.10.6). diff --git a/src/commands/upgrade.ts b/src/commands/upgrade.ts index 0a18bbb..09f35db 100644 --- a/src/commands/upgrade.ts +++ b/src/commands/upgrade.ts @@ -37,7 +37,7 @@ export function registerUpgradeCommand(program: Command): void { command: "upgrade", current, latest, - upToDate: true, + up_to_date: true, updated: false, }); } else { @@ -53,7 +53,7 @@ export function registerUpgradeCommand(program: Command): void { command: "upgrade", current, latest, - upToDate: false, + up_to_date: false, updated: false, }); } else { @@ -83,7 +83,7 @@ export function registerUpgradeCommand(program: Command): void { command: "upgrade", current, latest, - upToDate: false, + up_to_date: false, updated: true, }); } else { diff --git a/test/commands/upgrade.test.ts b/test/commands/upgrade.test.ts index f3672b4..80af65c 100644 --- a/test/commands/upgrade.test.ts +++ b/test/commands/upgrade.test.ts @@ -64,7 +64,7 @@ describe("upgrade command", () => { expect(parsed.command).toBe("upgrade"); expect(typeof parsed.current).toBe("string"); expect(typeof parsed.latest).toBe("string"); - expect(typeof parsed.upToDate).toBe("boolean"); + expect(typeof parsed.up_to_date).toBe("boolean"); expect(parsed.updated).toBe(false); } }); From b3c70c31db12643f1f100a71dcd8a1a2df81a357 Mon Sep 17 00:00:00 2001 From: warren-agent Date: Mon, 15 Jun 2026 10:17:56 +0000 Subject: [PATCH 2/3] mulch: record cli snake_case JSON convention + close mulch-4ca6 --- .mulch/expertise/cli.jsonl | 1 + .seeds/issues.jsonl | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.mulch/expertise/cli.jsonl b/.mulch/expertise/cli.jsonl index 2212d0a..fe1c3b2 100644 --- a/.mulch/expertise/cli.jsonl +++ b/.mulch/expertise/cli.jsonl @@ -211,3 +211,4 @@ {"type":"pattern","classification":"tactical","recorded_at":"2026-05-28T17:38:57.949Z","evidence":{"seeds":"mulch-a11b","commit":"968089263e0ba4007a82a67a2a7496b7a26a28cf"},"name":"l5-check-all-ci-wiring","description":"L5 check:all aggregator chains fail-fast: check:size && check:debt && check:dups && check:deps && check:agents && check:coverage. CI runs test:ci BEFORE check:all so check:coverage reads the freshly-written coverage/lcov.info. mulch's test:ci writes junit.xml at repo root (not test-results/), so upload-artifact paths are coverage/lcov.info and junit.xml. report:timing/report:quality self-append to $GITHUB_STEP_SUMMARY (no redirect needed).","files":[".seeds/issues.jsonl",".seeds/plans.jsonl"],"tags":["author:jayminwest"],"id":"mx-aeea73"} {"type":"convention","classification":"tactical","recorded_at":"2026-05-28T18:57:29.972Z","evidence":{"commit":"9680892","seeds":"mulch-6048"},"content":"L5 check:all coverage ratchet runs at the very end of the chain (check:size→debt→dups→deps→agents→coverage) and is the gate most likely to fail: line coverage sits at 83.99% against an 83% floor (≈1% margin), so a single new under-tested file can break CI. When adding source files, add tests in the same commit or expect check:all/CI red. Floors live in scripts/coverage-budgets.json.","tags":["author:jayminwest"],"id":"mx-52f52d"} {"type":"failure","classification":"tactical","recorded_at":"2026-06-02T19:23:18.124Z","evidence":{"seeds":"mulch-35c9","commit":"a82ceb059e64c18cb37adc6952305b97b6bb865f"},"description":"pino-pretty is a devDependency, so selecting the pino-pretty transport in src/log.ts whenever stderr.isTTY makes published consumers (npm i -g, bun add, prod installs) throw 'unable to determine transport target for pino-pretty' in interactive terminals.","resolution":"Gate the pretty path on isPinoPrettyAvailable() (createRequire(import.meta.url).resolve in try/catch); fall back to pino.destination(2) JSON-on-stderr when pino-pretty is absent. createLogger accepts a prettyAvailable override so tests can exercise the fallback without uninstalling the dep.","tags":["author:jayminwest"],"id":"mx-c59e1e"} +{"type":"convention","classification":"tactical","recorded_at":"2026-06-15T10:17:41.198Z","evidence":{"commit":"49f3aef108e18241f0459d9b94774648078fc935"},"content":"All ml subcommands emit snake_case JSON keys (up_to_date, not_installed, default_mode, extracts_files, etc.). When adding a new --json field, use snake_case. ml upgrade --json originally used camelCase upToDate; it was renamed to up_to_date in mulch-4ca6 to match ml onboard --json and the rest of the codebase. Mixed-case JSON for the same concept across commands is a defect, not a style choice.","id":"mx-ab3155"} diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index 4f93af4..3715a11 100644 --- a/.seeds/issues.jsonl +++ b/.seeds/issues.jsonl @@ -332,11 +332,11 @@ {"id":"mulch-ab79","title":"Add the canonical scripts/check-all.ts quiet runner copied byte-identical from templates/l5-toolkit/scripts/check-all.ts, with mulch's exported GATES manifest in the standard's order: lint, typecheck, check:agents, check:dups, check:deps, check:size, check:debt, check:coverage, check:ci-parity (last) -- note lint and typecheck must be ADDED to the manifest (they exist as scripts but are absent from the current && chain). Replace package.json check:all with `bun scripts/check-all.ts`, add `verify`: `bun run check:all`, and add scripts/check-all.test.ts. Confirm the quiet-output contract.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:56:59.979Z","plan_id":"pl-237d","blocks":["mulch-c658","mulch-f16f"],"closedAt":"2026-06-12T05:56:59.979Z"} {"id":"mulch-c658","title":"Add scripts/check-ci-parity.ts (with test) copied from templates/l5-toolkit/scripts, importing the GATES array from check-all.ts; add the check:ci-parity script as the final gate in the manifest. Reconcile any residual non-canonical gate name. Verify check:ci-parity passes against .github/workflows/ci.yml.","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.030Z","plan_id":"pl-237d","blocks":["mulch-c6f8","mulch-f16f"],"closedAt":"2026-06-12T05:57:00.030Z"} {"id":"mulch-c6f8","title":"Wire .github/workflows/ci.yml to invoke the canonical gates (or `bun run check:all`) so the local manifest matches CI. Run `bun run check:all` and `bun run verify` green end-to-end with the quiet-output contract and a passing check:ci-parity.","status":"closed","type":"task","priority":2,"plan_step_index":2,"description":"\nStep 3 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.083Z","plan_id":"pl-237d","blocks":["mulch-f16f"],"closedAt":"2026-06-12T05:57:00.083Z"} -{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-4ca6","mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]} -{"id":"mulch-4ca6","title":"Canonicalize JSON `up_to_date` vs `upToDate` across upgrade/onboard output","status":"open","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} +{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]} +{"id":"mulch-4ca6","title":"Canonicalize JSON `up_to_date` vs `upToDate` across upgrade/onboard output","status":"closed","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:17:52.971Z","closeReason":"Landed in 49f3aef: ml upgrade --json now emits up_to_date (snake_case) to match ml onboard --json. Test + CHANGELOG updated. bun run verify 9/9 green."} {"id":"mulch-fed1","title":"Dedupe local parseStrictPositiveInt/parseStrictNonNegativeNumber copies; import from src/utils/numeric-flags.ts","status":"open","type":"task","priority":3,"plan_step_index":1,"description":"\nStep 2 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-4bd0","title":"Replace `(err as Error).message` with `err instanceof Error ? err.message : String(err)` across src/commands and src/utils","status":"open","type":"task","priority":3,"plan_step_index":2,"description":"\nStep 3 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-9465","title":"Fix path-segment boundary in src/utils/git.ts fileMatchesAny + add false-positive coverage","status":"open","type":"task","priority":2,"plan_step_index":3,"description":"\nStep 4 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-a424","title":"Unify JSON vs human error wording in src/commands/ready.ts unknown-domain branch","status":"open","type":"task","priority":3,"plan_step_index":4,"description":"\nStep 5 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-4dc4","title":"Backfill direct unit tests for src/utils/domain-rules.ts and src/utils/format-helpers.ts","status":"open","type":"task","priority":3,"plan_step_index":5,"description":"\nStep 6 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} -{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-4ca6","mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]} +{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]} From 45735704478b6fee9b49b28bf79b2be6fa40f259 Mon Sep 17 00:00:00 2001 From: warren Date: Mon, 15 Jun 2026 10:18:09 +0000 Subject: [PATCH 3/3] chore(warren): seeds state --- .seeds/issues.jsonl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index 3715a11..f201fbb 100644 --- a/.seeds/issues.jsonl +++ b/.seeds/issues.jsonl @@ -332,11 +332,11 @@ {"id":"mulch-ab79","title":"Add the canonical scripts/check-all.ts quiet runner copied byte-identical from templates/l5-toolkit/scripts/check-all.ts, with mulch's exported GATES manifest in the standard's order: lint, typecheck, check:agents, check:dups, check:deps, check:size, check:debt, check:coverage, check:ci-parity (last) -- note lint and typecheck must be ADDED to the manifest (they exist as scripts but are absent from the current && chain). Replace package.json check:all with `bun scripts/check-all.ts`, add `verify`: `bun run check:all`, and add scripts/check-all.test.ts. Confirm the quiet-output contract.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"\nStep 1 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:56:59.979Z","plan_id":"pl-237d","blocks":["mulch-c658","mulch-f16f"],"closedAt":"2026-06-12T05:56:59.979Z"} {"id":"mulch-c658","title":"Add scripts/check-ci-parity.ts (with test) copied from templates/l5-toolkit/scripts, importing the GATES array from check-all.ts; add the check:ci-parity script as the final gate in the manifest. Reconcile any residual non-canonical gate name. Verify check:ci-parity passes against .github/workflows/ci.yml.","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"\nStep 2 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.030Z","plan_id":"pl-237d","blocks":["mulch-c6f8","mulch-f16f"],"closedAt":"2026-06-12T05:57:00.030Z"} {"id":"mulch-c6f8","title":"Wire .github/workflows/ci.yml to invoke the canonical gates (or `bun run check:all`) so the local manifest matches CI. Run `bun run check:all` and `bun run verify` green end-to-end with the quiet-output contract and a passing check:ci-parity.","status":"closed","type":"task","priority":2,"plan_step_index":2,"description":"\nStep 3 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.083Z","plan_id":"pl-237d","blocks":["mulch-f16f"],"closedAt":"2026-06-12T05:57:00.083Z"} -{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]} -{"id":"mulch-4ca6","title":"Canonicalize JSON `up_to_date` vs `upToDate` across upgrade/onboard output","status":"closed","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:17:52.971Z","closeReason":"Landed in 49f3aef: ml upgrade --json now emits up_to_date (snake_case) to match ml onboard --json. Test + CHANGELOG updated. bun run verify 9/9 green."} +{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:18:09.429Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]} +{"id":"mulch-4ca6","title":"Canonicalize JSON `up_to_date` vs `upToDate` across upgrade/onboard output","status":"closed","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:18:09.429Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:18:09.429Z","closeReason":"Landed in 49f3aef: ml upgrade --json now emits up_to_date (snake_case) to match ml onboard --json. Test + CHANGELOG updated. bun run verify 9/9 green."} {"id":"mulch-fed1","title":"Dedupe local parseStrictPositiveInt/parseStrictNonNegativeNumber copies; import from src/utils/numeric-flags.ts","status":"open","type":"task","priority":3,"plan_step_index":1,"description":"\nStep 2 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-4bd0","title":"Replace `(err as Error).message` with `err instanceof Error ? err.message : String(err)` across src/commands and src/utils","status":"open","type":"task","priority":3,"plan_step_index":2,"description":"\nStep 3 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-9465","title":"Fix path-segment boundary in src/utils/git.ts fileMatchesAny + add false-positive coverage","status":"open","type":"task","priority":2,"plan_step_index":3,"description":"\nStep 4 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-a424","title":"Unify JSON vs human error wording in src/commands/ready.ts unknown-domain branch","status":"open","type":"task","priority":3,"plan_step_index":4,"description":"\nStep 5 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} {"id":"mulch-4dc4","title":"Backfill direct unit tests for src/utils/domain-rules.ts and src/utils/format-helpers.ts","status":"open","type":"task","priority":3,"plan_step_index":5,"description":"\nStep 6 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]} -{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:17:52.971Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]} +{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:18:09.429Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-fed1","mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]}