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
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,15 @@ Goal prose, acceptance and vision basis. A display limit must never become a
settlement limit. Retain the current complete read until that parity and stale-
head recovery are qualified on legacy, File and SQLite backends.

**Checkpoint repair authoring.** The existing TS vision owner must project only
repair choices the validator accepts: without a persisted vision, a missing
checkpoint requires a vision patch; unchanged reasoning is available only with
that baseline. The authoring contract shares the validator's `todo_delta`
limits: retain the first eight entries, with at most 80 characters per retained
entry. Isolated real CLI recovery must preserve the original settlement identity
and replay fences. This closes a recovery-guidance correctness gap; it does not
qualify lower context, IO or latency costs.

**Recovery boundary (2026-09-22).** The
[authority archive command](../../reference/authority-archive.md) places retained
history validation, delta reconstruction and resumable restore in the existing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,12 @@ codec;较大的完整事实快照通过私有临时文件和摘要绑定的引
内存,也不证明分布式执行。游标/checkpoint 归约保留为以测量驱动、完整源语义一致
为前提的后续工作,不再造 Python 规则。见[历史决策证据](ledger/typescript-control-plane-migration-v0/2026-09-22-replan-history-policy.zh-CN.md)。

**Checkpoint 恢复编写契约。** 现有 TS vision owner 只能投影校验器接受的恢复
选项:没有持久 vision 时,缺失的 checkpoint 必须提交 vision patch;有该基线时
才提供 unchanged reason。Authoring 契约复用校验器的 `todo_delta` 限制:保留前
八项,每个保留项至多 80 字符。隔离的真实 CLI 恢复必须保持原结算身份和 replay
约束。这闭合恢复指引的正确性缺口,不代表上下文、IO 或延迟成本已降低。

**恢复边界(2026-09-22)。** [authority archive 命令](../../reference/authority-archive.md)
由现有 TS coordination owner 负责历史校验、状态 delta 重建和可重入恢复;Python
只解析 CLI 路径、传递请求并展示紧凑结果。复用 state-log codec,避免各 provider
Expand Down
19 changes: 15 additions & 4 deletions loopx/control_plane/goals/vision_checkpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const GOAL_VISION_BUDGET_ERROR = "vision_budget_exceeded";
const GOAL_VISION_TOTAL_LIMIT = 1_800;
const GOAL_VISION_ADVANCEMENT_POLICIES = ["as_needed", "repeat_until_closed"] as const;
const VISION_UNCHANGED_REASON_LIMIT = 240;
const VISION_TODO_DELTA_ENTRY_LIMIT = 8;
const VISION_TODO_DELTA_TEXT_LIMIT = 80;
const VISION_BUDGET_SUGGESTION_LIMIT = 96;

