From 37a84163fab6b4e2b607066cc90ee9a230d4b3f7 Mon Sep 17 00:00:00 2001 From: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:23:39 +0800 Subject: [PATCH] perf(authority): check Todo order through validated identities Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --- .../2026-09-28-retirement-cadence.md | 17 +++++-- .../2026-09-28-retirement-cadence.zh-CN.md | 13 +++++- .../coordination/coordination_projection.ts | 7 ++- .../coordination_projection.test.ts | 44 +++++++++++++++++++ 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.md index 33c26ec154..f9f6491843 100644 --- a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.md +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.md @@ -269,6 +269,17 @@ Three warm samples give File medians of 430→425 ms and SQLite 493→481 ms. The small latency difference is not cold-start or provider-default evidence. Actual agent and full-Goal CLI responses retain their size and semantics apart from observation time/age fields. The full-Goal response remains about 2 MB. -Next coordinate full-Goal frontend summary/list/detail consumers and measure -remaining cold-path preparation. Agent status already has bounded display; -final JSON compaction alone does not remove full-source computation. +A follow-up on `b9a34c3e7` isolates the shared read-model validator: it +serialized the full Todo array twice solely to check record order, despite an +already validated unique-id index. Compare that index's insertion order with +its existing Unicode-sorted ids instead; retain the full content digest, +record validation and provider reads. On a detached 1,117-Todo/36-lease current +projection, ten warm Node samples per provider reduced validator medians from +42–43 ms to 27 ms. This is a common TS cost, not evidence to rank providers or +change the default. No cached authority, lease omission, response cap or +frontend contract change is introduced. Unicode order, duplicates, malformed +JSON, archived-record tampering and both record formats remain rejection tests. +Next qualify reuse of the complete validated Todo/lease snapshot across +ownership and status, then coordinate full-Goal frontend summary/list/detail +consumers. Agent status already has bounded display; final JSON compaction +alone does not remove full-source computation. diff --git a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.zh-CN.md b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.zh-CN.md index ce8b70eaa0..50325433f0 100644 --- a/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.zh-CN.md +++ b/docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-28-retirement-cadence.zh-CN.md @@ -203,5 +203,14 @@ Resume 输入现在仅在分组含等待条件时准备;succession 仍读取 结构化调用由 2,687 降为 1,570;原生读取仍为一次,TS effect 调用仍为 16 次。 三个热样本中位数为 File 430→425 ms、SQLite 493→481 ms。这点延迟差异不能证明冷启动 或默认 provider 已验收。实际 Agent/整 Goal CLI 输出除观测时间和时效字段外,大小和 -语义保持一致;整 Goal 输出仍约 2 MB。下一步协同改造整 Goal 前端摘要/列表/详情, -继续测量冷路径准备成本。Agent status 已有有界展示,仅压缩最终 JSON 不会消除完整来源计算。 +语义保持一致;整 Goal 输出仍约 2 MB。 + +以 `b9a34c3e7` 为基线继续分解发现:共有读模型校验为了检查记录顺序,在已完成唯一 ID +索引校验后仍将完整 Todo 数组序列化两遍。改为比较该索引的插入顺序和现有 Unicode +排序 ID;完整内容摘要、记录校验及 provider 读取继续保留。隔离的 1,117 条 Todo/36 条 +租约当前投影中,每个 provider 取十个热 Node 样本,校验中位数由 42–43 ms 降至 27 ms。 +这是共有 TS 成本,不能据此给 provider 排名或改变默认值;没有增加权威缓存、遗漏租约、 +限制响应条数或改变前端合同。Unicode 顺序、重复 ID、非法 JSON、归档记录篡改及两种 +记录格式的拒绝规则均有回归覆盖。 +下一步验证 ownership 与 status 复用完整、已校验的 Todo/租约快照,再协同改造整 Goal +前端摘要/列表/详情。Agent status 已有有界展示,仅压缩最终 JSON 不会消除完整来源计算。 diff --git a/loopx/control_plane/coordination/coordination_projection.ts b/loopx/control_plane/coordination/coordination_projection.ts index f57ae6be30..0c713f9a23 100644 --- a/loopx/control_plane/coordination/coordination_projection.ts +++ b/loopx/control_plane/coordination/coordination_projection.ts @@ -181,8 +181,11 @@ export function validateCoordinationTodoReadModel( ): JsonObject { const index = indexCoordinationProjectionTodos(value, expectedGoalId); const records = index.todo_ids.map((todoId) => index.todos.get(todoId)!); - if (!Array.isArray(value.todos) || - !canonicalAuthorityBytes(value.todos).equals(canonicalAuthorityBytes(records))) { + // Identity indexing already validates/copies every record and rejects duplicate + // IDs. The insertion order of those same records proves order; serializing + // both full arrays again adds no content validation. The digest below still + // covers every field, including nested metadata. + if ([...index.todos.keys()].some((todoId, position) => todoId !== index.todo_ids[position])) { throw new AuthorityStoreProtocolError( "coordination Todo read records must use deterministic todo_id order", ); diff --git a/tests/control_plane_ts/coordination_projection.test.ts b/tests/control_plane_ts/coordination_projection.test.ts index b882080aa4..aba4fa4899 100644 --- a/tests/control_plane_ts/coordination_projection.test.ts +++ b/tests/control_plane_ts/coordination_projection.test.ts @@ -481,3 +481,47 @@ for (const native of [false, true]) { assert.deepEqual(validateCoordinationTodoReadModel(head, head.goal_id), model); }); } + +for (const native of [false, true]) { + test(`read-model order uses unique Unicode identities without weakening ${native ? "domain" : "canonical"} content validation`, () => { + // U+E000 precedes U+10000 in persisted Unicode code-point order, but not + // in JavaScript's default UTF-16 sort order. Include an archived dependency. + const ids = ["todo_a", "todo_\uE000", "todo_\u{10000}"]; + const todos: JsonObject[] = ids.map((todo_id, index) => ({ + schema_version: native ? TODO_DOMAIN_ITEM_SCHEMA : "todo_item_v0", + todo_id, role: "agent", status: index === 0 ? "done" : "open", done: index === 0, + text: "Preserve the complete retained record", archive_state: index === 0 ? "archive" : "active", + completion_result: {nested: [null, false, {label: "original"}]}, + ...(native ? {} : {source_section: "Agent Todo"}), + })); + const schema = native ? TODO_DOMAIN_READ_RECORD_SCHEMA : TODO_CANONICAL_READ_RECORD_SCHEMA; + const head = {goal_id: "order-goal", todos, leases: [], todo_read_model: coordinationTodoReadModel(todos, schema)}; + const before = structuredClone(head); + assert.deepEqual(validateCoordinationTodoReadModel(head, head.goal_id), head.todo_read_model); + assert.deepEqual(head, before); + for (const order of [[1, 0, 2], [0, 2, 1], [2, 1, 0]]) { + const reordered = order.map(index => todos[index]!); + // Even a matching digest cannot legalize a noncanonical record order. + assert.throws(() => validateCoordinationTodoReadModel({...head, todos: reordered, + todo_read_model: {...head.todo_read_model, records_sha256: canonicalAuthoritySha256(reordered)}}, head.goal_id), + /deterministic todo_id order/); + } + assert.throws(() => validateCoordinationTodoReadModel({...head, todos: [todos[0]!, todos[0]!, todos[2]!]}, head.goal_id), + /duplicate todo ids/); + const altered = structuredClone(todos); + altered[0]!.completion_result = {nested: [null, false, {label: "tampered archive"}]}; + assert.throws(() => validateCoordinationTodoReadModel({...head, todos: altered}, head.goal_id), /digest mismatch/); + for (const invalid of [undefined, Number.NaN, new Date()]) { + const malformed = structuredClone(todos); + malformed[1]!.completion_result = {invalid} as unknown as JsonObject; + assert.throws(() => validateCoordinationTodoReadModel({...head, todos: malformed}, head.goal_id)); + } + const unknownField = todos.map(todo => ({...todo, metadata: {unversioned: true}})); + assert.throws(() => validateCoordinationTodoReadModel({...head, todos: unknownField, + todo_read_model: {...head.todo_read_model, records_sha256: canonicalAuthoritySha256(unknownField)}}, head.goal_id), + /unversioned fields: metadata/); + assert.throws(() => validateCoordinationTodoReadModel(head, "foreign-goal"), /goal mismatch/); + assert.deepEqual(validateCoordinationTodoReadModel({...head, todos: [], + todo_read_model: coordinationTodoReadModel([], schema)}, head.goal_id), coordinationTodoReadModel([], schema)); + }); +}