Skip to content

deferredwork: dev session writes ledger markdown directly — give it a structured sink the orchestrator renders #326

Description

@pbean

Summary

The inner dev session writes deferred-work ledger markdown directly. bmad-dev-auto's
step-04-review.md:69-74 instructs it to append a flat block to {deferred_work_file}:

- source_spec: `{spec_file}`
  summary: <one sentence>
  evidence: <why this is real>

and engine.py:2391-2396 reinforces it in the follow-up-review prompt the orchestrator sends
("append them to the deferred-work ledger as NEW entries only").

This sits awkwardly against deferredwork.py's own module docstring — "The orchestrator never
trusts an LLM to have edited it"
— which is true of status flips and decision records, and not true
of entry creation. It is also the reason two recent bugs existed:

Every flat entry also costs a whole extra LLM migration session before it is sweepable
(sweep.py:714-720 — "One LLM session rewrites the legacy items into canonical DW entries").

Design sketch

Give the dev session a structured sink and let orchestrator Python render the ledger.

The channel already exists in two forms — neither needs an upstream fork:

  1. Spec frontmatter. devcontract.synthesize_result (devcontract.py:197) already builds the
    dev result dict entirely from spec frontmatter — dev sessions emit no result.json at all
    (devcontract.py:1-10). A deferred: list there is parsed by the existing read_frontmatter.
  2. The generic result.json mixin. adapters/generic.py:187-207 is available to any skill that
    writes one; bmad-loop-sweep uses it today. bmad-dev-auto simply doesn't.

Either way the orchestrator calls deferredwork.append_entry per item, so entries arrive canonical
(### DW-<seq>) and pre-sanitized, and has_legacy/migration stops firing for new work.

bmad-dev-auto is upstream and not bundled here (install.py:62-70,
data/skills/README.md:21-23), but the orchestrator already overrides its ledger instructions by
prompt injection at engine.py:2391-2396 — so this is a prompt-contract plus renderer change on the
bmad-loop side, not a fork. An upstream change would be cleaner if Alex is open to it.

What this does NOT replace

A newline inside a JSON or YAML string value is still a real newline once parsed. Structured input
fixes syntax corruption (malformed blocks, broken indentation, boundary ambiguity), not value
content — so deferredwork's _one_line sanitizer from #305 remains load-bearing. What this buys is
making that chokepoint universal instead of partial, and deleting a migration session per flat
defer.

Scope note

Feature-sized: touches the dev contract, the flat-entry parser, migration, and legacy-ledger
handling. Filing for maintainer confirmation before any implementation, per CONTRIBUTING.

Backward compatibility is the main design question — flat appends must keep working for
already-installed bmad-dev-auto versions and for ledgers already containing them, so the renderer
is additive and parse_legacy/migration stay as the fallback path rather than being removed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions