diff --git a/tests/control_plane_ts/production_scale_coordination_fixture.test.ts b/tests/control_plane_ts/production_scale_coordination_fixture.test.ts index b3cdd1871e..2ee4366a83 100644 --- a/tests/control_plane_ts/production_scale_coordination_fixture.test.ts +++ b/tests/control_plane_ts/production_scale_coordination_fixture.test.ts @@ -9,7 +9,13 @@ import { TODO_ITEM_SCHEMA, } from "../../loopx/control_plane/coordination/coordination_state_contract.ts"; import {validateCoordinationTodoReadModel} from "../../loopx/control_plane/coordination/coordination_projection.ts"; -import {productionScaleCoordinationFixture} from "./production_scale_coordination_fixture.ts"; +import { + PRODUCTION_SCALE_AGENT_TODO_COUNT, + PRODUCTION_SCALE_COMPLETION_TARGET_INDEX, + PRODUCTION_SCALE_SUPERSEDE_TARGET_INDEX, + productionScaleCoordinationFixture, + requireProductionScaleTargetIndex, +} from "./production_scale_coordination_fixture.ts"; test("production-scale fixture is deterministic and explicitly ordered", () => { const first = productionScaleCoordinationFixture("fixture-goal", "legacy"); @@ -75,3 +81,42 @@ test("fixture rejects silent status-count drift at construction time", () => { ); assert.notEqual(TODO_ITEM_SCHEMA, TODO_DOMAIN_ITEM_SCHEMA); }); + +test("fixture rejects a target index that addresses no generated agent Todo", () => { + // Invariant (typescript-control-plane-migration-v0 ยง2.5): parsed JSON enters + // the system as unknown, and a type annotation does not prove the bytes + // satisfy the contract. The envelope's two target indices are the only + // envelope fields consumed as positional lookups, so they are validated at + // the boundary. The cases below are derived from that rule, not from the + // generated fixture: an index either addresses a generated agent Todo or it + // is rejected, whatever the fixture happens to contain. + const agentTodoCount = PRODUCTION_SCALE_AGENT_TODO_COUNT; + assert.ok(agentTodoCount > 0, "the envelope must generate at least one agent Todo"); + + assert.equal(requireProductionScaleTargetIndex(0, "test target index", agentTodoCount), 0); + assert.equal( + requireProductionScaleTargetIndex(agentTodoCount - 1, "test target index", agentTodoCount), + agentTodoCount - 1, + ); + + // Mutation: the boundary one past the last generated Todo. Before the + // validation existed this value reached `agents[value]` and produced + // `undefined` instead of a diagnosis. + assert.throws( + () => requireProductionScaleTargetIndex(agentTodoCount, "test target index", agentTodoCount), + /does not address a generated agent Todo/u, + ); + assert.throws( + () => requireProductionScaleTargetIndex(-1, "test target index", agentTodoCount), + /does not address a generated agent Todo/u, + ); + assert.throws( + () => requireProductionScaleTargetIndex(1.5, "test target index", agentTodoCount), + /does not address a generated agent Todo/u, + ); + + // The checked-in envelope must satisfy the rule its consumers rely on. + assert.ok(PRODUCTION_SCALE_COMPLETION_TARGET_INDEX < agentTodoCount); + assert.ok(PRODUCTION_SCALE_SUPERSEDE_TARGET_INDEX < agentTodoCount); + assert.notEqual(PRODUCTION_SCALE_COMPLETION_TARGET_INDEX, PRODUCTION_SCALE_SUPERSEDE_TARGET_INDEX); +}); diff --git a/tests/control_plane_ts/production_scale_coordination_fixture.ts b/tests/control_plane_ts/production_scale_coordination_fixture.ts index f3cbc68d0f..41bf57a013 100644 --- a/tests/control_plane_ts/production_scale_coordination_fixture.ts +++ b/tests/control_plane_ts/production_scale_coordination_fixture.ts @@ -199,7 +199,7 @@ function todoRecords( ...(index % 8 === 0 ? {watch_only: "true"} : {max_no_change_before_replan: "5"})}); } if (role === "agent" && status === "done" && index < 3) { - record.successor_todo_ids = [todoId("agent", envelope.completion_target_index + index)]; + record.successor_todo_ids = [todoId("agent", PRODUCTION_SCALE_COMPLETION_TARGET_INDEX + index)]; record.completion_continuation = "successor"; } if (role === "user" && index < envelope.standing_user_decision_count) { @@ -219,7 +219,7 @@ function todoRecords( record.decision_scope = {kind: "direction", granularity: "goal", scope_key: goalId}; if (index >= partialEnd) { record.decision_outcome = "approve"; - record.unblocks_todo_id = todoId("agent", envelope.completion_target_index); + record.unblocks_todo_id = todoId("agent", PRODUCTION_SCALE_COMPLETION_TARGET_INDEX); } } // An explicit rejection is a recorded decision, not absent authority: the @@ -255,8 +255,8 @@ export function productionScaleCoordinationFixture( const archiveDependent = [...agents].reverse().find(item => item.status === "open")!; archiveDependent.task_class = "advancement_task"; archiveDependent.resume_when = `todo_done:${todoId("agent", 3)}`; - const completionTodo = agents[envelope.completion_target_index]!; - const supersedeTodo = agents[envelope.supersede_target_index]!; + const completionTodo = agents[PRODUCTION_SCALE_COMPLETION_TARGET_INDEX]!; + const supersedeTodo = agents[PRODUCTION_SCALE_SUPERSEDE_TARGET_INDEX]!; completionTodo.task_class = "advancement_task"; completionTodo.claimed_by = "agent-a"; completionTodo.completion_validation_required = true; @@ -355,6 +355,38 @@ function requireSafeCount(value: number, label: string): number { return value; } +/** + * Validate the two envelope fields that address a generated agent Todo. + * + * The envelope is parsed JSON, so `as` proves nothing about its numbers: the + * two target indices below are the only envelope fields a consumer turns into a + * positional lookup. They are validated once here, at the boundary, and every + * consumer reads the validated constant instead of the raw field, so a drifted + * index fails the fixture instead of yielding `undefined` mid-construction. + */ +export function requireProductionScaleTargetIndex( + value: number, + label: string, + agentTodoCount: number, +): number { + if (!Number.isSafeInteger(value) || value < 0 || value >= agentTodoCount) { + throw new Error(`production fixture ${label} does not address a generated agent Todo`); + } + return value; +} + +export const PRODUCTION_SCALE_AGENT_TODO_COUNT = statusSeries( + envelope.agent_status_counts, envelope.agent_status_order, "agent", +).length; + +export const PRODUCTION_SCALE_COMPLETION_TARGET_INDEX = requireProductionScaleTargetIndex( + envelope.completion_target_index, "completion target index", PRODUCTION_SCALE_AGENT_TODO_COUNT, +); + +export const PRODUCTION_SCALE_SUPERSEDE_TARGET_INDEX = requireProductionScaleTargetIndex( + envelope.supersede_target_index, "supersede target index", PRODUCTION_SCALE_AGENT_TODO_COUNT, +); + /** * Checked while the module loads, so a drifted history envelope fails every * consumer instead of quietly shrinking a provider's retained history.