Skip to content

T-OLTA-task-work-step7-worktree-baseline-dir

Status: open/ready · Impact: medium · Complexity: small

AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-07-19 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.

/sdlc:task-work Step 7’s baseline-gated quality gate cannot find the quality baseline when the task runs from a worktree, so the gate fails open with baseline not found instead of diffing against the captured baseline. The baseline lives in the main checkout but the worktree’s default --baseline-dir resolves to the worktree’s own (empty) .sdlc/. This task makes the gate resolve the baseline from a checkout-shared location so it runs meaningfully from any worktree.

Spawned from the post-mortem of T-JV2A-adopt-augmented-books-desktop in git@github.com:sksizer/dev.git:

task-work Step 7’s baseline-gated quality gate fails with ‘baseline not found’ when run from a worktree: the default --baseline-dir resolves to the empty worktree .sdlc/ instead of the main checkout’s .sdlc/quality-baselines/. Fix by having Step 7 pass an explicit --baseline-dir pointing at the main checkout, or capture the baseline into a checkout-shared location. Prior tasks T-5X6Y (superseded) and T-44OO (obsoleted) never shipped, so the bug is still live.

LocationRole today
apps/sdlc/lib/services/quality/ops/run.tsThe sdlc quality run op. When --diff-against-baseline is set and --baseline-dir is omitted, the baseline dir defaults to <projectRoot>/.sdlc/quality-baselines/; a missing <sha>.json there throws baseline not found.
apps/sdlc/lib/config/load.ts#resolveProjectRootResolves ctx.projectRoot by walking up from cwd to the first sdlc.yaml. A git worktree carries its own sdlc.yaml, so from a worktree this returns the worktree root — not the main checkout.
apps/sdlc/skills/task-work/SKILL.mdStep 3a captures the baseline into the main checkout’s .sdlc/quality-baselines/ while still on main; Step 7 runs the gate from the worktree with no --baseline-dir, so the worktree-rooted default misses the captured file.
apps/sdlc/lib/services/git/commit-to-main.ts#resolveMainCheckoutExisting resolver for the main checkout (git-common-dir’s parent), correct even from a worktree — the pattern this fix reuses.
apps/sdlc/lib/util/git.ts#isLinkedWorktreeShared worktree helpers (WORKTREES_DIR_REL, isLinkedWorktree) — the natural home for a shared main-checkout resolver.

Resolve the baseline directory from a checkout-shared location so the Step 7 gate finds the baseline captured on main from any linked worktree. When --baseline-dir is not passed, sdlc quality run defaults to the main checkout’s .sdlc/quality-baselines/ (the git-common-dir parent) instead of the current worktree’s own .sdlc/. Capture (Step 3a, on main) and gate (Step 7, in a worktree) then agree on one shared cache with no per-run path plumbing, and an explicit --baseline-dir still overrides it.

  1. Add an exported mainCheckoutRoot(projectRoot: string): string helper to apps/sdlc/lib/util/git.ts that runs git -C <projectRoot> rev-parse --path-format=absolute --git-common-dir and returns the parent directory of the reported common .git dir. On any non-zero exit or empty output (not a git repo, git unavailable) it returns projectRoot unchanged. This centralizes the git-common-dir-parent logic already inlined in commit-to-main.ts and docs/generate.ts.
  2. In apps/sdlc/lib/services/quality/ops/run.ts, change the baseline-dir default: when args.diffAgainstBaseline is set and args.baselineDir is undefined, resolve to realResolve(join(mainCheckoutRoot(projectRoot), ".sdlc", "quality-baselines")) instead of realResolve(join(projectRoot, ".sdlc", "quality-baselines")). Import the helper from @lib/util/git. An explicit --baseline-dir still wins (the branch is unchanged when the flag is present).
  3. Keep the baseline not found error, ensuring it prints the resolved (checkout-shared) path so a genuine miss stays diagnosable.
  4. Update apps/sdlc/skills/task-work/SKILL.md Step 3a’s note (the paragraph claiming the gate-time default is <project-root>/.sdlc/quality-baselines/): state that the gate-time default now resolves to the main checkout’s .sdlc/quality-baselines/ (git-common-dir parent), which is why capturing on main and gating from a worktree agree. Leave Step 7’s invocation unchanged — it relies on the corrected default.
  5. Add a test to apps/sdlc/lib/services/quality/tests/quality_ops.test.ts: create a temp git repo, capture a baseline in the main checkout, add a linked worktree, run quality run --diff-against-baseline <sha> with the project root set to the worktree and no --baseline-dir, and assert the gate reads the main checkout’s baseline (no baseline not found).
  6. Run the project’s quality-check verbs (type-check plus the quality service test suite) and confirm they pass.
