Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
cb3bb3d
fix(verify): require a dispatch-time expectation before a park skips …
Aug 30, 2026
b15408a
Revert "fix(verify): require a dispatch-time expectation before a par…
Aug 30, 2026
b6b4f08
fix(verify): require a dispatch-time expectation before a park skips …
Aug 30, 2026
b067642
sweep dw-park-skip-expectation-and-record: DW-1, DW-6 via bmad-loop
Aug 30, 2026
ff1f3e8
sweep dw-verify-command-seam-faults-and-records: DW-2, DW-4, DW-5 via…
Aug 30, 2026
da3b917
sweep dw-root-divergence-test-fixtures: DW-3, DW-9 via bmad-loop
Aug 30, 2026
ac99718
sweep dw-session-task-id-namespace: DW-7, DW-8 via bmad-loop
Aug 30, 2026
f31c2bb
sweep dw-stale-restore-fault-and-redaction: DW-10, DW-12 via bmad-loop
Aug 30, 2026
dd69b32
sweep dw2-gather-escalations-hardening: DW-68, DW-70, DW-71, DW-72, D…
Aug 30, 2026
dc0c36f
sweep escalation-watermark: DW-11 via bmad-loop
Aug 30, 2026
5aff222
Revert "sweep escalation-watermark: DW-11 via bmad-loop"
Aug 30, 2026
79aac6e
sweep dw2-escalation-watermark: DW-11 via bmad-loop
Aug 31, 2026
abc239d
Add source-scan parity guards for three prose-only invariants
Aug 31, 2026
359bee8
sweep dw2-source-scan-parity-guards: DW-65, DW-66, DW-82 via bmad-loop
Aug 31, 2026
63ddb1f
Make rearm_escalation a transaction from the spec flip to save_state
Aug 31, 2026
368302d
Close the re-arm transaction's remaining escapes from the spec flip w…
Aug 31, 2026
a66900b
sweep dw2-rearm-transaction-window: DW-79, DW-83, DW-85 via bmad-loop
Aug 31, 2026
c8dd4d8
sweep dw2-rearm-commits-probe-record: DW-81 via bmad-loop
Aug 31, 2026
c9ff25a
fix(loop): journal spent review budgets, dedupe harvest sightings, cl…
Aug 31, 2026
96c3afb
sweep dw-resolve-session-root-context: DW-14, DW-35 via bmad-loop
Sep 1, 2026
b5b9c35
sweep dw-remove-dead-artifact-relpaths: DW-15 via bmad-loop
Sep 1, 2026
8ae6957
sweep dw-peel-task-generation-suffix: DW-16 via bmad-loop
Sep 1, 2026
550f11c
sweep dw-document-spec-path-resolvers: DW-17, DW-18, DW-36 via bmad-loop
Sep 1, 2026
1de78e4
sweep dw-atomic-tui-replan: DW-33 via bmad-loop
Sep 1, 2026
2468c0d
sweep dw2-isolation-flip-mount-state: DW-41, DW-42, DW-45 via bmad-loop
Sep 1, 2026
bc18a0b
sweep dw2-path-assertion-test-hardening: DW-43, DW-44 via bmad-loop
Sep 1, 2026
a445f1c
Fix session-authored park assertions
Sep 1, 2026
8221ebe
Harden park marker provenance
Sep 1, 2026
bf682b8
sweep dw2-session-authored-park-assertion: DW-46, DW-47 via bmad-loop
Sep 1, 2026
9213f9a
sweep dw2-proof-probe-consistency: DW-48, DW-49, DW-50 via bmad-loop
Sep 1, 2026
1eea08e
sweep dw2-document-optional-baseline-claim: DW-51 via bmad-loop
Sep 1, 2026
64dc983
sweep dw3-authoritative-rearm-outcome: DW-40 via bmad-loop
Sep 1, 2026
928270f
sweep dw3-verify-command-fault-contract: DW-53, DW-54 via bmad-loop
Sep 1, 2026
2d8d467
sweep dw3-root-divergence-fixture-hardening: DW-56, DW-57, DW-58, DW-…
Sep 1, 2026
2ce281c
sweep dw3-session-artifact-contract-docs: DW-67, DW-75 via bmad-loop
Sep 1, 2026
5399d20
sweep dw3-adapter-task-dir-confinement: DW-74 via bmad-loop
Sep 1, 2026
0dc9626
sweep dw4-diagnostic-journal-sanitization: DW-76, DW-77, DW-80, DW-84…
Sep 1, 2026
b660ca6
sweep dw4-session-artifact-json-hardening: DW-86, DW-89 via bmad-loop
Sep 1, 2026
46732d3
sweep dw4-resolve-context-contract-docs: DW-87 via bmad-loop
Sep 1, 2026
bc9959c
sweep dw4-decision-dw-91: DW-91 via bmad-loop
Sep 2, 2026
baf463d
sweep dw4-decision-dw-93: DW-93 via bmad-loop
Sep 2, 2026
19d2a4c
sweep dw5-run-lifecycle-resume-exclusion: DW-94 via bmad-loop
Sep 2, 2026
96aa09a
fix(resolve): refuse the #414 pair before the interactive session
Sep 2, 2026
8100c53
test(guard): add journal-kind and refusal-site coverage gates
Sep 2, 2026
7899f0b
test(guard): inventory forwarder-kind literals; grade both kind arms …
Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
274 changes: 240 additions & 34 deletions CHANGELOG.md

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions README.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

