Skip to content
Open
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
103 changes: 103 additions & 0 deletions docs/architecture/rfcs/monorepo-distribution-split-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,109 @@ performance holds remain separate. Full source/wheel correctness and a matched,
unprofiled default-SQLite whole-path comparison are still required for a new
implementation; all earlier milestone, adoption and complete-cost gaps remain.

### 2026-11-07 — Reuse complete Todo display sources within a managed request

The existing `todo.context.page` owner can compose summary, planning and retained
terminal display views from one complete supplied source. The quota preparation
caller explicitly requests the Agent source's three views and passes retained
terminal rows to its frontier consumer. User-source and general display callers
keep their requested single view. Source selection and each display rule retain
their existing owners. The orchestration fallback reuses an independent copy of
the already selected summary instead of requesting it again.

Inside an already revision-pinned logical request, exact source JSON and request
options bound the transport memo. Changed source facts and later requests
revalidate; mutable callers receive independent decoded values. Large opt-in
inputs keep the original per-view transport, and incomplete bundles fail before
memo admission. The batch input threshold does not predict response size or
promise inline transport. An explicit multi-view request can use the existing
private response snapshot when the combined output exceeds the socket limit.

Independent review of the initial proposal found that the generic transport
expanded single-view calls into three views. An 8,000-row delivery-response
caller retained the same final output but materialized about 11.18 MB of unused
combined response instead of its roughly 3.73 MB single-view socket response.
That performance failure is retained. The corrected caller-owned composition
removes the implicit expansion; matching single-view and complete governed
source/wheel qualification are recorded with the revision being proposed.

The initial proposal against `main@32167518b3` passed six synthetic source and isolated-wheel
101-Todo File/SQLite governed CLI lifecycles. They retained the verified artifact,
original completion time, four settlement receipts, one debit, Effect restart
recovery and rejected evidence replacement. A dropped write-scope response
mutation fails at the independent public-guard scope check. Frozen display
fixtures and focused source-isolation tests also cover the existing three views.
One profiled SQLite guard reduced JSON parameter bytes from about 1.900 MB to
1.556 MB and calls from 89 to 87; loaded modules remained 503. These counts are
diagnostic and do not qualify complete wire cost, latency or long-horizon benefit.


The corrected single-call comparison uses the same synthetic source on
`main@dee549663`, the reviewed defective head and the repaired source. All three
produce the same final delivery response. The repaired request parameters and serialized response
bytes match main exactly; its nonempty response snapshot bytes are
zero for both row counts. Five warm calls per arm gave the following exploratory
medians, including the display and delivery-response projections:

| Rows | Main seconds | Defective proposal seconds | Repair seconds | Defective response snapshot bytes | Repair snapshot bytes |
| --- | --- | --- | --- | --- | --- |
| 8,000 | 0.159 | 0.636 | 0.161 | 9,480,165 | 0 |
| 15,000 | 0.284 | 1.344 | 0.286 | 17,775,165 | 0 |

This reproduces and removes the single-view regression. It does not qualify the
complete CLI, daemon CPU/memory, full marginal cost or long-horizon benefit.


The repaired source and isolated wheel pass six 101-Todo File/SQLite governed
CLI lifecycles with the verified artifact, original completion time, four
receipts, one debit, restart and refusal/replay checks. A recursive dropped-scope
response mutation fails at the independent public guard oracle. The isolated
PostgreSQL 16.15 suites pass 390 store and 11 service cases with zero skipped.

Three interleaved unprofiled default-SQLite whole-CLI pairs have median wall time
12.24 seconds on main and 12.71 seconds on the repair. Two candidate runs are
slower; ranges overlap. A separate profiled guard reduces parameter bytes from
1,899,603 to 1,546,162 and calls from 90 to 87, with 503 modules unchanged.
These observations do not establish a whole-path performance benefit. Daemon
CPU/memory, total wire/file writes, complete marginal cost and adoption remain
unqualified; the provider-first transaction remains the next accepted boundary.

