Skip to content
Open
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
32 changes: 22 additions & 10 deletions loopx/control_plane/work_items/replan_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,24 @@ function observationTodo(row: JsonObject): unknown {
return work == null ? row.todo_id : row.todo_id == null || row.todo_id === work ? work : null;
}

/** Reserve one source-ordered observation per displayed planned Todo before
* filling the remaining slots. Repetition on one work item must not hide all
* followthrough on another; the cap is presentation, never evidence eligibility. */
function boundedWorkEvidence(rows: JsonObject[], todoIds: string[]): JsonObject[] {
const first = new Set<JsonObject>();
const displayed = new Set(todoIds.slice(0, 6));
for (const id of displayed) {
const row = rows.find(row => observationTodo(row) === id);
if (row) first.add(row);
}
const relevant = rows.filter(row => displayed.has(String(observationTodo(row))));
for (const row of [...relevant, ...rows]) {
if (first.size >= 6) break;
first.add(row);
}
return rows.filter(row => first.has(row));
}

/** Recover the result -> decision -> subsequent work relation from the existing
* source history. A citation alone does not consume a result, and no extra
* ledger or execution authority is created. These are recorded associations,
Expand Down Expand Up @@ -326,7 +344,8 @@ function decisionFollowthrough(rows: JsonObject[], goalFacts: unknown, fromFullI
// The complete denominator is retained even when the review details are capped.
const observations = [...subsequent.values()];
const ordinaryEvidence = [...ordinary.values()];
const visibleOrdinary = ordinaryEvidence.slice(0, 6);
const visibleOrdinary = boundedWorkEvidence(ordinaryEvidence, todoIds);
const visible = boundedWorkEvidence(observations, todoIds);
const resultUse = workResultUse(scoped);
const todos = todoItems == null ? [] : objects(todoItems, "Todo source");
const plannedWork = todoIds.slice(0, 6).map(todoId => {
Expand All @@ -337,18 +356,11 @@ function decisionFollowthrough(rows: JsonObject[], goalFacts: unknown, fromFullI
return {todo_id: todoId,
current: current ? Object.fromEntries(["status", "claimed_by", "task_class", "action_kind"]
.filter(key => Object.hasOwn(current, key)).map(key => [key, current[key]])) : null,
observation_refs: observations.filter(row => observationTodo(row) === todoId)
.slice(0, 6).map(row => "replan-evidence-" + digest(readableEvidenceRow(row))),
observation_refs: visible.filter(row => observationTodo(row) === todoId)
.map(row => "replan-evidence-" + digest(readableEvidenceRow(row))),
...(ordinaryEvidence.length ? {ordinary_evidence_refs: visibleOrdinary
.filter(row => row.todo_id === todoId).map(row => row.evidence_ref)} : {})};
});
// Keep relevant experiment observations in the small visible window even
// when newer unrelated work would otherwise crowd them out.
const linkedRefs = new Set(plannedWork.flatMap(work => work.observation_refs));
const visible = [...observations.filter(row => linkedRefs.has("replan-evidence-" + digest(readableEvidenceRow(row)))),
...observations.filter(row => !linkedRefs.has("replan-evidence-" + digest(readableEvidenceRow(row))))].slice(0, 6);
const visibleRefs = new Set(visible.map(row => "replan-evidence-" + digest(readableEvidenceRow(row))));
for (const work of plannedWork) work.observation_refs = work.observation_refs.filter(ref => visibleRefs.has(ref));
return {
previous_decision: decision,
source_history_complete: fromFullIndex,
Expand Down
30 changes: 30 additions & 0 deletions tests/control_plane/test_replan_context_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ def test_named_newest_first_builder_preserves_order_without_a_status_source():
_assert_followthrough(context)


@pytest.mark.parametrize("typed", [False, True])
def test_declared_results_survive_busy_work_through_the_source_codec(typed):
_, decision, work = _rows()
decision["agent_vision"]["todo_delta"] = ["retain:todo-busy", "retain:todo-comparison"]

def result(todo, index):
item = {**work, "todo_id": todo, "turn_instance_id": f"turn-work-{index}",
"settlement_identity": {**work["settlement_identity"], "todo_id": todo,
"turn_instance_id": f"turn-work-{index}"},
"health_check": f"Independent measured result {index}."}
if typed:
item["progress_observation"] = {**work["progress_observation"], "work_item_id": todo,
"surface_id": f"surface-{index}"}
else:
item.pop("progress_observation", None)
return item

rows = [decision, result("todo-comparison", 0), *[result("todo-busy", i + 1) for i in range(12)]]
for strategy in ("off", "evidence_conditioned_v1"):
context = project_replan_context(goal_id="evidence-goal", agent_id="agent-a", runs=rows,
history_newest_first=False, stride_strategy=strategy)
follow = context["decision_followthrough"]
observed = follow["observations"] if typed else follow["ordinary_work"]["evidence"]
assert len(observed) == 6
assert {row["todo_id"] for row in observed} == {"todo-busy", "todo-comparison"}
planned = next(work for work in follow["planned_work"] if work["todo_id"] == "todo-comparison")
assert len(planned["observation_refs"] if typed else planned["ordinary_evidence_refs"]) == 1
assert follow["execution_and_goal_gain"] == "unknown"


def test_real_append_index_ignores_compact_display_order_and_clock_skew(tmp_path):
registry = tmp_path / "registry.json"
registry.write_text(json.dumps({"goals": [{"id": "evidence-goal", "repo": str(tmp_path)}]}))
Expand Down
35 changes: 35 additions & 0 deletions tests/control_plane_ts/replan_context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,41 @@ test("legacy descriptive Todo deltas stay readable and unresolved", () => {
assert.equal(validateReplanContext(context), context);
});

test("busy planned work cannot crowd another declared experiment out of review", () => {
const decision = reviewed(1);
decision._source_facts.planned_todo_ids = ["todo-busy", "todo-counterexample"];
for (const typed of [true, false]) {
const observation = (position: number, todo: string): JsonObject => ({...subsequent(position), todo_id: todo,
health_check: todo === "todo-counterexample" ? "The comparison rejected the proposed explanation." : "Repeated validation.",
progress_observation: typed ? {...progress, work_item_id: todo, fingerprint: `result-${position}`} : null});
const counterexample = observation(2, "todo-counterexample");
const rows = [decision, counterexample, ...Array.from({length: 12}, (_, i) => observation(i + 3, "todo-busy"))];
const input = {...strideRequest, rows};
const context = projectReplanContext(input);
const follow = context.decision_followthrough;
const evidence = typed ? follow.observations : follow.ordinary_work.evidence;
assert.equal(evidence.length, 6);
assert.deepEqual(evidence.map((row: JsonObject) => row.todo_id),
[...Array(5).fill("todo-busy"), "todo-counterexample"], "source order is retained within the balanced window");
const ref = evidence[5].evidence_ref;
const work = follow.planned_work[1];
assert.deepEqual(typed ? work.observation_refs : work.ordinary_evidence_refs, [ref]);
assert.equal(typed ? follow.omitted_observation_count : follow.ordinary_work.omitted_count, 7);
assert.equal(typed ? follow.recorded_progress_count : follow.ordinary_work.recorded_count, 13);
assert.equal(validateReplanContext(context), context);
assert.equal(projectReplanContext({...input, operation: "resolve", evidence_ref: ref}).evidence.health_check,
counterexample.health_check);
const previous = follow.previous_decision.evidence_ref;
const review = {previous_review: {reference_decision_ref: previous, adoption: "executed",
information_gain: "new_evidence", goal_gain: "unknown", evidence_refs: [ref], lesson: "Retain the negative comparison."}};
const replay = projectReplanContext({...input, operation: "review_evidence", previous_decision_ref: previous, evidence_refs: [ref]});
assert.equal(strideReviewMismatch(review, context, replay), null);
assert.deepEqual(projectReplanContext({...input, stride_strategy: "off"}).decision_followthrough, follow);
assert.deepEqual(projectReplanContext({...input, rows: [...rows].reverse()}).decision_followthrough, follow);
assert.equal(follow.execution_and_goal_gain, "unknown");
}
});

test("declared work returns canonical state and only its subsequent observations", () => {
const decision = reviewed(2);
decision._source_facts.planned_todo_ids = ["todo-experiment", "todo-unavailable"];
Expand Down
Loading