66 changes: 54 additions & 12 deletions docs/FEATURES.md

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion docs/adapter-authoring-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,17 @@ Three frozen dataclasses cross the seam:

Required (abstract):

- `start_session(spec) -> SessionHandle` — launch the session.
- `start_session(spec) -> SessionHandle` — launch the session. An adapter that
persists the standard `tasks/<id>/` directory must reset its shared cycle
artifacts when an id is reused: after creating the task directory and before
launching the session, remove every file named by
`journal.TASK_CYCLE_ARTIFACTS` (shared artifacts: [`result.json`,
`escalation.json`]).
Use missing-safe deletion; a missing artifact is a normal no-op and must not
make startup fail. This tuple covers only artifacts shared across adapters and
readers. Adapter-private breadcrumbs such as `heartbeat.json`,
`resultless-stops.jsonl`, `session-lifecycle.jsonl`, and `messages.json` remain
outside the shared cleanup contract and are managed by their owning adapter.
- `wait_for_completion(handle, spec) -> SessionResult` — block until the session
ends (or stalls/times out), then report status. Poll
`runs.read_stop_request_mode(run_dir) == "hard"` on both sides of the loop's
Expand Down
72 changes: 47 additions & 25 deletions docs/plugin-authoring-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,16 @@ escalation emits before the run stops, on either leg.