This is a reversible display-transport increment, not the complete provider-first
Todo projection transaction. Provider reads, revisions, lease/actor fences and
state writes retain their existing owners. The remaining canonical-source
transaction, matched complete-cost qualification and affected backend acceptance
stay open. I3 remains at least one minor release; M1/#8011, full R0/V10/R1,
D2/D5/D6/D3, context/model/split-install, adoption and all frozen failures remain.

#### Remaining provider-first transaction boundary

The next implementation must compose the existing provider-admitted
`canonicalTodoCollection` and projection owners. The native snapshot owner binds
Goal, store incarnation, provider revision, cursor and query to complete rows,
leases, read-model validation and acceptance guards. A continuation is a position
within that read, not a reusable current-head handle; a changed snapshot restarts
the complete read. Displaying a retained source does not obtain fresh authority.

`quota_selection.py` still sends a complete summary source alongside encoded
selection rows and source-row facts. Its request also includes the clock,
actor/profile, capabilities, closure evidence, route/handoff facts and resume
inputs. Move canonical row materialization into the existing typed owner before
collapsing that transport. Preserve the Python-value codec where strict integer,
boolean or text distinctions remain observable. Provider rows cannot substitute
for independent caller evidence or pending intent; all-done counts alone cannot
reconstruct a closure declaration.

`goal_vision_wait` separately consumes complete lineage, scoped blockers, acceptance gaps and resume facts. The combined transaction must preserve each
causal obligation, including when two obligations share a witness. Full notes,
write scopes, archive/settled identity and source provenance remain part of its
parity oracle.

The real PostgreSQL integration case connects the existing native snapshot read
to all three display views, checks unchanged provider/source data, observes a
new provider revision after a separate commit, and refuses a stale continuation.
This qualifies a composition prerequisite. The combined guard transaction,
PostgreSQL source/wheel host journey and complete-cost benefit remain open.

## Appendix B: Decision log

| Date | Decision | Owner / approval | Alternatives | Normative sections changed |
Expand Down
85 changes: 85 additions & 0 deletions docs/architecture/rfcs/monorepo-distribution-split-v0.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,91 @@ lineage、pause/gates 与 pending intents。新增更多 leaf RPC 或有损裁
解决的性能 hold 保持独立。新实现仍需完整 source/wheel 正确性,以及不插桩、
匹配条件的默认 SQLite 全路径比较;既有里程碑、采纳与完整成本缺口继续开放。

### 2026-11-07 — 在受管请求内复用完整 Todo 展示来源

既有 `todo.context.page` owner 可从同一完整输入来源组合 summary、planning 和
保留 terminal 的展示视图。Quota preparation 调用方显式请求 Agent 来源的三种
视图,并把保留 terminal 的 rows 传给 frontier 消费方。User 来源及通用展示调用方
保留自己请求的单一视图。来源选择和每种展示规则保留原 owner。Orchestration
fallback 复用已选 summary 的独立副本,避免再次请求相同展示。

已经固定 runtime revision 的逻辑请求内,以完整 source JSON 和请求选项约束
传输 memo。来源事实变化和后续请求重新验证;可变调用方获得独立解码值。较大的
显式组合输入保留原逐视图传输,不完整组合响应在进入 memo 前失败。Batch 输入
阈值不能预测响应大小,也不保证 socket 内联传输;显式多视图的合计输出超过
socket 限制时,仍可能使用既有私有响应 snapshot。

初始提案的独立评审发现,通用传输把单视图调用扩大为三种视图。8,000 条记录的
单次 delivery-response 调用最终输出相同,却把原约 3.73 MB 的单视图 socket
响应扩大成约 11.18 MB 的组合响应并写盘。保留这次性能失败。修复后的调用方
显式组合移除了这种隐式扩大;单视图对照和完整受管 source/wheel 验证按本次提案
revision 记录。

