diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index e22b3b9..2e3a2d9 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:38:05.028Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]} +{"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:47:19.521Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["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":"closed","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:28:34.748Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:28:34.748Z"} {"id":"mulch-4bd0","title":"Replace `(err as Error).message` with `err instanceof Error ? err.message : String(err)` across src/commands and src/utils","status":"closed","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:38:05.028Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"extensions":{"role":"pi","lastRunId":"run_ch27daacnb7q","lastRunAt":"2026-06-15T10:32:18.766Z"},"closedAt":"2026-06-15T10:38:05.028Z"} -{"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-9465","title":"Fix path-segment boundary in src/utils/git.ts fileMatchesAny + add false-positive coverage","status":"closed","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:47:19.521Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:47:19.521Z"} {"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:38:05.028Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["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:47:19.521Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]} diff --git a/src/utils/git.ts b/src/utils/git.ts index 45b65f9..544384e 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -105,8 +105,16 @@ export function getActiveFiles(cwd: string): string[] { } export function fileMatchesAny(file: string, changedFiles: string[]): boolean { + // Suffix matches must align on a path-segment boundary so that 'cli.ts' + // does not falsely match 'other-cli.ts'. Either the strings are equal, or + // the longer side has a '/' immediately before the suffix. + const suffixMatches = (longer: string, shorter: string): boolean => { + if (longer.length <= shorter.length) return false; + if (!longer.endsWith(shorter)) return false; + return longer[longer.length - shorter.length - 1] === "/"; + }; return changedFiles.some( - (changed) => changed === file || changed.endsWith(file) || file.endsWith(changed), + (changed) => changed === file || suffixMatches(changed, file) || suffixMatches(file, changed), ); } diff --git a/test/commands/prime.test.ts b/test/commands/prime.test.ts index 347344b..c7792d7 100644 --- a/test/commands/prime.test.ts +++ b/test/commands/prime.test.ts @@ -1170,6 +1170,17 @@ describe("prime command", () => { expect(fileMatchesAny("src/commands/prime.ts", ["prime.ts"])).toBe(true); }); + it("fileMatchesAny requires path-segment boundary on suffix match", () => { + // Non-boundary suffix must NOT match: 'cli.ts' is a string suffix of + // 'src/other-cli.ts' but they are different basenames. + expect(fileMatchesAny("cli.ts", ["src/other-cli.ts"])).toBe(false); + expect(fileMatchesAny("src/other-cli.ts", ["cli.ts"])).toBe(false); + expect(fileMatchesAny("prime.ts", ["src/commands/reprime.ts"])).toBe(false); + // Boundary-aligned suffix still matches. + expect(fileMatchesAny("cli.ts", ["src/cli.ts"])).toBe(true); + expect(fileMatchesAny("commands/prime.ts", ["src/commands/prime.ts"])).toBe(true); + }); + it("filterByContext keeps conventions (no files field)", () => { const records = filterByContext( [