From cf66d260395b4c3a22e0ef8102d6aadd35c73335 Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Tue, 27 Oct 2026 12:27:32 +0800 Subject: [PATCH] perf(context): reuse cumulative acceptance evidence in warm deliveries Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- docs/reference/required-work-context.md | 11 ++++ loopx/control_plane/quota/context_delivery.ts | 22 +++++++- .../test_goal_outcome_refinement.py | 38 +++++++++++++ .../control_plane_ts/context_delivery.test.ts | 55 +++++++++++++++++++ 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/docs/reference/required-work-context.md b/docs/reference/required-work-context.md index 7b581bc770..a8477c87f9 100644 --- a/docs/reference/required-work-context.md +++ b/docs/reference/required-work-context.md @@ -180,6 +180,13 @@ branch identity, selection, status, resume facts and orchestration gates remain current. Reordering, refutation, removed evidence and changed guidance reconstruct the exact current source; no timestamp, revision or text is normalized away. +Within successfully read cumulative Goal outcomes, source summaries, review notes +and string evidence references also use exact reuse. They are provenance and +explanations, not current acceptance decisions. Requirement status, review +conclusion, basis currency, independent verification, revisions and unknown fields +remain literal current input. Changed, removed or reordered evidence reconstructs +the complete current source; failed or incomplete sources retain full delivery. + Object edits may group complete current fields in `values`, alongside recursive `changed` edits and `removed` keys. Array edits use exact indices in `items` and `values`, with `length` for resizing. These literals are present in the current @@ -434,6 +441,10 @@ TurnEnvelope。在基线连续性成立的口径内,两入口仍逐轮发送 ` 条件、身份、命令与未知控制仍逐轮发送。Explore owner 登记分支证据审计与证据关联 模板的精确复用;分支身份、选择、状态、恢复事实与编排门仍是当前输入。重排、反证、 移除与指导变更完整重建当前来源,不规范化时间戳、修订或正文。 +已成功完整读取的累计 Goal outcome 中,来源说明、复核笔记及字符串证据引用也按精确 +差分传输。它们是来源与解释;要求状态、复核结论、依据是否当前、独立验证标记、修订 +及未知字段仍逐轮完整发送。证据变化、移除或重排后仍须精确还原当前来源;来源失败或 +读取不完整时保留完整投递。 对象编辑可以在 `values` 中合并携带本轮完整字段,同时保留递归 `changed` 与删除 `removed`;数组的 `items` 与 `values` 使用精确索引,`length` 调整长度。 字段仍在本轮输入中,只减少重复 wrapper;codec 比较普通编辑、合并字段 diff --git a/loopx/control_plane/quota/context_delivery.ts b/loopx/control_plane/quota/context_delivery.ts index aeb9873e7d..ccd0f85e33 100644 --- a/loopx/control_plane/quota/context_delivery.ts +++ b/loopx/control_plane/quota/context_delivery.ts @@ -51,7 +51,7 @@ function parentAt(root: JsonObject, path: Path): Record(); @@ -112,6 +112,16 @@ function splitContext(context: JsonObject): Split { seen.add(outcome.id); const path = [...prefix, "goal_acceptance_contract", "outcome_requirements", "outcomes", j]; add(JSON.stringify([kind, outcome.id, "objective"]), [...path, "objective"]); + // Cumulative provenance and review explanations are evidence, not a + // current acceptance decision. Reuse only these registered fields; + // conclusions, basis currency, independent verification and unknown + // controls still reach every input literally. + if (Array.isArray(outcome.sources)) { + outcome.sources.forEach((entry, index) => { + if (jsonObject(entry)) add(JSON.stringify([kind, outcome.id, "source_summary", index]), + [...path, "sources", index, "summary"]); + }); + } const requirements = outcome.requirements; if (!Array.isArray(requirements)) continue; const requirementIds = new Set(); @@ -121,7 +131,15 @@ function splitContext(context: JsonObject): Split { valid = false; continue; } requirementIds.add(requirement.id); - add(JSON.stringify([kind, outcome.id, requirement.id, "description"]), [...path, "requirements", k, "description"]); + const requirementPath = [...path, "requirements", k]; + const identity = [kind, outcome.id, requirement.id]; + add(JSON.stringify([...identity, "description"]), [...requirementPath, "description"]); + const review = jsonObject(requirement.agent_review); + if (review) { + add(JSON.stringify([...identity, "review_note"]), [...requirementPath, "agent_review", "note"]); + if (Array.isArray(review.evidence_refs) && review.evidence_refs.every(ref => typeof ref === "string")) + add(JSON.stringify([...identity, "review_evidence"]), [...requirementPath, "agent_review", "evidence_refs"], true); + } } } } else { diff --git a/tests/control_plane/test_goal_outcome_refinement.py b/tests/control_plane/test_goal_outcome_refinement.py index b8caa91ac3..1552e49e29 100644 --- a/tests/control_plane/test_goal_outcome_refinement.py +++ b/tests/control_plane/test_goal_outcome_refinement.py @@ -117,6 +117,44 @@ def test_review_only_cli_retains_origins_and_requires_provenance_for_new_require assert cli("inspect")[1] == before +def test_cumulative_review_evidence_reuses_real_quota_sources_without_hiding_new_judgment(acceptance_goal): + from loopx.control_plane.quota.turn_envelope import prepare_context_delivery, restore_context_delivery + + project, _, cli, run = acceptance_goal + declared = refinement([{"id": f"r{i}", "description": "Retain the original requirement"} + for i in range(12)], "message:first") + assert record(project, cli, declared, "declare")[0][0] == 0 + review = {"outcome_id": "tour", "review": [{"id": r["id"], "conclusion": "uncertain", + "evidence_refs": ["artifact:validation/" + "segment/" * 12], + "note": ("Retain the measured result and its applicability. " * 10).strip()} for r in declared["requirements"]]} + (code, result), _ = record(project, cli, review, "review") + assert code == 0, result + + def capture(): + code, packet = run("quota", "should-run", "--goal-id", "goal-acceptance", "--agent-id", "agent-a") + assert code == 0, packet + return packet["interaction_contract"]["agent_channel"]["work_context"] + + original = capture() + scope = dict(goal_id="goal-acceptance", agent_id="agent-a", session_id="fixture", context_epoch="cycle") + baseline = prepare_context_delivery(original, scope=scope, capture_id="original") + review["review"][0]["conclusion"] = "unmet" + assert record(project, cli, review, "negative-review")[0][0] == 0 + current = capture() + full = prepare_context_delivery(current, scope=scope, capture_id="current") + delta = prepare_context_delivery(current, scope=scope, capture_id="current", baseline=baseline, + retained={"complete": True, "target": baseline["target"]}) + assert delta["mode"] == "delta", delta.get("reason") + assert "segment/" not in json.dumps(delta), "unchanged evidence must not be retransmitted" + restored = restore_context_delivery(delta, baseline=baseline, current=full) + assert restored["context"] == current + acceptance = next(s["content"] for s in restored["context"]["sources"] if s.get("source") == "goal_acceptance") + row = acceptance["goal_acceptance_contract"]["outcome_requirements"]["outcomes"][0]["requirements"][0] + assert row["agent_review"]["conclusion"] == "unmet" and row["agent_review"]["evidence_refs"] == review["review"][0]["evidence_refs"] + assert not row["planning_satisfied"] and row["status"] != "accepted" + assert restore_context_delivery(delta, baseline=None, current=full)["context"] == current + + def test_typed_outcome_gaps_are_transported_only_to_their_agent(): gap = {"kind": "goal_outcome_uncovered", "agent_id": "author", "outcome_id": "tour", "requirement_ids": ["opening"]} summary = {"goal_acceptance_contract": {"enabled": False, "outcome_requirements": {"acceptance_gaps": [gap]}}} diff --git a/tests/control_plane_ts/context_delivery.test.ts b/tests/control_plane_ts/context_delivery.test.ts index 5d31f3337d..6b7514f406 100644 --- a/tests/control_plane_ts/context_delivery.test.ts +++ b/tests/control_plane_ts/context_delivery.test.ts @@ -124,6 +124,61 @@ test("fresh control with exact warm bodies; changed source revisions do not rese assert.deepEqual(baseline.context, original); }); +test("cumulative acceptance evidence reuses exact history while current judgments stay inline on every surface", () => { + const evidence = "artifact:validation/" + "evidence-segment/".repeat(80); + const outcome = {id: "result", objective: "Preserve the original goal.", revision: 1, + sources: [{ref: "owner:original", summary: long, unknown_source_control: {must_read: true}}], + requirements: Array.from({length: 12}, (_, i) => ({id: `r${i}`, description: "Verify the result.", + status: "unverified", planning_satisfied: false, + agent_review: {id: `r${i}`, conclusion: "uncertain", basis_current: false, + independently_verified: false, note: long, evidence_refs: [evidence + i], unknown_review_control: true}}))}; + const work = {complete: true, sources: [{source: "goal_acceptance", content: {ok: true, + provider_revision: "current", goal_acceptance_contract: {outcome_requirements: {revision: 1, outcomes: [outcome]}}}}]}; + for (const surface of ["work_context", "quota_packet", "turn_envelope"]) { + const prefix = surface === "quota_packet" ? ["interaction_contract", "agent_channel", "work_context"] + : surface === "turn_envelope" ? ["work_context"] : []; + const wrap = (value: unknown): JsonObject => surface === "quota_packet" + ? {interaction_contract: {agent_channel: {work_context: value}}} + : surface === "turn_envelope" ? {work_context: value} : value as JsonObject; + const original = wrap(work), baseline = prepareContextDelivery({context: original, scope, capture_id: "a", surface}); + const current = structuredClone(work), updated = current.sources[0].content.goal_acceptance_contract.outcome_requirements; + updated.revision = 2; + updated.outcomes[0].requirements[0].agent_review.conclusion = "unmet"; + const args = {context: wrap(current), scope, capture_id: "b", surface}; + const delta = prepareContextDelivery({...args, baseline, retained: {complete: true, target: baseline.target}}); + assert.equal(delta.mode, "delta"); + assert.ok(JSON.stringify(delta).length < JSON.stringify(original).length / 8); + const root = [...prefix, "sources", 0, "content", "goal_acceptance_contract", "outcome_requirements"]; + assert.equal(inline(delta, [...root, "revision"]), 2); + const row = [...root, "outcomes", 0, "requirements", 0]; + for (const [field, expected] of Object.entries(updated.outcomes[0].requirements[0].agent_review)) + if (!["note", "evidence_refs"].includes(field)) assert.deepEqual(inline(delta, [...row, "agent_review", field]), expected); + assert.equal(inline(delta, [...row, "status"]), "unverified"); + assert.equal(inline(delta, [...row, "planning_satisfied"]), false); + assert.deepEqual(inline(delta, [...root, "outcomes", 0, "sources", 0, "unknown_source_control"]), {must_read: true}); + assert.deepEqual(restoreContextDelivery({delivery: delta, baseline, current: prepareContextDelivery(args)}).context, wrap(current)); + assert.deepEqual(baseline.context, original); + // Changed, reordered, removed and empty evidence never inherit an old claim. + updated.outcomes[0].sources[0].summary = "A new owner correction."; + updated.outcomes[0].requirements.reverse(); + updated.outcomes[0].requirements[0].agent_review.note = ""; + updated.outcomes[0].requirements[0].agent_review.evidence_refs = ["artifact:new"]; + updated.outcomes[0].requirements[1].agent_review.evidence_refs = []; + delete (updated.outcomes[0].requirements[2].agent_review as JsonObject).note; + const edited = {...args, context: wrap(current)}; + const next = prepareContextDelivery({...edited, baseline, retained: {complete: true, target: baseline.target}}); + assert.deepEqual(restoreContextDelivery({delivery: next, baseline, current: prepareContextDelivery(edited)}).context, wrap(current)); + } + // An unavailable source is not historical evidence eligible for omission. + const unavailable = structuredClone(work) as JsonObject; + ((unavailable.sources as JsonObject[])[0].content as JsonObject).read_complete = false; + const initial = full(work), delta = warm(unavailable, initial); + const result = delta.mode === "full" ? delta.context : recover(delta, initial, unavailable).context; + assert.deepEqual(result, unavailable); + if (delta.mode === "delta") assert.equal(inline(delta, ["sources", 0, "content", "goal_acceptance_contract", + "outcome_requirements", "outcomes", 0, "requirements", 0, "agent_review", "note"]), long); +}); + test("relocated reusable strings reference the exact base while current controls stay inline", () => { const original = {registry: {authoring: long}, current_control: {instruction: long}}; const current = {registry: {attachment: {guidance: long}}, current_control: {instruction: long}};