`post_dev_verify` exposes `ctx.command_results`: an immutable tuple of the
per-command `CommandResult` records core just executed. Each has `command`,
`returncode`, the existing merged bounded `output_tail`, and separate `stdout`
and `stderr` strings. Those two are intended to be the streams essentially whole
`returncode`, the existing merged bounded `output_tail`, separate `stdout`
and `stderr` strings, and `spawn_error` — normally `None`, and set when the child
could not be started at all. The typical cause is the directory it was to run in
(missing, not a directory, or unsearchable), which the message names, but any
spawn-time `OSError` lands here — a missing shell, EMFILE, ENOMEM — so read the
wrapped exception rather than assuming the directory. Such a result carries no
real exit status (`verify.SPAWN_FAULT_RC`, deliberately outside the range a
signal-killed child reports and distinct from the timeout leg's `-1`) and
classifies as an environment fault, which pauses the run. The two stream strings
are intended to be the streams essentially whole
— they are not cut to `[verify] stream_capture_kb`, which bounds only what is
written to disk — but they are not unbounded either: a hard 32 MiB per-stream
ceiling applies, so a pathologically chatty command cannot grow the orchestrator's
Expand All @@ -415,9 +423,13 @@ is always detectable rather than silent. Ordinary suites never reach it. This is
observation data only: a plugin cannot change the verifier's outcome or the commit
decision. The run's `journal.jsonl` also records
one `verify-command-result` entry per command with run/story/attempt/stage and
verification-sequence correlation, `output_tail`, byte counts, and run-relative `stdout_path` /
verification-sequence correlation — note that `attempt` is the dev/repair counter, so every review
cycle of one attempt shares a single value and only `verification_sequence` tells successive review
passes apart — `output_tail`, `spawn_error`, byte counts, and run-relative `stdout_path` /
`stderr_path` pointers under the run's `verify/` directory; full streams are not
embedded in the journal. That store is deliberately separate from `logs/`, which
embedded in the journal. `spawn_error` rides the record because the record's
readers are out-of-process and `returncode` alone cannot separate a child that
never started from one that ran. That store is deliberately separate from `logs/`, which
holds coding-CLI pane captures named after session task ids and is read as such
by the TUI.

Expand Down Expand Up @@ -470,34 +482,44 @@ carries the reason. A plugin reading these pointers must therefore treat both
file holds a command's whole output. Treat verifier output as potentially sensitive and store, upload, sign,
or act on it only from an explicitly configured plugin.

**The dev phase is the whole of this surface.** `[verify] commands` also run at
the _review_ gate — `verify_review` / `verify_review_stories` /
`verify_review_bundle` end on the same core classifier — and **none of those runs
are journalled or published to any hook.** They run in `repo_root`, the same root
**The dev phase is the whole of this HOOK, not of the journal.** `[verify]
commands` also run at the _review_ gate — `verify_review` /
`verify_review_stories` / `verify_review_bundle` end on the same core classifier
— and those runs **are journalled** (`verification_stage: "review"`, sharing the
story's one `verification_sequence` counter with the dev and fix passes) but are
**not published to any hook.** They run in `repo_root`, the same root
the dev phase uses (#695); only the gates' own artifact reads — the spec, the
sprint board, the deferred-work ledger — stay project-rooted. Five engine gates reach them: the
converged review pass, the review-budget-exhaustion rescue, the review-timeout
salvage, and both passes inside the skip-review commit path (which runs the gate
again after a repair). `bmad-loop confirm --reverify` runs the commands too, out
of band by construction — the run that parked the story is finished, so there is
no journal to write to and no hook bus to emit on.
again after a repair). The records do not name which of the five ran — the
neighbouring `review-result` / `review-skipped*` / `review-timeout-salvage*`
entries and the sequence ordering say that. `bmad-loop confirm --reverify` runs
the commands too, out of band by construction — the run that parked the story is
finished, so there is no journal to write to and no hook bus to emit on.

Two consequences a handler has to be written for:

- **`verify-command-result` entries are not a complete census of a run's verifier
invocations.** Every story that reaches a commit ran the commands at least once
more than the records show. Never derive "the verifier ran N times" or "the last
thing the verifier saw" from the journal — derive only "these are the dev-phase
passes", which is what the records claim.
- **A green commit is not evidence that the last journalled pass was green**, and a
red journalled pass is not evidence the commit was blocked: a `fix` pass can fail
and the story still commit after a later review-gate run that left no record.
Correlate a decision with the `dev-decision` / `fix-decision` / `review-result`
entries beside the results, not with the results alone.

The boundary is deliberate, not an oversight — the review leg would need its own
hook stage rather than a second meaning for one named `post_dev_verify` — and is
tracked as a follow-up in [#656](https://github.com/bmad-code-org/bmad-loop/issues/656).
- **`verify-command-result` entries are a complete census of a RUN's verifier
command invocations, but not of every gate visit or of a project's.** Every
command executed by an in-run dev, fix or review pass lands a record. A pass
with no `[verify] commands` configured executes nothing and therefore records
nothing; `bmad-loop confirm --reverify` stays outside because it runs after the
run that parked the story is over. Count distinct `verification_sequence`
values to derive recorded passes, while preserving that zero-command caveat.
- **One command record is not a pass verdict**, and an earlier red pass is not
evidence the commit was blocked: a failed pass can be followed by a green
review-gate pass and a commit. Group records by `verification_sequence`, then
correlate that group with its surrounding decision event instead of inferring
the decision from one command or from an older pass. The dev and fix legs use
`dev-decision` / `fix-decision`; review passes use the applicable neighbouring
`review-result`, `review-skipped*`, `review-timeout-salvage*`,
`review-budget-committed`, or `review-followup-damped` event described above.

The hook boundary is deliberate, not an oversight — the review leg would need its
own stage rather than a second meaning for one named `post_dev_verify` — and is
tracked as a follow-up in [#656](https://github.com/bmad-code-org/bmad-loop/issues/656),
which now narrows to that stage: the journalling half of it has landed.

### Review

Expand Down
Loading
Loading