T-7PXF-declare-worktree-init-bun-install
Status: closed/done · Impact: medium · Complexity: small
AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-06-03. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.
This repo’s root sdlc.yaml declares no worktree_init: key, so
/sdlc:task-work Step 4 no-ops and fresh worktrees start with no
node_modules. Declaring worktree_init: ["bun install"] would arm
each worktree deterministically before Step 7’s quality checks run.
Fresh /sdlc:task-work worktrees start with no node_modules, so every bun-test quality verb fails with
Cannot find module 'eta'until a manualbun install. This project’s sdlc.yaml declares noworktree_init:key, so task-work Step 4 no-ops. Addworktree_init: ["bun install"]to the repo-root sdlc.yaml so worktrees are armed deterministically before Step 7’s quality checks run.— originating task T-XD7M-retire-task-sort-stub
| Location | Role today |
|---|---|
sdlc.yaml | Declares lease_authority, quality_checks (four bun-dependent verbs: bunx tsc --noEmit, bun test, bun test ./.claude, two audit runs), orchestrator, and pr_check — but no worktree_init: key, so task-work Step 4 no-ops and fresh worktrees lack node_modules. |
plugin/scripts/run_quality_checks.ts | The shared executor; worktree_init is already a schema-owned key (SCHEMA_OWNED_KEYS), and --allow-empty turns a missing/empty key into exit 0 with a stderr warning. No code change needed. |
plugin/skills/task-work/SKILL.md | Step 4 (“Initialize the worktree”) already invokes the executor with --key worktree_init --allow-empty against the project’s sdlc.yaml. No skill change needed. |
plugin/conventions/sdlc-yaml.md | Documents the worktree_init: key shape (a list of shell verbs) with worked examples. No doc change needed. |
Proposed
Section titled “Proposed”Add a worktree_init: key to the repo-root sdlc.yaml declaring
- bun install, with a one-paragraph comment mirroring the file’s
house style (why: every quality verb is bun-run and needs the
project’s node_modules; fresh task-work worktrees start without
them). The plugin machinery already consumes the key — this is pure
project configuration, exactly the declared-not-inferred shape
S-0003-deterministic-general-extension-points prescribes.
Approach
Section titled “Approach”- Edit
sdlc.yaml: add theworktree_init:key (a list with the single verbbun install) next toquality_checks:, with a brief comment in the file’s existing comment style. - Verify the executor accepts it: from the repo root run
bun run plugin/scripts/run_quality_checks.ts --config sdlc.yaml --key worktree_init --log --allow-empty— it must runbun installand exit 0 (instead of the current “no worktree_init configured” warning path). - Smoke the real flow: create a throwaway worktree
(
git worktree add /tmp/t7pxf-smoke -b chore/t7pxf-smoke main), run the same executor invocation with--project-root /tmp/t7pxf-smoke, confirmnode_modules/appears there and a previously-failing verb (bun test plugin/cli/task_cli/) now resolves modules; tear the worktree down.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
sdlc.yaml | modify | Add worktree_init: declaring - bun install, with a house-style comment. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
command grep -A2 'worktree_init:' sdlc.yamlshows a list containingbun install. - AC-2:
bun run plugin/scripts/run_quality_checks.ts --config sdlc.yaml --key worktree_init --logexits 0 having executedbun install(no “no worktree_init configured” warning). - AC-3: In a fresh worktree, the Step-4 invocation
(
--key worktree_init --allow-empty --project-root <worktree>) leaves<worktree>/node_modules/present, andbun test plugin/cli/task_cli/there no longer fails withCannot find module 'eta'.
Out of scope
Section titled “Out of scope”- Implicit detection for downstream consumers — having
/sdlc:setup//sdlc:find-quality-checksprobe forpackage.json+ a bun lockfile and offer the recipe (the PR #255 design question; see Discovery context). Spawn separately if wanted; this task is the one-line declaration for this repo only. - Any change to
run_quality_checks.ts, task-work Step 4, or thesdlc-yaml.mdconvention — the machinery already supports the key.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-06-03 UTC from T-XD7M-retire-task-sort-stub in git@github.com:sksizer/dev.git.
Design question (PR #255 review, 2026-06-03): should the SDLC system
run bun install implicitly, since bun is its runtime? Two layers to
separate. The plugin’s own runtime is not what broke — plugin scripts
execute from the plugin install with the plugin’s own dependencies.
What failed was the project’s quality verbs (bun test over this
repo’s suites) needing the project’s node_modules in a fresh
worktree; this repo is the degenerate case where project == plugin. An
implicit bun install in every consumer worktree would misfire on
non-JS consumers (no package.json), and S-0003-deterministic-general-extension-points
keeps init recipes declared, not inferred — worktree_init: is the
same shape as quality_checks:. The implicit-friendly middle:
/sdlc:setup / /sdlc:find-quality-checks detect package.json + a
bun lockfile and offer worktree_init: ["bun install"] at setup
time. Receiver should weigh folding that detection into this task or
spawning it separately.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: Fresh worktree had no node_modules; the implementing sub-agent had to run bun install manually before anything worked — already tracked by T-7PXF-declare-worktree-init-bun-install; link, don’t respawn Keywords searched: t-7pxf-declare-worktree-init-bun-install, node_modules, sub-agent, worktree, manually, anything, install, tracked Excluded: T-VWH3-ts-index-generator-script Top candidates (score / status / headline):
- 36 / closed/done / T-SIHV-task-state-frontmatter-commits-on-main-not-worktree-branch — All task-state frontmatter commits land on main; worktree branch is implementation diff only
- 35 / closed/done / T-6HFR-orchestrator-categorized-in-flight-limits — Replace orchestrator parallelism cap with categorized in-flight limits configurable in sdlc.yaml
- 35 / planning/backlog / T-ZFE9-task-work-uses-worktree-skill-md — task-work loads SKILL.md from the worktree, not ${CLAUDE_PLUGIN_ROOT}
- 34 / closed/done / T-G834-move-plugin-runtime-state-to-sdlc-dir — Migrate sdlc plugin runtime state from .claude/ to .sdlc/
- 33 / closed/superseded / T-407I-subagent-invariant-preflight-lint — Run skill-prose invariant linter inline during sub-agent edits to catch forbidden-phrase violations pre-flight Decision: SPAWNED → overridden to LINKED-EXISTING Rationale: The originating post-mortem bullet (T-VWH3-ts-index-generator-script) explicitly names this task as its tracker (“already tracked by T-7PXF…; link, don’t respawn”) and per-task inputs flagged it LINKED-EXISTING. The script scored T-7PXF below threshold (it didn’t surface in the top-5 — the task is freshly minted and shares few keywords with the bullet) but the bullet’s symptom (fresh worktree missing node_modules until a manual bun install) is exactly this task’s scope: declaring worktree_init: [“bun install”] in sdlc.yaml. Linked from: T-VWH3-ts-index-generator-script
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-06-04. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: agent-manual —
grep -A2 'worktree_init:' sdlc.yamlshows a list containingbun install. - AC-2: agent-manual — ran
run_quality_checks.ts --config sdlc.yaml --key worktree_init --log; it executedbun installand exited 0 with no “no worktree_init configured” warning. - AC-3: agent-manual — created a throwaway worktree from the task branch (no
node_modules), ran the Step-4 invocation (--key worktree_init --allow-empty --project-root <worktree>); it installed 78 packages,node_modules/etaappeared, andbun test plugin/cli/task_cli/there passed 15/15 (previously failed withCannot find module 'eta').
What worked
Section titled “What worked”- The machinery was already in place —
worktree_initis a schema-owned key, the executor honours--key worktree_init --allow-empty, and task-work Step 4 already invokes it. This task was pure one-line project configuration, exactly the declared-not-inferred shape the spec called for. - The resume path recovered cleanly: the implementation commit had already landed on the task branch, the working tree was clean, and the orphaned heartbeat from the killed run had kept the lease alive (same-host re-acquire succeeded).
Friction and automation gaps
Section titled “Friction and automation gaps”- Baseline-diff quality gate reported 12 spurious
new-driftlines — all benign- OKaudit-corpus rows (and the## tasks (schema vN) — N file(s)header) that differ only because the task branch was cut from an older main carrying other in-flight tasks’ start-commits. The line-based differ overaudit_entities.tscorpus listings flags task-count churn as drift even when no genuine finding changed. A gap worth closing:--diff-against-baselineshould diff on genuine finding lines (DRIFT/FAIL rows) rather than the whole corpus listing, or the gate should be re-run after Step 9’s rebase so the corpus matches origin/main. (Plugin-meta: routes upstream.) → T-TWZD-normalize-baseline-diff-nondeterministic-output
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-TWZD-normalize-baseline-diff-nondeterministic-output — linked (existing open/ready tracker
for
--diff-against-baselinefalse-positive masking; cross-refs T-BCNP-quality-gate-ignores-summary-and-corpus-lines for the count/corpus dimension this run actually hit)