Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion loopx/control_plane/goals/goal_frontier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1699,7 +1699,11 @@ def build_goal_frontier_projection_context_from_status(
agent_todo_items=agent_todo_source_items,
stride_strategy=stride_strategy,
)
frontier_transition_candidate = {"obligation": source, "ack": source_ack}
frontier_transition_candidate = {
"obligation": source,
"ack": source_ack,
"reconstructed_vision_review": True,
}

lifecycle_candidate = None
if receipt_bound_replan_obligation_id and receipt_bound_guard_recorded_at:
Expand Down
21 changes: 20 additions & 1 deletion loopx/control_plane/work_items/replan_semantics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ function preserveReceiptBoundObligation(request: JsonObject): JsonObject {
throw new EffectRuntimeRequestError("receipt-bound replan facts are malformed");
}
let original: JsonObject | null = null;
let openVisionReview: JsonObject | null = null;
let delta: JsonObject | null = null;
let historicalAckRecorded = false;
for (const value of request.transition_candidates) {
Expand All @@ -280,7 +281,19 @@ function preserveReceiptBoundObligation(request: JsonObject): JsonObject {
historicalAckRecorded = true;
break;
}
if (obligation.obligation_id !== selected || !requiredSemanticOutcomes(obligation).includes("new_runnable_successor")) continue;
if (obligation.obligation_id !== selected) continue;
if (request.guard_scoped && candidate.reconstructed_vision_review === true &&
obligation.schema_version === "autonomous_replan_obligation_v0" && obligation.required === true &&
typeof request.agent_id === "string" && request.agent_id.trim() &&
obligation.agent_id === request.agent_id && obligation.resolution_mode == null &&
obligation.capability_guard == null) {
const kinds = triggerKinds(obligation);
if (kinds.some(kind => VISION_TRIGGERS.has(kind)) &&
kinds.every(kind => VISION_TRIGGERS.has(kind) || kind === "goal_outcome_uncovered")) {
openVisionReview = obligation;
}
}
if (!requiredSemanticOutcomes(obligation).includes("new_runnable_successor")) continue;
const result = projectTurnTransition({guard_scoped: request.guard_scoped,
selected_obligation_id: selected, transition_candidates: [candidate],
stride_strategy: request.stride_strategy, goal_id: request.goal_id,
Expand Down Expand Up @@ -331,6 +344,12 @@ function preserveReceiptBoundObligation(request: JsonObject): JsonObject {
triggerKinds(current).some(kind => ACCEPTANCE_HOLD_TRIGGERS.has(kind))) {
return {obligation: {...current, obligation_id: selected, selection_binding: "heartbeat_receipt"}};
}
// Another review may own the live frontier while the canonical Vision
// gaps still reconstruct the admitted review. Keep its full checks and
// require a fresh qualifying outcome before settlement.
if (openVisionReview !== null) {
return {obligation: {...openVisionReview, selection_binding: "heartbeat_receipt"}};
}
// Work-link maintenance can remove this frontier-only review before its
// writeback. The exact receipt retains its typed kind, never raw task prose
// or an old decision context. Other duties keep their canonical owners.
Expand Down
43 changes: 43 additions & 0 deletions tests/control_plane/test_refresh_state_replan_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,49 @@ def test_rotated_vision_obligation_contains_all_three_acceptance_gaps() -> None:
assert obligation["triggers"][2]["completed_todo_threshold"] == 5


def test_admitted_vision_checkpoint_survives_a_new_periodic_review() -> None:
admission_runs = [_open_vision_after_prior_ack()]
arguments = {"state_text": STATE_TEXT, "agent_id": AGENT_ID, "goal_id": GOAL_ID}
admitted, _ = qualify_replan_writeback(newest_first_runs=admission_runs, **arguments)
assert admitted is not None
assert [trigger["kind"] for trigger in admitted["triggers"]] == [
"vision_acceptance_gap",
"vision_outcome_checkpoint_required",
]

later_runs = [
{**run, "generated_at": f"2026-08-13T12:{index:02d}:00+08:00"}
for index, run in enumerate(_durable_runs(AUTONOMOUS_REPLAN_PERIODIC_RUN_THRESHOLD))
][::-1]
current, _ = qualify_replan_writeback(
newest_first_runs=[*later_runs, *admission_runs], **arguments,
)
assert current is not None
assert [trigger["kind"] for trigger in current["triggers"]] == ["periodic_review_due"]
assert current["obligation_id"] != admitted["obligation_id"]

bound = {
**arguments,
"newest_first_runs": [*later_runs, *admission_runs],
"guard_scoped": True,
"guard_semantic_replan_obligation_id": admitted["obligation_id"],
"receipt_bound_guard_recorded_at": "2026-08-13T11:28:00+08:00",
"receipt_bound_guard_turn_instance_id": "vision-before-periodic",
}
with pytest.raises(ReplanWritebackRejected, match="typed semantic delta"):
enforce_open_replan_writeback(**bound)
delta = enforce_open_replan_writeback(
**bound,
agent_vision={
"vision_patch": {"acceptance_summary": "An independent check supports continuing."},
"path_delta": {"outcome": "continue", "evidence_refs": ["evidence:checkpoint-review"]},
},
)
assert delta is not None
assert delta["obligation_id"] == admitted["obligation_id"]
assert delta["satisfying_outcomes"] == ["fresh_vision_path_outcome"]


def test_refresh_state_run_rejects_maintenance_after_vision_obligation_rotation(
tmp_path: Path,
) -> None:
Expand Down
22 changes: 22 additions & 0 deletions tests/control_plane_ts/replan_semantics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,28 @@ test("verified original writeback projects only its outstanding debit even after
current_obligation: null, transition_candidates: []}), /malformed/);
});

test("an open Vision reconstruction must come from the exact scoped receipt source", () => {
const id = "replan-1111111111111111";
const original = {schema_version: "autonomous_replan_obligation_v0", required: true,
obligation_id: id, agent_id: "reviewer", triggers: [{kind: "vision_outcome_checkpoint_required"}]};
const candidate = {obligation: original, ack: null, reconstructed_vision_review: true};
const request = {operation: "receipt_bound_obligation", guard_scoped: true,
replay_phase: "open", selected_obligation_id: id, agent_id: "reviewer",
current_obligation: null, transition_candidates: [candidate]};
assert.deepEqual(projectReplanSemantics(request).obligation,
{...original, selection_binding: "heartbeat_receipt"});
for (const changes of [
{guard_scoped: false}, {agent_id: "peer"}, {selected_obligation_id: "replan-2222222222222222"},
{transition_candidates: [{...candidate, reconstructed_vision_review: false}]},
{transition_candidates: [{...candidate, obligation: {...original,
triggers: [...original.triggers, {kind: "periodic_review_due"}]}}]},
{transition_candidates: [{...candidate, obligation: {...original,
capability_guard: {schema_version: "semantic_replan_capability_guard_v0"}}}]},
]) {
assert.throws(() => projectReplanSemantics({...request, ...changes}), /identity conflicts/);
}
});

test("only plain vision and outcome reviews have a scalar receipt source", () => {
const source = {schema_version: "autonomous_replan_obligation_v0", required: true,
obligation_id: "replan-1111111111111111", agent_id: "reviewer", trigger_count: 1,
Expand Down
Loading