Research: composition-advance-alignment

R-1 Grounding

  • Decision: close the gap by routing the composition advance through engine.plan_advance / commit_advance (operator ruling: a specified behaviour change).
  • Rationale: GROUNDING.md §"#2562 design-spike finding" shows that the adapter's planner runs only apply_result + plan_next. A composition-backed advance therefore records no SignificanceEvaluated event and no raci: record.
  • Alternatives considered:
  • Keep the parallel planner and add the two calls to it. Rejected: that keeps two planning authorities, which goes against the charter's single-canonical-authority principle.
  • Behaviour-preserving dedup only. Rejected by the operator ruling.

R-2 Post-spec adversarial squad (2026-10-06, advisory)

Two lenses ran: consumer impact (reviewer-renata profile) and design invariants (architect-alphonso profile). Each finding's disposition:

#LensSeverityFindingDisposition
1bothBLOCKER/MAJORThe adapter unit tests (test_bridge_engine.py:341-640, test_bridge_decision_log_flush.py:359-400) stub _planner.plan_next with an object() template. plan_advance reads neither, so these tests crash.Folded. Spec US3 now allows re-seaming them onto a real minimal frozen template with every assertion kept. Each re-seam is listed in the PR.
2designMAJORA complete_run(emit) hook could drop or duplicate MissionRunCompleted.Folded. The hook becomes `before_run_completed: Callable[[], None] \
3designMAJORA malformed significance block now blocks a composition advance (EDGE-003).Folded. It is an edge case in the spec and is named in the FR-012 changelog entry. This matches the engine path.
4designMINORplan_composition_advance would forward to plan_advance (C-003).Folded. It is deleted together with CompositionAdvancePlan, and the bridge calls _engine_adapter.plan_advance(..., "success").
5designMINORSymbols become dead: the apply_result wrapper, _mark_step_completed, _live_template_path and the payload imports.Folded. They are deleted in IC-03. The _append_event / _write_snapshot wrappers are kept (pinned by the six-wrapper test).
6designMINORThe legacy path catches StaleAdvancePlan and falls back to runtime_next_step; that must not be copied here.Folded. The FR-010 test asserts that runtime_next_step is never called.
7consumerMINORA run paused at a MEDIUM gate from before this change can mismatch: it holds approve/reject options and no significance record.Recorded residual (spec edge cases). The composition path never re-polls a pending decision, so this mission does not reach that state.
8consumerMINORDecisionGitLog committed content changes for MEDIUM/LOW gates.Folded. It is an edge case in the spec and is named in the changelog.
9consumerNOTEAnswered records gain raci_source, which nothing outside the engine reads. No contract changes (events, Decision, orchestrator-api CONTRACT_VERSION 1.10.0).No action. C-005 holds, so no escalation to the orchestrator.
10designNOTEQ1: StaleAdvancePlan cannot fire spuriously, because nothing writes state.json between plan and commit.No action; the analysis is recorded.
11designNOTEThe legacy and composition strict gates differ on refusal: the composition path leaves NextStepAutoCompleted in the log, while the legacy path rolls back.Out of scope (preserved deliberately); named under the PR's Deferred section.
12designNOTEEmitter seeding could reuse plan.source.Kept as _read_snapshot to preserve today's behaviour exactly; this is a NOTE only.
13designQ7Proposed split of provide_decision_answer.Adopted as the IC-01 helper map.

No finding needs an operator decision beyond the ruling. Both lenses confirm that C-005 holds.

R-3: Post-tasks squad (planner-priti lens, 2026-10-06, advisory)

There were 4 MAJOR findings, all folded:

FindingDisposition
(1) Silently dead planner.plan_next patchesRepatch onto engine.plan_next, with a fake-ran assertion
(2) Retrospective order not pinned on the composition pathOrder and strict-abort tests added to WP02
(3) The FR-010 red case was missing (C-004)Committed red in the gate file
(4) The untracked gate file would block implementThe gate was committed before WP01

Minor findings 5-11 and 13-14 are folded into the WP02 prompt ("Post-tasks squad folds") and the WP01 DoD. Note 12 (non-blocking capture now runs after the snapshot write) is recorded for the PR. Note 15 needs no action: the gates are confirmed safe. Note 16 also needs no action: the historical ADR is left as is.

R-4: Pre-PR squad (2026-10-06, advisory)

Two lenses ran: correctness (debugger-debbie) and boundary/overlap (architect-alphonso). Neither found a BLOCKER or a MAJOR.

#LensSeverityFindingDisposition
1correctnessMINORA failure while building the best-effort retrospective capture, after the commit, turned a terminal advance into a false blocked Decision.Fixed at the root (runtime_bridge_retrospective). The callback is now built inside the policy's try. Red-first test in tests/runtime/test_bridge_retrospective.py.
2correctnessMINORA strict-gate refusal leaves NextStepAutoCompleted (and now SignificanceEvaluated) in the run journal. The legacy path rolls back; the composition path does not.Fixed at landing (operator ruling 2026-10-07). The guard runs before anything is appended or emitted, so a refusal writes nothing and a retry does not stack events.
3correctnessNOTEThe strict-refusal operator message differs between the paths, and a stale plan re-dispatches the composed action on the next call.Deferred / by design (FR-010). Named in the PR.
4boundaryMINORThe adapter's _append_event / _write_snapshot wrappers are dead, kept alive only by a pin test.Fixed. Wrappers deleted. The pin covers reads and planner names, and a new check asserts the adapter wraps no writer.
5boundaryMINORThe shape gate missed SignificanceEvaluatedPayload and direct writer calls.Fixed, with planted rows.
6boundaryMINORThe terminal predicate is restated in the adapter.Deferred. It is low risk. An after_run_completed engine hook is named in the PR.
7boundaryMINORThe adapter docstring cited stale call-site lines.Fixed.
8boundaryMINORThe no-bridge positive-presence check has no planted row.Accepted: it is a positive check.
9boundaryNOTEUpgrade note for readers of decisions.events.jsonl.Added to the CHANGELOG.
10boundaryNOTEengine.apply_result / existing_template_path could become private again.Out of scope (#5834 surface).

R-5: Landing residuals (2026-10-07)

RefResidualDisposition
#5853spec-kitty next in query mode previews a MEDIUM audit gate as approve/reject, but the persisted request and the answer validator use decide_solo / open_stand_up / defer: query mode plans through plan_next on the live template and never evaluates significance. The engine path had this gap before this change and the composition path now shares it. Only operator-authored templates that declare significance: reach it.Open follow-up; plan_advance applies a result, so it cannot be dropped into query mode as is.
#5854The stale-plan check in commit_advance detects a run that moved between plan and commit but does not serialise concurrent writers. On a stale plan the engine path (_dn_advance_engine) re-plans through next_step and can complete a step this caller never ran; the composition path refuses with a blocked Decision.Open follow-up (a run-dir lock, and a refusing engine path). The limits are stated in the commit_advance docstring and the changelog.
#5855Re-polling a pending audit gate evaluates its significance again. A run paused at a MEDIUM gate before this change keeps its approve/reject request, so a re-poll records the MEDIUM band and a later approve is refused. Engine re-poll behaviour that predates this change.Open follow-up. Stated in the changelog Upgrade Notes: answer such a gate before polling again.