Skip to content

fix(status): print the scope beside the projection-route verdict - #4594

Closed
huangruiteng wants to merge 6 commits into
mainfrom
codex/status-projection-route-scope-20260917
Closed

huangruiteng wants to merge 6 commits into
mainfrom
codex/status-projection-route-scope-20260917

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

The disagreement this fixes

loopx doctor and loopx status both print a healthy value for runtime projection routes. They read different denominators, and neither line said so.

Reproduced on this machine before the change:

$ loopx doctor    # global registry, every route
- runtime_projection_routes_healthy: `False`
  {"healthy": 0, "ready": 2, "single_runtime": 29, "missing": 13, ...}

$ loopx status    # project registry, no goal filter
- runtime_projection_routes: healthy=True

$ loopx status --goal-id loopx-meta
- runtime_projection_routes: healthy=True

Both values are arithmetically correct. doctor collects the shared global registry and marks the fleet unhealthy because 13 goals report source_registry_missing; status scopes the same collector to its own registry, and further to one goal under --goal-id. Pointed at the same registry, status already agreed with doctor:

$ loopx status --registry ~/.codex/loopx/registry.global.json
- runtime_projection_routes: healthy=False

So the operator-visible contradiction was the missing scope, not a wrong number: an owner running doctor after status saw red next to green with nothing to reconcile them.

Change

  • runtime_projection_routes in the status projection gains the route count it was computed over.
  • The status renderer prints registry, goal filter and route count beside the flag.
  • The doctor line prints registry, route count and the full counts map, so a red reading is actionable without --format json.

After:

- runtime_projection_routes: healthy=True (goals=1)
- runtime_projection_routes_healthy: `False` (registry=`<global>`, goals=`44`, counts=`{"missing": 13, ...}`)

The status line carries only the denominator, because the agent-facing markdown
rows allow 32 extra characters each; doctor names the registry and the full
counts map on the unhealthy reading.

Interface budget

runtime_projection_routes grows by exactly one key. This is a deliberately budgeted hot-path payload, so the scope is limited to the denominator the flag needs rather than inlining the full diagnostics. The interface-budget smoke passes with the dashboard status payload at 19155/19500 chars.

Validation

  • examples/control_plane/refresh-state-shared-runtime-projection-smoke.py — added the reconciliation invariant: status and doctor must agree on healthy and goal_count over the same registry, and doctor's markdown must name its scope.
  • examples/control_plane/shared-runtime-material-projection-smoke.py, examples/control_plane/hot-path-interface-budget-smoke.py — updated the assertions that pinned the previous lossy {"healthy": ...} shape.
  • pytest tests/ -k "status or doctor or projection_route" — 311 passed, 1 skipped. Two test_task_graph_topology.py sqlite-current/sqlite-missing failures are environmental and reproduce unchanged on origin/main.
  • loopx check — clean.

Boundary

Public-safe: no private state, credentials, local paths or raw evidence. No control-plane decision, permission or scoring behavior changes; only the projection's self-description and the two rendered lines.

huangruiteng and others added 3 commits September 17, 2026 03:20
`loopx status` and `loopx doctor` both print a `healthy` value for runtime
projection routes, but they read different denominators: doctor collects the
shared global registry and reports on every route in it, while status scopes
the same collector to its own registry and, with `--goal-id`, to a single
goal. Neither surface named that scope, so an operator comparing the two read
a flat contradiction — doctor red, status green — with nothing in either line
to explain it.

The projection now carries the route count it was computed over, and both
renderers print the registry and denominator beside the flag:

    - runtime_projection_routes: healthy=False (registry=<global>, goals=44), details=loopx doctor
    - runtime_projection_routes: healthy=True (registry=<global>, goal=<goal>, goals=1)

Verified on this machine before the change: `loopx doctor` reported
`healthy=False` (44 goals, 13 missing) while `loopx status` reported
`healthy=True`; with the fix, an unfiltered `status` reads the same registry as
doctor and agrees at `healthy=False (goals=44)`.

`runtime_projection_routes` grows by exactly one key. It is a deliberately
budgeted hot-path payload, so the scope is kept to the denominator the flag
actually needs instead of inlining the full diagnostics; the interface-budget
smoke still passes with the dashboard status payload at 19155/19500 chars.

Validated: refresh-state shared-runtime projection smoke, shared-runtime
material projection smoke, and hot-path interface budget smoke pass;
`pytest tests/ -k "status or doctor or projection_route"` reports 311 passed,
1 skipped, with two pre-existing `sqlite-current`/`sqlite-missing` failures
reproduced unchanged on origin/main; `loopx check` is clean.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
The first revision of this change printed `registry=...`, `goal=...` and
`goals=...` on the projection-route line. That grew the agent-facing markdown
rows by 119-125 characters, and
`examples/control_plane/cli-output-base-head-differential-smoke.py` allows 32
characters and 64 bytes per row:

    surface/status/crowded/markdown     chars grew by 121; allowance is 32
    surface/status/multi_agent/markdown chars grew by 125; allowance is 32
    surface/status/small/markdown       chars grew by 119; allowance is 32

The line now carries only the denominator — `healthy=False (goals=44)`,
`healthy=True (goals=1)` — which is the fact that explains the disagreement:
a scoped goal is one route, the fleet is forty-four. The registry stays out of
this row because `doctor` already names it along with the full counts map on
the unhealthy reading, and the status JSON keeps `registry` at the top level
for machine readers. Growing the budget instead would have been a gate change
for a presentation fix.

