Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Summary work-count consumer closure (2026-09-19)

| Boundary | Delivered evidence |
| --- | --- |
| Goal/source | Overall roadmap R5/S2, TS T3 and shared-authority L5; baseline `96d98f3d4`. |
| Observable gap | A complete source with 21 actionable advancement Todos becomes 8 when a consumer counts the bounded backlog; quota payload compaction reduces the apparent count further. A different legacy fallback classifies unseen rows as advancement. |
| Owning change | `todos/summary_lanes.ts` selects lanes in one typed batch and supplies pre-limit work counts. Existing quota selection reuses the count owner after Agent filtering. Python retains normalization, timestamp/presentation adaptation and ordinal readback; its lane-selection and hidden-work inference loops are removed. |
| Semantics | Complete counts survive list/status/quota compaction. Incomplete scope knowledge survives repeated projection; contradictory legacy fragments cannot prove completeness. Unknown tasks are not inferred as executable. Canonical `todo list` carries the read revision's acceptance guard, matching status without hiding held records. |
| Compatibility | Full baseline/candidate role and scoped summaries agree apart from the disclosed additive counts; completed/deferred conventions, ordering, Monitor timing and successor/closure policies remain. Empty canonical sources stay authoritative and unavailable providers cannot fall back to Markdown. |
| Real paths | File/SQLite CLI and installed-wheel CLI/Chat HTTP readback; isolated real PostgreSQL authority/service reads; both complete synthetic record schemas and an authorized frozen full-graph snapshot. Existing heads/Todos/leases and independent display bytes remain unchanged. |
| Cost | Two compact ordinal-planning requests per two-role summary; no per-Todo RPC and no new persisted queue or provider state. The whole Python summary adapter still has other rule/effect callers. |
| Remaining boundary | This closes the count consumer within L5, not permanent projection freshness, all T3 sources, event callers, executor-held effect fences, D2 capacity/elapsed soak or D3 integrated promotion. No default change or old-writer retirement is claimed. |

See [the read contract](../../../../reference/todo-work-counts.md) for field
meaning, public read commands, incomplete-source behavior and rollback.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# 摘要工作计数消费者闭合(2026-09-19)

| 边界 | 交付证据 |
| --- | --- |
| 目标 | 总纲 R5/S2、TS T3、shared-authority L5;基线 `96d98f3d4`。 |
| 可观察缺口 | 完整来源中 21 条可执行推进 Todo 因 backlog 展示上限被下游报成 8 条,quota 压缩进一步缩小数量;另一旧路径把未看到的任务猜成 advancement。 |
| 唯一 owner | `todos/summary_lanes.ts` 批量选择 lane 并计算裁剪前数量;已有 quota selection 在 Agent 筛选后复用计数 owner。Python 保留规范化、时间/展示适配及索引回读,删除原 lane 选择和隐藏任务推断循环。 |
| 语义修复 | list/status/quota 压缩保留完整计数;重复投影保留来源不完整状态;矛盾旧片段不能证明完整,未知任务不再被推断为可执行。canonical `todo list` 保留同版本 acceptance 限制,与 status 一致但不隐藏受阻记录。 |
| 兼容 | 除已声明新增计数,基线/候选的完整 role 与作用域摘要一致;完成/延期约定、排序、Monitor 时间规则及 successor/closure 策略保留。空 canonical 来源仍有权威性,provider 不可用时不回退 Markdown。 |
| 真实路径 | File/SQLite CLI、wheel 安装后的 CLI/真实 Chat HTTP、隔离真实 PostgreSQL authority/service 读取;两种完整合成记录 schema 与授权冻结图快照。原 head/Todo/lease 及独立展示字节不变。 |
| 成本 | 双 role 摘要增加两次紧凑索引规划请求,没有逐 Todo RPC、新持久队列或 provider 状态。Python 完整摘要 adapter 仍有其他规则/效果调用,不能整体删除。 |
| 剩余 | 本次只闭合 L5 计数消费者;永久投影新鲜度、其他 T3 来源、event caller、执行器 effect fence、D2 容量/真实时间 soak 及 D3 集成晋升仍未完成。不改变默认 provider,也不宣称旧 writer 已退出。 |

[读取合同](../../../../reference/todo-work-counts.md)说明字段、公有读取命令、
不完整来源语义和回滚边界。
Original file line number Diff line number Diff line change
Expand Up @@ -2957,6 +2957,8 @@ source paths, authorize monitor writeback, or change provider/promotion holds.

**D1 — qualify permanent projection delivery; may overlap T1/T2.**

