From 3cd8d9604c51abb5bf06e77acfacc99728911ea9 Mon Sep 17 00:00:00 2001 From: hhyykk <4408344+hhyykk@users.noreply.github.com> Date: Mon, 2 Nov 2026 20:48:09 +0800 Subject: [PATCH 1/2] refactor(todos): classify global Todo readiness in TypeScript Global Todo readiness for loopx global-todos and the goal portfolio now runs as one todo.global_readiness.project request next to the decision scope owner. TypeScript traverses the candidate sources, merges first-source fields, tracks provenance, evaluates gate relations in process and applies blocked > deferred_ready > runnable with conflict warnings. Python keeps quota acquisition, the shared open_user_gate_todo_items selector, persisted-field codecs, public redaction, grouping and Markdown. The request carries only the candidate containers. Frozen JSON/Markdown characterization for both consumers stays byte-identical; the unused scalar relation operation is retired. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> Signed-off-by: hhyykk <4408344+hhyykk@users.noreply.github.com> --- .../2026-11-02-global-todo-readiness.md | 110 ++++ .../2026-11-02-global-todo-readiness.zh-CN.md | 91 ++++ .../typescript-control-plane-migration-v0.md | 1 + ...script-control-plane-migration-v0.zh-CN.md | 1 + .../quota-agent-scoped-user-gate-smoke.py | 4 +- .../control_plane/effect_runtime_handlers.ts | 1 + loopx/control_plane/todos/decision_scope.py | 66 ++- loopx/control_plane/todos/decision_scope.ts | 89 +++- loopx/global_todos.py | 173 +------ ...st_todo_decision_scope_runtime_boundary.py | 57 ++- .../global_todo_readiness.test.ts | 50 ++ tests/fixtures/global_todo_readiness.json | 473 ++++++++++++++++++ ..._global_todo_readiness_characterization.py | 155 ++++++ 13 files changed, 1096 insertions(+), 175 deletions(-) create mode 100644 docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.md create mode 100644 docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.zh-CN.md create mode 100644 tests/control_plane_ts/global_todo_readiness.test.ts create mode 100644 tests/fixtures/global_todo_readiness.json create mode 100644 tests/test_global_todo_readiness_characterization.py diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.md new file mode 100644 index 0000000000..00b43443a5 --- /dev/null +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.md @@ -0,0 +1,110 @@ +# Global Todo readiness owner cutover — 2026-11-02 + +## Boundary and economics + +Baseline: `fb16c6cb1369efce52a673030c914b38e1dac166`. This bounded slice +moves the complete Global Todo readiness decision from `global_todos.py` to +`projectGlobalTodoReadiness` in the existing `todos/decision_scope.ts` owner, +registered as `todo.global_readiness.project`. Both `loopx global-todos` and +`loopx goal-portfolio` use it through their shared display adapter; portfolio +classifies each registered Agent independently. + +TypeScript owns ordered selected/lane/summary/frontier traversal, first-source +merge with missing-field fill, source/status provenance, in-process `todoGateRelation`, blocked/deferred/runnable +precedence, and warning ordering. `normal_delivery_allowed` remains a readiness +projection signal and grants no execution permission. Existing readiness values +are reused; the new versioned request/result describe this bounded projection, +not a new lifecycle or authority vocabulary. + +Instrumentation pins all cross-runtime requests, including envelope sealing: + +| Operation | Baseline | Candidate | +| --- | --- | --- | +| One classification, gates and candidates present | 1 relation request | 1 complete readiness request | +| One classification, no gates | 0 | 1 | +| One classification, no candidates (including empty payload) | 0 | 1 | +| Global command, one classified Goal with gates | 2 including envelope | 2 including envelope | +| Global command, gate-free or empty classification | 1 envelope | 2 including envelope | +| Portfolio, two Agents with gates | 2 | 2 | +| Portfolio, two gate-free/empty Agent classifications | 0 | 2 | + +The gate-free/empty increase is intentional and disclosed. No latency or +long-horizon effectiveness/efficiency benefit is claimed. + +Product physical diff: +163/−166 lines, net −3. Python removes source +traversal/merge helpers, blocked/deferred classification, readiness precedence +composition and its separate safety-rank table. The uncalled Python scalar +`todo_gate_relation` bridge and its TS scalar dispatch are deleted. Its synthetic +smoke and decoder tests use the production batched bridge retained for summary. + +Python retains `open_user_gate_todo_items` as the single gate-selection owner: +summary, stall repair, Todo summary and agent scope still call it. Its ordered +selection, done filtering and Python-equality deduplication must not be copied +into TypeScript. Selected gates cross as decoded facts with target text. +Shared `_facts` retains persisted ID/scope normalization and legacy task-class +interpretation. The bounded request carries only selected/lane records, delivery +signal, and list-valued summary/frontier fields. Python decodes dict elements of +every such list generically; TypeScript alone owns candidate list-key traversal. +There is no recursive payload walk. The largest frozen case's compact UTF-8 JSON +request shrinks from 9,749 to 6,447 bytes (33.9%); outputs remain byte-identical. +Python also retains status/quota IO, public text redaction, `_work_kind` display +interpretation, final grouping/deduplication/display sorting, envelope sealing +and Markdown. These compatibility and presentation boundaries are not a second +candidate-readiness owner. + +Facade exit: delete `project_global_todo_readiness` and its decoded-field +sidecar once both global and portfolio host/read models consume the typed Todo +snapshot and projection directly, with native legacy metadata decoding and +public-safe rendering at their owning boundaries. Delete the shared display +adapter when neither consumer needs Python normalization. Retire the temporary +characterization corpus/archive comparison at that exit after durable semantic +and public-entrypoint tests cover the retained contracts. + +## Qualification and limits + +Seven synthetic characterization cases passed on unchanged Python before the +cutover; their complete JSON/Markdown bytes and baseline/candidate crossing +lists were then frozen. The fixture SHA-256 is +`eaf17921f81357329ba7bc3c7dcb34253eed83b53d31c31d6dba0fdb5c547641`. +Cases cover complementary duplicate fields, conflicting statuses, delivery +denial, exact/scope conflict, unrelated gates, blocked/deferred overlap, +missing identities, two Agents, warning order, empty inputs and public-text +redaction. Independent TS tests assert precedence, denial and exact/scope +conflict semantics, plus malformed protocol rejection. Python decoder tests +reject malformed results without fallback. + +`tests/test_global_todo_readiness_characterization.py::test_production_cli_archive_parity` +archives `HEAD` without stash and compares both public commands, JSON and +Markdown, on the same synthetic temporary home with real File and SQLite +providers. Only clocks are frozen before importing the production CLI; field +presence, diagnostics, source versions and hashes are compared unchanged. +All eight command/provider/format pairs match and require populated Todo and +Agent results. This qualifies a source checkout, not installed packaging or +frontend behavior; no caller capability or user journey was added. + +The focused scheduler-state readback test +`test_real_cli_quota_should_run_discloses_unreadable_scheduler_state` fails on +both the changed checkout and the archived baseline: its quota command omits +Turn identity and returns `QUOTA_VALIDATION_FAILED` with the requirement for +`--turn-instance-id` or `--begin-turn`. This is a pre-existing caller/validation +mismatch, outside readiness ownership. Preserve that failure; do not relax the +argument gate or rewrite this migration's expected outputs to conceal it. + +Semantic drift remains `independently_maintained=45/45`; there are no new +control-plane source files or same-basename pairs. Maintainability and interface +budgets pass unchanged. The integrated canary passes File and SQLite. The +diff-scoped advisory detects no supported new vocabulary carriers across four +changed product source files; its supported scope excludes test sources. + +## Review correction validation + +After removing duplicate gate selection and bounding the request: requested +Python suite 151 passed / 1 failed (the scheduler caller mismatch above); +native Node tests 19 passed / 0 failed; boundary suite 28 passed / 0 failed. +Ruff on all four changed Python files, control-plane typecheck, both requested +smokes and diff whitespace checks pass. Seven frozen characterization cases +remain byte-identical, with the fixture hash unchanged. File/SQLite production +CLI parity covers all eight command/format/provider pairs. A focused boundary +regression proves generic decoding of unknown list fields, omission of unrelated +objects and reuse of shared gate deduplication. No commit, staging or push was +performed; generated uv.lock was removed. diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.zh-CN.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.zh-CN.md new file mode 100644 index 0000000000..e00c0e6b58 --- /dev/null +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.zh-CN.md @@ -0,0 +1,91 @@ +# Global Todo 就绪分类归属切换 — 2026-11-02 + +## 边界与经济性 + +基线:`fb16c6cb1369efce52a673030c914b38e1dac166`。本次有界切片将 +完整 Global Todo 就绪决策从 `global_todos.py` 移至现有 +`todos/decision_scope.ts` owner 的 `projectGlobalTodoReadiness`,注册为 +`todo.global_readiness.project`。`loopx global-todos` 与 +`loopx goal-portfolio` 均通过共享展示适配器使用它;portfolio 对每个已注册 +Agent 分别分类。 + +TypeScript 负责 selected/lane/summary/frontier 的有序遍历、首个来源优先并补齐 +缺失字段的合并、来源/状态溯源、进程内 +`todoGateRelation`、blocked/deferred/runnable 优先级,以及警告顺序。 +`normal_delivery_allowed` 仍只是就绪投影信号,不授予执行权限。复用现有就绪值; +新增版本化请求/结果仅描述本次有界投影,不构成新的生命周期或权限词汇。 + +测试插桩固定所有跨运行时请求,包括 envelope sealing: + +| 操作 | 基线 | 候选 | +| --- | --- | --- | +| 单次分类,同时存在 gate 与候选 | 1 次关系请求 | 1 次完整就绪请求 | +| 单次分类,无 gate | 0 | 1 | +| 单次分类,无候选(含空 payload) | 0 | 1 | +| Global 命令,分类一个有 gate 的 Goal | 2,含 envelope | 2,含 envelope | +| Global 命令,无 gate 或空分类 | 1 次 envelope | 2,含 envelope | +| Portfolio,两个有 gate 的 Agent | 2 | 2 | +| Portfolio,两个无 gate/空分类的 Agent | 0 | 2 | + +无 gate/空路径的增加是有意且已披露的。不声称延迟或长程效果/效率收益。 + +产品物理行差异:+163/−166 行,净 −3。Python 删除来源遍历/合并 helper、 +blocked/deferred 分类、就绪优先级组合及独立 safety-rank 表。删除无生产调用方的 +Python 标量 `todo_gate_relation` 桥及其 TS dispatch;对应 smoke 和 decoder 测试 +使用 summary 仍在调用的批量关系桥。 + +Python 保留 `open_user_gate_todo_items` 为唯一 gate 选择 owner:summary、 +stall repair、Todo summary 和 agent scope 仍依赖它。有序选择、done 过滤及 +Python 相等去重不可复制到 TypeScript。已选 gate 以解码 facts 和目标文本传输。 +共享 `_facts` 保留持久化 ID/scope 归一化与旧 task-class 解释。有界请求仅传输 +selected/lane 记录、delivery 信号以及 summary/frontier 的 list 字段。Python +通用解码每个 list 的 dict 元素;TypeScript 独占候选 list key 遍历规则,不再递归 +遍历整个 payload。最大冻结用例的紧凑 UTF-8 JSON 请求从 9,749 降至 6,447 字节 +(减少 33.9%),输出字节不变。Python 还保留 status/quota IO、公开文本脱敏、 +`_work_kind` 展示解释、最终分组/去重/展示排序、envelope sealing 和 Markdown。 +这些兼容与展示边界不是第二个候选就绪 owner。 + +Facade 退出条件:当 global 与 portfolio 的宿主/读模型都直接消费 typed Todo +snapshot 和投影,且各自边界已原生承接旧元数据解码及公开安全渲染时,删除 +`project_global_todo_readiness` 及其字段解码 sidecar。当两个消费者均不再需要 +Python 归一化时,删除共享展示适配器。在该退出点,持久语义与公开入口测试覆盖 +保留契约后,移除临时 characterization corpus/archive 对照。 + +## 资格与限制 + +七个合成 characterization 用例先在未改动的 Python 上通过,然后冻结完整 +JSON/Markdown 字节及基线/候选 crossing 列表。fixture SHA-256 为 +`eaf17921f81357329ba7bc3c7dcb34253eed83b53d31c31d6dba0fdb5c547641`。 +覆盖互补重复字段、冲突状态、delivery 拒绝、精确目标/scope 冲突、无关 gate、 +blocked/deferred 重叠、缺失身份、两个 Agent、警告顺序、空输入与公开文本脱敏。 +独立 TS 测试断言优先级、拒绝及精确目标/scope 冲突语义,并拒绝畸形协议。 +Python decoder 测试拒绝畸形结果且不作回退。 + +`tests/test_global_todo_readiness_characterization.py::test_production_cli_archive_parity` +通过 archive `HEAD`、不用 stash,在同一合成临时 home 上以真实 File 和 SQLite +provider 对比两个公开命令的 JSON 与 Markdown。仅在导入生产 CLI 前冻结时钟; +字段存在性、诊断、来源版本与哈希均原样比较。八组命令/provider/格式均一致, +并要求结果实际包含 Todo 与 Agent。此证据资格为 source checkout,不覆盖安装包 +或前端行为;没有新增调用方能力或用户旅程。 + +聚焦 scheduler-state 读回测试 +`test_real_cli_quota_should_run_discloses_unreadable_scheduler_state` 在修改树与 +archive 基线上都失败:其 quota 命令缺少 Turn 身份,返回 +`QUOTA_VALIDATION_FAILED`,要求 `--turn-instance-id` 或 `--begin-turn`。 +这是已有的调用方/验证不匹配,位于就绪 owner 之外。保留该失败;不得放宽参数门禁, +也不得改写本次迁移的期望输出来掩盖它。 + +语义漂移仍为 `independently_maintained=45/45`;未新增 control-plane 源文件或 +同名配对。Maintainability 与接口预算保持不变并通过。集成 canary 的 File 和 +SQLite 均通过。diff 范围 advisory 在四个变更产品源文件中未发现受支持的新词汇 +载体;该工具的支持范围不包含测试源文件。 + +## 评审修正验证 + +删除重复 gate 选择并收窄请求后:指定 Python 套件 151 通过 / 1 失败(上述 +scheduler 调用参数不匹配);原生 Node 测试 19 通过 / 0 失败;边界套件 +28 通过 / 0 失败。四个已修改 Python 文件的 Ruff、control-plane typecheck、 +两个指定 smoke 和 diff 空白检查均通过。七个冻结 characterization 用例的输出 +字节不变,fixture 哈希不变。File/SQLite 生产 CLI 对照覆盖八组命令/格式/provider。 +聚焦边界回归验证未知 list 字段的通用解码、排除无关对象及复用共享 gate 去重。 +未 commit、stage 或 push;已删除生成的 uv.lock。 diff --git a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md index 7de643ef70..f30134a160 100644 --- a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md +++ b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md @@ -2845,3 +2845,4 @@ with shared write/read status-phase checks. See the [2026-10-02 checkpoint](ledg - Complete durable-completion evidence read: [2026-11-02 owner and crossings ledger](ledger/typescript-control-plane-migration-v0/2026-11-02-completion-evidence-read.md). - Complete adaptive child admission decision: [2026-11-02 checkpoint](ledger/typescript-control-plane-migration-v0/2026-11-02-adaptive-child-admission.md). - Progress-review receipt qualification: [2026-11-02 checkpoint](ledger/typescript-control-plane-migration-v0/2026-11-02-progress-review-qualification.md). +- Global Todo readiness complete owner cutover (both consumers): [2026-11-02 ledger](ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.md). diff --git a/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md b/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md index 6acd04ee2a..ac9c783314 100644 --- a/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md +++ b/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md @@ -2110,3 +2110,4 @@ SQLite 中位数略升,收益不能外推为全面加速。这只资格化本 - 完整 durable-completion 证据读取:[2026-11-02 owner 与调用边界记录](ledger/typescript-control-plane-migration-v0/2026-11-02-completion-evidence-read.zh-CN.md)。 - 完整自适应子 Agent 准入决策:[2026-11-02 检查点](ledger/typescript-control-plane-migration-v0/2026-11-02-adaptive-child-admission.zh-CN.md)。 - 进度评审 receipt 资格判定:[2026-11-02 检查点](ledger/typescript-control-plane-migration-v0/2026-11-02-progress-review-qualification.zh-CN.md)。 +- Global Todo 就绪分类完整 owner 切换(两个消费者):[2026-11-02 记录](ledger/typescript-control-plane-migration-v0/2026-11-02-global-todo-readiness.zh-CN.md)。 diff --git a/examples/control_plane/quota-agent-scoped-user-gate-smoke.py b/examples/control_plane/quota-agent-scoped-user-gate-smoke.py index 88c1c56a61..43a64c5baf 100644 --- a/examples/control_plane/quota-agent-scoped-user-gate-smoke.py +++ b/examples/control_plane/quota-agent-scoped-user-gate-smoke.py @@ -11,7 +11,7 @@ if str(REPO_ROOT) not in sys.path: sys.path.insert(0, str(REPO_ROOT)) -from loopx.control_plane.todos.decision_scope import todo_gate_relation # noqa: E402 +from loopx.control_plane.todos.decision_scope import todo_gate_relations # noqa: E402 from loopx.control_plane.scheduler.execution_context import ( # noqa: E402 GENERIC_CLI_OUTER_CONTROLLER_SCHEDULER_CONTEXT, scheduler_execution_context_for_runtime_profile, @@ -967,7 +967,7 @@ def assert_conflicting_exact_and_decision_scope_requires_projection_repair() -> } ], } - relation = todo_gate_relation(gate, agent_item) + relation = todo_gate_relations([gate], [agent_item])[0][0] assert relation["source"] == "unblocks_todo_id+decision_scope", relation assert relation["state"] == "projection_repair_required", relation assert relation["reason"] == ( diff --git a/loopx/control_plane/effect_runtime_handlers.ts b/loopx/control_plane/effect_runtime_handlers.ts index 9ff53d1a99..d9a5207d39 100644 --- a/loopx/control_plane/effect_runtime_handlers.ts +++ b/loopx/control_plane/effect_runtime_handlers.ts @@ -276,6 +276,7 @@ export function createEffectRuntimeHandlers( ["todo.succession.project", lazyHandler(() => import("./todos/succession.ts"), ({projectTodoSuccession}) => projectTodoSuccession)], ["todo.work_counts.project", lazyHandler(() => import("./todos/summary_lanes.ts"), ({projectLegacyTodoWorkCounts}) => projectLegacyTodoWorkCounts)], ["projection.envelope.seal", lazyHandler(() => import("./projection_envelope.ts"), ({sealProjectionEnvelope}) => sealProjectionEnvelope)], + ["todo.global_readiness.project", lazyHandler(() => import("./todos/decision_scope.ts"), ({projectGlobalTodoReadiness}) => projectGlobalTodoReadiness)], ["todo.decision_scope.evaluate", lazyHandler(() => import("./todos/decision_scope.ts"), ({evaluateDecisionScope}) => evaluateDecisionScope)], ["todo.user_completion.plan", lazyHandler(() => import("./todos/user_completion.ts"), ({evaluateUserCompletion}) => evaluateUserCompletion)], ["agent.capability_gate.evaluate", lazyHandler(() => import("./agents/capability_gate.ts"), ({evaluateCapabilityGate}) => evaluateCapabilityGate)], diff --git a/loopx/control_plane/todos/decision_scope.py b/loopx/control_plane/todos/decision_scope.py index 3b4ec46c31..82120f64ef 100644 --- a/loopx/control_plane/todos/decision_scope.py +++ b/loopx/control_plane/todos/decision_scope.py @@ -14,7 +14,7 @@ normalize_todo_id, normalize_todo_required_decision_scopes, ) -from .user_gate import is_user_gate_todo_item +from .user_gate import is_user_gate_todo_item, open_user_gate_todo_items from .todo_semantics import todo_projection_sort_key, todo_item_task_class, todo_item_has_removed_continuation_policy DECISION_SCOPE_CONSISTENCY_SCHEMA_VERSION = "required_decision_scope_consistency_v0" @@ -293,13 +293,6 @@ def build_required_decision_scope_repair_hint( return result -def todo_gate_relation(gate: dict[str, Any], agent_item: dict[str, Any]) -> dict[str, Any] | None: - return _optional_relation( - "relation", - _evaluate("relation", gate=_facts(gate), item=_facts(agent_item)), - ) - - def todo_gate_relations(gates: list[dict[str, Any]], items: list[dict[str, Any]]) -> list[list[dict[str, Any] | None]]: """Evaluate a consumer's candidate set in one RPC, retaining positional identity.""" if not gates or not items: @@ -356,3 +349,60 @@ def facts(item: dict[str, Any]) -> dict[str, Any]: if not isinstance(projections, list) or len(projections) != len(items): raise TypeError("invalid typed gate scope projection cardinality") return [_required_projection("gate_scope", row, schema_version="todo_gate_scope_projection_v0") for row in projections] + + +def _readiness_facts(item: dict[str, Any]) -> dict[str, Any]: + return { + **_facts(item), + "identity_text": str(item.get("todo_id") or ""), + "status_text": str(item.get("status") or ""), + "target_text": str(item.get("unblocks_todo_id") or ""), + } + + +def _global_readiness_request(payload: dict[str, Any]) -> dict[str, Any]: + """Bound transport to candidate containers; TS alone selects their list keys.""" + bounded = { + key: payload.get(key) + for key in ("selected_todo", "agent_lane_next_action", "normal_delivery_allowed") + } + decoded = { + f"/{key}": _readiness_facts(value) + for key, value in bounded.items() + if isinstance(value, dict) + } + for container_key in ("agent_todo_summary", "agent_scope_frontier"): + container = payload.get(container_key) + lists = { + key: value for key, value in container.items() if isinstance(value, list) + } if isinstance(container, dict) else {} + bounded[container_key] = lists + for key, values in lists.items(): + for index, item in enumerate(values): + if isinstance(item, dict): + decoded[f"/{container_key}/{key}/{index}"] = _readiness_facts(item) + return { + "schema_version": "global_todo_readiness_request_v0", + "payload": bounded, + "decoded": decoded, + "gates": [ + _readiness_facts(gate) + for gate in open_user_gate_todo_items(payload.get("user_todo_summary")) + ], + } + + +def project_global_todo_readiness(payload: dict[str, Any]) -> dict[str, Any]: + """Decode persisted fields and reuse the shared Python gate selector.""" + result = effect_runtime_result( + "todo.global_readiness.project", _global_readiness_request(payload), + ) + projection = _required_projection( + "global_readiness", result, schema_version="global_todo_readiness_v0", + ) + for key in ("warnings", "candidates"): + if not isinstance(projection.get(key), list) or any( + not isinstance(row, dict) for row in projection[key] + ): + raise TypeError("invalid typed decision scope global readiness rows") + return projection diff --git a/loopx/control_plane/todos/decision_scope.ts b/loopx/control_plane/todos/decision_scope.ts index da0c8faf11..e072d3054c 100644 --- a/loopx/control_plane/todos/decision_scope.ts +++ b/loopx/control_plane/todos/decision_scope.ts @@ -1,5 +1,6 @@ /** Read-only decision dependency rules over one complete source snapshot. * A consistent dependency is not approval, a lease, or a mutation receipt. */ +import {stripPythonWhitespace} from "../coordination/python_whitespace.ts"; import type {JsonObject} from "../effect_program.ts"; import {EffectRuntimeRequestError} from "../effect_runtime_errors.ts"; import {requireJsonObject, optionalNonEmptyString, requireBoolean, requireInteger} from "../runtime_decode.ts"; @@ -240,8 +241,94 @@ export function evaluateDecisionScope(value: unknown): JsonObject { result = rows(request.gates).map(gate => items.map(item => todoGateRelation(gate, item))); break; } - case "relation": result = todoGateRelation(requireJsonObject(request.gate, "gate"), requireJsonObject(request.item, "item")); break; default: throw new EffectRuntimeRequestError("unsupported decision scope operation"); } return {schema_version: "todo_decision_scope_result_v0", result}; } + +/** One complete readiness projection; normal_delivery_allowed is a read signal, + * never execution permission. Persisted-field codecs remain at the host edge. */ +export function projectGlobalTodoReadiness(value: unknown): JsonObject { + const request = requireJsonObject(value, "global readiness request"); + if (request.schema_version !== "global_todo_readiness_request_v0") { + throw new TypeError("global readiness request schema mismatch"); + } + const payload = requireJsonObject(request.payload, "payload"); + const decoded = requireJsonObject(request.decoded, "decoded"); + const gates = rows(request.gates); + const candidates: JsonObject[] = [], warnings: JsonObject[] = []; + const records = new Map; statuses: Set; + }>(); + const add = (source: string, value: unknown, path: string): void => { + if (!object(value)) return; + const facts = requireJsonObject(decoded[path], `decoded ${path}`); + const todoId = readinessCodecText(facts, "identity_text"); + if (!todoId) { + warnings.push({reason_code: "todo_identity_missing", + detail: `Structured todo candidate from ${source} has no todo_id.`}); + return; + } + let record = records.get(todoId); + if (!record) { + record = {item: {...value}, facts: {...facts}, sources: new Set(), statuses: new Set()}; + records.set(todoId, record); + } + record.sources.add(source); + const status = readinessCodecText(facts, "status_text").toLowerCase(); + if (status) record.statuses.add(status); + for (const [key, field] of Object.entries(value)) { + if (readinessMissing(record.item[key]) && !readinessMissing(field)) { + record.item[key] = field; + if (Object.hasOwn(facts, key)) record.facts[key] = facts[key]; + } + } + }; + add("selected_todo", payload.selected_todo, "/selected_todo"); + add("agent_lane_next_action", payload.agent_lane_next_action, "/agent_lane_next_action"); + for (const containerKey of ["agent_todo_summary", "agent_scope_frontier"]) { + const container = object(payload[containerKey]) ? payload[containerKey] : {}; + for (const key of ["first_open_items", "first_executable_items", "items", "open_items", "deferred_items", + "deferred_resume_candidates", "blocker_items", "resume_blocked_items"]) { + const values = container[key]; + if (Array.isArray(values)) values.forEach((item, index) => + add(`${containerKey}.${key}`, item, `/${containerKey}/${key}/${index}`)); + } + } + const selected = object(payload.selected_todo) + ? readinessCodecText(requireJsonObject(decoded["/selected_todo"], "selected codec"), "identity_text") : ""; + for (const [todoId, record] of records) { + const sources = [...record.sources]; + const blocked = sources.some(source => + ["blocker_items", "resume_blocked_items"].includes(source.split(".").at(-1)!)) || + gates.some(gate => { + const relation = todoGateRelation(gate, record.facts); + return readinessCodecText(gate, "target_text") === todoId || + relation?.state === "gate_targets_todo" || relation?.state === "gate_covers_action"; + }) || record.statuses.has("blocked"); + const deferred = sources.some(source => source.endsWith(".deferred_resume_candidates")) || + (record.statuses.has("deferred") && record.item.resume_ready === true); + const runnable = todoId === selected && payload.normal_delivery_allowed === true; + if (!blocked && !deferred && !runnable) continue; + if (Number(blocked) + Number(deferred) + Number(runnable) > 1) warnings.push({ + reason_code: "conflicting_readiness_projection", todo_id: todoId, + detail: "Multiple structured readiness signals were projected.", + }); + candidates.push({item: record.item, readiness: blocked ? "blocked" : deferred ? "deferred_ready" : "runnable"}); + } + return {schema_version: "global_todo_readiness_v0", candidates, warnings}; +} + +// Python's merge sentinel is equality with (None, "", []), not truthiness: +// false, zero and an empty object must survive the first-source merge. +function readinessMissing(value: unknown): boolean { + return value == null || value === "" || (Array.isArray(value) && !value.length); +} + +// Preserve legacy scalar spelling (including Python booleans and floats) at +// the codec edge; traversal, whitespace normalization and decisions stay here. +function readinessCodecText(facts: JsonObject, key: string): string { + const value = facts[key]; + if (typeof value !== "string") throw new TypeError(`global readiness codec ${key} must be a string`); + return stripPythonWhitespace(value); +} diff --git a/loopx/global_todos.py b/loopx/global_todos.py index 29e577f60f..71103af9b1 100644 --- a/loopx/global_todos.py +++ b/loopx/global_todos.py @@ -14,8 +14,7 @@ QuotaIdentityPreconditionError, ) from .control_plane.runtime.time import now_utc_iso -from .control_plane.todos.decision_scope import todo_gate_relations -from .control_plane.todos.user_gate import open_user_gate_todo_items +from .control_plane.todos.decision_scope import project_global_todo_readiness from .presentation.markdown import as_dict, as_list from .presentation.public_safety import public_safe_boundary, redact_public_text from .quota import build_quota_should_run @@ -31,19 +30,7 @@ "active-state todo projections", "compact run-history projection consumed by status", ] -_CANDIDATE_LIST_KEYS = ( - "first_open_items", - "first_executable_items", - "items", - "open_items", - "deferred_items", - "deferred_resume_candidates", - "blocker_items", - "resume_blocked_items", -) -_BLOCKER_SOURCE_KEYS = {"blocker_items", "resume_blocked_items"} _READINESS_DISPLAY_RANK = {"runnable": 0, "deferred_ready": 1, "blocked": 2} -_READINESS_SAFETY_RANK = {"blocked": 0, "deferred_ready": 1, "runnable": 2} def _redact_text(value: object, *, limit: int = 260) -> str: @@ -308,107 +295,6 @@ def _quota_matches_agent(payload: dict[str, Any], *, agent_id: str | None) -> bo return str(identity.get("agent_id") or "").strip() == agent_id -def _candidate_sources(payload: dict[str, Any]) -> list[tuple[str, dict[str, Any]]]: - sources: list[tuple[str, dict[str, Any]]] = [] - - def add(source: str, value: object) -> None: - if isinstance(value, dict): - sources.append((source, value)) - - add("selected_todo", payload.get("selected_todo")) - add("agent_lane_next_action", payload.get("agent_lane_next_action")) - for container_key in ("agent_todo_summary", "agent_scope_frontier"): - container = as_dict(payload.get(container_key)) - for list_key in _CANDIDATE_LIST_KEYS: - for item in as_list(container.get(list_key)): - add(f"{container_key}.{list_key}", item) - return sources - - -def _candidate_records( - payload: dict[str, Any], - *, - goal_id: str, - warnings: list[dict[str, Any]], -) -> dict[str, dict[str, Any]]: - records: dict[str, dict[str, Any]] = {} - for source, item in _candidate_sources(payload): - todo_id = str(item.get("todo_id") or "").strip() - if not todo_id: - warnings.append( - _warning( - "todo_identity_missing", - goal_id=goal_id, - detail=f"Structured todo candidate from {source} has no todo_id.", - ) - ) - continue - record = records.setdefault( - todo_id, - {"item": dict(item), "sources": set(), "statuses": set()}, - ) - record_sources = record["sources"] - if isinstance(record_sources, set): - record_sources.add(source) - status = str(item.get("status") or "").strip().lower() - record_statuses = record["statuses"] - if status and isinstance(record_statuses, set): - record_statuses.add(status) - merged = as_dict(record.get("item")) - for key, value in item.items(): - if merged.get(key) in (None, "", []) and value not in (None, "", []): - merged[key] = value - return records - - -def _verified_blocked_ids( - payload: dict[str, Any], - records: dict[str, dict[str, Any]], -) -> set[str]: - blocked_ids: set[str] = set() - for todo_id, record in records.items(): - sources = record.get("sources") - if isinstance(sources, set) and any( - source.rsplit(".", 1)[-1] in _BLOCKER_SOURCE_KEYS - for source in sources - ): - blocked_ids.add(todo_id) - - user_summary = as_dict(payload.get("user_todo_summary")) - gates = open_user_gate_todo_items(user_summary) - relations = todo_gate_relations(gates, [as_dict(record.get("item")) for record in records.values()]) - for gate, gate_relations in zip(gates, relations, strict=True): - exact_todo_id = str(gate.get("unblocks_todo_id") or "").strip() - if exact_todo_id in records: - blocked_ids.add(exact_todo_id) - for todo_id, relation in zip(records, gate_relations, strict=True): - if relation and relation.get("state") in { - "gate_targets_todo", - "gate_covers_action", - }: - blocked_ids.add(todo_id) - return blocked_ids - - -def _deferred_ready_ids(records: dict[str, dict[str, Any]]) -> set[str]: - ready_ids: set[str] = set() - for todo_id, record in records.items(): - item = as_dict(record.get("item")) - statuses = record.get("statuses") - sources = record.get("sources") - structured_candidate = isinstance(sources, set) and any( - source.endswith(".deferred_resume_candidates") for source in sources - ) - explicitly_ready = ( - isinstance(statuses, set) - and "deferred" in statuses - and item.get("resume_ready") is True - ) - if structured_candidate or explicitly_ready: - ready_ids.add(todo_id) - return ready_ids - - def _work_kind(item: dict[str, Any]) -> str: action_kind = str(item.get("action_kind") or "").strip().lower() tokens = {token for token in action_kind.split("_") if token} @@ -443,47 +329,20 @@ def _classify_goal_todos( goal_id: str, warnings: list[dict[str, Any]], ) -> list[dict[str, Any]]: - records = _candidate_records(payload, goal_id=goal_id, warnings=warnings) - blocked_ids = _verified_blocked_ids(payload, records) - deferred_ready_ids = _deferred_ready_ids(records) - selected_todo_id = str( - as_dict(payload.get("selected_todo")).get("todo_id") or "" - ).strip() - normal_delivery_allowed = payload.get("normal_delivery_allowed") is True - todos: list[dict[str, Any]] = [] - - for todo_id, record in records.items(): - statuses = record.get("statuses") - signals: set[str] = set() - if todo_id in blocked_ids or ( - isinstance(statuses, set) and "blocked" in statuses - ): - signals.add("blocked") - if todo_id in deferred_ready_ids: - signals.add("deferred_ready") - if todo_id == selected_todo_id and normal_delivery_allowed: - signals.add("runnable") - if not signals: - continue - if len(signals) > 1: - warnings.append( - _warning( - "conflicting_readiness_projection", - goal_id=goal_id, - todo_id=todo_id, - detail="Multiple structured readiness signals were projected.", - ) - ) - readiness = min(signals, key=_READINESS_SAFETY_RANK.__getitem__) - todos.append( - _normalize_todo( - as_dict(record.get("item")), - goal_id=goal_id, - readiness=readiness, - recommended_action=payload.get("recommended_action"), - ) + projection = project_global_todo_readiness(payload) + warnings.extend( + _warning(goal_id=goal_id, **warning) + for warning in projection["warnings"] + ) + return [ + _normalize_todo( + candidate["item"], + goal_id=goal_id, + readiness=candidate["readiness"], + recommended_action=payload.get("recommended_action"), ) - return todos + for candidate in projection["candidates"] + ] def _priority_rank(value: object) -> int: @@ -524,8 +383,8 @@ def _deduplicate_todos( detail="Duplicate todo rows projected different readiness states.", ) ) - if _READINESS_SAFETY_RANK.get(incoming_readiness, 3) < ( - _READINESS_SAFETY_RANK.get(existing_readiness, 3) + if _READINESS_DISPLAY_RANK.get(incoming_readiness, -1) > ( + _READINESS_DISPLAY_RANK.get(existing_readiness, -1) ): deduplicated[key] = todo if todo.get("work_kind") == "review": diff --git a/tests/control_plane/test_todo_decision_scope_runtime_boundary.py b/tests/control_plane/test_todo_decision_scope_runtime_boundary.py index 4f57254799..6985b639f4 100644 --- a/tests/control_plane/test_todo_decision_scope_runtime_boundary.py +++ b/tests/control_plane/test_todo_decision_scope_runtime_boundary.py @@ -54,10 +54,10 @@ def _response(value: object) -> dict[str, object]: ), {"schema_version": "wrong_standing_v0"}, ), - (lambda: decision_scope.todo_gate_relation(GATE, AGENT_ITEM), True), + (lambda: decision_scope.todo_gate_relations([GATE], [AGENT_ITEM])[0][0], [[True]]), ( - lambda: decision_scope.todo_gate_relation(GATE, AGENT_ITEM), - {"schema_version": "unknown_relation_v0"}, + lambda: decision_scope.todo_gate_relations([GATE], [AGENT_ITEM])[0][0], + [[{"schema_version": "unknown_relation_v0"}]], ), ( lambda: decision_scope.todo_gate_relations([GATE], [AGENT_ITEM]), @@ -116,7 +116,7 @@ def test_outer_runtime_envelope_fails_closed( ) with pytest.raises(TypeError, match="invalid typed decision scope projection"): - decision_scope.todo_gate_relation(GATE, AGENT_ITEM) + decision_scope.todo_gate_relations([GATE], [AGENT_ITEM])[0][0] def test_nullable_operations_still_accept_explicit_null( @@ -125,10 +125,11 @@ def test_nullable_operations_still_accept_explicit_null( monkeypatch.setattr( decision_scope, "effect_runtime_result", - lambda *_args, **_kwargs: _response(None), + lambda *_args, **_kwargs: _response([[None]]), ) - assert decision_scope.todo_gate_relation(GATE, AGENT_ITEM) is None + assert decision_scope.todo_gate_relations([GATE], [AGENT_ITEM])[0][0] is None + monkeypatch.setattr(decision_scope, "effect_runtime_result", lambda *_args, **_kwargs: _response(None)) assert decision_scope.select_scoped_gate_fallback( [GATE], [AGENT_ITEM], agent_id="agent-a", allow_unrelated_gate=True, monitor_debt_backoff_active=False, @@ -145,7 +146,7 @@ def test_fallback_runtime_result_fails_closed(monkeypatch, value): ) -@pytest.mark.parametrize("operation", ["covers", "scope_relation", "exact_relation"]) +@pytest.mark.parametrize("operation", ["covers", "scope_relation", "exact_relation", "relation"]) def test_retired_scalar_operations_are_rejected_by_real_runtime(operation: str) -> None: with pytest.raises(EffectRuntimeRejected, match="unsupported decision scope operation"): effect_runtime_result("todo.decision_scope.evaluate", { @@ -156,3 +157,45 @@ def test_retired_scalar_operations_are_rejected_by_real_runtime(operation: str) "gate": {**GATE, "is_gate": True}, "item": AGENT_ITEM, }) + + +@pytest.mark.parametrize("value", [ + None, {}, {"schema_version": "wrong"}, + {"schema_version": "global_todo_readiness_v0", "candidates": {}, "warnings": []}, + {"schema_version": "global_todo_readiness_v0", "candidates": [], "warnings": [True]}, +]) +def test_global_readiness_transport_fails_closed_without_python_fallback(monkeypatch, value): + calls = [] + + def result(method, params): + calls.append(method) + return value + + monkeypatch.setattr(decision_scope, "effect_runtime_result", result) + with pytest.raises(TypeError, match="invalid typed decision scope"): + decision_scope.project_global_todo_readiness({"selected_todo": AGENT_ITEM}) + assert calls == ["todo.global_readiness.project"] + + +def test_global_readiness_request_bounds_codecs_and_reuses_gate_selection(): + gate = {**GATE, "text": "Confirm scope", "index": 1} + request = decision_scope._global_readiness_request({ + "selected_todo": AGENT_ITEM, + "normal_delivery_allowed": True, + "unrelated": {"items": [{"todo_id": "unrelated"}]}, + "agent_todo_summary": { + "future_list": [AGENT_ITEM, None], + "metadata": {"todo_id": "metadata"}, + }, + "agent_scope_frontier": {"items": [AGENT_ITEM], "count": 1}, + "user_todo_summary": {"gate_open_items": [gate], "items": [dict(gate)]}, + }) + assert set(request["payload"]) == { + "selected_todo", "agent_lane_next_action", "normal_delivery_allowed", + "agent_todo_summary", "agent_scope_frontier", + } + assert request["payload"]["agent_todo_summary"] == {"future_list": [AGENT_ITEM, None]} + assert set(request["decoded"]) == { + "/selected_todo", "/agent_todo_summary/future_list/0", "/agent_scope_frontier/items/0", + } + assert request["gates"] == [decision_scope._readiness_facts(gate)] diff --git a/tests/control_plane_ts/global_todo_readiness.test.ts b/tests/control_plane_ts/global_todo_readiness.test.ts new file mode 100644 index 0000000000..1a1394beda --- /dev/null +++ b/tests/control_plane_ts/global_todo_readiness.test.ts @@ -0,0 +1,50 @@ +import assert from "node:assert/strict"; +import {test} from "node:test"; +import {EffectRuntimeRequestError} from "../../loopx/control_plane/effect_runtime_errors.ts"; +import {projectGlobalTodoReadiness} from "../../loopx/control_plane/todos/decision_scope.ts"; + +const scope = {kind: "write_scope", granularity: "action", scope_key: "sample"}; +const item = {todo_id: "todo_sample", status: "deferred", resume_ready: true, required_decision_scopes: [scope]}; +const gate = {todo_id: "todo_gate", unblocks_todo_id: "todo_sample"}; +const request = { + schema_version: "global_todo_readiness_request_v0", + payload: {selected_todo: item, normal_delivery_allowed: true}, + gates: [{...gate, is_gate: true, target_text: gate.unblocks_todo_id}], + decoded: { + "/selected_todo": {todo_id: item.todo_id, required_decision_scopes: [scope], + identity_text: item.todo_id, status_text: item.status}, + }, +}; + +test("blocked beats deferred and selected; dependency evidence grants no execution authority", () => { + const result = projectGlobalTodoReadiness(request); + assert.deepEqual(result, { + schema_version: "global_todo_readiness_v0", + candidates: [{item, readiness: "blocked"}], + warnings: [{reason_code: "conflicting_readiness_projection", todo_id: "todo_sample", + detail: "Multiple structured readiness signals were projected."}], + }); + const denied = projectGlobalTodoReadiness({...request, + decoded: {...request.decoded, "/selected_todo": {...request.decoded["/selected_todo"], status_text: "open"}}, + gates: [], + payload: { + selected_todo: {...item, status: "open", resume_ready: false}, normal_delivery_allowed: false, + }}); + assert.deepEqual(denied.candidates, []); +}); + +test("a scope covering a different exact target cannot block this candidate", () => { + const otherGate = {...gate, unblocks_todo_id: "todo_other", decision_scope: scope}; + const result = projectGlobalTodoReadiness({...request, + gates: [{...otherGate, is_gate: true, target_text: otherGate.unblocks_todo_id}], + }); + assert.deepEqual(result.candidates, [{item, readiness: "deferred_ready"}]); +}); + +test("malformed protocol envelopes and codecs fail closed", () => { + for (const value of [null, {}, {...request, schema_version: "wrong"}, + {...request, decoded: {}}, {...request, payload: []}]) { + assert.throws(() => projectGlobalTodoReadiness(value), error => + error instanceof TypeError || error instanceof EffectRuntimeRequestError); + } +}); diff --git a/tests/fixtures/global_todo_readiness.json b/tests/fixtures/global_todo_readiness.json new file mode 100644 index 0000000000..9fb404a02e --- /dev/null +++ b/tests/fixtures/global_todo_readiness.json @@ -0,0 +1,473 @@ +[ + { + "name": "merged_conflicts_exact_scope_warning_order_redaction", + "quota": { + "ok": true, + "normal_delivery_allowed": true, + "selected_todo": { + "todo_id": "todo_sample", + "status": "open", + "title": "", + "priority": null, + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + "agent_lane_next_action": { + "todo_id": "todo_sample", + "status": "blocked", + "title": "Complementary title", + "priority": "P0", + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + "agent_todo_summary": { + "items": [ + { + "todo_id": "todo_scope", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + { + "todo_id": "todo_unrelated", + "status": "open" + }, + { + "text": "Missing identity" + } + ], + "deferred_resume_candidates": [ + { + "todo_id": "todo_sample", + "status": "deferred", + "resume_ready": true + }, + { + "todo_id": "todo_deferred", + "status": "deferred", + "resume_ready": true + } + ], + "blocker_items": [ + { + "todo_id": "todo_blocked", + "status": "open" + } + ] + }, + "agent_scope_frontier": { + "items": [ + { + "text": "Second missing identity" + }, + { + "todo_id": "todo_sample", + "status": "open" + } + ] + }, + "user_todo_summary": { + "gate_open_items": [ + { + "todo_id": "todo_gate", + "task_class": "user_gate", + "unblocks_todo_id": "todo_sample", + "decision_scope": { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + }, + { + "todo_id": "todo_other_gate", + "task_class": "user_gate", + "unblocks_todo_id": "todo_other" + } + ] + }, + "recommended_action": "Inspect synthetic /home/sample/private.txt details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details " + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"3 of 3 classified todos returned.\",\"matched_todo_count\":3,\"returned_todo_count\":3,\"runnable_count\":0,\"blocked_count\":2,\"deferred_ready_count\":1,\"review_count\":0,\"source_warning_count\":3,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[{\"todo_id\":\"todo_deferred\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"deferred_ready\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"blocked\":[{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_blocked\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"review\":[]},\"todos\":[{\"todo_id\":\"todo_deferred\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"deferred_ready\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_blocked\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"source_warnings\":[{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_scope_frontier.items has no todo_id.\"},{\"reason_code\":\"conflicting_readiness_projection\",\"goal_id\":\"sample\",\"todo_id\":\"todo_sample\",\"detail\":\"Multiple structured readiness signals were projected.\"}],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":3,\"available_count\":3,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `3`\n- returned: `3`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- goal=`sample` todo=`todo_deferred` priority=`unknown` owner=`agent`: Untitled todo. Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n\n## Blocked\n- goal=`sample` todo=`todo_sample` priority=`P0` owner=`agent`: Complementary title Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n- goal=`sample` todo=`todo_blocked` priority=`unknown` owner=`agent`: Untitled todo. Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n\n## Review\n- None.\n\n## Source Warnings\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_scope_frontier.items has no todo_id.\n- `conflicting_readiness_projection` goal=`sample` todo=`todo_sample`: Multiple structured readiness signals were projected.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":0,\"stale\":0,\"conflicting\":1,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":false},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"conflicting\",\"progress\":\"unknown\",\"warnings\":[\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\",\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\"],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_deferred\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"deferred_ready\"},{\"todo_id\":\"todo_blocked\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[\"todo_gate\",\"todo_other_gate\"]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_deferred\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"deferred_ready\"},{\"todo_id\":\"todo_blocked\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[\"todo_gate\",\"todo_other_gate\"]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:ede2b0223a69ab0e6804e43ecd21be15d27e66ed64fe895b333439264fb30108\"}", + "portfolio_markdown": "Goal coverage: 0/1 sources verified; complete=False\n- sample: conflicting; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "todo.decision_scope.evaluate", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.decision_scope.evaluate", + "todo.decision_scope.evaluate" + ] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "scope_gate", + "quota": { + "ok": true, + "normal_delivery_allowed": true, + "selected_todo": { + "todo_id": "todo_sample", + "status": "open", + "title": "", + "priority": null, + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + "agent_lane_next_action": { + "todo_id": "todo_sample", + "status": "blocked", + "title": "Complementary title", + "priority": "P0", + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + "agent_todo_summary": { + "items": [ + { + "todo_id": "todo_scope", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + }, + { + "todo_id": "todo_unrelated", + "status": "open" + }, + { + "text": "Missing identity" + } + ], + "deferred_resume_candidates": [ + { + "todo_id": "todo_sample", + "status": "deferred", + "resume_ready": true + }, + { + "todo_id": "todo_deferred", + "status": "deferred", + "resume_ready": true + } + ], + "blocker_items": [ + { + "todo_id": "todo_blocked", + "status": "open" + } + ] + }, + "agent_scope_frontier": { + "items": [ + { + "text": "Second missing identity" + }, + { + "todo_id": "todo_sample", + "status": "open" + } + ] + }, + "user_todo_summary": { + "items": [ + { + "todo_id": "todo_gate", + "task_class": "user_gate", + "decision_scope": { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + } + ] + }, + "recommended_action": "Inspect synthetic /home/sample/private.txt details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details details " + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"4 of 4 classified todos returned.\",\"matched_todo_count\":4,\"returned_todo_count\":4,\"runnable_count\":0,\"blocked_count\":3,\"deferred_ready_count\":1,\"review_count\":0,\"source_warning_count\":3,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[{\"todo_id\":\"todo_deferred\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"deferred_ready\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"blocked\":[{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_blocked\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_scope\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"review\":[]},\"todos\":[{\"todo_id\":\"todo_deferred\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"deferred_ready\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_blocked\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"},{\"todo_id\":\"todo_scope\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\"}],\"source_warnings\":[{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_scope_frontier.items has no todo_id.\"},{\"reason_code\":\"conflicting_readiness_projection\",\"goal_id\":\"sample\",\"todo_id\":\"todo_sample\",\"detail\":\"Multiple structured readiness signals were projected.\"}],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":4,\"available_count\":4,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `4`\n- returned: `4`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- goal=`sample` todo=`todo_deferred` priority=`unknown` owner=`agent`: Untitled todo. Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n\n## Blocked\n- goal=`sample` todo=`todo_sample` priority=`P0` owner=`agent`: Complementary title Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n- goal=`sample` todo=`todo_blocked` priority=`unknown` owner=`agent`: Untitled todo. Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n- goal=`sample` todo=`todo_scope` priority=`unknown` owner=`agent`: Untitled todo. Next: Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\n\n## Review\n- None.\n\n## Source Warnings\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_scope_frontier.items has no todo_id.\n- `conflicting_readiness_projection` goal=`sample` todo=`todo_sample`: Multiple structured readiness signals were projected.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":0,\"stale\":0,\"conflicting\":1,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":false},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"conflicting\",\"progress\":\"unknown\",\"warnings\":[\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\",\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\"],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_scope\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_deferred\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"deferred_ready\"},{\"todo_id\":\"todo_blocked\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"P0\",\"title\":\"Complementary title\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_scope\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"},{\"todo_id\":\"todo_deferred\",\"role\":\"agent\",\"status\":\"deferred\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"deferred_ready\"},{\"todo_id\":\"todo_blocked\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"\",\"next_safe_action\":\"Inspect synthetic details details details details details details details details details details details details details details details details details details details details details details details details details details details det…\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:6456d8ee70ecfe5098f51e7b47d1d7b31fd8398d6dd1249d886588fbdd6c7610\"}", + "portfolio_markdown": "Goal coverage: 0/1 sources verified; complete=False\n- sample: conflicting; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "todo.decision_scope.evaluate", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.decision_scope.evaluate", + "todo.decision_scope.evaluate" + ] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "delivery_denied", + "quota": { + "ok": true, + "normal_delivery_allowed": false, + "selected_todo": { + "todo_id": "todo_sample", + "status": "open", + "title": "", + "priority": null, + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + } + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"0 of 0 classified todos returned.\",\"matched_todo_count\":0,\"returned_todo_count\":0,\"runnable_count\":0,\"blocked_count\":0,\"deferred_ready_count\":0,\"review_count\":0,\"source_warning_count\":0,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[],\"blocked\":[],\"review\":[]},\"todos\":[],\"source_warnings\":[],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":0,\"available_count\":0,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `0`\n- returned: `0`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- None.\n\n## Blocked\n- None.\n\n## Review\n- None.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":1,\"stale\":0,\"conflicting\":0,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":true},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"verified\",\"progress\":\"unknown\",\"warnings\":[],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:4bf8cc4643fd1d06f832be5e145b1e6a14a7d44d4a673505c2ce48fee89af385\"}", + "portfolio_markdown": "Goal coverage: 1/1 sources verified; complete=True\n- sample: verified; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "projection.envelope.seal" + ], + "portfolio": [] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "no_gates", + "quota": { + "ok": true, + "normal_delivery_allowed": true, + "selected_todo": { + "todo_id": "todo_sample", + "status": "open", + "title": "", + "priority": null, + "text": "Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text /home/sample/private.txt", + "required_decision_scopes": [ + { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + ] + } + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"1 of 1 classified todos returned.\",\"matched_todo_count\":1,\"returned_todo_count\":1,\"runnable_count\":1,\"blocked_count\":0,\"deferred_ready_count\":0,\"review_count\":0,\"source_warning_count\":0,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text…\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"runnable\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"\"}],\"deferred_ready\":[],\"blocked\":[],\"review\":[]},\"todos\":[{\"todo_id\":\"todo_sample\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text…\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"runnable\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"\"}],\"source_warnings\":[],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":1,\"available_count\":1,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `1`\n- returned: `1`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- goal=`sample` todo=`todo_sample` priority=`unknown` owner=`agent`: Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text…\n\n## Deferred Ready\n- None.\n\n## Blocked\n- None.\n\n## Review\n- None.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":1,\"stale\":0,\"conflicting\":0,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":true},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"verified\",\"progress\":\"unknown\",\"warnings\":[],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text…\",\"next_safe_action\":\"\",\"claimed_by\":null,\"readiness\":\"runnable\"}],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Synthetic long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text long text…\",\"next_safe_action\":\"\",\"claimed_by\":null,\"readiness\":\"runnable\"}],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:dd2c5bfc2b9563a685ec290b332888d27bbc5770746ce99af7634e22d80485cc\"}", + "portfolio_markdown": "Goal coverage: 1/1 sources verified; complete=True\n- sample: verified; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "projection.envelope.seal" + ], + "portfolio": [] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "no_candidates", + "quota": { + "ok": true, + "user_todo_summary": { + "items": [ + { + "todo_id": "todo_gate", + "task_class": "user_gate", + "unblocks_todo_id": "todo_sample", + "decision_scope": { + "kind": "write_scope", + "granularity": "action", + "scope_key": "sample" + } + } + ] + } + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"0 of 0 classified todos returned.\",\"matched_todo_count\":0,\"returned_todo_count\":0,\"runnable_count\":0,\"blocked_count\":0,\"deferred_ready_count\":0,\"review_count\":0,\"source_warning_count\":0,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[],\"blocked\":[],\"review\":[]},\"todos\":[],\"source_warnings\":[],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":0,\"available_count\":0,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `0`\n- returned: `0`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- None.\n\n## Blocked\n- None.\n\n## Review\n- None.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":1,\"stale\":0,\"conflicting\":0,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":true},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"verified\",\"progress\":\"unknown\",\"warnings\":[],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:4bf8cc4643fd1d06f832be5e145b1e6a14a7d44d4a673505c2ce48fee89af385\"}", + "portfolio_markdown": "Goal coverage: 1/1 sources verified; complete=True\n- sample: verified; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "projection.envelope.seal" + ], + "portfolio": [] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "empty", + "quota": { + "ok": true + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"0 of 0 classified todos returned.\",\"matched_todo_count\":0,\"returned_todo_count\":0,\"runnable_count\":0,\"blocked_count\":0,\"deferred_ready_count\":0,\"review_count\":0,\"source_warning_count\":0,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[],\"blocked\":[],\"review\":[]},\"todos\":[],\"source_warnings\":[],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":0,\"available_count\":0,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `0`\n- returned: `0`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- None.\n\n## Blocked\n- None.\n\n## Review\n- None.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":1,\"stale\":0,\"conflicting\":0,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":true},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"verified\",\"progress\":\"unknown\",\"warnings\":[],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:4bf8cc4643fd1d06f832be5e145b1e6a14a7d44d4a673505c2ce48fee89af385\"}", + "portfolio_markdown": "Goal coverage: 1/1 sources verified; complete=True\n- sample: verified; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "projection.envelope.seal" + ], + "portfolio": [] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + }, + { + "name": "empty_values", + "quota": { + "ok": true, + "normal_delivery_allowed": true, + "selected_todo": { + "todo_id": "todo_empty", + "status": false, + "title": [], + "text": {}, + "priority": 0 + }, + "agent_lane_next_action": { + "todo_id": "todo_empty", + "status": "blocked", + "title": "Filled", + "text": "Filled text", + "priority": "P2" + }, + "agent_todo_summary": { + "items": [ + { + "todo_id": 0 + }, + { + "todo_id": false + }, + { + "todo_id": [] + }, + { + "todo_id": {} + } + ] + } + }, + "expected": { + "global_json": "{\"ok\":true,\"schema_version\":\"global_manager_command_response_v0\",\"request\":{\"schema_version\":\"global_manager_command_request_v0\",\"command\":\"/loopx-global-todos\",\"legacy_aliases\":[\"/loop-global-todos\"],\"cli_command\":\"loopx global-todos\",\"include\":[\"runnable\",\"blocked\",\"deferred_ready\",\"review\"],\"privacy_mode\":\"public_safe_summary\",\"dry_run\":true},\"generated_at\":\"2026-11-02T00:00:00+00:00\",\"summary\":{\"headline\":\"1 of 1 classified todos returned.\",\"matched_todo_count\":1,\"returned_todo_count\":1,\"runnable_count\":0,\"blocked_count\":1,\"deferred_ready_count\":0,\"review_count\":0,\"source_warning_count\":5,\"source_surfaces\":[\"status attention queue\",\"quota should-run summaries\",\"active-state todo projections\",\"compact run-history projection consumed by status\"],\"truncated\":false,\"goal_scan_limit\":160,\"goal_scan_truncated\":false},\"groups\":{\"runnable\":[],\"deferred_ready\":[],\"blocked\":[{\"todo_id\":\"todo_empty\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Filled\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"\"}],\"review\":[]},\"todos\":[{\"todo_id\":\"todo_empty\",\"goal_id\":\"sample\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Filled\",\"claimed_by\":null,\"action_kind\":\"\",\"readiness\":\"blocked\",\"work_kind\":\"ordinary\",\"next_safe_action\":\"\"}],\"source_warnings\":[{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"todo_identity_missing\",\"goal_id\":\"sample\",\"detail\":\"Structured todo candidate from agent_todo_summary.items has no todo_id.\"},{\"reason_code\":\"conflicting_readiness_projection\",\"goal_id\":\"sample\",\"todo_id\":\"todo_empty\",\"detail\":\"Multiple structured readiness signals were projected.\"}],\"source_warnings_truncated\":false,\"projection_envelope\":{\"schema_version\":\"loopx_projection_envelope_v0\",\"projection\":\"global_todos\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"served_at\":\"2026-11-02T00:00:00+00:00\",\"age_seconds\":0,\"served_from_cache\":false,\"fresh\":false,\"complete\":false,\"alert\":true,\"alert_reasons\":[\"incomplete_coverage\",\"missing_required_sources\"],\"alert_source_ids\":[\"global_registry\",\"status\"],\"sources\":[{\"source_id\":\"global_registry\",\"required\":true,\"read_status\":\"missing\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"missing\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"missing\"]},{\"source_id\":\"goal_quota\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"attention_queue\",\"required\":true,\"read_status\":\"read\",\"last_read_at\":\"2026-11-02T00:00:00+00:00\",\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":0,\"status\":\"fresh\",\"item_count\":1,\"missing_count\":0,\"unreadable_count\":0,\"alert\":false,\"alert_reasons\":[]},{\"source_id\":\"status\",\"required\":true,\"read_status\":\"not_read\",\"last_read_at\":null,\"source_updated_at\":null,\"window_seconds\":300,\"staleness_seconds\":null,\"status\":\"not_read\",\"item_count\":null,\"missing_count\":0,\"unreadable_count\":0,\"alert\":true,\"alert_reasons\":[\"not_read\"]}],\"coverage\":{\"scope\":\"global\",\"expected_count\":null,\"included_count\":0,\"omitted\":[],\"shown_count\":1,\"available_count\":1,\"truncated\":false,\"complete\":false},\"upstream\":[]},\"omissions\":[\"Raw logs, raw transcripts, connector payloads, credential values, local paths, and private source bodies were intentionally omitted.\",\"Recent progress, gates, and unrelated risks are outside this focused command.\"],\"boundary\":{\"raw_logs_recorded\":false,\"raw_transcripts_recorded\":false,\"raw_connector_payloads_recorded\":false,\"credential_values_recorded\":false,\"absolute_paths_recorded\":false,\"private_source_bodies_recorded\":false}}", + "global_markdown": "# LoopX Global Todos\n\n- command: `/loopx-global-todos`\n- matched: `1`\n- returned: `1`\n- truncated: `False`\n- goal_scan_truncated: `False`\n- projection: 🔴 envelope=`loopx_projection_envelope_v0` observed_at=`2026-11-02T00:00:00+00:00` age=`0s` sources_fresh=`2/4` coverage=`0/None` scope=`global`\n- 🔴 projection alerts: `incomplete_coverage,missing_required_sources` sources=`global_registry,status` omitted=`-`; state this before treating the projection as current or whole\n\nReview is an overlapping work-kind facet of the readiness groups.\n\n## Runnable\n- None.\n\n## Deferred Ready\n- None.\n\n## Blocked\n- goal=`sample` todo=`todo_empty` priority=`unknown` owner=`agent`: Filled\n\n## Review\n- None.\n\n## Source Warnings\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `todo_identity_missing` goal=`sample`: Structured todo candidate from agent_todo_summary.items has no todo_id.\n- `conflicting_readiness_projection` goal=`sample` todo=`todo_empty`: Multiple structured readiness signals were projected.\n\n## Boundary\n- Raw/private material omitted; local paths are not recorded.", + "portfolio_json": "{\"ok\":true,\"schema_version\":\"goal_portfolio_v0\",\"collected_at\":\"2026-11-02T00:00:00+00:00\",\"collection_completed_at\":\"2026-11-02T00:00:00+00:00\",\"inventory_revision\":\"sha256:fefe0094588f824dc245d7b04ded8653cb5021c00c8daea19ceb3b16fbc131d4\",\"scope\":{\"kind\":\"caller_authorized_registry\",\"requested_goal_ids\":[\"sample\"],\"missing_goal_ids\":[]},\"coverage\":{\"discovered\":1,\"attempted\":1,\"stopped_excluded\":0,\"verified\":0,\"stale\":0,\"conflicting\":1,\"unreadable\":0,\"partial\":0,\"omitted\":0,\"invalid_registry_entries\":0,\"complete\":false},\"warnings\":[],\"goals\":[{\"goal_id\":\"sample\",\"host_id\":null,\"project_id\":null,\"quality\":\"conflicting\",\"progress\":\"unknown\",\"warnings\":[\"todo_identity_missing\",\"todo_identity_missing\",\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\",\"todo_identity_missing\",\"todo_identity_missing\",\"todo_identity_missing\",\"todo_identity_missing\",\"conflicting_readiness_projection\"],\"agents\":[{\"agent_id\":\"alpha\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_empty\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Filled\",\"next_safe_action\":\"\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[]},{\"agent_id\":\"beta\",\"source_verified\":true,\"waiting_on\":null,\"todos\":[{\"todo_id\":\"todo_empty\",\"role\":\"agent\",\"status\":\"open\",\"priority\":\"\",\"title\":\"Filled\",\"next_safe_action\":\"\",\"claimed_by\":null,\"readiness\":\"blocked\"}],\"owner_gate_ids\":[]}],\"deliveries\":[],\"source\":{\"kind\":\"core_status\",\"revision\":\"sha256:bd5039affc9f0707912ac5b617e70b516e3227aa91761cf23d6e4f9a2cda8155\",\"observed_at\":\"2026-11-02T00:00:00+00:00\",\"file_metadata_revisions\":{\"run_index\":null},\"latest_recorded_at\":\"2026-11-02T00:00:00+00:00\"},\"agent_coverage\":{\"discovered\":2,\"attempted\":2,\"omitted\":0},\"activation_state\":\"active\"}],\"limitations\":[\"Local registry projection; unavailable remote sources are not fetched.\",\"Evidence refs identify Core records, not an independent artifact audit.\",\"Latest evidence-bearing delivery per Agent; not a complete delivery history.\",\"Todo readiness reuses the Core summary; the returned task list is not exhaustive.\",\"No absence-of-progress or all-healthy conclusion; external sharing needs its own scope authorization.\"],\"snapshot_id\":\"sha256:e57553a4b369731114dd18f344df46367288305d073a30f1c7aec44d75b98a9f\"}", + "portfolio_markdown": "Goal coverage: 0/1 sources verified; complete=False\n- sample: conflicting; progress=unknown; recorded deliveries=0" + }, + "crossings_before": { + "global": [ + "projection.envelope.seal" + ], + "portfolio": [] + }, + "crossings_after": { + "global": [ + "todo.global_readiness.project", + "projection.envelope.seal" + ], + "portfolio": [ + "todo.global_readiness.project", + "todo.global_readiness.project" + ] + } + } +] diff --git a/tests/test_global_todo_readiness_characterization.py b/tests/test_global_todo_readiness_characterization.py new file mode 100644 index 0000000000..8cb18d5c87 --- /dev/null +++ b/tests/test_global_todo_readiness_characterization.py @@ -0,0 +1,155 @@ +"""Temporary cutover corpus: remove after the Python display facade exits.""" +from __future__ import annotations + +import json +from copy import deepcopy +from datetime import datetime, timezone +from pathlib import Path + +import pytest + +import loopx.global_todos as todos +import loopx.goal_portfolio as portfolio +import loopx.control_plane.effect_runtime as runtime + +FIXTURE = Path(__file__).parent / "fixtures/global_todo_readiness.json" +NOW = "2026-11-02T00:00:00+00:00" + + +def observe(case, monkeypatch, tmp_path): + quota = deepcopy(case["quota"]) + status = { + "ok": True, + "attention_queue": {"items": [{"goal_id": "sample"}]}, + "run_history": {"goals": [{"id": "sample", "latest_status_run": { + "generated_at": NOW, + }}]}, + } + path = tmp_path / "registry.json" + path.write_text(json.dumps({"goals": [{"id": "sample", "coordination": { + "registered_agents": ["alpha", "beta"], + }}]})) + class Clock(datetime): + @classmethod + def now(cls, tz=None): + return datetime.fromisoformat(NOW) + + monkeypatch.setattr(portfolio, "datetime", Clock) + monkeypatch.setattr(todos, "now_utc_iso", lambda: NOW) + monkeypatch.setattr(todos, "collect_status", lambda **_: deepcopy(status)) + monkeypatch.setattr(portfolio, "collect_status", lambda **_: deepcopy(status)) + monkeypatch.setattr(portfolio, "_source_versions", lambda *_: {"run_index": None}) + monkeypatch.setattr(todos, "build_quota_should_run", lambda *_, **__: deepcopy(quota)) + monkeypatch.setattr(portfolio, "build_quota_should_run", lambda *_, agent_id, **__: { + **deepcopy(quota), "agent_identity": {"agent_id": agent_id}, + }) + calls = [] + request = runtime.effect_runtime_request + + def counted(method, *args, **kwargs): + calls.append(method) + return request(method, *args, **kwargs) + + monkeypatch.setattr(runtime, "effect_runtime_request", counted) + global_payload = todos.build_global_todos( + registry_path=path, runtime_root_override=None, agent_id=None, limit=40, + ) + global_calls = list(calls) + calls.clear() + portfolio_payload = portfolio.build_goal_portfolio( + registry_path=path, now=datetime.fromisoformat(NOW).astimezone(timezone.utc), + ) + return { + "global_json": json.dumps(global_payload, ensure_ascii=False, separators=(",", ":")), + "global_markdown": todos.render_global_todos_markdown(global_payload), + "portfolio_json": json.dumps(portfolio_payload, ensure_ascii=False, separators=(",", ":")), + "portfolio_markdown": portfolio.render_goal_portfolio(portfolio_payload), + }, {"global": global_calls, "portfolio": calls} + + +@pytest.mark.parametrize("case", json.loads(FIXTURE.read_text()), ids=lambda c: c["name"]) +def test_complete_outputs_and_crossings(case, monkeypatch, tmp_path): + observed, calls = observe(case, monkeypatch, tmp_path) + assert observed == case["expected"] + # Both measurements are pinned before cutover; output bytes never change. + assert calls == case["crossings_after"] + + +@pytest.mark.parametrize("provider", ["file", "sqlite"]) +def test_production_cli_archive_parity(provider, tmp_path): + import os + import subprocess + import sys + + from loopx.control_plane.testing.canary_harness import ( + import_fixture_authority, + project_state_path, + write_fixture_registry, + ) + + source = Path(__file__).resolve().parents[1] + base = tmp_path / "base" + base.mkdir() + archive = subprocess.run( + ["git", "archive", "HEAD"], cwd=source, capture_output=True, check=True, + ) + subprocess.run(["tar", "-xf", "-", "-C", str(base)], input=archive.stdout, check=True) + home = tmp_path / "home" + project, runtime_root = home / "project", home / "runtime" + registry = project / ".loopx/registry.json" + write_fixture_registry( + project=project, runtime_root=runtime_root, registry_path=registry, + goal_id="sample", domain="synthetic", adapter_kind="generic_project_goal_v0", + registered_agents=["alpha", "beta"], quota_allowed_slots=10, + ) + state = project_state_path(project, "sample") + state.parent.mkdir(parents=True, exist_ok=True) + state.write_text( + "---\nstatus: active\nupdated_at: 2026-11-02T00:00:00+00:00\n---\n\n" + "# Synthetic goal\n\n## Agent Todo\n\n" + "- [ ] [P1] Deliver synthetic change.\n" + " \n\n" + "- [ ] [P2] Review synthetic change.\n" + " \n\n" + "## User Todo\n\n- [ ] Confirm synthetic scope.\n" + " \n" + ) + import_fixture_authority(registry, "sample", provider=provider) + # Freeze only the clock, before importing the real public CLI. Both copies + # read the same physical files, preserving source versions and their hashes. + launcher = """ +import datetime, sys, time +sys.path.insert(0, sys.argv.pop(1)) +class Clock(datetime.datetime): + @classmethod + def now(cls, tz=None): + return cls(2026, 11, 2, tzinfo=datetime.timezone.utc) +datetime.datetime = Clock +time.time = lambda: 1793577600.0 +from loopx.entrypoint import main +raise SystemExit(main()) +""" + for command in ("global-todos", "goal-portfolio"): + for output_format in ("json", "markdown"): + outputs = [] + for tree in (base, source): + result = subprocess.run( + [sys.executable, "-c", launcher, str(tree), "--registry", str(registry), + "--runtime-root", str(runtime_root), "--format", output_format, command], + cwd=tree, env={**os.environ, "HOME": str(home)}, capture_output=True, + timeout=60, + ) + assert result.returncode == 0, result.stdout + result.stderr + outputs.append(result.stdout) + assert outputs[0] == outputs[1] + if output_format == "json": + payload = json.loads(outputs[1]) + if command == "goal-portfolio": + assert len(payload["goals"][0]["agents"]) == 2 + assert any(agent["todos"] for agent in payload["goals"][0]["agents"]) + else: + assert payload["todos"] + print(f"CLI parity: {provider} {command} {output_format} bytes={len(outputs[1])}") From 45184d5edd88722d505e41d6384c07bb68c92d66 Mon Sep 17 00:00:00 2001 From: huangruiteng Date: Wed, 4 Nov 2026 14:47:54 +0800 Subject: [PATCH 2/2] test(todos): pin readiness parity to pre-cutover revision Signed-off-by: huangruiteng --- tests/test_global_todo_readiness_characterization.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_global_todo_readiness_characterization.py b/tests/test_global_todo_readiness_characterization.py index 8cb18d5c87..fc947079dc 100644 --- a/tests/test_global_todo_readiness_characterization.py +++ b/tests/test_global_todo_readiness_characterization.py @@ -14,6 +14,7 @@ FIXTURE = Path(__file__).parent / "fixtures/global_todo_readiness.json" NOW = "2026-11-02T00:00:00+00:00" +BASE_REVISION = "d4aaaaefbd37a83a30f10681de839b45d631eeb9" def observe(case, monkeypatch, tmp_path): @@ -90,8 +91,12 @@ def test_production_cli_archive_parity(provider, tmp_path): source = Path(__file__).resolve().parents[1] base = tmp_path / "base" base.mkdir() + assert subprocess.run( + ["git", "merge-base", "--is-ancestor", BASE_REVISION, "HEAD"], + cwd=source, + ).returncode == 0 archive = subprocess.run( - ["git", "archive", "HEAD"], cwd=source, capture_output=True, check=True, + ["git", "archive", BASE_REVISION], cwd=source, capture_output=True, check=True, ) subprocess.run(["tar", "-xf", "-", "-C", str(base)], input=archive.stdout, check=True) home = tmp_path / "home"