LocationKindChange
apps/sdlc/lib/util/git.tsmodifyAdd exported mainCheckoutRoot(projectRoot) helper (git-common-dir parent; falls back to projectRoot).
apps/sdlc/lib/services/quality/ops/run.tsmodifyDefault the --diff-against-baseline baseline dir to mainCheckoutRoot(projectRoot)/.sdlc/quality-baselines when --baseline-dir is omitted; import the helper.
apps/sdlc/skills/task-work/SKILL.mdmodifyCorrect Step 3a’s gate-time-default note to describe the checkout-shared (main-checkout) baseline location.
apps/sdlc/lib/services/quality/tests/quality_ops.test.tsmodifyAdd a worktree baseline-resolution test asserting the gate finds the main-checkout baseline with no --baseline-dir.
  • AC-1: apps/sdlc/lib/util/git.ts exports a mainCheckoutRoot function that returns the git-common-dir parent for a linked worktree and returns the passed projectRoot unchanged when the path is not a git repo.
  • AC-2: In apps/sdlc/lib/services/quality/ops/run.ts, when --diff-against-baseline is set and --baseline-dir is omitted, the resolved baseline directory is <mainCheckoutRoot>/.sdlc/quality-baselines/ rather than <projectRoot>/.sdlc/quality-baselines/.
  • AC-3: An explicit --baseline-dir argument still overrides the default (the new resolution applies only when the flag is absent).
  • AC-4: A test in apps/sdlc/lib/services/quality/tests/quality_ops.test.ts captures a baseline in a main checkout, runs sdlc quality run --diff-against-baseline <sha> from a linked worktree with no --baseline-dir, and asserts the gate resolves the main-checkout baseline instead of throwing baseline not found.
  • AC-5: apps/sdlc/skills/task-work/SKILL.md Step 3a no longer claims the gate-time default is <project-root>/.sdlc/quality-baselines/; it describes the checkout-shared main-checkout location.
  • AC-6: The project’s quality-check verbs (type-check and the quality service test suite) pass on the change.
  • The alternative fix of having task-work Step 7 pass an explicit --baseline-dir per run instead of correcting the op’s default resolution.
  • Backfilling or migrating baseline JSON files already written under existing worktrees’ .sdlc/quality-baselines/.
  • Changing the sdlc quality baseline capture op, whose --baseline-dir is a required argument (callers already pass an explicit, main-checkout-rooted path).
  • Refactoring the duplicate git-common-dir-parent logic in commit-to-main.ts and docs/generate.ts to call the new helper (a separate cleanup).
  • none

Spawned by /sdlc:spawn-task-pr on 2026-07-19 UTC from T-JV2A-adopt-augmented-books-desktop in git@github.com:sksizer/dev.git.

Linked from the post-mortem of T-1YSW-amend-d0001-solutions-tier on 2026-07-19 — a second independent observation of this gap, recorded there as already tracked here:

Step 7’s --baseline-dir default resolves from the worktree, not the superproject, so the gate could not find the captured baseline until the flag was passed explicitly.

No duplicate spawned.

Dedup search (spawn-from-post-mortem, from T-B98V)

Section titled “Dedup search (spawn-from-post-mortem, from T-B98V)”

Bullet: Step 7’s --diff-against-baseline gate resolved the baseline dir from the WORKTREE (.sdlc/worktrees/<t>/.sdlc/quality-baselines/) while Step 3a captured into the main checkout — needed a manual copy; exactly the gap T-OLTA-task-work-step7-worktree-baseline-dir already tracks Keywords searched: t-olta-task-work-step7-worktree-baseline-dir, diff-against-baseline, quality-baselines, worktrees, resolved, baseline, worktree, checkout Excluded: T-B98V-adopt-vimit Top candidates (score / status / headline):

  • 287 / closed/obsoleted / T-44OO-plugin-scripts-self-discover-project-root — Plugin scripts self-discover project root from cwd
  • 172 / closed/done / T-TWZD-normalize-baseline-diff-nondeterministic-output — run_quality_checks —diff-against-baseline masks ephemeral tmpdir paths and transient SHAs before line-diffing
  • 123 / open/ready / T-OLTA-task-work-step7-worktree-baseline-dir — task-work Step 7 resolves the quality baseline dir from a worktree
  • 105 / closed/superseded / T-5X6Y-task-work-step7-explicit-baseline-dir — task-work Step 7 must pass —baseline-dir explicitly to defeat silent fallback in worktree
  • 89 / closed/done / T-G834-move-plugin-runtime-state-to-sdlc-dir — Migrate sdlc plugin runtime state from .claude/ to .sdlc/ Decision: SPAWNED Rationale: Script decision overridden to LINKED-EXISTING — the bullet itself names this task as already tracking the gap, and PR #921 is open for it. Linked from the post-mortem of T-B98V-adopt-vimit on 2026-07-31; a third independent observation of this gap. No duplicate spawned.

