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
Original file line number Diff line number Diff line change
Expand Up @@ -1700,12 +1700,12 @@ facade-exit condition in §4), TS gathers the facts directly and the adapter is
deleted.

Rollout. `status` (including `--goal-id` and projection-cache hits),
`global-summary`, `global-gates`, `global-todos` and `global-risks` now carry
the envelope. Every other `collect_status` caller receives the status envelope
in its payload but does not yet emit its own. Next, in order: `quota
should-run`, `review-packet`, and Decision Context packets. A read model added
to or migrated into TypeScript emits the envelope in the same PR; §6 makes
this a promotion gate.
`global-summary`, `global-gates`, `global-todos`, `global-risks`, and `quota
should-run` now carry the envelope. Every other `collect_status` caller receives
the status envelope in its payload but does not yet emit its own. Next, in
order: `review-packet` and Decision Context packets. A read model added to or
migrated into TypeScript emits the envelope in the same PR; §6 makes this a
promotion gate.

Consumers treat a missing envelope as unknown freshness, and disclose an
alerting one before stating any conclusion that depends on it. Field
Expand Down Expand Up @@ -1777,7 +1777,7 @@ choice is now implemented rather than hypothetical.
| Quota monitor-poll commit transaction | TypeScript owns monitor admission revalidation, target/event/result construction, effect replay/index CAS, provider intent, and repairable JSON/Markdown/index persistence | Python projects compact `should-run` facts, invokes the real Todo provider between at most two reductions, reloads legacy status, and holds the cross-writer index lock |
| Runtime decoders ([#3443](https://github.com/loopx-project/loopx/pull/3443)) | Stable primitive decoding has one small shared module; domain decoders remain local | No larger schema framework is justified |
| Transaction payoff ([#3464](https://github.com/loopx-project/loopx/pull/3464), [#3481](https://github.com/loopx-project/loopx/pull/3481), and Todo completion) | Turn settlement, quota delivery routing, and Todo completion each cross one coarse TS boundary; the Todo transaction owns identity, replay fencing, validation planning/result reduction, continuation/recovery, and completion metadata | Python still executes explicitly external providers and materializes legacy Markdown results; other domains still need their own bounded cutovers |
| Projection envelope | TypeScript owns decoding of `loopx_projection_envelope_v0` and every freshness, alert, completeness and replay decision | Python gathers read facts for `status`, `global-summary`, `global-gates`, `global-todos` and `global-risks` until those projections migrate |
| Projection envelope | TypeScript owns decoding of `loopx_projection_envelope_v0` and every freshness, alert, completeness and replay decision | Python gathers read facts for `status`, `global-summary`, `global-gates`, `global-todos`, `global-risks`, and quota `should-run` until those projections migrate |
| Promoted-authority Todo claim | TypeScript owns the provider-head read, lifecycle validation, complete-record update, hard-lease check, CAS, receipt, and readback-safe result for claims after authority promotion | Default local Markdown mode remains on the legacy writer; other Todo mutations and Markdown regeneration remain bounded follow-ups |

The scheduler facade exit now includes its first bounded Stage 3 route. A
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1197,11 +1197,11 @@ status projection 迁入 kernel(§4 已将其列为 facade 退出条件),
facts,adapter 随之删除。

推广顺序。`status`(含 `--goal-id` 与 projection cache 命中)、`global-summary`、
`global-gates`、`global-todos` 与 `global-risks` 现已携带 envelope。其他 `collect_status`
调用方会在 payload 里收到 status envelope,但尚未输出自己的 envelope。下一步依次为:
`quota should-run`、`review-packet`,
以及 Decision Context packet。新加入或迁入 TypeScript 的读模型在同一个 PR 里输出
envelope;§6 把这一条定为 promotion 门禁。
`global-gates`、`global-todos`、`global-risks` 与 `quota should-run` 现已携带
envelope。其他 `collect_status` 调用方会在 payload 里收到 status envelope,但尚未
输出自己的 envelope。下一步依次为:`review-packet` 与 Decision Context packet。
新加入或迁入 TypeScript 的读模型在同一个 PR 里输出 envelope;§6 把这一条定为
promotion 门禁。

消费者把缺失 envelope 视为新鲜度未知;envelope 告警时,必须先披露,再陈述依赖它的
结论。字段语义与消费者规则见
Expand Down Expand Up @@ -1259,7 +1259,7 @@ replay、receipt 与 settlement。这个架构选择已经落地,不再是假
| Quota monitor-poll commit transaction | TypeScript 拥有 monitor admission 复核、target/event/result 构造、effect replay/index CAS、provider intent,以及可修复的 JSON/Markdown/index persistence | Python 投影 compact `should-run` facts,在最多两次 reduction 之间调用真实 Todo provider,刷新 legacy status,并持有 cross-writer index lock |
| Runtime decoder([#3443](https://github.com/loopx-project/loopx/pull/3443)) | 稳定 primitive decoding 进入一个很小的共享模块;domain decoder 仍留在本地 | 没有理由建设更大的 schema framework |
| Transaction 兑现([#3464](https://github.com/loopx-project/loopx/pull/3464)、[#3481](https://github.com/loopx-project/loopx/pull/3481) 与 Todo completion) | Turn settlement、quota delivery routing 与 Todo completion 均只跨一个粗粒度 TS boundary;Todo transaction 拥有 identity、replay fence、validation planning/result reduction、continuation/recovery 与 completion metadata | Python 仍执行显式 external provider,并物化 legacy Markdown result;其他 domain 仍需各自的 bounded cutover |
| Projection envelope | TypeScript 拥有 `loopx_projection_envelope_v0` 的解码,以及全部 freshness、告警、完整性与重放判定 | 在 `status`、`global-summary`、`global-gates`、`global-todos`、`global-risks` 迁移前,Python 仍为它们收集读取 facts |
| Projection envelope | TypeScript 拥有 `loopx_projection_envelope_v0` 的解码,以及全部 freshness、告警、完整性与重放判定 | 在这些投影迁移前,Python 仍为 `status`、`global-summary`、`global-gates`、`global-todos`、`global-risks` 与 quota `should-run` 收集读取 facts |

Scheduler facade exit 已交付第一段有边界的 Stage 3 路径。带版本的
`heartbeat_followup_cli.ts` 从生成的 ACK/failure hint 接收有大小上限的 compact host
Expand Down
35 changes: 19 additions & 16 deletions 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 <= 5400` 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 <= 16500` | `nested_keys <= 386` | `top_level_keys <= 54` |
| `quota_should_run_json` | quota guard | decide whether the selected goal may spend compute | `status`, `history`, or active state | `json_chars <= 20500` | `nested_keys <= 525` | `top_level_keys <= 54` |
| `dashboard_status_json` | operator dashboard | render first-screen operator state | `history`, run artifacts, or project-local adapter output | `json_chars <= 24000` | `nested_keys <= 350` | `top_level_keys <= 27` |

These four budgets measure compact machine payloads. For
Expand All @@ -23,21 +23,24 @@ indentation and Markdown wrappers can make emitted output materially larger;
the emitted-output qualification matrix below measures that separate boundary
through the real CLI entry point.

The current quota fixture retains 378 nested keys: the M3 automatic-cadence
readback established 368, and full-source frontier counts add ten keys for
deferred readiness and explicit known/unknown coverage. On the same synthetic
workload, base/head measure 14,897/15,115 JSON characters, 368/378 nested keys
and 52/52 top-level keys. Dashboard status grows 22,256/22,362 characters while
its 336 nested and 26 top-level keys stay unchanged. The quota nested-key
ceiling moves from 376 to 386, preserving eight keys of headroom. Character,
top-level, per-Todo growth and other surface ceilings remain unchanged. These
facts prevent hidden rows from becoming blocked work; removing the coverage
fields to meet the old ceiling would lose useful meaning.

同一合成 workload 的 quota 在 base/head 分别为 14,897/15,115 字符、368/378
嵌套键和 52/52 顶层键。新增十个键保留 deferred 就绪计数及 known/unknown 证据;
只将嵌套键预算从 376 调至 386,仍留八键余量。字符、顶层键、每任务增长和其他
surface 上限不变;不通过删除来源完整性来把未展示任务误报为 blocked。
The current quota fixture measures 15,419 characters, 378 nested keys, and 52
top-level keys on `main`. The `quota_should_run` projection envelope raises the
same workload to 18,636 characters, 513 nested keys, and 53 top-level keys. The
new keys carry the inherited status sources, direct live-read facts, freshness,
alerts, and Goal coverage that a consumer must inspect before spending compute.
The character ceiling moves from 16,500 to 20,500, and the nested-key ceiling
moves from 386 to 525. The top-level ceiling stays at 54. The new ceilings leave
1,864 characters, 12 nested keys, and one top-level key on the measured head.
Removing envelope rows would violate the projection contract, so the budget
records the useful contract growth instead of hiding it through compaction.

同一合成 workload 在 `main` 上为 15,419 字符、378 个嵌套键和 52 个顶层键;加入
`quota_should_run` projection envelope 后为 18,636 字符、513 个嵌套键和 53 个
顶层键。新增字段携带继承的 status 来源、实时读取事实、freshness、告警与 Goal
覆盖,消费者必须在花费 compute 前读取这些信息。字符上限从 16,500 调至 20,500,
嵌套键上限从 386 调至 525,顶层键上限仍为 54。精确 head 仍保留 1,864 字符、
12 个嵌套键与一个顶层键余量。删除 envelope 行会破坏投影合同,因此这里记录有用的
合同增长,而不是用压缩隐藏它。

The successful thin heartbeat projection contains only `schema_version`,
`ok`, `goal_id`, optional `agent_id`, `task_body`, and the compact
Expand Down
8 changes: 8 additions & 0 deletions docs/reference/contracts/projection-envelope-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,18 @@ Python-owned projections do so through `loopx/control_plane/projection_envelope_
| `loopx global-gates` | `global_gates` | `global` |
| `loopx global-todos` | `global_todos` | `global` |
| `loopx global-risks` | `global_risks` | `global` |
| `loopx quota should-run` | `quota_should_run` | `goal` |

Other read models adopt the envelope in the order listed in the RFC; until
then they carry no freshness guarantee and consumer rule 1 below applies.

`quota_should_run` inherits the status envelope. It also records each live
source that the decision reads, including automation cadence, an applicable
App scheduler state, the selected delivery workspace, the operator inbox, and
replan exploration. A missing persisted App scheduler state is a successful
empty read. `owner_read_failed` makes automation cadence unreadable, while
`runtime_root_unavailable` means that source was not read.

## Shape

```json
Expand Down
16 changes: 7 additions & 9 deletions examples/control_plane/hot-path-interface-budget-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,13 @@
# provider-neutral app_automation packet becomes canonical.
# Full Goal/selected-work read commands add necessary source continuity.
# One Agent-channel carrier avoids duplicating them in the CLI channel.
# M3 adds one validated cadence readback envelope to the quota packet:
# 357 -> 368 nested keys and 51 -> 52 top-level keys.
# Identical raw packet: 15,201 at the ordinary temp root, 15,865 at
# the original longer root. Full command routes are useful; retain
# them with 635 chars of headroom, without widening structural guards.
"max_json_chars": 16_500,
# Full-source frontier readiness/coverage adds ten useful keys:
# base 368 -> 378, preserving eight keys of structural headroom.
"max_nested_keys": 386,
# The projection envelope adds the source freshness and goal coverage
# needed to trust this decision. On the same fixture, main/head measure
# 15,419/18,636 characters, 378/513 nested keys, and 52/53 top-level
# keys. Keep the complete typed envelope rather than dropping source
# facts that the consumer must inspect before it spends compute.
"max_json_chars": 20_500,
"max_nested_keys": 525,
"max_top_level_keys": 54,
},
"dashboard_status_json": {
Expand Down
Loading
Loading