T-H7LB-task-work-appends-post-mortem-stub
Status: closed/done · Impact: medium · Complexity: small
Have /sdlc:task-work append a post-mortem template stub — correctly
placed at the end of the task document, pre-seeded with the three
required H3 subsections — to the task file at start-time, so the
implementation sub-agent fills a pre-positioned, pre-structured section
rather than authoring placement and structure from scratch.
During /sdlc:task-work, the implementation sub-agent placed the
Post-mortem section mid-document (before ## Out of scope) instead
Section titled “Post-mortem section mid-document (before ## Out of scope) instead”of at the end, and omitted the required ### Acceptance criteria coverage / ### What worked / ### Friction and automation gaps substructure, forcing the orchestrator to relocate and restructure it. Have task-work append a post-mortem template stub (correct end-of-document placement plus the three required H3 subsections) to the task file at start-time so the sub-agent fills a pre-positioned, pre-structured section rather than authoring placement and structure from scratch — preventing the recurring placement/structure drift.
— from
T-J71K-backport-events-collection-to-wikilink-refs
/sdlc:task-work Step 8 (plugin/skills/task-work/SKILL.md, the
## 8. Post-mortem section) documents the required post-mortem
structure — an H2 ## Post-mortem, a _Captured by …_ caption line,
and exactly three H3 subsections (### Acceptance criteria coverage,
### What worked, ### Friction and automation gaps) — but nothing
materializes that structure into the task file before the implementation
sub-agent runs. Step 5b’s start_task.ts is the only start-time
mechanical mutation of the task file (it flips frontmatter to
in-progress, validates, stages one file, and lands the
chore(tasks): start <basename> commit on main); it does not touch the
body. So at Step 8 the sub-agent authors the section from scratch —
inventing its placement and re-deriving its three H3 headings from the
prose in Step 8 — and placement/structure drift (the section landing
mid-document, or one H3 missing) is recurring.
| Location | Role today |
|---|---|
plugin/skills/task-work/SKILL.md | Step 8 (## 8. Post-mortem …, ~line 900) documents the required ## Post-mortem H2 + caption + three H3 subsections as a fenced template; Step 5b (### 5b. Mark the task started …, ~line 608) shells out to start_task.ts as the sole start-time task-file mutation. |
plugin/skills/task-work/start_task.ts | Start-time mechanical mutator: edits frontmatter (status → in-progress, last_reviewed), validates, stages only the task file, commits chore(tasks): start <basename> on main, transitions the lease, resets the feature branch. Never edits the body. |
plugin/skills/task-work/tests/start_task.test.ts | Behavioral tests for start_task.ts (frontmatter flip, commit, lease transition, idempotency). No coverage of body mutation today. |
Proposed
Section titled “Proposed”start_task.ts (invoked from Step 5b) appends a ## Post-mortem
template stub to the end of the task-file body, on the main-repo
copy, as part of the same chore(tasks): start <basename> commit — but
only when no ## Post-mortem H2 already exists. The stub is the exact
structure Step 8 documents: the ## Post-mortem H2, the
_Captured by /sdlc:task-work on <YYYY-MM-DD>. PR: pending._ caption,
and the three H3 subsections ### Acceptance criteria coverage,
### What worked, ### Friction and automation gaps, each with a single
_TBD — filled at Step 8._ placeholder line. The H2 lands after the
last existing body section, so placement is fixed by the tool, not the
sub-agent.
Step 8 prose is reworded from “append a ## Post-mortem section” to
“fill the ## Post-mortem stub that Step 5b already appended” — Step 8
now fills a pre-positioned, pre-structured section rather than
authoring placement and structure. The three documented H3 headings stay
in Step 8 as the source of truth for the stub’s content (so the stub and
the fill-time guidance can never drift apart silently).
Idempotency is preserved: re-running start_task.ts against a task that
already carries a ## Post-mortem H2 (resumed session, or a task that
reached Step 8 on an earlier run) leaves the body untouched and produces
no new commit when frontmatter is also already current.
Approach
Section titled “Approach”- In
start_task.ts, add a body-mutation step that runs againstmainTaskPathalongside the existing frontmatter edit. Parse the body (the text after the frontmatter block) and detect an existing## Post-mortemH2 with a line-anchored, case-sensitive scan (/^## Post-mortem\s*$/m). If present, skip — the body is already stubbed. - When absent, append the stub to the end of the body: ensure exactly
one trailing blank line before it, emit the H2, the
_Captured by /sdlc:task-work on <YYYY-MM-DD>. PR: pending._caption (UTC date from the existingtodayUtc()helper /--today), then the three H3 subsections in documented order, each followed by a single_TBD — filled at Step 8._line. Single-source the stub text and the three H3 headings as a module-level constant instart_task.tsso there is one literal to maintain. - Fold the body change into the existing semantic-change path: the stub
append counts as a semantic change, so the file is written, validated
(
sdlc entities validate), staged (still exactly one file —mainTaskPath), and committed under the samechore(tasks): start <basename>message. No second commit; no change to the staged-file sanity check (one file in, one file out). - Update Step 5b prose in
SKILL.mdto state thatstart_task.tsnow also appends the## Post-mortemstub at the end of the body when one is absent. Update Step 8 prose to say it fills the stub Step 5b appended (not appends a section), keeping the three documented H3 headings as the structure source. - Extend
plugin/skills/task-work/tests/start_task.test.ts: assert that afterstartTask()on a stub-less task the body ends with the## Post-mortemH2 followed by the three H3 subsections in order; that the H2 is the last H2 in the document (correct placement); that a secondstartTask()run is a no-op on the body (no duplicate## Post-mortem); and that a task already carrying a## Post-mortemH2 is left unchanged.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/skills/task-work/start_task.ts | modify | Add the end-of-body ## Post-mortem stub-append (H2 + caption + three H3 subsections), guarded by an “H2 already present” check; fold into the existing semantic-change write/validate/stage/commit path; single-source the stub literal. |
plugin/skills/task-work/SKILL.md | modify | Step 5b: note that start_task.ts appends the stub at start-time. Step 8: reword from “append a ## Post-mortem section” to “fill the stub Step 5b appended,” keeping the three documented H3 headings as the structure source. |
plugin/skills/task-work/tests/start_task.test.ts | modify | Add cases: stub appended at end with the three H3s in order; H2 is last in doc; second run is a body no-op; pre-existing ## Post-mortem left untouched. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: After
startTask()runs on a task file with no## Post-mortemH2, the resulting body contains a## Post-mortemH2 followed (in order) by### Acceptance criteria coverage,### What worked, and### Friction and automation gaps— asserted by a new case inplugin/skills/task-work/tests/start_task.test.ts. - AC-2: The appended
## Post-mortemH2 is the last H2 heading in the document (correct end-of-document placement) — asserted instart_task.test.ts. - AC-3: Running
startTask()a second time against a task that already carries a## Post-mortemH2 leaves the body byte-identical (no duplicate section, no new commit from the body) — asserted instart_task.test.ts. - AC-4: After the stub append,
sdlc entities validate <task>passes on the mutated file (frontmatter valid; the_TBD —_placeholders are in body prose, not in a required-section gate position) — exercised by the validate call insidestart_task.ts’s commit path and confirmed by the existing test that asserts a clean commit. - AC-5:
SKILL.mdStep 8 no longer instructs the sub-agent to author the section’s placement/structure — it instructs filling the stub Step 5b appended — and Step 5b documents the stub-append; verifiable by greppingplugin/skills/task-work/SKILL.mdfor the reworded phrasing. - AC-6: The start-task test suite at
plugin/skills/task-work/tests/start_task.test.tspasses underbun test.
Out of scope
Section titled “Out of scope”- Backfilling the stub into already-open or already-closed task files — the stub is appended only at Step 5b start-time for newly-started tasks.
- Changing the post-mortem’s three-H3 schema, the caption wording, or the
spawn-from-post-mortemfriction-parsing contract — this task fixes where and how the section is materialized, not what it captures. - Adding a
## Post-mortemH2 to the taskbody-template.eta— the stub is start-time tooling, not part of the authored task template (a template H2 would trip the readiness gate before work begins).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-06-11 UTC from
T-J71K-backport-events-collection-to-wikilink-refs in
git@github.com:sksizer/family.git.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-06-20. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto —
start_task.test.tscase “stub-less task → body gains## Post-mortemH2 + the three H3s in order”. - AC-2: auto —
start_task.test.tscase “appended## Post-mortemH2 is the last H2 in the document”. - AC-3: auto —
start_task.test.tscase “second run on an already-stubbed task: body byte-identical, no new body commit”. - AC-4: auto — exercised by
start_task.ts’s validate-in-commit path; the AC-1/AC-2 tests land the start commit, which throws ifentities validaterejects the appended stub. - AC-5: auto — grep on
SKILL.md: Step 5b (line 643) documents the stub-append; Step 8 (line 889) instructs filling the Step-5b stub; the old “append a## Post-mortemsection” phrasing count is 0. - AC-6: auto —
bun test plugin/skills/task-work/tests/start_task.test.ts→ 12 pass / 0 fail.
What worked
Section titled “What worked”- The deterministic readiness gate (
task gap-report) passed in one shot — all six required sections present, both touchpoint tables resolved, zero placeholders — so the task went start→implement with no definition round-trip. - The sub-agent landed all three source edits plus the regenerated site
mirror in a single focused commit, and every pre-commit hook passed
without
--no-verify.
Friction and automation gaps
Section titled “Friction and automation gaps”project-check-task-state-originblocked the implementation commit because Step 5a/5b’s verify+start commits sat on localmainun-pushed whileorigin/mainwas stale — the hook compares the task branch againstorigin/main. It resolved only when a parallel session pushedorigin/main. Candidate fix: have the hook resolve its base to localmainwhenorigin/mainis an ancestor of localmain(T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-no). → T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-nosdlc quality run --diff-against-baselinefrom a worktree defaulted--baseline-dirto the worktree-local path, so the first run erroredbaseline not found; the baseline lives in the superproject. Needed an explicit--baseline-dir <superproject>/.sdlc/quality-baselines(T-44OO-plugin-scripts-self-discover-project-root). → T-44OO-plugin-scripts-self-discover-project-root- The baseline-gated gate reported
new-drift=10, all of itbun testephemeral stdout (randomhttp://127.0.0.1:<port>/ports, PIDs, and example PR URLs from the parallel T-CW4K dashboard tests) —normalizeFindingmasks neither the URL port nor bare PID columns, so the lines mismatch the baseline and surface as false new-drift that FAILS an unrelated task’s gate. This makes T-BQRU-quality-normalize-ports-pids-timings a concrete cross-task gate-blocker, not just cosmetic noise. → T-BQRU-quality-normalize-ports-pids-timings - Editing
plugin/skills/task-work/SKILL.mdregeneratessite/src/content/docs/reference/skills/task-work.md; that mirror must be staged in the same commit orproject-check-docs-driftblocks. Known pattern — handled bysdlc docs generate+ staging the page. (SKIPPED — no new automation gap; the regenerate-and-stage fix at its source is already in flight via T-PA51-task-state-commits-regen-site-page, PR #443.)
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-no — linked (existing tracker for
the stale-
origin/maintask-state-origin gate; the local-main-ancestor candidate fix recorded against it). - T-44OO-plugin-scripts-self-discover-project-root — linked (existing tracker for the baseline-dir worktree-vs-main self-discovery friction; 7th post-mortem to surface it).
- T-BQRU-quality-normalize-ports-pids-timings — linked (existing tracker for
normalizeFindingephemeral-token masking; enriched with the new cross-task gate-blocker data point + the example-PR-URL token kind). - docs-drift mirror staging — none (SKIPPED; known, already-handled pattern, source fix in flight via T-PA51-task-state-commits-regen-site-page).