diff --git a/docs/reference/required-work-context.md b/docs/reference/required-work-context.md index 1e56a486f3..2d0577a605 100644 --- a/docs/reference/required-work-context.md +++ b/docs/reference/required-work-context.md @@ -192,6 +192,13 @@ patch or an incompatible reader automatically recovers the same original full capture. Recovery never reruns the guard, asks the owner, spends quota or grants execution. Wire reduction alone does not establish actual model costs or outcomes. +After reading a native delta completely, the Agent uses its changes with the +retained model context. A resumed tool process may have no earlier Code Mode +variables; that alone does not mean the model lost the baseline. Materializing a +JavaScript object does not require another full read. If required baseline content +is unavailable or continuity is uncertain, recover the same capture in full before +dependent work. Compaction still invalidates the baseline and requires recovery. + ### Machine default **Settings → This machine → Capabilities → Differential context → Codex** uses the @@ -403,6 +410,11 @@ TurnEnvelope。在基线连续性成立的口径内,两入口仍逐轮发送 ` 或读者不兼容时,自动恢复同一原始 full capture,不重跑 guard、不问询、不扣额, 也不授予执行权限。传输减少本身不证明实际模型费用或结果改善。 +完整读完原生差分后,Agent 将变化与模型仍保留的上下文一起使用。恢复后的工具进程可能 +没有此前的 Code Mode 变量;仅此并不表示模型丢失了基线。不必为了组装 JavaScript +对象再读一次全量。若当前工作所需的基线内容不可用或连续性不确定,仍须先完整恢复 +同一捕获,再做依赖它的工作。压缩仍会使基线失效,并要求恢复。 + ### 机器级默认 在**设置 → 本机设置 → 能力中心 → 差分上下文 → Codex**选择关闭或开启,沿用现有 diff --git a/loopx/control_plane/quota/context_delivery.ts b/loopx/control_plane/quota/context_delivery.ts index e31d1277a1..aeb9873e7d 100644 --- a/loopx/control_plane/quota/context_delivery.ts +++ b/loopx/control_plane/quota/context_delivery.ts @@ -446,7 +446,12 @@ export function prepareContextDelivery(request: JsonObject, legacyQuotaFields: r ...(assumed ? {continuity_basis: "native_hook_assumption"} : {}), instruction: "Current controls are inline even when unchanged. Other fields inherit the " + (assumed ? "exact baseline under the native-hook continuity assumption" : "confirmed baseline") - + "; all requirements remain binding. A value replaces its subtree; from copies the exact string at that path in the base capture, never in current changes. Values assigns complete fields (exact indices with items); changed/items recurse, removed deletes object keys, length sets array length. Lost context triggers automatic full recovery from this capture, never an owner question."}; + + "; all requirements remain binding. " + + (assumed ? "After reading this delta completely, use it with the retained model context. " + + "Do not also fetch the full projection just to materialize JSON or replace missing Code Mode variables; " + + "tool-process memory is separate from retained model context. If required baseline content is unavailable " + + "or continuity is uncertain, recover this capture in full before dependent work. " : "") + + "A value replaces its subtree; from copies the exact string at that path in the base capture, never in current changes. Values assigns complete fields (exact indices with items); changed/items recurse, removed deletes object keys, length sets array length. Lost context triggers automatic full recovery from this capture, never an owner question."}; if (bytes(delta) >= bytes(full("delta_not_smaller"))) return full("delta_not_smaller"); if (!equal(applyTree(prior, changes), context)) return full("reconstruction_failed"); // Native consumers page the wire before they can use its baseline. Deliver diff --git a/tests/control_plane_ts/context_delivery.test.ts b/tests/control_plane_ts/context_delivery.test.ts index 6558a3c785..5d31f3337d 100644 --- a/tests/control_plane_ts/context_delivery.test.ts +++ b/tests/control_plane_ts/context_delivery.test.ts @@ -477,6 +477,27 @@ test("whole packet reuses complete projections; live controls and unknown fields assert.equal(restoreContextDelivery({delivery: broken, baseline, current: packetFull(current, "capture-b")}).mode, "full"); }); +test("native delta controls are usable without an executable copy of the baseline", () => { + const current = packet(), baseline = packetFull(current); + const cli = (current.interaction_contract as JsonObject).cli_channel as JsonObject; + cli.selection_command = {command_args_template: "select-current-task"}; + const delta = prepareContextDelivery({context: current, scope, capture_id: "capture-b", surface: "quota_packet", + baseline, continuity: {basis: "native_hook_assumption", capture_bytes_verified: true, target: baseline.target}}); + // This reader has only the serialized new input, as after a tool-process + // restart. Retained requirement text belongs to model context, not this reader. + const input = JSON.parse(JSON.stringify(delta)) as JsonObject; + assert.equal(input.mode, "delta"); + assert.equal(inline(input, ["interaction_contract", "cli_channel", "selection_command", "command_args_template"]), + "select-current-task"); + assert.equal(inline(input, ["interaction_contract", "cli_channel", "settlement_plan", "ordered_steps", 1, "command_template"]), + "writeback-a"); + assert.equal(inline(input, ["goal_boundary", "approval"]), "pending"); + // Actual baseline loss still requires the immutable current full capture. + const recovered = restoreContextDelivery({delivery: input, current: packetFull(current, "capture-b")}); + assert.equal(recovered.mode, "full"); + assert.deepEqual(recovered.context, current); +}); + test("array edits preserve append, removal, reorder, duplicate entries and exact scalar types", () => { const before = packet(), baseline = packetFull(before); const old = (before.planning_horizon as JsonObject).work_items as JsonObject[];