From fff98079dcde28d085b16129e074cae8cfda0a17 Mon Sep 17 00:00:00 2001 From: warren Date: Sat, 30 May 2026 10:07:35 +0000 Subject: [PATCH] chore(warren): seeds state --- .seeds/issues.jsonl | 6 ++++++ .seeds/plans.jsonl | 1 + 2 files changed, 7 insertions(+) diff --git a/.seeds/issues.jsonl b/.seeds/issues.jsonl index 4d02cbf..5b0d597 100644 --- a/.seeds/issues.jsonl +++ b/.seeds/issues.jsonl @@ -327,3 +327,9 @@ {"id":"mulch-6145","title":"T4: trim redundant git init/commits from beforeEach","status":"open","type":"task","priority":2,"createdAt":"2026-05-28T19:15:24.041Z","updatedAt":"2026-05-28T19:16:03.243Z","description":"GOAL: Stop paying for real `git init` + git config + commits in beforeEach for tests that do not actually assert git behavior. Real git subprocesses (3-5 per test) dominate several files.\n\nWorking dir: cd /Users/jayminwest/Projects/os-eco/mulch\nINDEPENDENT: no dependency on other Ts.\n\nHOTSPOTS (run real execFileSync('git', ...) in setup):\n- test/commands/sync.test.ts (9.15s/19 tests; initGitRepo + gitCommitAll per test)\n- test/commands/config.test.ts (worktree blocks)\n- test/commands/record.test.ts, test/commands/prime.test.ts\n- test/utils/active-work.test.ts, test/utils/worktree.test.ts\n\nMETHOD:\n- Introduce a small helper (e.g. test/helpers/git.ts withGitRepo(dir)) using `git init -q`, single `git config` for user.name/email, and only commit when the test needs commits.\n- Move git setup OUT of blanket beforeEach and INTO the specific describe/it blocks that assert git-dependent behavior. Tests that only touch .mulch/ files should not init a repo at all.\n- Where a git repo is genuinely required for every test in a file (e.g. sync), keep it but minimize subprocess count (skip extra commits/config not asserted).\n\nVERIFICATION (must exit 0; test count unchanged):\n bun run lint && bun run typecheck\n bun test test/commands/sync.test.ts test/commands/config.test.ts test/commands/record.test.ts test/commands/prime.test.ts test/utils/active-work.test.ts test/utils/worktree.test.ts\n bun run test:ci && bun run report:timing # record reductions\n\nACCEPTANCE:\n- No test loses coverage of git-dependent behavior.\n- Per-test git subprocess count reduced; sync/record/prime/active-work file times drop.\n\nPITFALLS:\n- getMulchDir()/worktree resolution depends on a real .git — keep git for tests that exercise worktree/sync semantics.\n- Do not share a single mutable repo across tests that commit; isolation matters. Per-test temp repos stay, just leaner.","blocks":["mulch-bee4"]} {"id":"mulch-f7bf","title":"T5: adaptive parallel shard runner (core-count agnostic)","status":"open","type":"task","priority":1,"createdAt":"2026-05-28T19:15:54.049Z","updatedAt":"2026-05-28T19:16:03.298Z","description":"GOAL: `bun test` runs all files sequentially in ONE process, so wall-clock = sum of file times. Add a runner that splits test files into N balanced shards and runs them as concurrent `bun test ` processes. Shard count MUST be derived from the runtime environment — never hardcoded to any developer machine spec.\n\nWorking dir: cd /Users/jayminwest/Projects/os-eco/mulch\nINDEPENDENT build (blocks T6).\n\nFILES TO ADD:\n- ADD scripts/test-parallel.ts (run via Bun):\n - Determine shard count: `MULCH_TEST_SHARDS` env > `--shards N` arg > Math.max(1, os.availableParallelism?.() ?? os.cpus().length). Cap to number of test files.\n - Discover test files (glob test/**/*.test.ts).\n - Weight files by historical timing parsed from junit.xml when present (reuse parseJUnit from scripts/report-test-timing.ts), else by file size; greedily bin-pack into shards for balance.\n - Spawn one `bun test ` per shard concurrently (Bun.spawn), stream/prefix output, await all, exit non-zero if ANY shard fails.\n - SEQUENTIAL FALLBACK: if resolved shards <= 1, exec a single plain `bun test` (identical behavior to today).\n- ADD package.json script: \"test:parallel\": \"bun run scripts/test-parallel.ts\".\n- ADD scripts/test-parallel.test.ts: unit-test the pure pieces (shard-count resolution precedence, bin-packing balance, sequential fallback) — pure functions, no real spawning.\n\nDESIGN CONSTRAINTS:\n- Core-count agnostic + cloud-safe: works on a 1-vCPU box (falls back to sequential), a 2-4 vCPU cloud dev box, and large CI runners with the SAME code. No machine-specific constants.\n- Tests already isolate via mkdtemp unique prefixes, so cross-shard temp-dir collisions are not a concern.\n- Deterministic file->shard assignment given the same inputs (stable sort) for reproducibility.\n\nVERIFICATION (must exit 0):\n bun run lint && bun run typecheck\n bun test scripts/test-parallel.test.ts\n MULCH_TEST_SHARDS=1 bun run test:parallel # sequential fallback, full suite green\n MULCH_TEST_SHARDS=4 bun run test:parallel # parallel, same pass/fail outcome + lower wall-clock\n\nACCEPTANCE:\n- Same overall pass/fail result as `bun test` at any shard count.\n- Wall-clock scales down with shard count; sequential fallback exactly mirrors plain `bun test`.\n\nPITFALLS:\n- Aggregate exit code: fail if ANY shard fails (do not mask with tail/pipe).\n- os.availableParallelism may be undefined on older runtimes — guard with cpus().length.\n- Coverage merge across shards is handled in T6, but design spawn args so per-shard `--coverage --coverage-reporter=lcov` with distinct outfiles is possible.","blocks":["mulch-d61d","mulch-bee4"]} {"id":"mulch-d61d","title":"T6: wire CI to sharded runner + coverage merge","status":"open","type":"task","priority":2,"createdAt":"2026-05-28T19:15:54.152Z","updatedAt":"2026-05-28T19:16:03.352Z","description":"GOAL: Use the T5 shard runner in CI with an EXPLICIT, deterministic shard matrix (not derived from runner core count, so behavior is reproducible across runner sizes), merge per-shard coverage, and keep the timing report.\n\nWorking dir: cd /Users/jayminwest/Projects/os-eco/mulch\nDEPENDS ON: T5 (runner must exist).\n\nFILES TO EDIT:\n- .github/workflows/ci.yml:\n - Replace the single test:ci step with a small matrix (e.g. shard: [1,2,3,4], total 4) OR a single job invoking `MULCH_TEST_SHARDS=4 bun run test:parallel` — choose whichever keeps coverage merge simplest; document the choice in the job.\n - Each shard runs `bun test --coverage --coverage-reporter=lcov --coverage-reporter=...` writing a shard-unique lcov path, plus --reporter=junit to a shard-unique junit file.\n - Add a merge step: combine shard lcov files into coverage/lcov.info (concatenate/merge) and shard junit files into junit.xml so existing check:coverage + report:timing + report:quality keep working unchanged.\n - Keep uploading coverage/lcov.info and junit.xml artifacts (VAL-CROSS-003) and appending report:timing to GITHUB_STEP_SUMMARY.\n\nVERIFICATION (must exit 0):\n bun run lint && bun run typecheck\n # Locally emulate: run the runner with coverage, merge, then:\n bun run check:coverage\n bun run report:timing\n ls -la coverage/lcov.info junit.xml\n\nACCEPTANCE:\n- CI wall-clock for tests drops vs the previous single sequential run.\n- Merged coverage feeds check:coverage with no budget regression; merged junit feeds report:timing.\n- Matrix is explicit/deterministic — independent of the physical runner's core count.\n\nPITFALLS:\n- lcov merge: same source files appear in multiple shards' reports only if executed there; merge must union records, not double-count lines (use a real lcov merge approach, not naive concat if it corrupts totals — verify check:coverage numbers are sane).\n- junit merge must keep total tests = sum across shards for report:timing accuracy.\n- Do not regress check:all ordering or artifact-upload steps.","blockedBy":["mulch-f7bf"],"blocks":["mulch-bee4"]} +{"id":"mulch-f7bc","title":"nightwatch patrol: 2026-05-30","status":"open","type":"task","priority":3,"createdAt":"2026-05-30T10:06:40.427Z","updatedAt":"2026-05-30T10:07:21.189Z","description":"Code-patrol findings: oversize test file breaking check:size, duplicated numeric-flag helpers across commands, dead utils/index.ts re-export aggregator, knip-flagged unused exports, and stale knip.json hints. See child seeds spawned via sd plan submit.","labels":["patrol","nightwatch"],"plan_id":"pl-a152","blockedBy":["mulch-ccf7","mulch-d344","mulch-9266","mulch-28f0","mulch-3195"]} +{"id":"mulch-ccf7","title":"Split test/commands/record.test.ts to clear the check:size ratchet","status":"open","type":"task","priority":3,"plan_step_index":0,"description":"\nStep 1 of plan pl-a152.\n\nParent seed: mulch-f7bc — nightwatch patrol: 2026-05-30\nPlan template: refactor\nPlan approach: Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite…\n\nRun `sd plan show pl-a152` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","labels":["nightwatch","testing"],"plan_id":"pl-a152","blocks":["mulch-3195","mulch-f7bc"]} +{"id":"mulch-d344","title":"Replace duplicate parseStrictPositiveInt / parseStrictNonNegativeNumber copies with utils/numeric-flags imports","status":"open","type":"task","priority":3,"plan_step_index":1,"description":"\nStep 2 of plan pl-a152.\n\nParent seed: mulch-f7bc — nightwatch patrol: 2026-05-30\nPlan template: refactor\nPlan approach: Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite…\n\nRun `sd plan show pl-a152` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","labels":["nightwatch","cli"],"plan_id":"pl-a152","blocks":["mulch-3195","mulch-f7bc"]} +{"id":"mulch-9266","title":"Delete unused src/utils/index.ts aggregator and prune knip-flagged unused exports","status":"open","type":"task","priority":4,"plan_step_index":2,"description":"\nStep 3 of plan pl-a152.\n\nParent seed: mulch-f7bc — nightwatch patrol: 2026-05-30\nPlan template: refactor\nPlan approach: Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite…\n\nRun `sd plan show pl-a152` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","labels":["nightwatch","cleanup"],"plan_id":"pl-a152","blocks":["mulch-3195","mulch-f7bc"]} +{"id":"mulch-28f0","title":"Tidy knip.json: drop redundant entry patterns, stale ignore globs, and jscpd ignoreDependencies entry","status":"open","type":"task","priority":4,"plan_step_index":3,"description":"\nStep 4 of plan pl-a152.\n\nParent seed: mulch-f7bc — nightwatch patrol: 2026-05-30\nPlan template: refactor\nPlan approach: Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite…\n\nRun `sd plan show pl-a152` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","labels":["nightwatch","tooling"],"plan_id":"pl-a152","blocks":["mulch-3195","mulch-f7bc"]} +{"id":"mulch-3195","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":4,"description":"\nStep 5 of plan pl-a152.\n\nParent seed: mulch-f7bc — nightwatch patrol: 2026-05-30\nPlan template: refactor\nPlan approach: Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite…\n\nRun `sd plan show pl-a152` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n","createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","labels":["nightwatch"],"plan_id":"pl-a152","blockedBy":["mulch-ccf7","mulch-d344","mulch-9266","mulch-28f0"],"blocks":["mulch-f7bc"]} diff --git a/.seeds/plans.jsonl b/.seeds/plans.jsonl index 257c676..197929a 100644 --- a/.seeds/plans.jsonl +++ b/.seeds/plans.jsonl @@ -9,3 +9,4 @@ {"id":"pl-7a81","seed":"mulch-e7f6","template":"refactor","status":"approved","revision":1,"sections":{"context":"Nightwatch patrol on 2026-05-28 found four small quality issues: (1) outcome.duration is parsed with bare Number.parseFloat in three CLI commands, so junk input silently writes NaN to .mulch/expertise/*.jsonl — violating the project's strict-numeric-flag-parsing convention (mx-5b9578, already followed by rank.ts); (2) fatal-error console.error sites have drifted — some use chalk.red('Error: ...'), but the common 'No .mulch/ directory found.' message is plain text in delete/ready/archive/query/prime/edit/restore/search, plus a few generic catch-block 'Error: ${err.message}' lines that are also plain — readability across call sites suffers; (3) the Claude setup recipe parses settings.json with bare JSON.parse and no path context, so a corrupted file throws an unhelpful 'Unexpected token …' error inconsistent with the file:line context convention used by readExpertiseFile (mx-7c199c); (4) the deprecated 'mulch update' command prints a non-JSON warning to stderr even when --json is set, breaking the JSON-output contract every other command honors. Quality gates (bun test, bun run lint, bun run typecheck) are green at HEAD — these are not regressions, just drift that has accumulated.","behavior_invariant":"All existing tests continue to pass. Public CLI surface, command names, flags, and JSON schema shapes are unchanged. Successful command paths produce byte-identical stdout/stderr to before for every input that was valid before. The only observable changes are: (a) invalid --outcome-duration / --duration inputs now exit non-zero with a clear error instead of silently writing NaN; (b) error lines that were plain text become chalk.red-wrapped to match peer commands (no message wording changes); (c) corrupted Claude settings.json yields an error mentioning the file path instead of raw JSON parser output; (d) 'mulch update --json' emits the standard JSON error envelope. No new commands, no new flags, no dependency changes, no public API signature changes.","approach":"Targeted, isolated fixes. Each step touches a small set of files and lands as a single PR. Independent steps (parsing, error-coloring, JSON.parse hardening, update.ts JSON output) can ship in any order; the release step is last and blocked by all four.","steps":[{"title":"Validate --outcome-duration / --duration with strict regex parser","description":"Files: src/commands/record.ts (line ~806), src/commands/edit.ts (line ~128), src/commands/outcome.ts (line ~124). All three currently call `Number.parseFloat(options.outcomeDuration as string)` (or options.duration) with no validation, so `--outcome-duration foo` writes `\"duration\": null` or NaN into the JSONL Outcome object. This violates the strict-numeric-flag-parsing convention (mulch record mx-5b9578) which rank.ts already follows. Fix: introduce a shared helper (e.g. parseStrictNonNegativeNumber in src/utils/format-helpers.ts or a new src/utils/numeric-flags.ts) mirroring the regex+Number() pair in src/commands/rank.ts:31-37, and call it from all three sites. On parse failure, print `Error: --outcome-duration must be a non-negative number (got \"\")` (chalk.red in non-JSON, outputJsonError in JSON mode), set process.exitCode = 1, and return without writing the record. Add unit tests under test/commands/record.test.ts (and edit/outcome equivalents) that pass a bogus value and assert exit code 1 + no JSONL mutation. Do NOT change the flag name or add new flags.","labels":["nightwatch"],"blocks":[]},{"title":"Normalize fatal-error coloring across commands","description":"Plain-text `console.error(\"Error: ...\")` and `console.error(\\`Error: ${...}\\`)` calls have drifted from the chalk.red(`Error: ...`) idiom used by most commands. Specifically: src/commands/delete.ts:303,309; src/commands/ready.ts:177,183; src/commands/archive.ts:201,207; src/commands/query.ts:91,203,209; src/commands/prime.ts:150,162,183,255,283,514,675,681; src/commands/onboard.ts:369; src/commands/edit.ts:202,208; src/commands/restore.ts:154,160; src/commands/search.ts:316,322; src/commands/learn.ts:174; src/commands/move.ts:314,317; src/commands/rank.ts:166,173. Wrap each with chalk.red so non-JSON output is visually consistent with peer commands (delete.ts:60, archive.ts uses it earlier, etc.). Do not change message wording or add new error paths. Verify by running `bun test` and a quick `grep -rn 'console.error(\"Error:\\|console.error(\\`Error:' src/` — should return no matches.","labels":["nightwatch"],"blocks":[]},{"title":"Add file-path context to Claude settings.json parse errors in setup.ts","description":"src/commands/setup.ts at lines 199, 234, and 266 call `JSON.parse(raw) as ClaudeSettings` on the contents of `~/.claude/settings.json` (resolved via claudeSettingsPath(cwd)) with no try/catch, so a corrupted/edited settings file throws a bare `SyntaxError: Unexpected token ...` with no path or hint. The project's convention is to wrap JSONL parse errors with file:line context (mulch record mx-7c199c, see src/utils/expertise.ts:67-76). Fix: extract a small helper inside setup.ts (e.g. `parseClaudeSettings(path: string, raw: string): ClaudeSettings`) that wraps JSON.parse in try/catch and rethrows `Error(`Malformed Claude settings at ${path}: ${err.message}. Edit or remove the file to recover.`)`. Use it from install(), check(), and remove(). No behavior change on the happy path. Add a test in test/commands/setup.test.ts that writes a corrupt settings.json, invokes the claude recipe's check(), and asserts the error message mentions the file path.","labels":["nightwatch"],"blocks":[]},{"title":"Honor --json in the deprecated 'mulch update' command","description":"src/commands/update.ts unconditionally calls `printWarning(...)` and exits with code 1, even when the global --json flag is set. Every other command branches on `program.opts().json === true` and emits a structured envelope via outputJson/outputJsonError. Fix: in registerUpdateCommand's action, capture `const jsonMode = program.opts().json === true;` and call `outputJsonError(\"update\", \"'mulch update' is deprecated. Use 'mulch upgrade' instead.\")` when jsonMode, otherwise the existing printWarning. Keep `process.exitCode = 1` either way. Add a one-line test verifying the JSON envelope shape under --json. No new flags, no rename, the command stays hidden.","labels":["nightwatch"],"blocks":[]},{"title":"Release: run /release per .claude/commands/release.md","description":"Final patrol step. After steps 1-4 land, run /release as documented in .claude/commands/release.md to cut and publish the patch release containing these fixes. Bumps version in package.json and src/cli.ts in lockstep (mulch record mx-5ab2bc), updates CHANGELOG.md (mx-900a53), and runs the usual release ritual.","labels":["nightwatch"],"blocks":[]}],"acceptance":["bun test passes (all 1460+ existing tests plus the new tests added in steps 1, 3, and 4).","bun run lint and bun run typecheck both exit 0.","`grep -rn 'console.error(\"Error:\\|console.error(\\`Error:' src/` returns no matches after step 2.","Running `ml record cli --type pattern --name x --description y --outcome-status success --outcome-duration foo` exits non-zero with a 'must be a non-negative number' error and does NOT append a record to .mulch/expertise/cli.jsonl.","Writing invalid JSON to ~/.claude/settings.json and running `ml setup claude --check` produces an error message that contains the settings.json path, not a bare 'Unexpected token'.","`ml update --json` writes a JSON object with {\"success\": false, \"command\": \"update\", \"error\": ...} to stderr and exits non-zero.","No new CLI commands, flags, or dependencies are introduced. Public API and JSON schema shapes are unchanged."]},"children":["mulch-5b9c","mulch-2a17","mulch-1b36","mulch-a8cd","mulch-201a"],"createdAt":"2026-05-28T10:06:37.862Z","updatedAt":"2026-05-28T10:06:37.862Z","name":"nightwatch patrol fixes 2026-05-28"} {"id":"pl-4fb9","seed":"mulch-3204","template":"feature","status":"done","revision":1,"sections":{"context":"Mulch is the structured-expertise CLI tool in the os-eco ecosystem. The os-eco L5 uplift mission targets Level 5 (≥80% pass rate, matching warren's ceiling per docs/l5-uplift/library/warren-ceiling.md) for every sub-repo by porting templates/l5-toolkit/ (the warren-derived toolkit, finalized 2026-05-27) and authoring repo-specific artifacts. Mulch has NOT started uplift yet — this plan ports the toolkit from scratch and lifts mulch to ~50/63 ≈ ~80% → Level 5 ✓ per the per-repo expected math in docs/l5-uplift/library/warren-ceiling.md. The 6 children of this plan are self-contained: an agent reading `sd show ` has the full target dir, files-to-add/edit, source-of-truth refs, verification commands, rubric criteria closed, commit guidance, and mulch-specific pitfalls without needing the parent mission context.","approach":"Port the os-eco L5 toolkit (templates/l5-toolkit/) into mulch/ in six focused commits, in dependency order. Each child seed targets one feature from the mission's seed-plan-source/mulch.json. Mulch hasn't started, so the first child (mulch-repo-scaffolding) lays down all the baseline configs + devcontainer + env + gitignore + biome extension; subsequent children layer ratchet scripts + budgets, coverage + reporters, AGENTS.md + validator + RUNBOOK + skill, pino logger + governance hooks (pre-commit + dependabot cooldown + labels.yml), and finally the check:all aggregator + CI workflow extension. Each child commits one feature to mulch main; do NOT push (user pushes manually). After the final child seals, the user runs /readiness-report from mulch/ to confirm Level 5 ≥80%.","steps":[{"title":"mulch-repo-scaffolding: port baseline configs + devcontainer + env + gitignore + biome/knip/jscpd/bunfig"},{"title":"mulch-ratchet-scripts: port check-file-sizes + check-debt-markers + budgets"},{"title":"mulch-test-coverage-and-reporters: wire coverage + test:ci + report-test-timing + report-quality-metrics"},{"title":"mulch-agents-md-validator-runbook-skills: author AGENTS.md + validator + RUNBOOK + mulch-expertise skill"},{"title":"mulch-pino-logger-and-governance: add pino + redact + pre-commit hook + dependabot cooldown + labels.yml"},{"title":"mulch-check-all-and-ci-finalize: wire check:all aggregator + extend ci.yml + final verification"}],"acceptance":["VAL-MULCH-002 (naming_consistency), VAL-MULCH-003 (cyclomatic_complexity), VAL-MULCH-005 (duplicate_code_detection), VAL-MULCH-007 (unused_dependencies_detection), VAL-MULCH-012 (devcontainer), VAL-MULCH-017 (env_template), VAL-MULCH-018 (gitignore_comprehensive) closed by step 1","VAL-MULCH-004 (large_file_detection), VAL-MULCH-006 (tech_debt_tracking) closed by step 2","VAL-MULCH-008 (test_performance_tracking), VAL-MULCH-009 (test_coverage_thresholds), VAL-MULCH-015 (code_quality_metrics) closed by step 3","VAL-MULCH-010 (agents_md), VAL-MULCH-011 (agents_md_validation), VAL-MULCH-016 (runbooks_documented), VAL-MULCH-020 (skills) closed by step 4","VAL-MULCH-001 (pre_commit_hooks), VAL-MULCH-013 (structured_logging), VAL-MULCH-014 (log_scrubbing), VAL-MULCH-019 (min_release_age), VAL-MULCH-021 (issue_labeling_system) closed by step 5","VAL-MULCH-FINAL: post-mission /readiness-report from mulch/ shows Level 5 / 5 with pass rate ≥80%; each VAL-MULCH-001..021 criterion at 1/1","From cd /Users/jayminwest/Projects/os-eco/mulch: bun install && bun run lint && bun run typecheck && bun test && bun run check:all all exit 0 after step 6"]},"children":["mulch-409a","mulch-3fda","mulch-8cd7","mulch-d919","mulch-3fd5","mulch-6048"],"createdAt":"2026-05-28T03:22:52.773Z","updatedAt":"2026-05-28T18:57:32.181Z","name":"L5 uplift: mulch"} {"id":"pl-099d","seed":"mulch-5acb","template":"feature","status":"done","revision":1,"sections":{"context":"Mulch is one of five sub-repos targeted by the os-eco L5 readiness uplift mission. Prior /readiness-report audits placed mulch below Level 5 because it lacks the ratchet scripts, governance artifacts, validators, structured logger, and CI wiring that warren (the exemplar at Level 5) ships. The orchestrator has already finalised templates/l5-toolkit/ at the os-eco root; this work ports that toolkit into mulch so the next /readiness-report audit can certify Level 5 (≥80% pass rate) and close every VAL-MULCH-* assertion in docs/l5-uplift/validation-contract.md. Mulch's test directory layout (test/ rather than src/) and existing debug/output channels make this slightly different from the canopy and plot ports already shipped — those deltas are documented in docs/l5-uplift/library/porting-playbook.md.","approach":"Port the L5 toolkit (templates/l5-toolkit/) into mulch in six dependent stages, matching warren's ceiling and closing the VAL-MULCH-* assertions enumerated in docs/l5-uplift/validation-contract.md. Each stage lands in one commit on mulch's working branch (no push) and is gated by bun install / lint / typecheck / test exit 0. Special handling for mulch's test/ directory layout (no bunfig change needed for discovery) and the requirement to route the existing debug/output channels through pino in stage 5 instead of adding a parallel logger. Final stage wires check:all + extends ci.yml and asks the user to run /readiness-report.","steps":[{"title":"mulch-repo-scaffolding"},{"title":"mulch-ratchet-scripts"},{"title":"mulch-test-coverage-and-reporters"},{"title":"mulch-agents-md-validator-runbook-skills"},{"title":"mulch-pino-logger-and-governance"},{"title":"mulch-check-all-and-ci-finalize"}],"acceptance":["All six child seeds exist as dependent open seeds linked to parent mulch-5acb.","Each child seed has a self-contained description (>3000 chars) covering goal, working dir, references to templates/l5-toolkit/ + docs/l5-uplift/library/, files to add/edit, exact verification commands, acceptance rubric criteria, commit guidance, and pitfalls.","After all six children complete, bun install && bun run lint && bun run typecheck && bun test exit 0 from /Users/jayminwest/Projects/os-eco/mulch.","bun run check:all exits 0 after the final child lands.","The agent-readiness auditor (/readiness-report) confirms mulch reaches Level 5 (≥80% pass rate) closing each VAL-MULCH-001..021 plus VAL-MULCH-FINAL."]},"children":["mulch-3744","mulch-5c6f","mulch-f8d1","mulch-cbf4","mulch-9258","mulch-a11b"],"createdAt":"2026-05-28T13:14:50.739Z","updatedAt":"2026-05-28T17:38:48.524Z","name":"L5 uplift: mulch"} +{"id":"pl-a152","seed":"mulch-f7bc","template":"refactor","status":"approved","revision":1,"sections":{"context":"Code-patrol scan of mulch (v0.10.6) surfaced five quality issues and zero feature gaps. Headline pain: `bun run check:size` now FAILS in CI because `test/commands/record.test.ts` (2939 LOC) exceeds the frozen 2750 budget — the ratchet only goes down, so the only legal fix is to split the file. Secondary: four CLI commands (rank, prime, compact, ready) each hand-roll a `parseStrictPositiveInt` copy with their own `POSITIVE_INT_RE` even though `src/utils/numeric-flags.ts` already exports the exact helper (cf. mx-5b9578 cross-references in their own comments). `src/utils/index.ts` is an unused re-export aggregator (knip: 'Unused files'), and ~40 more knip-flagged exports / types are never imported. Finally, `knip.json` carries redundant `entry` patterns (`src/cli.ts`, `src/index.ts` are already declared in package.json) and a stale `ignoreDependencies: [\"jscpd\"]` plus dead `ignore` globs for directories that no longer exist in scan scope. All findings are internal-only — no public CLI surface, no record schema, and no JSONL on-disk format changes.","behavior_invariant":"1) Every existing `bun test` test continues to pass with identical assertions and identical test names (suites can be redistributed across files but no test is added, removed, renamed, or weakened). 2) The four affected CLI commands (`ml rank`, `ml prime`, `ml compact`, `ml ready`) accept and reject exactly the same `--limit` / `--min-group` / `--max-records` / numeric inputs as before — including the strict-rejection semantics for trailing garbage and decimals — and emit byte-identical error messages and JSON error payloads. 3) `outputJson` / `outputJsonError` envelopes and exit codes are unchanged for every command. 4) `bun run lint`, `bun run typecheck`, `bun test`, `bun run check:size`, `bun run check:debt`, `bun run check:coverage`, `bun run check:dups`, `bun run check:deps`, and `bun run check:agents` all exit 0. 5) No package.json dependency add/remove/upgrade. 6) `.mulch/expertise/*.jsonl` on-disk format and `ml record` upsert semantics untouched.","approach":"Land each finding as its own focused PR so reverts are surgical. Steps 1–4 are independent; step 5 is the release. Each step keeps the public CLI surface frozen, makes only internal restructuring, and ships with the existing test suite (plus, where helpful, redirected tests for the duplicate-helper consolidation). Anything that would change a public API signature is explicitly out of scope — none of the findings here require that.","steps":[{"title":"Split test/commands/record.test.ts to clear the check:size ratchet","type":"task","priority":3,"labels":["nightwatch","testing"],"blocks":[5]},{"title":"Replace duplicate parseStrictPositiveInt / parseStrictNonNegativeNumber copies with utils/numeric-flags imports","type":"task","priority":3,"labels":["nightwatch","cli"],"blocks":[5]},{"title":"Delete unused src/utils/index.ts aggregator and prune knip-flagged unused exports","type":"task","priority":4,"labels":["nightwatch","cleanup"],"blocks":[5]},{"title":"Tidy knip.json: drop redundant entry patterns, stale ignore globs, and jscpd ignoreDependencies entry","type":"task","priority":4,"labels":["nightwatch","tooling"],"blocks":[5]},{"title":"Release: run /release per .claude/commands/release.md","type":"task","priority":3,"labels":["nightwatch"]}],"acceptance":["`bun test` exits 0 with the same test count as on the patrol baseline (1494 pass).","`bun run lint` and `bun run typecheck` exit 0.","`bun run check:size` exits 0 — test/commands/record.test.ts is below its frozen 2750-line budget after the split (and any new sibling files are introduced into scripts/file-size-budgets.json at their actual size, not raised).","`bun run check:dups` reports zero new clones introduced by step 2; remaining clones are pre-existing.","`bunx knip --dependencies --include-entry-exports` no longer flags src/utils/index.ts as an unused file, no longer flags the exports removed in step 3, and emits no 'Configuration hints' after step 4.","`bun run check:debt` and `bun run check:agents` exit 0.","`ml rank --limit 10abc`, `ml prime --budget 5000abc`, `ml compact --min-group abc`, `ml ready --limit 3.7` each still exit non-zero with the same error string and same JSON error payload as on the patrol baseline (verified by the existing CLI tests for those commands)."]},"children":["mulch-ccf7","mulch-d344","mulch-9266","mulch-28f0","mulch-3195"],"createdAt":"2026-05-30T10:07:21.189Z","updatedAt":"2026-05-30T10:07:21.189Z","name":"nightwatch patrol 2026-05-30"}