Summary
A flat appender block (the - source_spec: / summary: / evidence: shape the inner
bmad-dev-auto review step appends, per step-04-review.md) that lands after the last canonical
### DW-<n> entry is absorbed into that entry's parse_ledger() span. parse_legacy() masks
canonical spans before scanning, so the flat finding is invisible to it — and therefore to the
sweep's migration/triage (sweep.py reads parse_legacy for leftovers) and to the TUI's legacy
view. The deferred finding is silently lost.
This is the work-losing failure class: the inner session did its job and recorded the defer, but
no downstream reader can ever see it.
Repro (current main, a82be01)
from bmad_loop.deferredwork import parse_ledger, parse_legacy
text = (
"# Deferred Work\n\n"
"### DW-1: canonical\n\n"
"origin: test\nlocation: n/a\nreason: test\nstatus: open\n\n"
"- source_spec: `spec-next.md`\n"
" summary: later flat finding\n"
" evidence: must not be swallowed by DW-1\n"
)
assert any("later flat finding" in e.body for e in parse_ledger(text)) # swallowed into DW-1
assert parse_legacy(text) == [] # invisible to the sweep
Expected: the flat block is not part of DW-1's body, and parse_legacy returns one entry titled
later flat finding.
Root cause
parse_ledger() ends an entry's span only at the next heading (HEADING_RE / ANY_HEADING_RE).
The flat appender writes a bullet block with no heading, and it appends at EOF — which is exactly
where the last canonical entry's span extends to. Any ledger whose tail is canonical (e.g. after a
migration, or after the orchestrator refiles a follow-up entry) then swallows every subsequent
inner-session defer.
Fix
PR #274 (@Haven2026) has the right fix: truncate the canonical span at the first flat appender
block, so the block stays visible to parse_legacy. The PR needs a rebase onto post-#300
deferredwork.py and a scope trim (review on the PR has details); its validation commits are
split out to a separate hardening issue.
Summary
A flat appender block (the
- source_spec:/summary:/evidence:shape the innerbmad-dev-auto review step appends, per
step-04-review.md) that lands after the last canonical### DW-<n>entry is absorbed into that entry'sparse_ledger()span.parse_legacy()maskscanonical spans before scanning, so the flat finding is invisible to it — and therefore to the
sweep's migration/triage (
sweep.pyreadsparse_legacyfor leftovers) and to the TUI's legacyview. The deferred finding is silently lost.
This is the work-losing failure class: the inner session did its job and recorded the defer, but
no downstream reader can ever see it.
Repro (current
main, a82be01)Expected: the flat block is not part of DW-1's body, and
parse_legacyreturns one entry titledlater flat finding.Root cause
parse_ledger()ends an entry's span only at the next heading (HEADING_RE/ANY_HEADING_RE).The flat appender writes a bullet block with no heading, and it appends at EOF — which is exactly
where the last canonical entry's span extends to. Any ledger whose tail is canonical (e.g. after a
migration, or after the orchestrator refiles a follow-up entry) then swallows every subsequent
inner-session defer.
Fix
PR #274 (@Haven2026) has the right fix: truncate the canonical span at the first flat appender
block, so the block stays visible to
parse_legacy. The PR needs a rebase onto post-#300deferredwork.pyand a scope trim (review on the PR has details); its validation commits aresplit out to a separate hardening issue.