初始提案对照 `main@32167518b3`,源码与隔离安装 wheel 的六组 101-Todo File/SQLite
受管 CLI 生命周期通过,保留已验证产物、原完成时间、四种 settlement receipt、
一次 debit、Effect 重启恢复及 evidence 替换拒绝。刻意丢弃 write-scope 响应字段的
mutation 在独立公开 guard scope 检查失败。冻结展示 fixture 和聚焦来源隔离用例
同时覆盖既有三种视图。一次带 profiler 的 SQLite guard 观察到 JSON 参数约
1.900 MB → 1.556 MB,调用 89 → 87,已加载模块仍为 503。这些计数仅用于诊断,
不验收完整 wire 成本、延迟或长程收益。


修复后的单次调用对照在 `main@dee549663`、已评审的缺陷 head 和修复源码上
使用相同合成来源,三者最终 delivery response 相同。修复的请求参数和响应字节
与 main 完全一致;两种记录规模的非空响应 snapshot 字节都为零。每个版本五次
热调用的探索性中位数如下,包含 display 和 delivery-response 两种 projection:

| Rows | Main 秒 | 缺陷提案秒 | 修复秒 | 缺陷响应 snapshot 字节 | 修复 snapshot 字节 |
| --- | --- | --- | --- | --- | --- |
| 8,000 | 0.159 | 0.636 | 0.161 | 9,480,165 | 0 |
| 15,000 | 0.284 | 1.344 | 0.286 | 17,775,165 | 0 |

此对照复现并消除了单视图性能回归,不能验收完整 CLI、daemon CPU/内存、完整
边际成本或长程收益。


修复后的源码及隔离 wheel 通过六组 101-Todo File/SQLite 受管 CLI 生命周期,
保留已验证产物、原完成时间、四种 receipt、一次 debit、重启恢复与拒绝/重放。
递归丢弃响应中的 write scope 的 mutation 在独立公开 guard oracle 失败。隔离
PostgreSQL 16.15 的 390 个 store 和 11 个 service 用例通过,零 skipped。

三组交错、无 profiler 的默认 SQLite 完整 CLI 对照中,main 墙钟中位数为
12.24 秒,修复为 12.71 秒;两次候选更慢,范围重叠。独立 profiled guard 的参数
字节从 1,899,603 降到 1,546,162,调用从 90 降到 87,模块仍为 503。这些观察
未证明完整路径性能收益。Daemon CPU/内存、总 wire/file 写入、完整边际成本及
采纳仍未验收;完整 provider-first 事务继续作为下一验收边界。

这是可独立回滚的展示传输增量,尚非完整 provider-first Todo projection
transaction。Provider 读取、revision、lease/actor fence 和状态写入保留原 owner。
后续 canonical-source 事务、匹配的完整成本对照及受影响后端验收仍开放。I3 至少
保留一个 minor release;M1/#8011、完整 R0/V10/R1、D2/D5/D6/D3、context/model/
split-install、adoption 和所有冻结失败继续保留。

#### 后续 provider-first 事务边界

下一实现应组合既有经过 provider 准入的 `canonicalTodoCollection` 和 projection
owner。Native snapshot owner 把 Goal、store incarnation、provider revision、cursor
及 query 绑定到完整 rows、leases、read-model 验证和 acceptance guards。Continuation
只是同一次读取中的位置,不是可复用的 current-head handle;snapshot 变化后应重新
完整读取。展示保留来源不会获取新的 authority。

`quota_selection.py` 仍在 encoded selection rows 和 source-row facts 之外发送
完整 summary source。请求还包含时钟、actor/profile、capabilities、closure evidence、
route/handoff facts 和 resume 输入。合并传输之前,先把 canonical row materialization
放入既有 typed owner。严格 integer、boolean 或文本区别仍可观测时,保留
Python-value codec。Provider rows 不能替代独立 caller evidence 或 pending intent;
all-done 计数本身无法重建 closure declaration。

