T-AHL1-sdlc-arm-commit-worktree-from-maincheckout
Status: closed/done · Impact: medium · Complexity: small
T-ML6A (PR #894) armed the ephemeral commit-worktree that
commitToMainViaWorktree creates, so pre-commit hooks can resolve the
workspace deps (commander, yaml) that Bun’s isolated linker places only
at apps/sdlc/node_modules. The arm reads its verb list from the caller’s
raw projectRoot, but ensure_ready_mutate.ts passes dirname(taskFilePath)
— for the canonical nested path that is …/docs/planning/tasks, where
loadConfig finds no sdlc.yaml and returns defaults (empty verbs). So the
arm silently no-ops and every /sdlc:task-work Step 5a (--commit-on main
readiness stamp) fails with Cannot find package 'commander'. This makes the
readiness gate unusable repo-wide; only Step 5b (start_task.ts, which passes
the resolved main-repo root) is arming correctly.
| Location | Role today |
|---|---|
apps/sdlc/lib/services/git/commit-to-main.ts | commitToMainViaWorktree resolves mainCheckout (git-common-dir’s parent, correct from any subdir) and creates the ephemeral worktree under it, but arms with the raw projectRoot |
apps/sdlc/skills/task-ensure-ready/ensure_ready_mutate.ts | Its --commit-on path passes projectRoot: dirname(path) — the tasks subdir for a canonical task path — so the arm verb list resolves empty |
apps/sdlc/lib/services/git/arm-worktree.ts | commitWorktreeInitVerbs(projectRoot) reads loadConfig(projectRoot); loadConfig reads sdlc.yaml only at the exact root (no walk-up), so a subdir yields defaults |
apps/sdlc/lib/services/git/tests/commit-to-main.test.ts | The arm test passes projectRoot: mainDir (the root), so the subdir case that breaks in production is untested |
Proposed
Section titled “Proposed”commitToMainViaWorktree arms the ephemeral worktree from the already-resolved
mainCheckout rather than the caller’s raw projectRoot. Because the ephemeral
worktree is created under mainCheckout/.sdlc/commit-worktrees/, its deps must
come from mainCheckout’s config — so arming from mainCheckout is both the
correct source and robust to any caller that passes a subdir. ensure_ready_mutate.ts
then arms correctly with no caller-side change, and start_task.ts (whose
projectRoot already equals its mainCheckout) is unaffected.
Approach
Section titled “Approach”- In
commitToMainViaWorktree, arm from the resolvedmainCheckoutinstead ofprojectRoot(the value is already computed above the worktree add). - Add a regression test: drive
commitToMainViaWorktreewithprojectRootpointed at a subdirectory of the main checkout and assert the declared arm verbs still run (they would resolve empty under the old code). - Run the git-service suite plus
tsc --noEmit; confirm the existing root-projectRoot arm test still passes.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
apps/sdlc/lib/services/git/commit-to-main.ts | modify | Arm from mainCheckout, not projectRoot |
apps/sdlc/lib/services/git/tests/commit-to-main.test.ts | modify | Add subdir-projectRoot arm regression test |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
commitToMainViaWorktreeinvoked with a subdirprojectRoot(whose main-checkout root declarescommit_worktree_init:) runs the declared arm verbs; a new test asserts this and fails against the pre-fix code. - AC-2: The existing “arms the worktree after
worktree add” test (rootprojectRoot) still passes unchanged. - AC-3:
bun test apps/sdlc/lib/services/gitandbunx tsc --noEmitpass in the worktree.
Out of scope
Section titled “Out of scope”- Changing
loadConfigto walk ancestors — the arm-source fix is sufficient and narrower; a walk-up default is a broader behavior change with its own blast radius. - The backlog-capture arm call site (
apps/sdlc/cli/backlog_cli/create.ts), which builds its worktree underopts.projectRootand arms with the sameopts.projectRoot(self-consistent), and is invoked from the project root.
Dependencies
Section titled “Dependencies”- none — builds on
T-ML6A, already merged.
Discovery context
Section titled “Discovery context”- Found 2026-07-18 while running
/sdlc:task-workon the augmented_books adoption tasks: Step 5a failed withCannot find package 'commander'even after #894 merged. Traced tocommitWorktreeInitVerbs(dirname(taskPath))resolving[]for the nested tasks-directory projectRoot.