Skip to content

Commit 4fa58bf

Browse files
committed
fix(status): preserve delegated identities and large snapshots
Signed-off-by: huangruiteng <huangrt01@163.com>
1 parent c9f8d90 commit 4fa58bf

4 files changed

Lines changed: 54 additions & 0 deletions

File tree

‎loopx/control_plane/effect_runtime_snapshot_methods.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"work_item.interaction_reads.project",
1313
"scheduler.hint.project",
1414
"work_item.task_graph.goal_topology",
15+
"work_item.task_graph.status",
1516
"work_item.replan_semantics.project",
1617
"quota.settlement.read",
1718
"quota.spend.commit",

‎loopx/control_plane/work_items/task_graph.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ function publicTextCodec(request: JsonObject): {
434434
} {
435435
const texts = requireJsonObject(request.public_texts, "public text codecs");
436436
const composedTexts = new Set<string>();
437+
const foldedTexts = new Set<string>();
437438
const composed = (value: string, parts: unknown[] = []): string => {
438439
for (const part of parts) {
439440
const text = String(part);
@@ -448,6 +449,10 @@ function publicTextCodec(request: JsonObject): {
448449
if (typeof text === "string") composed(text);
449450
}
450451
}
452+
for (const source of Object.keys(texts)) {
453+
const folded = source.toLowerCase();
454+
if (folded !== source) foldedTexts.add(folded);
455+
}
451456
const safe: PublicText = (value, limit) => {
452457
if (!truthy(value)) return null;
453458
const text = String(value);
@@ -460,6 +465,13 @@ function publicTextCodec(request: JsonObject): {
460465
if (result) composed(result);
461466
return result as string | null;
462467
}
468+
// Agent identities are normalized case-insensitively by the existing
469+
// handoff owner. The lower-case form is still derived from an approved
470+
// source fact; accept it only without inventing or recompacting text.
471+
if (foldedTexts.has(text) && Array.from(text).length <= limit) {
472+
composed(text);
473+
return text;
474+
}
463475
if (!composedTexts.has(text)) {
464476
throw new EffectRuntimeRequestError(`Missing public text facts for display cap ${limit}`);
465477
}

‎tests/control_plane/test_status_task_graph_characterization.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,22 @@ def test_empty_display_text_does_not_steal_selection(monkeypatch):
147147
output = status.build_task_graph_projection({"goal_id": "graph-fixture", "agent_todos": {
148148
"items": [todo("todo_empty", text=" "), todo("todo_visible")]}}, goal={"id": "graph-fixture"})
149149
assert output["nodes"][0]["refs"] == {"todo_ids": ["todo_visible"]}
150+
151+
152+
def test_large_status_note_uses_the_existing_snapshot_transport(monkeypatch):
153+
arguments = deepcopy(cases()["handoff_evidence"])
154+
parent = arguments["item"]["agent_todos"]["items"][1]
155+
parent.pop("evidence", None)
156+
parent["note"] = "Public note " + "x" * 4_300_016
157+
calls = []
158+
real = task_graph.effect_runtime_result
159+
160+
def observe(method, params, **kwargs):
161+
calls.append((method, kwargs.get("large_local_snapshot", False)))
162+
return real(method, params, **kwargs)
163+
164+
monkeypatch.setattr(task_graph, "effect_runtime_result", observe)
165+
monkeypatch.setattr(task_graph, "now_utc_iso", lambda: NOW)
166+
output = status.build_task_graph_projection(**arguments)
167+
assert output["nodes"]
168+
assert calls == [("work_item.task_graph.status", True)]

‎tests/control_plane_ts/task_graph.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,25 @@ test("status compaction fallback enumerates composed titles, identities, referen
463463
assert.match(String(edge.edge_id), /^edge_[a-z0-9_]+$/);
464464
}
465465
});
466+
467+
test("status accepts lower-case agent identities derived from approved source facts", () => {
468+
const values = {
469+
"synthetic-goal": {"120": "synthetic-goal", "80": "synthetic-goal"},
470+
"todo_root": {"120": "todo_root"}, "Review todo_root": {"160": "Review todo_root"},
471+
"open": {"80": "open"}, "todo_done:todo_parent": {"240": "todo_done:todo_parent"},
472+
"todo_parent": {"120": "todo_parent"}, "Review todo_parent": {"160": "Review todo_parent"},
473+
"done": {"80": "done"}, "Builder": {"80": "Builder"}, "Reviewer": {"80": "Reviewer"},
474+
};
475+
const result = projectStatusTaskGraph({
476+
schema_version: STATUS_TASK_GRAPH_REQUEST, goal_id: "synthetic-goal",
477+
summaries: {agent: {items: [
478+
statusTodo("todo_root", {resume_when: "todo_done:todo_parent"}),
479+
statusTodo("todo_parent", {status: "done", done: true, successor_todo_ids: ["todo_root"],
480+
handoff_note: {from_agent: "builder", to_agent: "reviewer", status: "done"}}),
481+
]}, user: {}},
482+
max_status_todos_per_role: 8, latest_runs: [], public_texts: values,
483+
fallback_time: "2026-11-02T12:00:00Z",
484+
});
485+
assert.equal(statusNodes(result).find(node => node.kind === "handoff")?.title,
486+
"Handoff from builder to reviewer");
487+
});

0 commit comments

Comments
 (0)