`goal_vision_wait` 还独立消费完整 lineage、scoped blockers、acceptance gaps 和
resume facts。合并事务应保留每个 causal obligation,包括两个 obligation 共用
witness 的情况。完整 note、write scopes、archive/settled identity 和来源 provenance
仍属于 parity oracle。

真实 PostgreSQL 集成用例把既有 native snapshot read 接到三种展示视图,检查
provider/source 数据不变,在独立 commit 后观察新的 provider revision,并拒绝旧
continuation。它验证的是组合前置条件;完整 guard transaction、PostgreSQL
source/wheel host journey 和完整成本收益仍开放。

## 附录 B:决策日志

| 日期 | 决策 | 负责人 / 批准 | 备选 | 变更的规范章节 |
Expand Down
14 changes: 13 additions & 1 deletion loopx/control_plane/effect_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,17 @@ def effect_runtime_result(
large_local_snapshot: bool = False,
) -> Any:
state = _REQUEST_RUNTIME_REVISION.get() if method == "todo.context.page" else None
def validate_result(result: Any) -> Any:
# A caller must explicitly request a bundle. A request scope or a small
# source does not establish that it will consume additional views.
if set(params) == {"summary_display_views"} and (not isinstance(result, dict) or any(
not isinstance(result.get(view), list)
or any(not isinstance(row, dict) for row in result[view])
for view in ("summary", "planning", "terminal")
)):
raise RuntimeError("invalid TypeScript Todo source views")
return result