Summary/work-lane counts now remain independent of display limits and retain incomplete-source knowledge through Agent scoping; canonical list acceptance holds match status. This closes one L5 read consumer, not permanent projection freshness or D1–D3. See [count semantics](../../reference/todo-work-counts.md).

The Goal Channel ownership observation consumes one complete provider revision before bounding display. It never repairs Markdown or revives old local leases; provider failures and truncation stay visible. This is a T3 read closure with shared TS interpretation, not D1/D2 qualification or D3 cutover. See [coordination observation](../../reference/coordination-observation.md).

The D1 document-ownership slice gives readers, editors and projection one visible-region
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2340,6 +2340,8 @@ Scoped fallback 的选择与门禁关系也已复用同一 TS decision owner,

**D1 — 资格化永久投影交付,可与 T1/T2 重叠推进。**

摘要与 work-lane 计数已独立于展示上限,并在 Agent 筛选后保留来源不完整状态;canonical 列表的 acceptance 限制与 status 一致。这只闭合 L5 的一个读取消费者,不代表永久投影新鲜度或 D1–D3 完成。见[计数语义](../../reference/todo-work-counts.md)。

Goal Channel 所有权观察先读取完整 provider revision,再限制展示;不修复 Markdown、不复活旧本地 lease,明确披露失败与截断。这是共用 TS 解释规则的 T3 读链路闭合,不完成 D1/D2 或 D3 切换,见 [coordination observation](../../reference/coordination-observation.md)。

D1 的文档归属切片把读取、编辑与投影放到同一可见区域/Todo 行解码边界,修复
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,15 @@ all T2 commands or authorize whole-Goal promotion.

**T3 — close remaining structured consumers, then remove their old reads.**

Todo summary lanes and pre-limit work counts now share `todos/summary_lanes.ts`.
Python's lane classification and hidden-work inference loops are removed; quota
recomputes counts after scope selection and carries incomplete source knowledge
through compaction/reprojection. Public canonical Todo lists retain the same
revision's acceptance guard. See [count semantics](../../reference/todo-work-counts.md).
This closes the summary-to-work-lane count consumer, not every T3 source or D1
projection delivery; legacy codecs/renderers and other summary policies remain.


Goal Channel ownership observation now reads a complete canonical Todo/lease revision and shares one TS batch policy with the legacy adapter. It retires display-layer lease time/generation/conflict decisions and local-file reads after promotion. Empty, unavailable and truncated observations remain distinct; see [coordination observation](../../reference/coordination-observation.md). This closes the Goal Channel ownership reader, not other channel panels or whole-Goal promotion.

The D1 document-ownership slice gives readers, editors and projection one visible-region
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,13 @@ delivery pending;这不代表全部 T2 命令或整 Goal promotion 已完成

**T3 — 闭合剩余 structured consumer,删除各自旧读路径。**

Todo 摘要 lane 与裁剪前工作计数现共用 `todos/summary_lanes.ts`,删除 Python 的
lane 分类和隐藏任务推断循环。quota 在作用域筛选后重新计数,不完整来源状态贯穿
压缩与重复投影;公开 canonical Todo 列表保留同版本 acceptance 限制。见
[计数语义](../../reference/todo-work-counts.md)。本切片闭合摘要到 work-lane 的计数
消费者,不代表所有 T3 来源或 D1 展示交付完成;旧格式解码、renderer 及其他摘要策略仍保留。


Goal Channel 所有权观察现从完整 canonical Todo/lease revision 读取,并与 legacy adapter 共用 TS 批量规则;删除展示层的时间/代数/冲突判断和晋升后的本地文件读路径。空值、不可用与截断分别披露,见 [coordination observation](../../reference/coordination-observation.md)。这只闭合所有权观察 reader,不宣称其余面板或整 Goal 晋升完成。

D1 的文档归属切片把读取、编辑与投影放到同一可见区域/Todo 行解码边界,修复
Expand Down
15 changes: 14 additions & 1 deletion docs/reference/contracts/interface-budget-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ and size/count budgets.
| --- | --- | --- | --- | --- | --- | --- |
| `heartbeat_prompt_json` | heartbeat automation | wake and route one bounded turn | `quota should-run`, `status`, or `review-packet --handoff-only` | `json_chars <= 4800` plus `interface_budget.within_budget=true` | `nested_keys <= 40` | `top_level_keys <= 30` |
| `review_packet_handoff_only_json` | project-agent handoff | forward the smallest sufficient task packet | full `review-packet` or run-history artifact | `json_chars <= 3000` plus `handoff_interface_budget.within_budget=true` | `nested_keys <= 40` | `top_level_keys <= 18` |
| `quota_should_run_json` | quota guard | decide whether the selected goal may spend compute | `status`, `history`, or active state | `json_chars <= 14000` | `nested_keys <= 350` | `top_level_keys <= 52` |
| `quota_should_run_json` | quota guard | decide whether the selected goal may spend compute | `status`, `history`, or active state | `json_chars <= 14500` | `nested_keys <= 360` | `top_level_keys <= 52` |
| `dashboard_status_json` | operator dashboard | render first-screen operator state | `history`, run artifacts, or project-local adapter output | `json_chars <= 19500` | `nested_keys <= 260` | `top_level_keys <= 25` |