Dedup search (spawn-from-post-mortem, from T-JOXA)

Section titled “Dedup search (spawn-from-post-mortem, from T-JOXA)”

Bullet: Step 7’s gate invocation resolved —baseline-dir relative to the worktree (where no baseline exists) and failed with baseline not found, even though Step 3a wrote it under the main repo. The skill calls —baseline-dir optional in spirit; it is in fact required whenever the gate runs from a worktree, and the Step 7 snippet should pass it explicitly like the Step 3a snippet does. Keywords searched: baseline-dir, invocation, explicitly, resolved, relative, worktree, baseline, optional Excluded: T-JOXA-task-kind-field-and-leaf-dispatch Top candidates (score / status / headline):

  • 363 / closed/obsoleted / T-44OO-plugin-scripts-self-discover-project-root — Plugin scripts self-discover project root from cwd
  • 167 / closed/done / T-TWZD-normalize-baseline-diff-nondeterministic-output — run_quality_checks —diff-against-baseline masks ephemeral tmpdir paths and transient SHAs before line-diffing
  • 128 / closed/superseded / T-5X6Y-task-work-step7-explicit-baseline-dir — task-work Step 7 must pass —baseline-dir explicitly to defeat silent fallback in worktree
  • 128 / open/ready / T-OLTA-task-work-step7-worktree-baseline-dir — task-work Step 7 resolves the quality baseline dir from a worktree
  • 99 / closed/done / T-2T20-task-work-backgrounds-quality-gate — task-work backgrounds the Step 7 quality gate and passes an explicit main-repo baseline-dir

Decision: SPAWNED Rationale: Script decision overridden to LINKED-EXISTING — the scorer’s top three are all closed (obsoleted / done / superseded) long files that win on raw keyword count; the live match is rank 4, this task (open/ready, relevance-verified 2026-08-01). Linked from the post-mortem of T-JOXA-task-kind-field-and-leaf-dispatch on 2026-08-03; a fourth independent observation of this gap. Also confirmed live against the current tree: apps/sdlc/skills/task-work/SKILL.md:406 still calls --baseline-dir “optional in spirit” and Step 7’s invocation at line 831 still omits it. No duplicate spawned.

Dedup search (spawn-from-post-mortem, from T-HTN8)

Section titled “Dedup search (spawn-from-post-mortem, from T-HTN8)”

Bullet: Step 7’s documented sdlc quality run --diff-against-baseline invocation omits --baseline-dir, and the default resolves against the run’s project root — which in Step 7 is the worktree, not the main checkout where Step 3a wrote the file. The first gate run died with baseline not found: <worktree>/.sdlc/quality-baselines/<sha>.json after a full 11-verb pass. Either the Step 7 example should carry --baseline-dir like Step 3a’s does, or the resolver should fall back to the superproject when run from a worktree. Keywords searched: diff-against-baseline, quality-baselines, baseline-dir, superproject, documented, invocation, resolves, worktree Excluded: T-HTN8-lease-gate-memo-fields Top candidates (score / status / headline):

  • 249 / closed/obsoleted / T-44OO-plugin-scripts-self-discover-project-root — Plugin scripts self-discover project root from cwd
  • 89 / open/ready / T-OLTA-task-work-step7-worktree-baseline-dir — task-work Step 7 resolves the quality baseline dir from a worktree
  • 87 / closed/superseded / T-5X6Y-task-work-step7-explicit-baseline-dir — task-work Step 7 must pass —baseline-dir explicitly to defeat silent fallback in worktree
  • 67 / closed/done / T-2T20-task-work-backgrounds-quality-gate — task-work backgrounds the Step 7 quality gate and passes an explicit main-repo baseline-dir
  • 64 / closed/done / T-TWZD-normalize-baseline-diff-nondeterministic-output — run_quality_checks —diff-against-baseline masks ephemeral tmpdir paths and transient SHAs before line-diffing

Decision: SPAWNED → overridden to LINKED-EXISTING Rationale: This task (rank #2, open/ready) is the exact live owner — its headline is “task-work Step 7 resolves the quality baseline dir from a worktree” and its Proposed already names both remedies the bullet offers (an explicit --baseline-dir on Step 7, or defaulting the resolver to the main checkout). The script’s #1 hit T-44OO is closed/obsoleted and #3 T-5X6Y is closed/superseded by this task, so a spawn would be the fifth coverage of one gap. Linked from the post-mortem of T-HTN8-lease-gate-memo-fields on 2026-08-03; a fourth independent observation, this time with the concrete cost recorded — the gate died only AFTER a full 11-verb pass. No duplicate spawned.


← Back to Tasks