key = None
if state is not None:
# Preserve JSON order and scalar types, including bool/int, signed zero
Expand All @@ -1613,14 +1624,15 @@ def effect_runtime_result(
if key is not None:
prior = state.todo_context_result(key)
if prior is not None:
return json.loads(prior) # A caller cannot mutate another view.
return validate_result(json.loads(prior)) # A caller cannot mutate another view.
result = effect_runtime_request(
method,
params,
timeout=timeout,
retry_safe=retry_safe,
large_local_snapshot=large_local_snapshot,
).get("result")
validate_result(result)
if state is not None and key is not None and isinstance(result, dict):
try:
encoded = json.dumps(result, ensure_ascii=False, allow_nan=False,
Expand Down
23 changes: 11 additions & 12 deletions loopx/control_plane/quota/should_run_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
todo_item_task_class as projection_todo_item_task_class,
)
from ..todos.quota_summary import (
select_planning_inventory_source_items,
select_quota_todo_display_views,
select_quota_todo_source_items,
select_quota_todo_summary,
select_task_orchestration_authority_items,
Expand Down Expand Up @@ -237,6 +237,7 @@ def _prepare_quota_replan_context(
project_asset: dict[str, Any],
user_todo_summary: dict[str, Any] | None,
agent_todo_summary: dict[str, Any] | None,
agent_todo_terminal_source_items: list[dict[str, Any]],
authoritative_fallback_todo_items: FallbackTodoSource,
effective_available_capabilities: Any,
work_lane_contract: dict[str, Any] | None,
Expand All @@ -251,11 +252,6 @@ def _prepare_quota_replan_context(
replan_explore_reader: Callable[[str, str | None], Mapping[str, Any] | None] | None,
) -> tuple[dict[str, Any], dict[str, Any] | None]:
"""Project the current frontier and contextualize its receipt-bound review."""
replan_todo_items = select_planning_inventory_source_items(
item.get("agent_todos"),
project_asset.get("agent_todos") if project_asset else None,
include_terminal=True,
)
goal_frontier_context = build_goal_frontier_projection_context_from_status(
replan_explore_reader=replan_explore_reader,
goal_id=safe_goal_id,
Expand All @@ -265,7 +261,7 @@ def _prepare_quota_replan_context(
project_asset=project_asset,
user_todo_summary=user_todo_summary,
agent_todo_summary=agent_todo_summary,
agent_todo_source_items=replan_todo_items,
agent_todo_source_items=agent_todo_terminal_source_items,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 给原回执的恢复分支传入同一份终态。 删除本地来源后,下面 attach_receipt_replan_context 的 todo_items=replan_todo_items 仍引用旧名。实际 CLI 先得到 autonomous_replan_required 和一张原轮次回执。补充验收要求并关联等待中的后续工作后,基线 8 例全部恢复,新提交 8 例均在第二次 should-run 返回 quota_unexpected_collection_error。File 和 SQLite 的诊断复跑各保留一张原回执,扣额仍为零,CLI 无法交付该轮次的继续信息。 在候选进程内只替换这一个参数表达式的对照中,File 和 SQLite 各恢复原身份、通过现有完整用例,读回原轮次的唯一扣额。 把 agent_todo_terminal_source_items 同时传给 attach_receipt_replan_context,并用 File、SQLite、stride 开关和并行 vision gap 的八个既有用例复验原身份、验收信息更新和一次结算。

fallback_todo_source_items=authoritative_fallback_todo_items,
available_capabilities=effective_available_capabilities,
work_lane_contract=work_lane_contract,
Expand Down Expand Up @@ -718,23 +714,25 @@ def _prepare_quota_should_run_item(
item.get("user_todos"),
project_asset.get("user_todos") if project_asset else None,
)
agent_todo_source_items = select_quota_todo_source_items(
item.get("agent_todos"),
project_asset.get("agent_todos") if project_asset else None,
)
agent_todo_planning_source_items = select_planning_inventory_source_items(
# Only this Agent source is consumed as summary, planning and retained
# terminal rows below. User-source and general display calls stay single-view.
agent_todo_display_views = select_quota_todo_display_views(
item.get("agent_todos"),
project_asset.get("agent_todos") if project_asset else None,
)
agent_todo_source_items = agent_todo_display_views["summary"]
agent_todo_planning_source_items = agent_todo_display_views["planning"]
task_orchestration_agent_items = select_task_orchestration_authority_items(
item.get("agent_todos"),
project_asset.get("agent_todos") if project_asset else None,
role="agent",
fallback_source_items=agent_todo_source_items,
)
task_orchestration_user_blockers = select_task_orchestration_authority_items(
item.get("user_todos"),
project_asset.get("user_todos") if project_asset else None,
role="user",
fallback_source_items=user_todo_source_items,
)
agent_scoped_user_todo_override = _agent_scoped_user_todo_override(
state=state,
Expand Down Expand Up @@ -986,6 +984,7 @@ def _prepare_quota_should_run_item(
project_asset=project_asset,
user_todo_summary=user_todo_summary,
agent_todo_summary=agent_todo_summary,
agent_todo_terminal_source_items=agent_todo_display_views["terminal"],
authoritative_fallback_todo_items=authoritative_fallback_todo_items,
effective_available_capabilities=effective_available_capabilities,
work_lane_contract=work_lane_contract,
Expand Down
13 changes: 13 additions & 0 deletions loopx/control_plane/todos/context_projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ const CONTEXT_FIELDS = [

/** Select before redaction; never convert nested scopes or booleans to prose. */
export function projectTodoContextPage(input: JsonObject): JsonObject {
if (input.summary_display_views !== undefined) {
if (Object.keys(input).length !== 1) throw new EffectRuntimeRequestError("summary display views cannot be combined with other views");
const source = requireJsonObject(input.summary_display_views, "summary display views");
if (Object.keys(source).some(key => key !== "source" && key !== "handoff_gates")) {
throw new EffectRuntimeRequestError("invalid summary display views fields");
}
requireJsonObject(source.source, "summary source");
return {
summary: projectTodoSummaryDisplay(source),
planning: projectTodoSummaryDisplay({source: source.source, include_terminal: false}),
terminal: projectTodoSummaryDisplay({source: source.source, include_terminal: true}),
};
}
if (input.summary_display !== undefined) {
if (Object.keys(input).length !== 1) throw new EffectRuntimeRequestError("summary display cannot be combined with other views");
return {items: projectTodoSummaryDisplay(requireJsonObject(input.summary_display, "summary display"))};
Expand Down
Loading
Loading