These four budgets measure compact machine payloads. For
Expand Down Expand Up @@ -52,6 +52,19 @@ route, pending-selection qualification, and hard-lane preemption evidence. The
budget retains modest headroom for those enforceable semantics; repeated action
details and command prefixes still belong in compact references or cold paths.

The work-count projection adds scope and completeness facts that a bounded Todo
list cannot supply. Its observed-row count is derived from `open - hidden`,
rather than repeated in the wire object. The quota ceiling moves from 14,000
to 14,500 characters and from 350 to 360 nested keys to retain modest headroom
for this useful semantic growth; the top-level ceiling stays 52. Existing
repeated Todo bodies across named lanes have distinct consumers and cannot be
removed without a separately validated caller migration.

工作计数增加了展示列表无法提供的完整性与作用域信息;已观察行数由 `open - hidden`
推导,不重复传输。quota 字符预算从 14,000 调至 14,500,嵌套键从 350 调至 360,
保留适量余量;顶层键上限仍为 52。不同 lane 重复携带的 Todo 有既有消费者,后续
去重应配合调用方迁移,不能仅为通过尺寸测试而删除。

| Emitted Surface | Default Qualification | Scale / Limit Contract | Cold Path |
| --- | --- | --- | --- |
| `start-goal --guided` | baseline and growth | small, crowded, and multi-agent goals; objective/command duplication | `packet_summary.detail_refs` and `bootstrap-command-pack` |
Expand Down
79 changes: 79 additions & 0 deletions docs/reference/todo-work-counts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Todo work counts and bounded display

Todo lists, status and quota summaries carry `work_counts` with schema
`todo_work_counts_v0`. Counts are computed before display limits; quota
recomputes them **after** the existing Agent scope and resume selection.
The contract is read-only. A count never grants a claim, lease, capability,
validation exemption or execution permission.

```sh
loopx --format json todo list --goal-id example --role agent --limit 1 --thin
loopx --format json status --goal-id example
loopx --format json quota should-run --goal-id example --agent-id agent-a
```

The first command returns one Todo while its role summary retains the matched
source's counts. A filtered list describes its filtered source. This is not a
new provider setting: legacy inputs and promoted File/SQLite inputs share the
same typed summary owner. PostgreSQL uses the same provider-neutral records;
service deployment and whole-Goal promotion remain separately qualified.

| Field | Meaning |
| --- | --- |
| `open` | Nonterminal source rows, including blocked work; it is not executable work |
| `advancement` | Observed actionable advancement rows; acceptance-denied and unsatisfied resume rows do not qualify |
| `monitor` | Observed actionable Monitor rows, including future/expired observation context; due/schedule-gap fields retain their existing separate meanings |
| `hidden` | Declared source rows not available for classification, not rows hidden by UI pagination |
| `complete` | Whether the available source covers the declared scope; false counts are lower bounds for classified task kinds |
| `agent_id` | Agent execution scope, or null for an unscoped/role summary |

The observed row count is derived as `open - hidden`; the payload does not
repeat it as a second value that could drift.

`complete=false` survives repeated quota projection, even when the surviving
subset fits on one screen. It cannot certify “Monitor-only work remains.”
Legacy display-only inputs are deduplicated by Todo identity; contradictory
fragments cannot certify completeness. A missing task is never guessed to be
advancement work. Invalid count envelopes and differently scoped count reuse
fail explicitly.

The TypeScript `todos/summary_lanes.ts` owner returns indexes into the one input
array instead of repeating full Todo bodies for each lane. The Python adapter
normalizes legacy fields/timestamps and validates the returned ordinal bounds.
One observation time governs Monitor due and expiry classification within the
batch. Source order, completed/deferred conventions and claimant visibility
remain compatible; `done_count` still includes deferred rows as required by its
existing summary contract.

Intentional corrections: 21 executable Todos no longer become 8 because the
backlog display limit is 8; a compact quota payload no longer turns that count
into 2. Unknown hidden rows are not classified. Public canonical `todo list`
also retains the acceptance guard from the same read revision, so held work
cannot appear executable there while status says it is held. Acceptance-off
reads keep their existing selection behavior.

Markdown stays a permanent display. These reads do not rewrite stale/missing
Markdown, create receipts or mutate canonical records. The additive count
field is not persisted in Todo authority. Older readers can ignore it, but
retain their old undercount behavior; rollback does not require data migration.
T1/T2 caller closure, D1 projection recovery, D2 capacity/elapsed soak and D3
fenced whole-Goal cutover remain separate work.

## 中文说明

`work_counts` 由完整来源计算,随后才裁剪展示。Agent quota 先按原有归属、排除、
能力与作用域规则筛选,再重新计数,不能沿用整个 Goal 的数量。`open` 包含 blocked
任务;`advancement` 才是已观察到的可执行推进任务。Monitor 是否到期仍使用独立字段。

`hidden` 表示未取得、无法分类的来源行,不是界面折叠的行数。`complete=false` 时,
已分类数量只是下界,重复投影也不能把未知变成完整,更不能据此声称“只剩 Monitor”。
旧摘要按 Todo 身份去重,矛盾片段不能证明完整;缺失任务不再被猜成 advancement。

TS 统一批量 lane 分类与计数,Python 保留旧格式解码、时间适配和展示。返回数组位置
索引减少同一任务在多个 lane 的重复传输;一个批次使用同一观察时刻。排序、延期与
完成计数约定、claim 展示保留。canonical `todo list` 同时修复了漏传同版本 acceptance
限制的问题,验收受阻的任务仍可见,但不会被列为可执行。

这不改变 provider 默认值,不授予执行权限,不写回 Markdown 或 canonical 状态。
新增计数字段不进入持久化 Todo;回滚无需数据迁移。默认切换、存量迁移、D1–D3 和旧
Python writer 退出仍有各自的验收条件,不能按本 PR 合并数量推定完成。
5 changes: 5 additions & 0 deletions examples/control_plane/cli-output-probe-runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ def _receipt_row(
if isinstance(payload, dict)
else []
),
"todo_work_counts_schema_versions": (
semantics.todo_work_counts_schema_versions(payload)
if isinstance(payload, dict)
else []
),
}


Expand Down
6 changes: 4 additions & 2 deletions examples/control_plane/hot-path-interface-budget-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@
"cold_path": "status, history, or active state",
# Codex keeps a lossless codex_app compatibility alias while the
# provider-neutral app_automation packet becomes canonical.
"max_json_chars": 14_000,
"max_nested_keys": 350,
# Pre-limit work counts add useful scope/completeness evidence; allow
# modest headroom after removing the redundant observed-row count.
"max_json_chars": 14_500,
"max_nested_keys": 360,
"max_top_level_keys": 52,
},
"dashboard_status_json": {
Expand Down
3 changes: 3 additions & 0 deletions loopx/control_plane/effect_runtime_handlers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {projectTodoSummaryLanes, projectLegacyTodoWorkCounts} from "./todos/summary_lanes.ts";
import {selectDelegationBinding, transitionDelegationObservation} from "./collaboration/delegation.ts";
import {resolveConversationScope} from "./collaboration/conversation_scope.ts";
import {previewTeamPlan, planTeamTransaction, teamTransactionIdentity} from "./work_items/team_plan.ts";
Expand Down Expand Up @@ -408,6 +409,8 @@ export function createEffectRuntimeHandlers(
["todo.field_update.plan", planTodoFieldUpdate],
["todo.public_update.plan", planPublicTodoUpdate],
["todo.standing_decision.project", evaluateStandingDecisionProjection],
["todo.summary_lanes.project", projectTodoSummaryLanes],
["todo.work_counts.project", projectLegacyTodoWorkCounts],
["todo.decision_scope.evaluate", evaluateDecisionScope],
["agent.capability_gate.evaluate", evaluateCapabilityGate],
["agent.capability_memory", agentCapabilityMemory],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ def scoped_monitor_watch_without_advancement(summary: dict[str, Any] | None) ->
return False
if not todo_summary_monitor_items(summary):
return False
return todo_summary_open_task_counts(summary).get("advancement", 0) <= 0
counts = todo_summary_open_task_counts(summary)
return counts["complete"] is True and counts["advancement"] == 0


def _monitor_item_matches_handle(
Expand Down
Loading
Loading