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
23 changes: 23 additions & 0 deletions docs/reference/protocols/quota-cli-hot-path-compaction-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ quota control plane. The full decision is built first. CLI-only projection then
retains action authority on the hot path and moves repeated diagnostic detail
behind explicit `--include-detail` selectors.

## Captured Initial Navigation

The TypeScript context owner also bounds `quota context-read --initial-read`.
For the current four-field supporting-address index, the first view retains
the original source identity, unconfirmed coverage, read-before-dependent-work
obligation and complete source instructions. Its pointer array stays unchanged
in the same immutable capture. Read the full list with the original reader
reference and `--select /context_details/unread_context_index/pointers` when
needed. Older, malformed or extended index layouts remain inline in full.
Goal and Task text, acceptance, permissions, stops and settlement are unchanged.
This changes the starting view, not the complete capture or explicit reads.
Include later index reads and their extra calls when comparing total cost;
fewer initial bytes alone do not establish retention, comprehension or benefit.

TypeScript 上下文 owner 同时约束 `quota context-read --initial-read`。
对现行四字段补读地址索引,初读保留原始来源身份、覆盖尚未确认的状态、依赖工作前
必须补读的义务及完整来源指引。地址数组原样保存在同一不可变 capture 中;需要完整
清单时,沿原 reader reference 读取
`--select /context_details/unread_context_index/pointers`。
旧格式、格式不符或增加未知字段的索引仍完整内联。目标、任务正文、验收、权限、
停止和结算不变;改变的只是起始视图,不是完整 capture 或显式读取。总成本比较须计入
后续索引补读及额外调用;初读字节减少本身不证明保留、理解或收益。

## Ownership Boundary

The quota control plane owns decision, precedence, scheduler, interaction,
Expand Down
19 changes: 16 additions & 3 deletions loopx/control_plane/quota/progressive_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,21 @@ export function initialContextReadPointers(context: JsonObject, decisionFields:
}
});
} else include(...planPath); // Unknown plan versions keep their complete obligations.
// Keep the complete unread index reachable after current controls, required
// sources and settlement obligations; its size must not displace them first.
include("context_details", "unread_context_index");
const details = object(context.context_details), unread = object(details?.unread_context_index);
const source = object(unread?.source);
// The current supporting-address inventory can dwarf the required facts.
// Keep its original source, unknown coverage and read-before-work obligation
// inline; the complete pointer list remains at this same captured address.
// Unknown/future layouts stay whole rather than hiding a new obligation.
if (unread && Object.keys(unread).length === 4 && unread.coverage_confirmed === false
&& unread.read_before_dependent_work === true && Array.isArray(unread.pointers)
&& unread.pointers.every(pointer => typeof pointer === "string")
&& typeof source?.path === "string" && typeof source.sha256 === "string"
&& typeof details?.instruction === "string" && details.instruction.length > 0) {
for (const field of ["source", "coverage_confirmed", "read_before_dependent_work"])
include("context_details", "unread_context_index", field);
include("context_details", "instruction");
include("context_details", "command_template");
} else include("context_details", "unread_context_index");
return pointers;
}
42 changes: 42 additions & 0 deletions tests/control_plane/test_context_first_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,48 @@ def read_selection(command):
return page, selected_context_values(page["content"])


def test_initial_read_keeps_supporting_index_obligations_and_recovers_its_full_list(tmp_path, decision):
# A complete address inventory is navigation, not the Goal/Task/stop text.
# Exercise the native reader and exact cold path over the same capture.
step = decision["interaction_contract"]["cli_channel"]["settlement_plan"]["ordered_steps"][0]
step.pop("optional_attachments")
evidence = decision["interaction_contract"]["agent_channel"]["work_context"]["sources"][1]["content"]["graph"]
evidence["writeback_results"] = [{"detail": f"Original evidence {i}"} for i in range(900)]
prefix = "/interaction_contract/agent_channel/work_context/sources/1/content/graph/writeback_results"
pointers = [f"{prefix}/{i}/detail" for i in range(900)]
source = tmp_path / "complete-source.json"
source.write_text(json.dumps(decision), encoding="utf-8")
index = {"coverage_confirmed": False, "read_before_dependent_work": True,
"source": {"path": str(source), "sha256": hashlib.sha256(source.read_bytes()).hexdigest()}, "pointers": pointers}
instruction = "Unread supporting fields remain unconfirmed. Read the applicable source before dependent work."
decision["context_details"] = {"unread_context_index": index, "instruction": instruction}
capture = tmp_path / "capture"
capture.mkdir()
view = native_context_capture_view(decision, capture)
raw = Path(view["recovery"]["path"]).read_bytes()