const GOAL_VISION_FIELD_LIMITS = {
Expand Down Expand Up @@ -66,7 +68,14 @@ const GOAL_PATH_DELTA_LIST_LIMITS = {
export function visionAuthoringContract(): JsonObject {
return {
schema_version: GOAL_VISION_REPLAN_SCHEMA_VERSION,
fields: {state: "lifecycle token", vision_patch: {...GOAL_VISION_FIELD_LIMITS}},
fields: {
state: "lifecycle token",
vision_patch: {...GOAL_VISION_FIELD_LIMITS},
todo_delta: {
max_retained_items: VISION_TODO_DELTA_ENTRY_LIMIT,
max_item_chars: VISION_TODO_DELTA_TEXT_LIMIT,
},
},
common_states: ["vision_patch_proposed", "vision_closed", "no_followup"],
advancement_policies: [...GOAL_VISION_ADVANCEMENT_POLICIES],
minimal_example: {schema_version: GOAL_VISION_REPLAN_SCHEMA_VERSION, state: "vision_patch_proposed", vision_patch: {
Expand Down Expand Up @@ -618,8 +627,8 @@ function prepareVisionRefresh(request: VisionRefreshPrepareRequest): JsonObject

const todoDelta: string[] = [];
if (Array.isArray(updatePacket.todo_delta)) {
for (const item of updatePacket.todo_delta.slice(0, 8)) {
const text = boundedPublicText("todo_delta", item, 80);
for (const item of updatePacket.todo_delta.slice(0, VISION_TODO_DELTA_ENTRY_LIMIT)) {
const text = boundedPublicText("todo_delta", item, VISION_TODO_DELTA_TEXT_LIMIT);
if (text) todoDelta.push(text);
}
}
Expand Down Expand Up @@ -883,7 +892,9 @@ export function buildVisionCheckpoint(value: unknown): JsonObject {
}
if (!satisfied) {
checkpoint.required_resolution = ["write_vision_patch"];
if (checkpoint.missing_baseline !== true) {
if (request.existing_agent_vision === null) {
checkpoint.missing_baseline = true;
} else {
(checkpoint.required_resolution as string[]).push(
"record_unchanged_reason",
);
Expand Down
54 changes: 30 additions & 24 deletions tests/control_plane/test_refresh_checkpoint_recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
AGENT_ID,
REPO_ROOT,
GOAL_ID,
SELECTED_REPLAN_TODO_ID,
TODO_ID,
TURN_ID,
_configure_selected_todo_replan_fixture,
_initialize_git_checkout,
_run_cli,
_write_fixture,
Expand Down Expand Up @@ -306,30 +304,21 @@ def test_checkpoint_only_recovery_bypasses_open_todo_completion_validation(
tmp_path: Path,
) -> None:
project, runtime, registry = _write_fixture(tmp_path)
_configure_selected_todo_replan_fixture(project, registry)
_initialize_git_checkout(project)
state_path = project / f".codex/goals/{GOAL_ID}/ACTIVE_GOAL_STATE.md"
state_text = state_path.read_text(encoding="utf-8")
selected_marker = (
f"todo_id={SELECTED_REPLAN_TODO_ID} status=open "
f"todo_id={TODO_ID} status=open "
"task_class=advancement_task action_kind=validate "
f"claimed_by={AGENT_ID} -->"
"-->"
)
assert selected_marker in state_text
state_path.write_text(
state_text.replace(
selected_marker,
selected_marker.replace(" -->", " validation_command=pytest -->"),
1,
),
encoding="utf-8",
)
turn_id = "turn-checkpoint-open-validator"
binding = (
"--agent-id",
AGENT_ID,
"--todo-id",
SELECTED_REPLAN_TODO_ID,
TODO_ID,
"--turn-instance-id",
turn_id,
)
Expand All @@ -341,17 +330,14 @@ def test_checkpoint_only_recovery_bypasses_open_todo_completion_validation(
"--codex-app",
"--goal-id",
GOAL_ID,
"--agent-id",
AGENT_ID,
"--turn-instance-id",
turn_id,
*binding,
"--scan-path",
str(project),
cwd=project,
)
assert rc == 0, guard
assert guard["decision"] == "autonomous_replan_required"
assert guard["selected_todo"]["todo_id"] == SELECTED_REPLAN_TODO_ID
assert guard["decision"] == "run"
assert guard["selected_todo"]["todo_id"] == TODO_ID

delivery = (
"refresh-state",
Expand All @@ -360,6 +346,8 @@ def test_checkpoint_only_recovery_bypasses_open_todo_completion_validation(
*binding,
"--classification",
"validated_progress",
"--progress-scope",
"goal",
"--delivery-batch-scale",
"implementation",
"--delivery-outcome",
Expand All @@ -378,15 +366,33 @@ def test_checkpoint_only_recovery_bypasses_open_todo_completion_validation(
"--suppress-external-sinks",
)
mutations = (
"--autonomous-replan-recorded",
"--repair-delta-kind",
"successor_or_supersede",
"--next-action",
"Inspect the remaining checkpoint recovery scope.",
)
rc, first = _run_cli(registry, runtime, *delivery, *mutations, cwd=project)
assert rc == 0, first
assert first["appended"] is True
assert first["vision_checkpoint"]["decision"] == "missing_required"

checkpoint = first["vision_checkpoint"]
assert checkpoint["missing_baseline"] is True
assert checkpoint["required_resolution"] == ["write_vision_patch"]
instructions = render_state_refresh_markdown(first)
_assert_checkpoint_instructions(instructions)
assert "No persisted vision baseline is available" in instructions
assert "--vision-unchanged-reason" not in instructions

# A controller may install completion validation before checkpoint repair.
# The supplement repairs the existing receipt while the Todo remains open.
state_path.write_text(
state_path.read_text(encoding="utf-8").replace(
selected_marker,
selected_marker.replace(" -->", " validation_command=pytest -->"),
1,
),
encoding="utf-8",
)

vision = (
"--vision-summary",
"Continue the accepted checkpoint recovery scope.",
Expand All @@ -403,7 +409,7 @@ def test_checkpoint_only_recovery_bypasses_open_todo_completion_validation(
)

wrong_binding = list(delivery)
wrong_todo_index = wrong_binding.index(SELECTED_REPLAN_TODO_ID)
wrong_todo_index = wrong_binding.index(TODO_ID)
wrong_binding[wrong_todo_index] = "todo_chain_000000000001"
rc, wrong_identity = _run_cli(
registry, runtime, *wrong_binding, *vision, cwd=project
Expand Down
38 changes: 38 additions & 0 deletions tests/control_plane_ts/vision_checkpoint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
buildVisionCheckpoint,
VISION_REFRESH_PREPARED_SCHEMA_VERSION,
VISION_REFRESH_REQUEST_SCHEMA,
visionAuthoringContract,
} from "../../loopx/control_plane/goals/vision_checkpoint.ts";

function finalizeRequest(overrides: Record<string, unknown> = {}) {
Expand Down Expand Up @@ -412,11 +413,48 @@ test("semantic closeout retains the strict material vision checkpoint", () => {
assert.equal(result.required, true);
assert.equal(result.satisfied, false);
assert.equal(result.decision, "missing_required");
assert.equal(result.missing_baseline, true);
assert.deepEqual(result.required_resolution, ["write_vision_patch"]);
assert.deepEqual(result.triggers, [
{ kind: "material_delivery_outcome", delivery_outcome: "outcome_progress" },
]);
});

test("missing checkpoint offers unchanged only with a persisted vision", () => {
const baseline = {state: "vision_active", generated_at: "2026-09-01T10:00:00Z"};
const missing = buildVisionCheckpoint(finalizeRequest({
existing_agent_vision: baseline,
}));
assert.equal(missing.satisfied, false);
assert.deepEqual(missing.required_resolution, [
"write_vision_patch", "record_unchanged_reason",
]);
assert.equal("missing_baseline" in missing, false);
assert.equal(buildVisionCheckpoint(finalizeRequest({
existing_agent_vision: baseline,
vision_unchanged_reason: "The verified scope is still current.",
})).satisfied, true);
const rejected = buildVisionCheckpoint(finalizeRequest({
vision_unchanged_reason: "The verified scope is still current.",
}));
assert.equal(rejected.satisfied, false);
assert.equal(rejected.missing_baseline, true);
assert.deepEqual(rejected.required_resolution, ["write_vision_patch"]);
});

test("advertised Todo delta limits match retained items and item validation", () => {
const fields = visionAuthoringContract().fields as Record<string, unknown>;
assert.deepEqual(fields.todo_delta, {max_retained_items: 8, max_item_chars: 80});
const packet = (todo_delta: string[]) => prepareRequest({
agent_vision_packet: {vision_summary: "Deliver the scoped result.", todo_delta},
});
const deltas = Array.from({length: 9}, (_, index) => String(index).repeat(80));
const vision = buildVisionCheckpoint(packet(deltas)).agent_vision as Record<string, unknown>;
assert.deepEqual(vision.todo_delta, deltas.slice(0, 8));
assert.throws(() => buildVisionCheckpoint(packet(["x".repeat(81)])),
/todo_delta uses 81 chars; limit is 80/);
});

test("a bounded blocked retry does not invent a vision change", () => {
const blockedRetry = {
schema_version: "quota_blocked_retry_v0",
Expand Down
Loading