os-sdlc: BriefAssembler emits empty stub briefs (no ticket text) #365

Closed
opened 2026-08-14 18:08:50 +00:00 by jared · 3 comments
Owner

Context

During the #361 run, briefs 001-011 carried no ticket text; programmer round 2 went astray inventing work (StatusTableTrimmer) from an empty brief. Corroborated 2026-08-15 (#402/#405 run, session https://claude.ai/code/session_01GSYJVRGmBiLGjPppHjY3bZ): every runner brief was a ~68-byte stub; the orchestrator hand-enriched all of them.
Code-probe 2026-08-15: TicketFlow#brief_body (lib/os_sdlc/runner/ticket_flow.rb:106-112) always emits the stub "Work the stage."; StageBriefAnnotations covers only test-writer/review/seam-designer (code-probe has no case). The tickets DB table has no body column and nothing in the dispatch path fetches from the tracker, so the ticket text is a capability gap, not a wiring gap. ticket[:target_name] + Project.load already exist but are never rendered into briefs. Prior-stage artifact paths already have the EvidenceBrief.path_for / SeamDecision.path_for pattern.
Decision (consistent with ADR-0109 briefs-are-markdown-files): fetch the ticket body once at intake via the tracker CLI and store it as .sdlc/tickets//ticket-body.md; briefs reference/inline it from there. Rejected: a DB body column (duplicates markdown-as-truth into SQLite); per-dispatch tracker fetches (network in every transition).