page, values = read_selection(view["first_read_command"])
base = "/context_details/unread_context_index"
assert values[base + "/coverage_confirmed"] is False
assert values[base + "/read_before_dependent_work"] is True
assert values[base + "/source"] == index["source"]
assert values["/context_details/instruction"] == instruction
assert not any(key == base or key.startswith(base + "/pointers") for key in values)
assert values["/goal_boundary"] == decision["goal_boundary"]
assert values["/selected_todo"] == decision["selected_todo"]
goal = "/interaction_contract/agent_channel/work_context/sources/0/content/text"
assert values[goal].endswith("STOP at the original budget.")
assert values["/interaction_contract/cli_channel/settlement_plan/identity"]["turn_instance_id"] == "original"

detail = read_context_capture(Namespace(capture_file=view["recovery"]["path"],
capture_sha256=view["recovery"]["sha256"], format="json", select=[base + "/pointers"],
offset=0, page_bytes=200000, max_page_output_bytes=200000))
assert detail["ok"] and detail["eof"]
assert json.loads(detail["content"])["selections"][0]["value"] == pointers
assert Path(view["recovery"]["path"]).read_bytes() == raw
assert json.loads(raw) == decision


@pytest.mark.parametrize("output_limit", [8192, 64000])
def test_cli_initial_pages_prioritize_required_facts_and_keep_the_complete_index(tmp_path, decision, output_limit):
goal = decision["interaction_contract"]["agent_channel"]["work_context"]["sources"][0]["content"]
Expand Down
20 changes: 19 additions & 1 deletion tests/control_plane_ts/progressive_context.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assert from "node:assert/strict";
import test from "node:test";
import {progressiveContextPlan} from "../../loopx/control_plane/quota/progressive_context.ts";
import {initialContextReadPointers, progressiveContextPlan} from "../../loopx/control_plane/quota/progressive_context.ts";
import {FULL_OUTCOME_READ_GUIDANCE, PROGRESSIVE_OUTCOME_READ_GUIDANCE} from "../../loopx/control_plane/work_items/interaction_contract.ts";

const outcome = {id: "o", objective: "Keep all requirements.", revision: 1, owner_agent_id: "a", todo_ids: ["t"],
Expand All @@ -11,6 +11,24 @@ const source = {source: "goal_acceptance", reason: "Adopt the current objective.
content: {status: "loaded", goal_acceptance_contract: {outcome_requirements: {
schema_version: "loopx_goal_outcomes_v0", outcomes: [outcome]}}}};

test("initial navigation keeps unknown supporting-index obligations whole", () => {
const known = {coverage_confirmed: false, read_before_dependent_work: true,
pointers: ["/supporting/evidence"], source: {path: "complete.json", sha256: "fixture-digest"}};
const base = "/context_details/unread_context_index";
for (const index of [{...known, future_obligation: "Preserve the newly required stop."},
{...known, coverage_confirmed: true}, {...known, read_before_dependent_work: false},
{...known, pointers: [42]}, {...known, source: null}]) {
const context = {interaction_contract: {schema_version: "loopx_interaction_contract_v0"},
context_details: {instruction: "Read applicable supporting evidence before dependent work.", unread_context_index: index}};
const before = structuredClone(context);
assert.ok(initialContextReadPointers(context, []).includes(base));
assert.deepEqual(context, before);
}
assert.ok(initialContextReadPointers({interaction_contract: {schema_version: "loopx_interaction_contract_v0"},
context_details: {unread_context_index: known}}, []).includes(base));
assert.deepEqual(initialContextReadPointers({interaction_contract: {schema_version: "loopx_interaction_contract_v0"}}, []), []);
});

test("only supporting materials move; cumulative obligations and merged source guidance survive", () => {
const payload = {ok: true, interaction_contract: {agent_channel: {work_context: {complete: true, sources: [source]}}}};
const before = structuredClone(payload);
Expand Down
Loading