T-N2X3-start-task-preserves-readiness-stamp
Status: closed/done · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
When /sdlc:task-work resumes a task whose prior run bailed after
ensure-ready’s READY: marker, plugin/skills/task-work/start_task.py
rewrites the task file on main and then git rebase main inside the
worktree replays ensure-ready’s docs(tasks): verify ... commit on
top. Both commits touch frontmatter, so the rebase hits a content
conflict on the status / readiness_verified_at lines that requires
a human to resolve. Closing this gap means resumed sessions
fast-forward cleanly without manual conflict surgery.
Surfaced by T-Z8VC-task-work-preflight-permissions-probe’s post-mortem.
start_task.py rewrites docs/planning/tasks/<basename>.md on main
to set status: in-progress and refresh last_reviewed:. The
script does NOT read the worktree’s copy of the same file, so a
fresher readiness_verified_at: value that ensure-ready stamped on
the feat branch is overwritten by whatever main had pre-rewrite.
git rebase main then surfaces a conflict on those frontmatter
lines: HEAD says status: in-progress with the older stamp, the
ensure-ready commit on the branch says status: open/ready with the
newer stamp, and git cannot pick a winner.
Evidence: the 2026-05-21 resumed run of
T-Z8VC-task-work-preflight-permissions-probe had to manually
resolve a conflict where HEAD held readiness_verified_at: '2026-05-21T04:34:15Z'
and the branch held readiness_verified_at: '2026-05-21T15:36:32Z'.
Both came from this same skill; the merge could have been computed
mechanically.
Proposed
Section titled “Proposed”start_task.py’s rewrite of main’s task file preserves the worktree’s
readiness_verified_at: value. After the rebase, the merged
frontmatter on the feat branch has status: in-progress (from main)
AND the latest stamp (from the worktree), with no conflict.
Acceptable shapes:
- Read the worktree’s task file first, lift its
readiness_verified_at:, and write that value into main’s file along with the status flip. - Use
git rebase -X theirsscoped just to the task file, so the worktree’s version of the frontmatter wins on conflict (the verify commit is “newer” by construction). - Detect the conflict and auto-resolve by union-merging frontmatter keys: status from HEAD, every other key from the incoming side.
Option 1 is simplest and lowest-magic; the conflict never arises because both sides agree on every key.
Approach
Section titled “Approach”- In
start_task.py, before rewriting main’s task file, read the worktree’s copy and capture itsreadiness_verified_at:value (if any). Apply it to the in-memory frontmatter for main’s rewrite. - Extend
test_start_task.pywith a case mirroring the observed conflict: the worktree’s task file has a fresherreadiness_verified_at:stamp than main’s, the script runs, the rebase fast-forwards with noREBASE_HEADleft behind, and the final task file on the feat branch carriesstatus: in-progressAND the fresher stamp. - Confirm the existing tests still pass — preserving the worktree value when the worktree has no stamp must remain a no-op.
Files to touch
Section titled “Files to touch”plugin/skills/task-work/start_task.py— read worktree file, preservereadiness_verified_at:into main’s rewrite.plugin/skills/task-work/test_start_task.py— new test case pinning the conflict-free behavior.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A test fixturing a fresher
readiness_verified_at:on the worktree’s task file than on main’s runsstart_task.pyand thegit rebase mainstep completes without leaving the repository inREBASEstate. The final task file on the feat branch hasstatus: in-progressAND the fresher stamp. - AC-2: Existing
test_start_task.pycases still pass — preserving a missingreadiness_verified_at:on the worktree side is a silent no-op. - AC-3: A resumed
/sdlc:task-worksession (where ensure-ready ran in a prior run andstart_task.pyruns now) does not need manual conflict resolution on the task file.
Out of scope
Section titled “Out of scope”- Changes to
/sdlc:task-ensure-ready’s stamping behavior. - Auto-resolution of conflicts on task files that arose for any other reason (e.g. body edits from two sub-agents).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-Z8VC-task-work-preflight-permissions-probe on 2026-05-21.
Re-linked from /sdlc:task-work post-mortem of
T-G834-move-plugin-runtime-state-to-sdlc-dir on 2026-05-22.
That session observed that even after PR #86 preserves the stamp at
the file-tree level, the line-add conflict on readiness_verified_at:
still requires manual resolution (the verify commit becomes empty
after resolution and gets dropped, but the conflict surfaces). The
linked task’s Option 1 approach (read worktree first, apply value to
main’s rewrite) should still close this — if implementation is
already merged and the line-add gap remains, treat this as a
follow-up: explicit skip-replay of the verify commit when both sides
agree on the stamp value, or detect-and-auto-resolve the trivial
frontmatter conflict.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: The rebase inside start_task.py (Step 5b) conflicted on the task file frontmatter because both the verify-stamp commit (ensure-ready output on feat) and the start-commit (start_task.py edit on main) added readiness_verified_at. The recent preserve readiness_verified_at across start_task rebase fix (PR #86) preserves the stamp at the file-tree level but does not avoid the line-add conflict - the verify commit becomes empty after the conflict resolution and gets dropped, but the conflict still requires manual resolution. Suggests: start_task.py could detect the case where the feat branch already carries a stamp and main is gaining the same stamp via the start-commit, and either skip-replay the verify commit explicitly or auto-resolve the trivial frontmatter conflict. Keywords searched: readiness_verified_at, verify-stamp, ensure-ready, start-commit, auto-resolve, frontmatter, skip-replay, start_task Excluded: 2026-05-22-move-plugin-runtime-state-to-sdlc-dir Top candidates (score / status / headline):
- 40 / in-progress / 2026-05-21-start-task-preserves-readiness-stamp — start_task.py should preserve readiness_verified_at across rebase
- 38 / closed/done / 2026-05-19-extract-start-task-script — Extract task-work Step 5b into scripts/start_task.py
- 38 / closed/done / 2026-05-19-task-ensure-ready-accepts-in-progress — task-ensure-ready accepts in-progress when readiness_verified_at is set
- 38 / closed/done / 2026-05-20-task-work-rebase-frontmatter-conflict — Avoid structural rebase conflict in /sdlc:task-work Step 5b
- 33 / closed/done / 2026-05-20-task-ensure-ready-flags-spec-placeholders — task-ensure-ready flags TBD and ‘final name’ placeholders in spec body Decision: LINKED-EXISTING 2026-05-21-start-task-preserves-readiness-stamp
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-05-21. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto — new
test_preserves_worktree_readiness_stampinplugin/skills/task-work/test_start_task.pyfixtures the older-on-main / fresher-on-worktree case, runsstart_task.py, and asserts (a) noREBASE_HEADis left behind, (b) the final feat-branch file hasstatus: in-progress, and (c) the fresher stamp survives. - AC-2: auto — full
test_start_task.pysuite (5/5) still passes, including the original happy-path / conflict-path / idempotent / closed-rejection cases. The lift is a silent no-op when the worktree file lacksreadiness_verified_at:because the lookup returnsNoneand theif wt_stamp and ...guard short-circuits. - AC-3: auto — the new test models the resumed-session scenario
end-to-end (older stamp seeded on main, verify-stamp commit landed on
feat branch with a fresher stamp, then
start_task.pyruns). The assertions that no REBASE state remains and the final file is correct are the operational meaning of “no manual conflict resolution needed”.
What worked
Section titled “What worked”- The bug’s mechanics were unambiguous from the spec — Today / Approach named the failing line, the conflict pair, and a clean implementation shape. No design conversation needed.
- The existing
test_start_task.pyhad atest_rebase_conflictcase to mirror against; the new case is a near-copy with the inverted resolution shape, which kept it small and obviously correct. - The
stamp_liftedboolean wired intosemantic_changeslotted into the existing idempotent-commit gating without disturbing the already-in-progress no-op path.
Friction and automation gaps
Section titled “Friction and automation gaps”- The first
/sdlc:task-workrun on this very task (the live run that authored the fix) did NOT reproduce the original conflict, because the rebase auto-merged the disjoint frontmatter edits cleanly. The bug is conditional on commit-content overlap, not just on divergent stamps — the spec implied it was universal. Future post-mortem-spawned tasks whose evidence comes from a single observed incident should call out “reliably reproducible” vs “intermittent” in the Today section. → T-WZ5O-post-mortem-evidence-reproducibility - Quality checks (
plugin/scripts/audit_entities.py) reported pre-existing drift on 8 unrelated task files (one a YAML parse error on2026-05-21-pr-check-schema-promote.md). The runner returns FAIL 1/11 for any drift, so every PR appears to fail the gate even when its diff is clean. Either the audit needs a baseline-allow mechanism (only fail on NEW drift), or the offending files need a triage sweep, or the gate needs to drop into a warning tier for pre-existing entries. → T-SDB5-audit-entities-baseline-allow
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-WZ5O-post-mortem-evidence-reproducibility — spawn-from-post-mortem should require reproducibility-tier labelling on the originating evidence, created
- T-SDB5-audit-entities-baseline-allow — audit_entities.py should distinguish pre-existing drift from PR-introduced drift, created