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
14 changes: 10 additions & 4 deletions docs/reference/required-work-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,12 +262,16 @@ 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
Within successfully read cumulative Goal outcomes, string source references,
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.
Containers emptied solely by removing reusable fields do not force those fields
back into the delta. Originally empty unknown records and non-string source
references remain literal current input. Reuse keeps the locator's exact value;
it neither rereads the referenced material nor refreshes its authority.

The registered preference owner permits exact reuse of its complete instructions,
statements, source quotes and source references. Each read still supplies the
Expand Down Expand Up @@ -598,10 +602,12 @@ TurnEnvelope。在基线连续性成立的口径内,两入口仍逐轮发送 `
条件、身份、命令与未知控制仍逐轮发送。Explore owner 登记分支证据审计与证据关联
模板的精确复用;分支身份、选择、状态、恢复事实与编排门仍是当前输入。重排、反证、
移除与指导变更完整重建当前来源,不规范化时间戳、修订或正文。
已成功完整读取的累计 Goal outcome 中,来源说明、复核笔记及字符串证据引用也按精确
已成功完整读取的累计 Goal outcome 中,字符串来源引用、来源说明、复核笔记及字符串证据引用也按精确
差分传输。它们是来源与解释;要求状态、复核结论、依据是否当前、独立验证标记、修订
及未知字段仍逐轮完整发送。证据变化、移除或重排后仍须精确还原当前来源;来源失败或
读取不完整时保留完整投递。
仅因移除可复用字段而变空的容器,不会把这些字段重新带回差分;原本为空的未知对象和
非字符串来源引用仍逐轮发送。复用保留定位符的精确值,不重读其指向的材料,也不刷新权限。
对象编辑可以在 `values` 中合并携带本轮完整字段,同时保留递归 `changed` 与删除
`removed`;数组的 `items` 与 `values` 使用精确索引,`length` 调整长度。
字段仍在本轮输入中,只减少重复 wrapper;codec 比较普通编辑、合并字段
Expand Down
19 changes: 12 additions & 7 deletions loopx/control_plane/quota/context_delivery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,11 @@ function splitContext(context: JsonObject, binding: JsonObject): Split {
// 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 source = jsonObject(entry);
if (!source) return;
add(JSON.stringify([kind, outcome.id, "source_summary", index]), [...path, "sources", index, "summary"]);
if (typeof source.ref === "string") add(JSON.stringify([kind, outcome.id, "source_ref", index]),
[...path, "sources", index, "ref"]);
});
}
const requirements = outcome.requirements;
Expand Down Expand Up @@ -193,17 +196,19 @@ const REUSABLE_PACKET_FIELDS = new Set([
function freshPaths(context: JsonObject, surface: Surface, legacyQuotaFields: readonly string[], binding: JsonObject): {paths: Path[]; valid: boolean} {
const paths: Path[] = [];
let valid = true;
const leaves = (value: unknown, path: Path) => {
if (Array.isArray(value) && value.length) value.forEach((v, i) => leaves(v, [...path, i]));
const leaves = (value: unknown, original: unknown, path: Path) => {
if (Array.isArray(value) && value.length) value.forEach((v, i) => leaves(v, (original as unknown[])[i], [...path, i]));
else if (jsonObject(value) && Object.keys(value as JsonObject).length)
Object.entries(value as JsonObject).forEach(([k, v]) => leaves(v, [...path, k]));
else paths.push(path);
Object.entries(value as JsonObject).forEach(([k, v]) => leaves(v, (original as JsonObject)[k], [...path, k]));
// Removing only registered reusable fields leaves an empty container, not
// a current control. An originally empty unknown record still stays literal.
else if (!(jsonObject(value) && jsonObject(original) && Object.keys(original as JsonObject).length)) paths.push(path);
};
const work = (value: unknown, path: Path) => {
const source = jsonObject(value);
if (!source) { paths.push(path); return; }
const split = splitContext(source, binding); valid &&= split.valid;
leaves(split.fresh, path);
leaves(split.fresh, source, path);
};
const vision = (value: unknown, path: Path) => {
const audit = jsonObject(value);
Expand Down
18 changes: 18 additions & 0 deletions tests/control_plane/test_context_delivery_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@ def test_real_cli_host_rendezvous_sends_delta_and_keeps_same_capture_full(tmp_pa
initialize_canonical_authority(runtime, GOAL_ID,
build_todo_runtime_shadow_projection(goal_id=GOAL_ID, todos=todos, handoff_mode="soft_claim"),
state_path=state, provider=provider)
state.write_text(state.read_text().replace("status: active-read-only", "status: active"))
settings = json.loads(registry.read_text())
settings["goals"][0]["status"] = "active"
registry.write_text(json.dumps(settings))
code, acceptance = _run_cli(registry, runtime, "goal-acceptance", "inspect", "--goal-id", GOAL_ID)
assert code == 0, acceptance
source_ref = "owner:validated-request-" + "original-scope-" * 4
document = tmp_path / "outcome.json"
document.write_text(json.dumps({"outcome_id": "delivery", "owner_agent_id": AGENT_ID,
"objective": "Deliver the requested artifact", "todo_ids": [TODO_ID],
"requirements": [{"id": "original", "description": "Retain evidence and stop before publication"}],
"source": {"ref": source_ref, "summary": "The original owner requested the artifact."}}))
code, declared = _run_cli(registry, runtime, "goal-acceptance", "refine", "--goal-id", GOAL_ID,
"--agent-id", AGENT_ID, "--document", str(document), "--operation-id", "declare-outcome",
"--expected-provider-revision", acceptance["provider_revision"], "--execute")
assert code == 0, declared
before_source = state.read_bytes()
root = tmp_path / "captures"
root.mkdir()
Expand Down Expand Up @@ -312,10 +328,12 @@ def release():

cold, first = invoke({"scope": scope})
assert cold["mode"] == "full"
assert source_ref in json.dumps(cold["context"])
assert json.loads((first / "projection.json").read_bytes()) == cold["context"]
warm, second = invoke({"scope": scope, "baseline": cold,
"retained": {"complete": True, "target": cold["target"]}})
assert warm["mode"] == "delta"
assert source_ref not in json.dumps(warm["changes"])
projection = json.loads((second / "projection.json").read_bytes())
current = prepare_context_delivery(projection, scope=scope,
capture_id=warm["target"]["capture_id"], surface=surface)
Expand Down
21 changes: 20 additions & 1 deletion tests/control_plane_ts/context_delivery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,9 @@ test("fresh control with exact warm bodies; changed source revisions do not rese
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}}],
sources: [{ref: "owner:original-" + "source-segment-".repeat(6), summary: long,
unknown_source_control: {must_read: true}, unknown_empty_control: {}},
{ref: "owner:second", summary: "A second source."}],
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,
Expand Down Expand Up @@ -278,10 +280,15 @@ test("cumulative acceptance evidence reuses exact history while current judgment
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(inline(delta, [...root, "outcomes", 0, "sources", 0, "unknown_empty_control"]), {});
assert.equal(inline(delta, [...root, "outcomes", 0, "sources", 0, "ref"]), undefined);
assert.equal(inline(delta, [...root, "outcomes", 0, "sources", 1, "ref"]), undefined);
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].sources[0].ref = "owner:corrected";
updated.outcomes[0].sources.reverse();
updated.outcomes[0].requirements.reverse();
updated.outcomes[0].requirements[0].agent_review.note = "";
updated.outcomes[0].requirements[0].agent_review.evidence_refs = ["artifact:new"];
Expand All @@ -290,6 +297,18 @@ test("cumulative acceptance evidence reuses exact history while current judgment
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));
for (const sources of [updated.outcomes[0].sources.slice(0, 1), [],
[{ref: {unknown_authority: "Do not reuse this control record."}, summary: long}]]) {
const changed = structuredClone(current) as JsonObject;
const outcomes = ((source(changed, 0).goal_acceptance_contract as JsonObject)
.outcome_requirements as JsonObject).outcomes as JsonObject[];
outcomes[0].sources = sources;
const args = {context: wrap(changed), scope, capture_id: "changed", surface};
const delta = prepareContextDelivery({...args, baseline, retained: {complete: true, target: baseline.target}});
assert.deepEqual(restoreContextDelivery({delivery: delta, baseline, current: prepareContextDelivery(args)}).context, wrap(changed));
if (sources.length && typeof sources[0].ref !== "string")
assert.deepEqual(inline(delta, [...root, "outcomes", 0, "sources", 0, "ref"]), sources[0].ref);
}
}
// An unavailable source is not historical evidence eligible for omission.
const unavailable = structuredClone(work) as JsonObject;
Expand Down
Loading