Validated: `cli-output-base-head-differential-smoke` ok with base=102,
candidate=102, candidate_only=0, review_required=0; the refresh-state
shared-runtime projection, shared-runtime material projection and hot-path
interface budget smokes pass; `pytest -k "status_markdown or cli_output or
projection_route"` reports 85 passed.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/status-projection-route-scope-20260917 branch from 86c2945 to 259789c Compare September 16, 2026 21:56
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

动机

本车道在 2026-09-17 的旅程资格里记录了同一会话内的矛盾:`loopx status` 报 `runtime_projection_routes: healthy=True`,`loopx doctor` 报 `runtime_projection_routes_healthy: False`,两个面都不说明各自读的是哪个范围,也没有对账规则。这是典型“读数缺分母”的问题:两者共用同一个 `healthy` 键,但一个读项目内 goal 路由、另一个读共享全局 registry。

改动思路

不做仲裁、不改判定逻辑,而是让每个面把“这个布尔值是在多少条路由上算出来的”一并说出来:`status` 在既有行尾补 `(goals=N)`,受 32 字符 agent 输出预算约束;`doctor` 额外给出 registry 路径、goals 数与完整 counts 映射,便于直接对账。两侧渲染都由 smoke 断言。

具体改动

  • loopx/control_plane/status/collection.py:`runtime_projection_routes` 增加 `goal_count`,取自同一路由诊断,缺省为 0。
  • loopx/presentation/renderers/status_markdown.py:`healthy={bool}` 后按需附 `(goals=N)`,并加 docstring 说明为何 registry 路径留给 doctor。
  • loopx/doctor.py:`runtime_projection_routes_healthy` 行补 `registry=`、`goals=`、`counts=`(JSON、键排序)。
  • 三个 smoke 由“等于 {"healthy": bool}”改为断言 `healthy` 与 `goal_count`,并新增 status/doctor 一致性断言与两处渲染文本断言。

对主干的风险

产品行为变化限于新增的展示字段与 renderer 文案:原先断言精确字典形状的 smoke 已同步改为逐键断言,避免把新增字段读成回归。scope 语义没有被重新定义,只是显式化;未改变任何门禁或判定结果。hot-path 输出预算 smoke 已在该 head 通过,说明 `(goals=N)` 未超出 agent 面行预算。

我的整体评价

以“补分母、两边都点名范围”而不是“改一个面附和另一个面”的方式修掉了我此前记录的 operator-truth 缺口,方向和最小性都对,且用 smoke 把两面对账固定下来。建议在该 head 的必过检查转绿后合并;合并后即可关闭依赖它的 todo_845adbcd6703。

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Head: 0061271

English verdict: APPROVE

…on-route-scope-20260917

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

动机

loopx doctor 与 loopx status 都会为 runtime projection routes 打印一个 healthy,但两边的分母不同,而且两边都没说自己用的是哪个分母。复现出来的结果就是:doctor 报 runtime_projection_routes_healthy: False(全局 registry,44 条路由里 13 条 source_registry_missing),同一次会话里 status 报 healthy=True(项目 registry、且可再按 --goal-id 收紧)——两个数在各自口径下都对,读的人却会以为其中一个错了。本车道在本地管家旅程里如实记下了这个分歧(todo_845adbcd6703)。

改动思路

让每条打印自己那一层:status 行只带分母 healthy=False (goals=44) / healthy=True (goals=1),registry 名与完整计数留给 doctor。这样既点名“这是哪一层的健康度”,又不去动 agent-facing 的输出预算——这一点很关键,因为第一版把 registry=、goal=、goals= 都塞进 status 行后,markdown 行涨了 119–125 字符,被 examples/control_plane/cli-output-base-head-differential-smoke.py 以每行 32 字符 / 64 字节的额度拒掉。

具体改动

  • loopx/presentation/renderers/status_markdown.py、loopx/control_plane/status/collection.py、loopx/doctor.py:status 侧输出收紧为分母,doctor 侧保留 registry 与完整 counts map。
  • examples/control_plane/hot-path-interface-budget-smoke.py、refresh-state-shared-runtime-projection-smoke.py、shared-runtime-material-projection-smoke.py:把新契约与该头的输出预算一起钉住。

对主干的风险

这是面向操作者的输出改动,风险是“为了说清楚而把 agent-facing 行撑大”,而第一版正是踩了这个坑,所以修正版把信息量压到分母上、并用差分 smoke 把额度钉住。本次复审在更新后的 head 上实测(该 head 只是把 origin/main 合进来,六个被评审文件在旧 head 与新 head 之间逐字节一致,已用内容哈希核对):

  • uv run --extra test python examples/control_plane/cli-output-base-head-differential-smoke.py → ok base_ref=origin/main base=102 candidate=102 candidate_only=0 review_required=0
  • uv run --extra test python -m pytest -k "status_markdown or cli_output or projection_route" -q → 85 passed, 9708 deselected

我的整体评价

把一个真实存在、且会让操作者得出相反结论的口径分歧变成“各自说明自己那一层”,并用输出预算门把“说清楚”和“别撑大”同时钉住,方向是对的。建议在该 head 的必过检查全绿的前提下合并。

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Head: 8888a92

English verdict: APPROVE

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Superseded by #4636. Retained the useful route count, but a denominator alone cannot distinguish equal-sized scopes. The replacement makes doctor report its actual diagnostic registry and filter metadata, reuses status registry/Goal/activation context, and labels the global drill-down. Real CLI fixtures cover same-route agreement and different registries with identical counts but different health. Output budgets and all 19 premerge checks pass. The route-health computation and write behavior are unchanged; closing this branch to keep one merge target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant