T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-no
Status: closed/done · Impact: medium · Complexity: small
<Why this task exists. The problem it solves, the work it unblocks, or the risk it mitigates. Two or three sentences — the elevator pitch.>
<Current state of the relevant area as a typed table. One row per touched location; the Location column uses the five-form grammar documented in the template’s header comment. The Role-today column is a one-line note on what that location does today (or what’s wrong/missing there).
Pure-narrative Todays (no path-bearing rows) may also be expressed as prose — but tables are the preferred shape because the verifier resolves each row against the live codebase, so the description doesn’t go stale as code drifts.>
| Location | Role today |
|---|---|
path/to/file.ext | |
path/to/dir/ | <what’s in this directory today> |
Proposed
Section titled “Proposed”<Target state after this task ships. Concrete enough that an implementer can tell when they’re done. Not the steps — the destination.>
Approach
Section titled “Approach”<Numbered, ordered steps to get from Today to Proposed. Each step should be small enough to commit on its own if useful. Call out any decisions still open inside the step.>
Files to touch
Section titled “Files to touch”<Typed table of every location you expect to touch. Location uses the
same five-form grammar as ## Today (see header comment). Kind is one
of new, modify, or delete. Change is a one-line note on what
happens there.
The verifier resolves each row by Kind: new rows require no existing
file; modify and delete rows must resolve in the codebase (file /
symbol / dir must exist; glob must expand to ≥1 match). Symbols on
glob rows are rejected.>
| Location | Kind | Change |
|---|---|---|
path/to/file.ext | modify | |
path/to/new-file.ext | new |
Acceptance criteria
Section titled “Acceptance criteria”<Each AC must be observable from outside the change — a test that passes, a user-visible behavior, a removed wart. Avoid “the code is cleaner” style ACs; pick something verifiable.>
- AC-1:
- AC-2:
- AC-3:
Out of scope
Section titled “Out of scope”<Things adjacent to this task that are deliberately NOT being addressed here. Useful for keeping PR review focused and for future tasks to point back to. Always required: if scope is obvious and nothing is excluded, leave a single ”- none” bullet so the explicit signal is “scope considered, nothing to exclude.”>
- none
Dependencies
Section titled “Dependencies”<Other tasks, branches, infra changes, or external decisions this task
waits on. For hard “B cannot start until A closes” dependencies on
other tasks or epics, also record them in the frontmatter
depends_on: array (strict wikilink shape, e.g. [T-0010](/planning/tasks/T-0010/)) — the
audit walks that graph for cycle detection. This prose section is the
human-readable narrative; depends_on: is the machine-readable
canonical list. Leave a single ”- none” bullet if there are none.>
- <dependency or “none”>
Discovery context
Section titled “Discovery context”Promoted from B-8YI7-precommit-hooks-consult-quality-baseline. The
project-check-task-state-origin (lint-state-origin) false positive this task
owns has now been independently observed across multiple /sdlc:task-work
post-mortems — T-L9WL-roadmap-idempotency-test-decouples-from-the-bun-ops-walk,
T-PA51-task-state-commits-regen-site-page, T-F31Q-migrate-site-to-bun,
and most recently T-CW4K-scaffold-dashboard-vite-vue (all linked below) — all
hitting the same root cause: _lint_state_origin_core.ts compares each task/*
branch against origin/main only, so state-only commits that land on local
main (ahead of origin/main under parallel WIP) read as branch-exclusive
violations.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: project-check-task-state-origin blocked every branch commit because Step 5a/5b’s task-state commits (verify-stamp, start-commit) were on local main but not on a stale origin/main; had to push origin/main mid-flow to unblock. Keywords searched: project-check-task-state-origin, verify-stamp, start-commit, task-state, mid-flow, blocked, because, commits Excluded: T-F31Q-migrate-site-to-bun Top candidates (score / status / headline):
- 64 / 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
- 45 / in-progress / T-PA51-task-state-commits-regen-site-page — Task-state commits regenerate the derived site page
- 30 / closed/superseded / T-TU0W-rerun-ensure-ready-after-start-commit-to-avoid-frontmatter-conflict — Re-run task-ensure-ready after Step 5b start-commit to avoid frontmatter rebase conflict
- 25 / planning/needs-definition / T-0015 — Dispatchability-aware task pickup:
sdlc task next(filter blocked deps by default) - 23 / closed/superseded / T-2QXZ-start-task-handles-frontmatter-rebase-cleanly — start_task.py auto-merges frontmatter on stamp/start rebase conflict Decision: SPAWNED → overridden to LINKED-EXISTING Rationale: This task (T-6R73, promoted from B-8YI7) is the active tracker for the pre-commit drift/task-state-origin gate firing on stale origin/main; its slug shares no keywords with the bullet so the score-based search missed it, but the originating post-mortem already wikilinks it as the owner. Linked from T-F31Q-migrate-site-to-bun.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: The lint-state-origin pre-commit hook false-positives when origin/main lags local main: parallel sessions’ state-only verify/start commits that sit on local main (ahead of origin/main) appear as task-branch violations, because _lint_state_origin_core.ts compares each task/* branch against origin/main only — not against local main too, contrary to its own docstring. Required pushing main mid-flow to clear it before any commit-on-main could land. Keywords searched: lint_state_origin_core, lint-state-origin, false-positives, commit-on-main, task-branch, pre-commit, state-only, violations Excluded: T-CW4K-scaffold-dashboard-vite-vue Top candidates (score / status / headline):
-
11 / closed/done / T-0008 — Implement markdown formatting in commit hooks + skill launcher
-
11 / closed/done / T-A5H1-lefthook-project-check-pre-commit — Gate commits on /project-check via lefthook pre-commit
-
10 / planning/needs-definition / T-EGI0-task-body-validator-at-authoring-and-commit-time — Author-time task body validator (AC shape, touchpoint kinds, gitignored paths)
-
10 / planning/proposed / T-RQU1-worktree-scope-guard-downstream-setup — Wire worktree-scope-guard lefthook into /sdlc:setup for downstream projects
-
9 / in-progress / T-PA51-task-state-commits-regen-site-page — Task-state commits regenerate the
derived site page Decision: LINKED-EXISTING T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-no Linked from: T-CW4K-scaffold-dashboard-vite-vue Rationale: Override script’s SPAWNED → LINKED-EXISTING. The dedup script searches only
docs/planning/tasks/task BODIES and scored every candidate low (top
- — none lexically matched
_lint_state_origin_core/lint-state-originbecause the canonical tracker for this gap (this task, T-6R73) was promoted from B-8YI7 the same day (2026-06-19) and still carries template-stub body sections with no keyword surface yet. Investigating beyond the script: the identicalproject-check-task-state-originfalse positive (origin/main lagging local main under parallel WIP) is documented verbatim in the post-mortems of T-L9WL (routed to T-PA51) and T-PA51 itself (routed to B-8YI7). B-8YI7 is nowstatus: promoted/taskwithresult: T-6R73, so T-6R73 is the live, dedicated tracker. Spawning a fresh task would fragment a gap that already has a just-promoted owner. Linked rather than spawned. Originating task: T-CW4K-scaffold-dashboard-vite-vue Bullet: project-check-task-state-origin blocked the implementation commit because Step 5a/5b’s verify+start commits sat on local main un-pushed while origin/main was stale — the hook compares the task branch against origin/main. It resolved only when a parallel session pushed origin/main. Candidate fix: have the hook resolve its base to local main when origin/main is an ancestor of local main. Keywords searched: project-check-task-state-origin, un-pushed, candidate, compares, resolved, parallel, ancestor, blocked Excluded: T-H7LB-task-work-appends-post-mortem-stub Top candidates (score / status / headline):
- 38 / planning/needs-definition / T-0015 — Dispatchability-aware task pickup:
sdlc task next(filter blocked deps by default) - 19 / open/ready / T-7RST-ensure-ready-flags-mid-migration-corpus-assumptions — ensure-ready: flag tasks whose Approach assumes a uniform corpus shape mid-migration
- 14 / closed/done / T-A2C6-spawn-from-post-mortem-stronger-dedup — Strengthen spawn-from-post-mortem dedup and record the search trail
- 13 / planning/draft / T-O4I9-refactor-task-work-step-2-via-skill-refine — Refactor task-work Step
2 preflight to
precheck_task.py(dropfeat/legacy) - 13 / closed/done / T-X24I-orchestrate-lease-aware-dispatch — Teach
/sdlc:orchestrateto gate on the control plane and claim leases before dispatch Decision: LINKED-EXISTING T-6R73 (script said LINKED-EXISTING T-0015 → overridden) Rationale: The score-based search shares no keywords with this task’s slug, so it landed on T-0015 (a dispatchability/sdlc task nextfeature) — a false positive driven by generic words (blocked, parallel, resolved, ancestor). T-6R73 is the active tracker for exactly this gap (project-check-task-state-origingating on a staleorigin/main), already wikilinked by the originating post-mortem as the owner. The post-mortem adds a concrete candidate fix (resolve the hook’s base to localmainwhenorigin/mainis an ancestor of localmain) worth weighing against this task’s existing approach. Linked from: T-H7LB-task-work-appends-post-mortem-stub
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: The verify/start task-state commits landed on the task BRANCH (stale SHAs) instead of only on main: start_task.ts reset the branch to local main’s tip, then the parent had to git pull —rebase main (origin/main had diverged under parallel WIP) which rewrote those commits’ SHAs — leaving the pre-rebase copies stranded on the branch. They tripped project-check-task-state-origin on every branch commit, forcing the implementation sub-agent to commit with LEFTHOOK=0 (bypassing ALL gates). Gap: when origin/main moves between start_task’s branch-reset and the parent’s main-push, the branch carries stale state commits; task-work Step 5b should rebase the task branch onto origin/main after the main-push (or start_task should reset against the post-push tip), so the implementer never sees the lint-state-origin false positive and never needs LEFTHOOK=0. Keywords searched: project-check-task-state-origin, lint-state-origin, branch-reset, task-state, start_task, pre-rebase, sub-agent, bypassing Excluded: T-LX04-activate-s0008-apps-adapter-validator Top candidates (score / status / headline):
- 40 / closed/superseded / T-2QXZ-start-task-handles-frontmatter-rebase-cleanly — start_task.py auto-merges frontmatter on stamp/start rebase conflict
- 37 / in-progress / T-H7LB-task-work-appends-post-mortem-stub — task-work appends a post-mortem template stub to the task file at start-time
- 37 / closed/superseded / T-Y7QU-start-task-fails-loud-on-cache-miss — start_task.py exits non-zero and surfaces cache-miss on lease lookup
- 32 / 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
- 30 / in-progress / T-PA51-task-state-commits-regen-site-page — Task-state commits regenerate the
derived site page
Decision: LINKED-EXISTING T-6R73 (script said SPAWNED → overridden) Linked from:
T-LX04-activate-s0008-apps-adapter-validator Rationale: Override script’s SPAWNED →
LINKED-EXISTING. The score-based search shares no keywords with this task’s slug (which still
carries template-stub body sections), so it ranked start_task-rebase neighbours instead. But this
bullet is the FOURTH independent observation of exactly the gap T-6R73 owns: state-only verify/start
commits on local
main(ahead of a staleorigin/mainunder parallel WIP) read as branch-exclusive violations toproject-check-task-state-origin, forcingLEFTHOOK=0/--no-verify— which is T-6R73’s title verbatim (“pre-commit drift hooks gate unconditionally, forcing —no-verify past pre-existing trunk drift”). The bullet’s candidate fix (rebase the task branch ontoorigin/mainafter the main-push, or reset against the post-push tip) is a concrete remedy worth weighing against T-6R73’s existing “resolve the hook’s base to local main when origin/main is an ancestor” approach. Linked rather than spawning a near-duplicate upstream PR. Originating task: T-LX04-activate-s0008-apps-adapter-validator
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: A sub-agent reaching for LEFTHOOK=0 to get unblocked silently skips the new validator + docs-drift + markdown-fmt gates; the parent then has to re-run the whole gate set by hand. The implementer brief should forbid LEFTHOOK=0 and instead surface a hook block to the parent for resolution. Keywords searched: markdown-fmt, docs-drift, resolution, sub-agent, unblocked, validator, reaching, lefthook Excluded: T-LX04-activate-s0008-apps-adapter-validator Top candidates (score / status / headline):
- 32 / 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
- 29 / planning/proposed / T-RQU1-worktree-scope-guard-downstream-setup — Wire worktree-scope-guard lefthook into /sdlc:setup for downstream projects
- 27 / planning/proposed / T-NP7H-task-work-sub-agent-verdict-contract-escape-recurrence —
task-work: sub-agents still emit ensure-ready
READY:as final verdict despite verdict-contract hardening - 26 / planning/needs-definition / T-EGI0-task-body-validator-at-authoring-and-commit-time — Author-time task body validator (AC shape, touchpoint kinds, gitignored paths)
- 24 / closed/done / T-A5H1-lefthook-project-check-pre-commit — Gate commits on /project-check via
lefthook pre-commit
Decision: LINKED-EXISTING T-6R73 (script said SPAWNED → overridden) Linked from:
T-LX04-activate-s0008-apps-adapter-validator Rationale: Override script’s SPAWNED →
LINKED-EXISTING, and folded into T-6R73 alongside the sibling bullet above rather than spawned as
its own PR. This bullet is the same friction’s other half: the implementer only reached for
LEFTHOOK=0because of the stale-state false positive T-6R73 owns, and T-6R73’s title is literally “forcing —no-verify past pre-existing trunk drift.” The general policy the bullet proposes (the implementer brief should forbidLEFTHOOK=0and surface a hook block to the parent for resolution instead of silently bypassing the validator/docs-drift/markdown-fmt gates) is the brief-side complement to T-6R73’s gate-side fix and belongs in the same unit of work — two near-identical upstream PRs would fragment one gap. No other tracker owns the implementer-brief no-verify policy (grep across docs/planning/tasks/ forLEFTHOOK=0/--no-verifysurfaces only T-6R73 and post-mortems of the same gap). Originating task: T-LX04-activate-s0008-apps-adapter-validator