VERDICT: CREATE — hard floor; observed failure in two separate runs (#361 bad-output trace, #402/#405 bounce + hand-enrichment).

Tasks

  • At intake, fetch the ticket body (os-backlog show / tea) and write .sdlc/tickets//ticket-body.md; fail intake loudly if the fetch fails.
  • TicketFlow#brief_body: include the ticket-body file content (or its path) and a target block (target name, code_path, test_path, test_command from Project.load) in every stage brief.
  • StageBriefAnnotations: add the missing code-probe case; each stage's annotation names the prior-stage artifact paths that exist for it (evidence-brief, seam-decision, verdict), reusing the existing path_for pattern.
  • Tests: intake writes ticket-body.md; a generated brief for each stage contains ticket text, target block, and the prior-stage paths that exist; missing tracker fetch fails loudly.

Acceptance criteria

  • A brief generated for any stage of a fresh intake contains the ticket body text, the target block, and existing prior-stage artifact paths — no hand-enrichment needed.
  • Intake without a reachable tracker fails with a loud error, not a stub brief.
  • Suite green, changed files rubocop-clean.

Out of scope

Namespaced-agent event matching (#400); review-packet content (#405, shipped).

## Context During the #361 run, briefs 001-011 carried no ticket text; programmer round 2 went astray inventing work (StatusTableTrimmer) from an empty brief. Corroborated 2026-08-15 (#402/#405 run, session https://claude.ai/code/session_01GSYJVRGmBiLGjPppHjY3bZ): every runner brief was a ~68-byte stub; the orchestrator hand-enriched all of them. Code-probe 2026-08-15: TicketFlow#brief_body (lib/os_sdlc/runner/ticket_flow.rb:106-112) always emits the stub "Work the <state> stage."; StageBriefAnnotations covers only test-writer/review/seam-designer (code-probe has no case). The tickets DB table has no body column and nothing in the dispatch path fetches from the tracker, so the ticket text is a capability gap, not a wiring gap. ticket[:target_name] + Project.load already exist but are never rendered into briefs. Prior-stage artifact paths already have the EvidenceBrief.path_for / SeamDecision.path_for pattern. Decision (consistent with ADR-0109 briefs-are-markdown-files): fetch the ticket body once at intake via the tracker CLI and store it as .sdlc/tickets/<n>/ticket-body.md; briefs reference/inline it from there. Rejected: a DB body column (duplicates markdown-as-truth into SQLite); per-dispatch tracker fetches (network in every transition). VERDICT: CREATE — hard floor; observed failure in two separate runs (#361 bad-output trace, #402/#405 bounce + hand-enrichment). ## Tasks - [ ] At intake, fetch the ticket body (os-backlog show / tea) and write .sdlc/tickets/<n>/ticket-body.md; fail intake loudly if the fetch fails. - [ ] TicketFlow#brief_body: include the ticket-body file content (or its path) and a target block (target name, code_path, test_path, test_command from Project.load) in every stage brief. - [ ] StageBriefAnnotations: add the missing code-probe case; each stage's annotation names the prior-stage artifact paths that exist for it (evidence-brief, seam-decision, verdict), reusing the existing path_for pattern. - [ ] Tests: intake writes ticket-body.md; a generated brief for each stage contains ticket text, target block, and the prior-stage paths that exist; missing tracker fetch fails loudly. ## Acceptance criteria - [ ] A brief generated for any stage of a fresh intake contains the ticket body text, the target block, and existing prior-stage artifact paths — no hand-enrichment needed. - [ ] Intake without a reachable tracker fails with a loud error, not a stub brief. - [ ] Suite green, changed files rubocop-clean. ## Out of scope Namespaced-agent event matching (#400); review-packet content (#405, shipped).
Author
Owner

Deviation incident 2026-08-15 — /os-sdlc:implement run for #402+#405, session https://claude.ai/code/session_01GSYJVRGmBiLGjPppHjY3bZ. Deviating skill: plugins/os-sdlc/skills/implement/SKILL.md.

Expected: runner-emitted briefs carry the ticket body, target block, and prior-stage artifact paths so the named agent can work from the brief path alone. Actual: every brief for #402 and #405 was a ~68-byte stub ('# code-probe brief for ticket 402 / Work the code-probe stage.'); the first code-probe dispatch bounced refusing to fabricate, and the orchestrator hand-enriched all 7+ briefs (ticket text from os-backlog show, target from .sdlc/project.yaml, pointers to evidence-brief/seam-decision/verdict). Minimal fix direction: intake/transition brief assembly should inline exactly those three blocks.

Deviation incident 2026-08-15 — /os-sdlc:implement run for #402+#405, session https://claude.ai/code/session_01GSYJVRGmBiLGjPppHjY3bZ. Deviating skill: plugins/os-sdlc/skills/implement/SKILL.md. Expected: runner-emitted briefs carry the ticket body, target block, and prior-stage artifact paths so the named agent can work from the brief path alone. Actual: every brief for #402 and #405 was a ~68-byte stub ('# code-probe brief for ticket 402 / Work the code-probe stage.'); the first code-probe dispatch bounced refusing to fabricate, and the orchestrator hand-enriched all 7+ briefs (ticket text from os-backlog show, target from .sdlc/project.yaml, pointers to evidence-brief/seam-decision/verdict). Minimal fix direction: intake/transition brief assembly should inline exactly those three blocks.
Author
Owner

Work starting: pre-flight passed (verdict CREATE, checklist present, ready-for-agent). Running via /os-sdlc:implement in parallel with #409.

Work starting: pre-flight passed (verdict CREATE, checklist present, ready-for-agent). Running via /os-sdlc:implement in parallel with #409.
Author
Owner

Resolution

Done: Intake fetches the ticket body once via the tracker port into .sdlc/tickets//ticket-body.md; every stage brief renders ticket body, target block (Project.load), and existing prior-stage artifact paths; StageBriefAnnotations gains the code-probe case; TeaTracker.for selects NullTracker only for genuinely tracker-less roots, configured-but-unreachable trackers fail intake loudly

Evidence: commit 25f35cf on branch worktree-issue-365; suite 946 runs 0 failures; 16 changed files rubocop-clean; reviewer APPROVE round 3 at .sdlc/tickets/365/verdict.md

Follow-ups: #411: dedup tracker-line regex (skeptic VERDICT: CREATE); gate-log evidence gap already tracked in #410

## Resolution **Done:** Intake fetches the ticket body once via the tracker port into .sdlc/tickets/<n>/ticket-body.md; every stage brief renders ticket body, target block (Project.load), and existing prior-stage artifact paths; StageBriefAnnotations gains the code-probe case; TeaTracker.for selects NullTracker only for genuinely tracker-less roots, configured-but-unreachable trackers fail intake loudly **Evidence:** commit 25f35cf on branch worktree-issue-365; suite 946 runs 0 failures; 16 changed files rubocop-clean; reviewer APPROVE round 3 at .sdlc/tickets/365/verdict.md **Follow-ups:** #411: dedup tracker-line regex (skeptic VERDICT: CREATE); gate-log evidence gap already tracked in #410
jared closed this issue 2026-08-16 06:28:38 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#365
No description provided.