From 99facff915f8ec3fc350bad835f9af179a635e7b Mon Sep 17 00:00:00 2001 From: hhyykk <4408344+hhyykk@users.noreply.github.com> Date: Mon, 2 Nov 2026 16:38:54 +0800 Subject: [PATCH] refactor(quota): compose quota summary in one TypeScript planning crossing Extend the existing todo.quota_planning.project request so TypeScript selects sources, composes lanes, counts, limits, warnings and display projection for user and project-asset quota summaries. Python gathers compatibility facts and dereferences owner-selected source references so original values survive the JSON transport. Pinned complete-output fixtures stay byte-identical; matrix paths drop from 1-5 crossings to one, non-dict input stays at zero and owner refusal stays at one without fallback. No handler, authority or persisted format is added. 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-quota-summary-transaction.md | 22 ++ ...6-11-02-quota-summary-transaction.zh-CN.md | 17 + .../typescript-control-plane-migration-v0.md | 1 + ...script-control-plane-migration-v0.zh-CN.md | 1 + .../control_plane/todos/context_projection.ts | 5 +- loopx/control_plane/todos/quota_selection.py | 94 +++++- loopx/control_plane/todos/quota_selection.ts | 213 +++++++++++- loopx/control_plane/todos/quota_summary.py | 314 +----------------- .../quota_summary_transaction_snapshots.json | 157 +++++++++ .../test_quota_planning_transport.py | 23 +- .../test_quota_summary_source_references.py | 112 +++++++ ...ta_summary_transaction_characterization.py | 147 ++++++++ .../quota_summary_transaction.test.ts | 90 +++++ 13 files changed, 887 insertions(+), 309 deletions(-) create mode 100644 docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.md create mode 100644 docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md create mode 100644 tests/control_plane/quota_summary_transaction_snapshots.json create mode 100644 tests/control_plane/test_quota_summary_source_references.py create mode 100644 tests/control_plane/test_quota_summary_transaction_characterization.py create mode 100644 tests/control_plane_ts/quota_summary_transaction.test.ts diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.md new file mode 100644 index 0000000000..424d6e637c --- /dev/null +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.md @@ -0,0 +1,22 @@ +# Quota summary transaction cutover (2026-11-02) + +The existing `todo.quota_planning.project` request now returns the complete +user or project-asset quota summary. TypeScript owns source selection, lane +composition, counts, limits, warnings and display projection in process. +Python gathers compatibility facts and validates and dereferences the response. +Source counts, metadata, selected Vision proofs, closure overlays and warning +fields retain their original Python values through owner-selected references; +planning and display rows retain their existing JSON normalization. + +The pre-cutover complete-output fixtures remain the parity guard. For both +summary variants, every matrix path previously using 1–5 crossings now uses +one; non-dict input stays at zero and owner refusal stays at one without fallback. +No handler, authority or persisted format is added. The planning-only Python +codec remains for direct planning consumers; remove it only after their last +caller migrates. Payload/status compaction and source helpers retain other +callers. No facade exit or latency improvement is claimed. + +The earlier Phase 1 transport-loss finding remains valid for plain JSON; +source references resolve that blocker without changing the pinned outputs. +This source-checkout slice does not qualify installed or long-horizon benefit. +Rollback is the code diff; no state migration is needed. diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md new file mode 100644 index 0000000000..f5061cdd18 --- /dev/null +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md @@ -0,0 +1,17 @@ +# 配额摘要事务切换(2026-11-02) + +现有 `todo.quota_planning.project` 请求现在返回完整的用户或项目资产配额摘要。 +TypeScript 在进程内负责来源选择、泳道组合、计数、限制、警告和显示投影。 +Python 收集兼容性事实,并校验响应、解析引用。 +来源计数、元数据、选中的 Vision 证明、闭合意图叠加及警告字段通过由所有者 +选择的引用保留原始 Python 值;规划和显示行保留现有的 JSON 归一化行为。 + +切换前的完整输出夹具继续作为等价性守卫。两种摘要的矩阵路径中,原先使用 +1–5 次跨运行时调用的路径现在均使用一次;非字典输入保持零次,所有者拒绝 +保持一次且不回退。不增加处理器、权限或持久化格式。仅供规划使用的 Python +编解码器仍有直接调用者;只有最后一个调用者迁移后才能删除。载荷和状态压缩 +以及来源辅助函数仍有其他调用者。不宣称外观层退出或延迟改善。 + +先前第一阶段关于纯 JSON 传输损失的发现仍然成立;来源引用在不改变固定输出 +的前提下解决了该阻塞。本源码检出切片不证明已安装行为或长程收益。 +回滚只需撤销代码差异,无需状态迁移。 diff --git a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md index 11916426e9..b7988256d0 100644 --- a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md +++ b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md @@ -2835,3 +2835,4 @@ The native query now owns recovery lookup and completion capability evidence, with shared write/read status-phase checks. See the [2026-10-02 checkpoint](ledger/typescript-control-plane-migration-v0/2026-10-02-turn-journal-readback.md) for compatibility, measured cost, validation boundaries and facade exit. - Summary-display final-head qualification and preserved tail cohorts: [2026-10-27 follow-up](ledger/typescript-control-plane-migration-v0/2026-10-27-todo-summary-qualification.md). +- Quota summary composition in one `todo.quota_planning.project` crossing with source references: [2026-11-02 cutover](ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.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 7fbae148e1..abc69a3925 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 @@ -2100,3 +2100,4 @@ SQLite 中位数略升,收益不能外推为全面加速。这只资格化本 原生查询统一拥有恢复定位和 completion capability 证据,并共享写入/回读的状态阶段约束。兼容变更、实测代价、验证范围与 facade 退出条件见 [2026-10-02 检查点](ledger/typescript-control-plane-migration-v0/2026-10-02-turn-journal-readback.zh-CN.md)。 - 摘要展示最终 head 验收与历史尾延迟批次:[2026-10-27 后续记录](ledger/typescript-control-plane-migration-v0/2026-10-27-todo-summary-qualification.zh-CN.md)。 +- 配额摘要经来源引用在一次 `todo.quota_planning.project` 跨运行时调用内完成组合:[2026-11-02 切换记录](ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md)。 diff --git a/loopx/control_plane/todos/context_projection.ts b/loopx/control_plane/todos/context_projection.ts index 95cde9ca0d..2802a09ccd 100644 --- a/loopx/control_plane/todos/context_projection.ts +++ b/loopx/control_plane/todos/context_projection.ts @@ -238,7 +238,7 @@ function compactSummaryRecord(item: JsonObject, body: unknown): JsonObject { } /** Standalone compatibility display, also composed inside quota planning. */ -export function projectTodoSummaryDisplay(input: JsonObject): JsonObject[] { +export function projectTodoSummaryDisplay(input: JsonObject, onSource?: (key: string, index: number) => void): JsonObject[] { const planning = input.include_terminal !== undefined, terminal = input.include_terminal === true; const source = input.source === undefined ? null : decodeTodoReadSource(requireJsonObject(input.source, "summary source")); const ready = new Set((Array.isArray(input.handoff_gates) ? input.handoff_gates : []).flatMap(value => { @@ -248,7 +248,7 @@ export function projectTodoSummaryDisplay(input: JsonObject): JsonObject[] { const selected: {item: JsonObject; text: unknown}[] = [], seen = new Set(); if (source) { for (const key of planning ? PLANNING_SOURCES : SUMMARY_SOURCES) { - for (const value of Array.isArray(source[key]) ? source[key] as unknown[] : []) { + for (const [index, value] of (Array.isArray(source[key]) ? source[key] as unknown[] : []).entries()) { if (!value || typeof value !== "object" || Array.isArray(value)) continue; const item = value as JsonObject, body = stripPythonWhitespace(pythonFieldText(item, "text")); let todo = id(item.todo_id); @@ -257,6 +257,7 @@ export function projectTodoSummaryDisplay(input: JsonObject): JsonObject[] { if (!planning && selected.some(({item: prior, text}) => item.todo_id && prior.todo_id ? item.todo_id === prior.todo_id : prior.index === item.index && text === body)) continue; if (todo) seen.add(todo); selected.push({item, text: body}); + onSource?.(key, index); } } } else { diff --git a/loopx/control_plane/todos/quota_selection.py b/loopx/control_plane/todos/quota_selection.py index eb1608fb4a..20b5dd4ce5 100644 --- a/loopx/control_plane/todos/quota_selection.py +++ b/loopx/control_plane/todos/quota_selection.py @@ -19,10 +19,11 @@ todo_item_has_removed_continuation_policy, todo_item_is_actionable_open, todo_item_next_due_at, todo_item_expires_at, todo_item_is_watch_only_monitor, todo_item_task_class, todo_projection_sort_key, - todo_summary_monitor_writeback_supported, + todo_summary_monitor_writeback_supported, todo_presentation_sort_key, ) from .resume_planning import build_referenced_todo_resume_planning_request from .handoff_note import todo_read_source +from .summary_item import TODO_SUMMARY_SOURCE_KEYS from .user_gate import is_user_gate_todo_item from .route_continuation import build_todo_route_continuation_facts from .handoff_gate import todo_summary_handoff_gates @@ -112,6 +113,7 @@ def project_quota_planning( source_open_count: Any, agent_identity: dict[str, Any] | None, filter_user_gate_blocks_agent: bool, available_capabilities: Any, resolve_capacity: bool = False, current_time: str | None = None, + summary_kind: str | None = None, ) -> dict[str, Any]: identity = agent_identity if isinstance(agent_identity, dict) else {} profile = identity.get("agent_profile") @@ -123,11 +125,12 @@ def project_quota_planning( observed_at = observed_now.timestamp() handoff_gates = todo_summary_handoff_gates(value) - def encode(item: dict[str, Any]) -> dict[str, Any]: + def encode(item: dict[str, Any], *, include_payload: bool = True) -> dict[str, Any]: priority, index = todo_projection_sort_key(item) due, expires = todo_item_next_due_at(item), todo_item_expires_at(item) return { - "payload": item, "display_source": todo_read_source(item), + **({"payload": item, "display_source": todo_read_source(item)} if include_payload else {}), + "presentation": list(todo_presentation_sort_key(item)), "claim": normalize_todo_claimed_by(item.get("claimed_by")), "bound": normalize_todo_bound_agent(item.get("bound_agent")), "blocks": normalize_todo_blocks_agent(item.get("blocks_agent")), @@ -151,6 +154,12 @@ def active(key: str) -> list[dict[str, Any]]: raw = value.get(key) return [encode(item) for item in raw if isinstance(item, dict)] if isinstance(raw, list) else [] + def integer_text(raw: Any) -> str | None: + try: + return str(int(raw)) if raw is not None else None + except (TypeError, ValueError): + return None + resume_request = build_referenced_todo_resume_planning_request( value, agent_id=agent, @@ -161,6 +170,19 @@ def active(key: str) -> list[dict[str, Any]]: wire = effect_runtime_result("todo.quota_planning.project", { "schema_version": "todo_quota_planning_request_v4", "current_time": observed_now.isoformat(), + **({"summary_request": { + "kind": summary_kind, "source": todo_read_source(value), + "integer_counts": {"source": integer_text(value.get("completed_without_successor_count")), + "warning": integer_text((value.get("todo_succession_warning") or {}).get("count")) + if isinstance(value.get("todo_succession_warning"), dict) else None}, + "next_fact": encode({"index": value.get("next_index", 1), + "text": str(value.get("next") or "").strip(), + **({"claimed_by": str(value.get("next_claimed_by") or "").strip()} + if str(value.get("next_claimed_by") or "").strip() else {})}), + "source_rows": {key: [encode(row, include_payload=False) if isinstance(row, dict) else None + for row in value.get(key, [])] + for key in TODO_SUMMARY_SOURCE_KEYS if isinstance(value.get(key), list)}, + }} if summary_kind else {}), "frontier_deadline": value.get("frontier_deadline"), "route_items": build_todo_route_continuation_facts(value, handoff_gates=handoff_gates), "handoff_items": [{"display": gate, @@ -185,6 +207,8 @@ def active(key: str) -> list[dict[str, Any]]: }, large_local_snapshot=True) except EffectRuntimeRejected as exc: raise ValueError(str(exc)) from None + if summary_kind: + return _decode_quota_summary_wire(wire, value) result = _decode_quota_planning_wire(wire) if not isinstance(result, dict) or result.get("schema_version") != "todo_quota_planning_v0": raise RuntimeError("TypeScript Todo quota planning shape mismatch") @@ -197,3 +221,67 @@ def active(key: str) -> list[dict[str, Any]]: elif result["closure_intent"] is not None: raise RuntimeError("TypeScript Todo quota planning closure intent shape mismatch") return result + + +def _decode_quota_summary_wire(wire: Any, source: dict[str, Any]) -> dict[str, Any]: + """Resolve owner-selected transport references after bounded validation.""" + error = "invalid TypeScript quota summary wire" + if not isinstance(wire, dict) or wire.get("schema_version") != "todo_quota_summary_wire_v1": + raise RuntimeError(error) + summary, copies, integers = wire.get("summary"), wire.get("source_copies"), wire.get("integer_copies") + if not isinstance(summary, dict) or not isinstance(copies, list) or not isinstance(integers, list): + raise RuntimeError(error) + expanded = len(json.dumps(summary, ensure_ascii=False, separators=(",", ":")).encode()) + patches: list[tuple[Any, Any, Any]] = [] + targets: set[tuple[Any, ...]] = set() + + def path(value: Any, *, nonempty: bool = False) -> list[Any]: + if (not isinstance(value, list) or (nonempty and not value) + or any(type(key) not in (str, int) or isinstance(key, int) and key < 0 for key in value)): + raise RuntimeError(error) + return value + + def child(parent: Any, key: Any) -> Any: + if not (isinstance(parent, dict) and isinstance(key, str) + or isinstance(parent, list) and type(key) is int): + raise RuntimeError(error) + return parent[key] + + try: + for copy in [*copies, *integers]: + if not isinstance(copy, dict): + raise RuntimeError(error) + target_path = path(copy.get("target"), nonempty=True) + coordinate = tuple(target_path) + if coordinate in targets: + raise RuntimeError(error) + targets.add(coordinate) + parent: Any = summary + for key in target_path[:-1]: + parent = child(parent, key) + if child(parent, target_path[-1]) is not None: + raise RuntimeError(error) + if "source" in copy: + original: Any = source + for key in path(copy["source"]): + original = child(original, key) + else: + raw = copy.get("value") + if not isinstance(raw, str) or not raw or raw.lstrip("-").strip("0123456789"): + raise RuntimeError(error) + original = int(raw) + expanded += len(json.dumps(original, ensure_ascii=False, separators=(",", ":")).encode()) - 4 + if expanded > MAX_LOCAL_SNAPSHOT_BYTES: + raise RuntimeError("TypeScript quota summary expanded response is oversized") + patches.append((parent, target_path[-1], original)) + except (ValueError, KeyError, IndexError, TypeError): + raise RuntimeError(error) from None + if expanded > MAX_LOCAL_SNAPSHOT_BYTES: + raise RuntimeError("TypeScript quota summary expanded response is oversized") + for parent, key, original in patches: + parent[key] = original + if (not isinstance(summary.get("work_counts"), dict) + or any(not isinstance(summary.get(key), list) for key in ( + "first_open_items", "first_executable_items", "monitor_open_items", "backlog_items"))): + raise RuntimeError(error) + return summary diff --git a/loopx/control_plane/todos/quota_selection.ts b/loopx/control_plane/todos/quota_selection.ts index 8545b72fa2..2007c11642 100644 --- a/loopx/control_plane/todos/quota_selection.ts +++ b/loopx/control_plane/todos/quota_selection.ts @@ -1,3 +1,5 @@ +import {COORDINATION_STATE_CONTRACT} from "../coordination/coordination_state_contract.generated.ts"; +import {decodeTodoReadSource, readAgent, pythonFieldText, writeScopes, readScope, readScopes, taskClass} from "./read_codec.ts"; import {projectTodoSummaryDisplay} from "./context_projection.ts"; import {isBoundedBlockedRetry} from "../quota/settlement_phase.ts"; import {parseTodoTimestampMicros} from "../runtime_timestamp.ts"; @@ -413,7 +415,8 @@ function quotaPlanningWire(planning: JsonObject): JsonObject { /** One quota read boundary composes scope/claim selection, resume, hint * visibility and the typed source closure rules. */ export function projectTodoQuotaPlanning(value: unknown): JsonObject { - const request = requireJsonObject(value, "quota planning"); + let request = requireJsonObject(value, "quota planning"); + if (request.summary_request !== undefined) request = prepareQuotaSummary(request); if (!["todo_quota_planning_request_v0", "todo_quota_planning_request_v1", "todo_quota_planning_request_v2", "todo_quota_planning_request_v3", "todo_quota_planning_request_v4"].includes(String(request.schema_version))) { throw new EffectRuntimeRequestError("quota planning schema mismatch"); @@ -488,5 +491,211 @@ export function projectTodoQuotaPlanning(value: unknown): JsonObject { const planning = {schema_version: "todo_quota_planning_v0", resume_planning: resume, ...selected, ...closure, ...(hasSourceContract ? {handoff_lanes: handoff, route_lanes: route} : {}), ...(now === null ? {} : frontier)}; - return referenced ? quotaPlanningWire(planning) : planning; + return request.summary_request !== undefined ? composeQuotaSummary(request, planning) : + referenced ? quotaPlanningWire(planning) : planning; +} + +type Path = (string | number)[]; +const summaryObject = (v: unknown): v is JsonObject => !!v && typeof v === "object" && !Array.isArray(v); +const truth = (v: unknown): boolean => Array.isArray(v) ? !!v.length : summaryObject(v) ? !!Object.keys(v).length : !!v; +const get = (v: JsonObject, k: string, fallback: unknown = null): unknown => Object.hasOwn(v, k) ? v[k] : fallback; +const summaryRows = (v: unknown): JsonObject[] => Array.isArray(v) ? v.filter(summaryObject) : []; + +/** Source selection is part of the existing quota read, using the display owner. */ +export function prepareQuotaSummary(request: JsonObject): JsonObject { + const summary = requireJsonObject(request.summary_request, "summary request"); + const source = decodeTodoReadSource(requireJsonObject(summary.source, "summary source")); + const legacy = summary.kind === "project_asset" && !( + (Array.isArray(source.items) || Array.isArray(source.first_open_items)) && + ["total_count", "open_count", "done_count"].some(k => Object.hasOwn(source, k))); + if (summary.kind !== "user" && summary.kind !== "project_asset") { + throw new EffectRuntimeRequestError("invalid quota summary kind"); + } + const pool = requireJsonObject(summary.source_rows, "source rows"); + const selectedFacts: JsonObject[] = []; + let selected: JsonObject[] = projectTodoSummaryDisplay({source: summary.source, + handoff_gates: (request.handoff_items as JsonObject[]).map(row => row.display)}, (key, index) => { + const lane = pool[key]; + if (!Array.isArray(lane)) throw new EffectRuntimeRequestError("quota summary source lane missing"); + selectedFacts.push(requireJsonObject(lane[index], "quota source fact")); + }).map((payload, index) => { + const fact = selectedFacts[index]!; + const presentation = [...fact.presentation as [number, number, string, string]]; + // Display rows already crossed JSON in the previous transaction. Integral + // floats therefore supplied Python int coordinates at that boundary. + const legacySchema = COORDINATION_STATE_CONTRACT.todo_read_record.item_schema_version; + const legacy = payload.schema_version === legacySchema || payload.schema_version == null && truth(payload.source_section); + const unknownSchema = payload.schema_version != null && ![legacySchema, COORDINATION_STATE_CONTRACT.todo_domain_record.item_schema_version].some(schema => schema === payload.schema_version); + if ((legacy || unknownSchema) && typeof payload.index === "number" && Number.isInteger(payload.index) && payload.index >= 0) { + presentation[1] = payload.index; presentation[2] = ""; presentation[3] = ""; + } + return {...fact, presentation, payload, display_source: {record: payload}}; + }); + if (legacy && !selected.length && summary.next_fact) { + const fact = requireJsonObject(summary.next_fact, "next fact"); + if (truth(requireJsonObject(fact.payload, "next payload").text)) selected = [fact]; + } + selected.sort((a, b) => { + const x = a.presentation as [number, number, string, string], y = b.presentation as typeof x; + return x[0] - y[0] || x[1] - y[1] || authorityUnicodeCompare(x[2], y[2]) || authorityUnicodeCompare(x[3], y[3]); + }); + const selection = requireJsonObject(request.selection, "selection"); + return {...request, summary_request: {...summary, legacy}, selection: {...selection, items: selected, + source_open_count: legacy ? get(source, "open", get(source, "open_count", selected.length)) : get(source, "open_count", selected.length)}}; +} + +/** Complete presentation decisions stay here. Copies are explicit transport + * references to values the old Python projection retained from its input. */ +export function composeQuotaSummary(request: JsonObject, planning: JsonObject): JsonObject { + const input = requireJsonObject(request.summary_request, "summary request"); + const source = decodeTodoReadSource(requireJsonObject(input.source, "summary source")); + const legacy = input.legacy === true; + const selection = requireJsonObject(request.selection, "selection"); + const agent = String(selection.agent_id ?? "").trim(); + const scoped = selection.user_gate_scope === true; + const lanes = requireJsonObject(planning.lanes, "lanes"); + const lane = (name: string): JsonObject[] => { + const value = lanes[name]; + if (!Array.isArray(value)) throw new EffectRuntimeRequestError(`quota summary lane missing: ${name}`); + return value.map(row => requireJsonObject(row, "quota summary lane row")); + }; + const resume = requireJsonObject(planning.resume_planning, "resume"); + const capacity = summaryObject(resume.capacity_fields) ? resume.capacity_fields : {}; + const value = {...source, ...capacity}; + const copies: {source: Path; target: Path}[] = []; + const refs = new Map(); + const integers = new Map(); + const integerCopies: {value: string; target: Path}[] = []; + const integer = (value: string): JsonObject => {const marker = {}; integers.set(marker, value); return marker;}; + const ref = (path: Path): JsonObject => {const marker = {}; refs.set(marker, path); return marker;}; + const field = (key: string, fallback: any = null): any => Object.hasOwn(capacity, key) ? capacity[key] : + Object.hasOwn(source, key) ? ref([key]) : fallback; + const sourceCountKey = legacy && Object.hasOwn(source, "open") ? "open" : "open_count"; + const count = lanes.open_count; + const summary: JsonObject = { + schema_version: field("schema_version"), + source_section: legacy ? truth(value.source_section) ? field("source_section") : "project_asset" : field("source_section"), + total_count: field(legacy && Object.hasOwn(value, "total") ? "total" : "total_count"), + open_count: count, work_counts: planning.work_counts, + done_count: field(legacy && Object.hasOwn(value, "done") ? "done" : "done_count"), + ...(!legacy ? {deferred_count: field("deferred_count"), source_completeness: planning.source_completeness} : {}), + first_open_items: lane("display_open_items").slice(0, 3), first_executable_items: lane("executable_items").slice(0, 3), + ...(!legacy ? {gate_open_items: lanes.gate_items} : {}), + monitor_open_items: lanes.monitor_items, monitor_due_count: lane("monitor_due_items").length, + monitor_due_items: lane("monitor_due_items").slice(0, 1), watch_only_monitor_count: lane("watch_only_monitor_items").length, + watch_only_monitor_due_count: lane("watch_only_monitor_due_items").length, + watch_only_monitor_due_items: lane("watch_only_monitor_due_items").slice(0, 1), + non_watch_only_monitor_due_items: lane("non_watch_only_monitor_due_items").slice(0, 1), + monitor_capability_blocked_due_count: lane("monitor_capability_blocked_due_items").length, + monitor_capability_blocked_due_items: lanes.monitor_capability_blocked_due_items, + ...(!legacy ? {monitor_schedule_gap_count: lane("monitor_schedule_gap_items").length, + monitor_schedule_gap_items: lane("monitor_schedule_gap_items").slice(0, 1)} : {}), + active_next_action_items: lanes.active_next_action_items, + active_next_action_executable_items: lanes.active_next_action_executable_items, + backlog_items: lane("display_open_items").slice(0, 8), executable_backlog_items: lane("executable_items").slice(0, 8), + }; + const display = (items: JsonObject[]) => projectTodoSummaryDisplay({items: items.map(record => ({record})), strip_text: true}); + if (!legacy) { + for (const key of ["goal_acceptance_contract", "advancement_frontier_revision_index"]) if (summaryObject(value[key])) summary[key] = field(key); + if (lane("watch_only_monitor_items").length) summary.convergence_open_count = field("convergence_open_count"); + const recent = summaryRows(value.recent_completed_advancement_items).filter(row => !agent || readAgent(row.claimed_by) === agent); + if (recent.length) summary.recent_completed_advancement_items = display(recent); + if (Array.isArray(value.vision_wait_states)) summary.vision_wait_states = value.vision_wait_states.flatMap((row: any, index: number) => + summaryObject(row) && row.agent_id === agent ? [ref(["vision_wait_states", index])] : []); + const blockers = lane("all_open_items").filter((row: JsonObject) => row.task_class === "blocker" && + String(row.status || "").trim().toLowerCase() === "blocked" && String(row.reason || "").trim()); + const current = blockers.filter((row: JsonObject) => agent && readAgent(row.claimed_by) === agent); + if (blockers.length) summary.blocker_open_count = blockers.length; + if (current.length) {summary.current_agent_blocker_count = current.length; summary.current_agent_blocker_items = current.slice(0, 2);} + if (truth(planning.closure_intent)) { + const closure = requireJsonObject(planning.closure_intent, "closure intent"); + summary.closure_intent = {...Object.fromEntries(Object.keys(source.closure_intent as JsonObject).map(key => [key, ref(["closure_intent", key])])), ...closure}; + } + } + for (const key of ["frontier_deadline", "blocked_retry_wait"]) if (truth(planning[key])) summary[key] = planning[key]; + const monitor = value.monitor_writeback; + if (summaryObject(monitor) && monitor.supported === false) { + const label = pythonFieldText(monitor, "source").trim(); + summary.monitor_writeback = {supported: false, ...(label ? {source: label} : {})}; + } + Object.assign(summary, planning.claim_visibility, resume.deferred_lanes, + ...(!legacy ? [resume.resume_blocked_lanes] : []), planning.handoff_lanes, planning.route_lanes); + if (!legacy) Object.assign(summary, successionWarning(value, ref, input.integer_counts, integer)); + const claimed = scoped ? null : value.claimed_open_count; + if (lane("claimed_open_items").length || truth(claimed)) { + summary.claimed_open_count = truth(claimed) ? field("claimed_open_count") : lane("claimed_open_items").length; + summary.unclaimed_open_count = !scoped && Object.hasOwn(value, "unclaimed_open_count") ? field("unclaimed_open_count") : + Math.max(0, Math.trunc(Number(lanes.open_count || 0)) - lane("claimed_open_items").length); + } + if (truth(lanes.claim_scope)) summary.claim_scope = lanes.claim_scope; + const allCount = () => field(sourceCountKey, lane("all_open_items").length); + if (!legacy && scoped) summary.all_open_count = allCount(); + if (truth(lanes.agent_scope_filter)) { + summary.agent_scope_filter = lanes.agent_scope_filter; + if (legacy) summary.all_open_count = allCount(); + summary.other_agent_scoped_open_count = lane("other_agent_scoped_items").length; + summary.other_agent_scoped_items = display(lane("other_agent_scoped_items").slice(0, 16)); + } + if (scoped && lane("user_action_open_items").length) { + summary.user_action_open_count = lane("user_action_open_items").length; + summary.user_action_items = display(lane("user_action_open_items").slice(0, 16)); + } + if (truth(lanes.user_action_agent_scope_filter)) { + summary.user_action_agent_scope_filter = lanes.user_action_agent_scope_filter; + summary.other_agent_bound_user_action_open_count = lane("other_agent_bound_user_action_items").length; + summary.other_agent_bound_user_action_items = display(lane("other_agent_bound_user_action_items").slice(0, 16)); + } + function encode(value: any, path: Path): any { + if (value && typeof value === "object" && integers.has(value)) { + integerCopies.push({value: integers.get(value)!, target: path}); return null; + } + if (value && typeof value === "object" && refs.has(value)) { + copies.push({source: refs.get(value)!, target: path}); return null; + } + if (Array.isArray(value)) return value.map((row, i) => encode(row, [...path, i])); + if (summaryObject(value)) return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, encode(child, [...path, key])])); + return value; + } + return {schema_version: "todo_quota_summary_wire_v1", summary: encode(summary, []), source_copies: copies, integer_copies: integerCopies}; +} + +function successionWarning(value: JsonObject, ref: (path: Path) => JsonObject, + integerFacts: unknown, integer: (value: string) => JsonObject): JsonObject { + const warning = summaryObject(value.todo_succession_warning) ? value.todo_succession_warning : {}; + const key = Array.isArray(warning.items) ? "todo_succession_warning" : "completed_without_successor_items"; + const source = key === "todo_succession_warning" ? warning.items : value[key]; + const items = (Array.isArray(source) ? source : []).flatMap((row: unknown, index: number) => { + if (!summaryObject(row)) return []; + const path: Path = key === "todo_succession_warning" ? [key, "items", index] : [key, index]; + const copy = (name: string) => Object.hasOwn(row, name) ? ref([...path, name]) : null; + const projected: JsonObject = {index: copy("index"), text: copy("text")}; + for (const name of [ + "schema_version", "todo_id", "role", "status", "priority", "title", "archive_state", "source_section", + "task_class", "action_kind", "task_domain", "task_repository", "continuation_policy", "required_write_scopes", + "required_capabilities", "target_capabilities", "decision_scope", "required_decision_scopes", "claimed_by", + "blocks_agent", "excluded_agents", "unblocks_todo_id", "resume_when", "resume_monitor_generation", + "resume_condition", "resume_ready", "no_followup", "successor_todo_ids", "target_key", "cadence", "next_due_at", + "expires_at", "last_checked_at", "result_hash", "consecutive_no_change", "material_change", + "material_change_generation", "max_no_change_before_replan", "route_continuation_replan_required", + "route_continuation_reason", "route_id", "route_key", "completed_at", "updated_at", "superseded_by", + "completion_continuation", "completion_recovery", "completion_turn_key", "done", "succession_tracked", "recommended_action", + ]) if (row[name] != null) projected[name] = copy(name); + for (const [name, normalized] of [["required_write_scopes", writeScopes(row.required_write_scopes)], + ["decision_scope", readScope(row.decision_scope)], ["required_decision_scopes", readScopes(row.required_decision_scopes)]] as const) { + if (normalized && (!Array.isArray(normalized) || normalized.length)) projected[name] = normalized; + else delete projected[name]; + } + projected.task_class = taskClass({...row, text: pythonFieldText(row, "text")}); + return [projected]; + }).slice(0, 8); + const facts = summaryObject(integerFacts) ? integerFacts : {}; + const encoded = Object.hasOwn(warning, "count") ? facts.warning : facts.source; + const numeric = typeof encoded === "string" ? BigInt(encoded) : BigInt(items.length); + const positive = numeric > 0n; + if (!positive && !items.length) return {}; + const count = numeric <= 0n ? 0 : numeric <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(numeric) : integer(String(numeric)); + const payload = {schema_version: Object.hasOwn(warning, "schema_version") ? ref(["todo_succession_warning", "schema_version"]) : "todo_succession_warning_v0", + reason_code: Object.hasOwn(warning, "reason_code") ? ref(["todo_succession_warning", "reason_code"]) : "completed_advancement_without_successor", count, items, + recommended_action: Object.hasOwn(warning, "recommended_action") ? ref(["todo_succession_warning", "recommended_action"]) : "Review remaining authorized Goal acceptance and the runnable frontier; follow the current quota settlement/replan contract. A summary warning does not authorize terminal action."}; + return {completed_without_successor_count: count, completed_without_successor_items: items, todo_succession_warning: payload}; } diff --git a/loopx/control_plane/todos/quota_summary.py b/loopx/control_plane/todos/quota_summary.py index 1e11253a23..f63c1353f3 100644 --- a/loopx/control_plane/todos/quota_summary.py +++ b/loopx/control_plane/todos/quota_summary.py @@ -1,31 +1,17 @@ from __future__ import annotations -from dataclasses import dataclass from typing import Any -from ..agents.agent_scope import agent_scope_item_claimed_by from ..goals.goal_vision_policy import COMPLETED_TODO_CHAIN_REPLAN_THRESHOLD from ..runtime.time import now_utc -from .contract import ( - TODO_TASK_CLASS_BLOCKER, -) from .quota_selection import project_quota_planning from .frontier_deadline import todo_summary_frontier_deadline -from .todo_semantics import ( - todo_item_task_class, - todo_presentation_sort_key, - todo_summary_monitor_writeback_contract, -) -from .succession_warning import build_todo_succession_warning_lanes from .summary_item import ( - compact_todo_summary_items, todo_planning_source_items, todo_summary_source_items, ) MONITOR_DUE_ITEM_LIMIT = 1 -TODO_BACKLOG_ITEM_LIMIT = 8 -TODO_VISIBILITY_LANE_LIMIT = 16 QUOTA_PAYLOAD_ITEM_TEXT_LIMIT = 180 QUOTA_PAYLOAD_VISIBILITY_LANE_LIMIT = 2 QUOTA_PAYLOAD_USER_ACTION_ITEM_LIMIT = 3 @@ -165,186 +151,19 @@ } -@dataclass(frozen=True) -class _QuotaTodoLanes: - all_open_items: list[dict[str, Any]] - blocking_open_items: list[dict[str, Any]] - user_action_open_items: list[dict[str, Any]] - other_agent_bound_user_action_items: list[dict[str, Any]] - user_action_agent_scope_filter: dict[str, Any] | None - other_agent_scoped_items: list[dict[str, Any]] - agent_scope_filter: dict[str, Any] | None - open_items: list[dict[str, Any]] - claim_scope: dict[str, Any] | None - executable_items: list[dict[str, Any]] - gate_items: list[dict[str, Any]] - monitor_items: list[dict[str, Any]] - monitor_due_items: list[dict[str, Any]] - monitor_schedule_gap_items: list[dict[str, Any]] - watch_only_monitor_items: list[dict[str, Any]] - watch_only_monitor_due_items: list[dict[str, Any]] - non_watch_only_monitor_due_items: list[dict[str, Any]] - monitor_capability_blocked_due_items: list[dict[str, Any]] - claimed_open_items: list[dict[str, Any]] - display_open_items: list[dict[str, Any]] - active_next_action_items: list[dict[str, Any]] - active_next_action_executable_items: list[dict[str, Any]] - open_count: Any - - def summarize_user_todos_for_quota( - value: Any, - *, - agent_identity: dict[str, Any] | None = None, - filter_user_gate_blocks_agent: bool = False, - available_capabilities: Any = None, + value: Any, *, agent_identity: dict[str, Any] | None = None, + filter_user_gate_blocks_agent: bool = False, available_capabilities: Any = None, resolve_capacity: bool = False, ) -> dict[str, Any] | None: if not isinstance(value, dict): return None - all_open_items = sorted( - todo_summary_source_items(value), - key=todo_presentation_sort_key, + return project_quota_planning( + value, all_open_items=[], source_open_count=value.get("open_count"), + agent_identity=agent_identity, filter_user_gate_blocks_agent=filter_user_gate_blocks_agent, + available_capabilities=available_capabilities, resolve_capacity=resolve_capacity, + summary_kind="user", ) - planning = project_quota_planning( - value, - all_open_items=all_open_items, - source_open_count=value.get("open_count", len(all_open_items)), - agent_identity=agent_identity, - filter_user_gate_blocks_agent=filter_user_gate_blocks_agent, - available_capabilities=available_capabilities, - resolve_capacity=resolve_capacity, - ) - lanes = _QuotaTodoLanes(**planning["lanes"]) - resume_planning = planning["resume_planning"] - value = {**value, **(resume_planning["capacity_fields"] or {})} - - blocker_items = [ - item - for item in lanes.all_open_items - if todo_item_task_class(item) == TODO_TASK_CLASS_BLOCKER - and str(item.get("status") or "").strip().lower() == "blocked" - and str(item.get("reason") or "").strip() - ] - agent_id = str((agent_identity or {}).get("agent_id") or "").strip() - recent_completed_advancement_items = compact_todo_summary_items([ - item for item in value.get("recent_completed_advancement_items") or [] - if isinstance(item, dict) - if not agent_id or agent_scope_item_claimed_by(item) == agent_id - ], strip_text=True) - current_agent_blocker_items = [ - item - for item in blocker_items - if agent_id and agent_scope_item_claimed_by(item) == agent_id - ] - summary = { - "schema_version": value.get("schema_version"), - "source_section": value.get("source_section"), - "total_count": value.get("total_count"), - "open_count": lanes.open_count, - "work_counts": planning["work_counts"], - "done_count": value.get("done_count"), - "deferred_count": value.get("deferred_count"), - "source_completeness": planning["source_completeness"], - "first_open_items": lanes.display_open_items[:3], - "first_executable_items": lanes.executable_items[:3], - "gate_open_items": lanes.gate_items, - "monitor_open_items": lanes.monitor_items, - "monitor_due_count": len(lanes.monitor_due_items), - "monitor_due_items": lanes.monitor_due_items[:MONITOR_DUE_ITEM_LIMIT], - "watch_only_monitor_count": len(lanes.watch_only_monitor_items), - "watch_only_monitor_due_count": len(lanes.watch_only_monitor_due_items), - "watch_only_monitor_due_items": lanes.watch_only_monitor_due_items[ - :MONITOR_DUE_ITEM_LIMIT - ], - "non_watch_only_monitor_due_items": lanes.non_watch_only_monitor_due_items[ - :MONITOR_DUE_ITEM_LIMIT - ], - "monitor_capability_blocked_due_count": len( - lanes.monitor_capability_blocked_due_items - ), - "monitor_capability_blocked_due_items": ( - lanes.monitor_capability_blocked_due_items - ), - "monitor_schedule_gap_count": len(lanes.monitor_schedule_gap_items), - "monitor_schedule_gap_items": lanes.monitor_schedule_gap_items[:MONITOR_DUE_ITEM_LIMIT], - "active_next_action_items": lanes.active_next_action_items, - "active_next_action_executable_items": lanes.active_next_action_executable_items, - "backlog_items": lanes.display_open_items[:TODO_BACKLOG_ITEM_LIMIT], - "executable_backlog_items": lanes.executable_items[:TODO_BACKLOG_ITEM_LIMIT], - } - if isinstance(value.get("goal_acceptance_contract"), dict): - summary["goal_acceptance_contract"] = value["goal_acceptance_contract"] - if isinstance(value.get("advancement_frontier_revision_index"), dict): - summary["advancement_frontier_revision_index"] = value[ - "advancement_frontier_revision_index" - ] - if lanes.watch_only_monitor_items: - summary["convergence_open_count"] = value.get("convergence_open_count") - if recent_completed_advancement_items: - summary["recent_completed_advancement_items"] = recent_completed_advancement_items - if isinstance(value.get("vision_wait_states"), list): - summary["vision_wait_states"] = [ - proof for proof in value["vision_wait_states"] - if isinstance(proof, dict) and proof.get("agent_id") == agent_id - ] - if blocker_items: - summary["blocker_open_count"] = len(blocker_items) - if current_agent_blocker_items: - summary["current_agent_blocker_count"] = len(current_agent_blocker_items) - summary["current_agent_blocker_items"] = current_agent_blocker_items[ - :QUOTA_PAYLOAD_DIAGNOSTIC_LANE_LIMIT - ] - if planning["closure_intent"]: - summary["closure_intent"] = planning["closure_intent"] - if planning.get("frontier_deadline"): - summary["frontier_deadline"] = planning["frontier_deadline"] - if planning.get("blocked_retry_wait"): - summary["blocked_retry_wait"] = planning["blocked_retry_wait"] - monitor_writeback = todo_summary_monitor_writeback_contract(value) - if monitor_writeback: - summary["monitor_writeback"] = monitor_writeback - summary.update(planning["claim_visibility"]) - summary.update(resume_planning["deferred_lanes"]) - summary.update(resume_planning["resume_blocked_lanes"]) - summary.update(planning["handoff_lanes"]) - summary.update(planning["route_lanes"]) - summary.update( - build_todo_succession_warning_lanes( - value, - item_limit=TODO_BACKLOG_ITEM_LIMIT, - ) - ) - source_claimed_open_count = None if filter_user_gate_blocks_agent else value.get("claimed_open_count") - if lanes.claimed_open_items or source_claimed_open_count: - summary["claimed_open_count"] = source_claimed_open_count or len(lanes.claimed_open_items) - summary["unclaimed_open_count"] = ( - max(0, int(lanes.open_count or 0) - len(lanes.claimed_open_items)) - if filter_user_gate_blocks_agent - else value.get( - "unclaimed_open_count", - max(0, int(lanes.open_count or 0) - len(lanes.claimed_open_items)), - ) - ) - if lanes.claim_scope: - summary["claim_scope"] = lanes.claim_scope - if filter_user_gate_blocks_agent: - summary["all_open_count"] = value.get("open_count", len(all_open_items)) - if lanes.agent_scope_filter: - summary["agent_scope_filter"] = lanes.agent_scope_filter - summary["other_agent_scoped_open_count"] = len(lanes.other_agent_scoped_items) - summary["other_agent_scoped_items"] = compact_todo_summary_items(lanes.other_agent_scoped_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - if filter_user_gate_blocks_agent and lanes.user_action_open_items: - summary["user_action_open_count"] = len(lanes.user_action_open_items) - summary["user_action_items"] = compact_todo_summary_items(lanes.user_action_open_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - if lanes.user_action_agent_scope_filter: - summary["user_action_agent_scope_filter"] = lanes.user_action_agent_scope_filter - summary["other_agent_bound_user_action_open_count"] = len( - lanes.other_agent_bound_user_action_items - ) - summary["other_agent_bound_user_action_items"] = compact_todo_summary_items( - lanes.other_agent_bound_user_action_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - return summary def _truncate_quota_payload_text(value: Any, *, limit: int) -> Any: @@ -600,123 +419,18 @@ def compact_agent_lane_todos_for_status_display(payload: dict[str, object]) -> N def summarize_project_asset_todos_for_quota( - value: Any, - *, - agent_identity: dict[str, Any] | None = None, - filter_user_gate_blocks_agent: bool = False, - available_capabilities: Any = None, + value: Any, *, agent_identity: dict[str, Any] | None = None, + filter_user_gate_blocks_agent: bool = False, available_capabilities: Any = None, resolve_capacity: bool = False, ) -> dict[str, Any] | None: if not isinstance(value, dict): return None - if ( - isinstance(value.get("items"), list) - or isinstance(value.get("first_open_items"), list) - ) and ( - "total_count" in value or "open_count" in value or "done_count" in value - ): - return summarize_user_todos_for_quota( - value, - agent_identity=agent_identity, - filter_user_gate_blocks_agent=filter_user_gate_blocks_agent, - available_capabilities=available_capabilities, - resolve_capacity=resolve_capacity, - ) - - all_open_items = sorted( - todo_summary_source_items(value), - key=todo_presentation_sort_key, - ) - if not all_open_items: - next_text = str(value.get("next") or "").strip() - next_index = value.get("next_index", 1) - all_open_items = [{"index": next_index, "text": next_text}] if next_text else [] - next_claimed_by = str(value.get("next_claimed_by") or "").strip() - if all_open_items and next_claimed_by: - all_open_items[0]["claimed_by"] = next_claimed_by - planning = project_quota_planning( - value, - all_open_items=all_open_items, - source_open_count=value.get("open", value.get("open_count", len(all_open_items))), - agent_identity=agent_identity, - filter_user_gate_blocks_agent=filter_user_gate_blocks_agent, - available_capabilities=available_capabilities, - resolve_capacity=resolve_capacity, + return project_quota_planning( + value, all_open_items=[], source_open_count=value.get("open_count"), + agent_identity=agent_identity, filter_user_gate_blocks_agent=filter_user_gate_blocks_agent, + available_capabilities=available_capabilities, resolve_capacity=resolve_capacity, + summary_kind="project_asset", ) - lanes = _QuotaTodoLanes(**planning["lanes"]) - resume_planning = planning["resume_planning"] - value = {**value, **(resume_planning["capacity_fields"] or {})} - summary = { - "schema_version": value.get("schema_version"), - "source_section": value.get("source_section") or "project_asset", - "total_count": value.get("total", value.get("total_count")), - "open_count": lanes.open_count, - "work_counts": planning["work_counts"], - "done_count": value.get("done", value.get("done_count")), - "first_open_items": lanes.display_open_items[:3], - "first_executable_items": lanes.executable_items[:3], - "monitor_open_items": lanes.monitor_items, - "monitor_due_count": len(lanes.monitor_due_items), - "monitor_due_items": lanes.monitor_due_items[:MONITOR_DUE_ITEM_LIMIT], - "watch_only_monitor_count": len(lanes.watch_only_monitor_items), - "watch_only_monitor_due_count": len(lanes.watch_only_monitor_due_items), - "watch_only_monitor_due_items": lanes.watch_only_monitor_due_items[ - :MONITOR_DUE_ITEM_LIMIT - ], - "non_watch_only_monitor_due_items": lanes.non_watch_only_monitor_due_items[ - :MONITOR_DUE_ITEM_LIMIT - ], - "monitor_capability_blocked_due_count": len( - lanes.monitor_capability_blocked_due_items - ), - "monitor_capability_blocked_due_items": ( - lanes.monitor_capability_blocked_due_items - ), - "active_next_action_items": lanes.active_next_action_items, - "active_next_action_executable_items": lanes.active_next_action_executable_items, - "backlog_items": lanes.display_open_items[:TODO_BACKLOG_ITEM_LIMIT], - "executable_backlog_items": lanes.executable_items[:TODO_BACKLOG_ITEM_LIMIT], - } - if planning.get("frontier_deadline"): - summary["frontier_deadline"] = planning["frontier_deadline"] - if planning.get("blocked_retry_wait"): - summary["blocked_retry_wait"] = planning["blocked_retry_wait"] - monitor_writeback = todo_summary_monitor_writeback_contract(value) - if monitor_writeback: - summary["monitor_writeback"] = monitor_writeback - summary.update(planning["claim_visibility"]) - summary.update(resume_planning["deferred_lanes"]) - summary.update(planning["handoff_lanes"]) - summary.update(planning["route_lanes"]) - source_claimed_open_count = None if filter_user_gate_blocks_agent else value.get("claimed_open_count") - if lanes.claimed_open_items or source_claimed_open_count: - summary["claimed_open_count"] = source_claimed_open_count or len(lanes.claimed_open_items) - summary["unclaimed_open_count"] = ( - max(0, int(lanes.open_count or 0) - len(lanes.claimed_open_items)) - if filter_user_gate_blocks_agent - else value.get( - "unclaimed_open_count", - max(0, int(lanes.open_count or 0) - len(lanes.claimed_open_items)), - ) - ) - if lanes.claim_scope: - summary["claim_scope"] = lanes.claim_scope - if lanes.agent_scope_filter: - summary["agent_scope_filter"] = lanes.agent_scope_filter - summary["all_open_count"] = value.get("open", value.get("open_count", len(all_open_items))) - summary["other_agent_scoped_open_count"] = len(lanes.other_agent_scoped_items) - summary["other_agent_scoped_items"] = compact_todo_summary_items(lanes.other_agent_scoped_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - if filter_user_gate_blocks_agent and lanes.user_action_open_items: - summary["user_action_open_count"] = len(lanes.user_action_open_items) - summary["user_action_items"] = compact_todo_summary_items(lanes.user_action_open_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - if lanes.user_action_agent_scope_filter: - summary["user_action_agent_scope_filter"] = lanes.user_action_agent_scope_filter - summary["other_agent_bound_user_action_open_count"] = len( - lanes.other_agent_bound_user_action_items - ) - summary["other_agent_bound_user_action_items"] = compact_todo_summary_items( - lanes.other_agent_bound_user_action_items[:TODO_VISIBILITY_LANE_LIMIT], strip_text=True) - return summary def is_canonical_attention_todo_summary(value: Any) -> bool: diff --git a/tests/control_plane/quota_summary_transaction_snapshots.json b/tests/control_plane/quota_summary_transaction_snapshots.json new file mode 100644 index 0000000000..d165fae02e --- /dev/null +++ b/tests/control_plane/quota_summary_transaction_snapshots.json @@ -0,0 +1,157 @@ +{ + "user/non_dict": { + "output": "null", + "calls": {} + }, + "user/empty": { + "output": "{\"schema_version\": null, \"source_section\": null, \"total_count\": null, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": null, \"deferred_count\": null, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "user/user_only": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 1, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"first_executable_items\": [], \"gate_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/agent_scoped": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 2, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 1, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": \"agent-a\"}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"first_executable_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"executable_backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"claimed_advancement_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"claimed_monitor_open_items\": [], \"claimed_advancement_open_count\": 2, \"claimed_monitor_open_count\": 0, \"current_agent_claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"current_agent_claimed_advancement_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"current_agent_claimed_open_count\": 1, \"current_agent_claimed_advancement_count\": 1, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 1, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"claimed_open_count\": 2, \"unclaimed_open_count\": 0, \"claim_scope\": {\"schema_version\": \"agent_claim_scope_v0\", \"agent_id\": \"agent-a\", \"agent_model\": \"peer_v1\", \"selection_order\": \"current_agent_claimed_then_unclaimed\", \"selectable_open_count\": 1, \"current_agent_claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"other_agent_claimed_open_count\": 1, \"other_agent_claimed_weight\": \"diagnostic_only\", \"other_agent_claimed_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"blocked_claimed_open_count\": 1, \"blocked_claimed_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"executor_excluded_self_count\": 0, \"executor_excluded_self_items\": [], \"executor_exclusion_policy\": \"excluded_agents_cannot_claim_or_execute\", \"removed_continuation_blocked_count\": 0, \"removed_continuation_blocked_items\": [], \"removed_continuation_policy\": \"legacy_review_handoffs_fail_closed_until_repaired\"}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/user_actions": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 3, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"current_agent_claimed_open_items\": [], \"current_agent_claimed_advancement_items\": [], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [], \"current_agent_claimed_open_count\": 0, \"current_agent_claimed_advancement_count\": 0, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 0, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"all_open_count\": 3, \"agent_scope_filter\": {\"schema_version\": \"agent_scoped_user_gate_filter_v0\", \"agent_id\": \"agent-a\", \"policy\": \"user todos scoped to another agent by blocks_agent or claimed_by remain visible but do not block this agent's quota lane\", \"current_agent_blocking_open_count\": 0, \"other_agent_scoped_open_count\": 1}, \"other_agent_scoped_open_count\": 1, \"other_agent_scoped_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"blocks_agent\": \"agent-b\"}], \"user_action_open_count\": 1, \"user_action_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"user_action_agent_scope_filter\": {\"schema_version\": \"agent_scoped_user_action_filter_v0\", \"agent_id\": \"agent-a\", \"policy\": \"user actions bound to another agent remain diagnostic-only and must not enter this agent's reminder channel\", \"current_agent_user_action_open_count\": 1, \"other_agent_bound_user_action_open_count\": 1}, \"other_agent_bound_user_action_open_count\": 1, \"other_agent_bound_user_action_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\", \"bound_agent\": \"agent-b\"}]}", + "calls": { + "todo.context.page": 4, + "todo.quota_planning.project": 1 + } + }, + "user/recent_batches": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 0, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"recent_completed_advancement_items\": [{\"index\": 1, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 2, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 3, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 4, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_4\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 5, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_5\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 6, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_6\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 7, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_7\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 8, \"text\": \"Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work. Completed synthetic work.\", \"todo_id\": \"todo_synthetic_8\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1, + "todo.context.page": 3 + } + }, + "user/vision_blockers": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 1, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": \"agent-a\"}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"executable_backlog_items\": [], \"vision_wait_states\": [{\"agent_id\": \"agent-a\", \"state\": \"waiting\"}], \"blocker_open_count\": 1, \"current_agent_blocker_count\": 1, \"current_agent_blocker_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"claimed_advancement_open_count\": 0, \"claimed_monitor_open_count\": 0, \"current_agent_claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"current_agent_claimed_advancement_items\": [], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [], \"current_agent_claimed_open_count\": 1, \"current_agent_claimed_advancement_count\": 0, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 0, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"claim_scope\": {\"schema_version\": \"agent_claim_scope_v0\", \"agent_id\": \"agent-a\", \"agent_model\": \"peer_v1\", \"selection_order\": \"current_agent_claimed_then_unclaimed\", \"selectable_open_count\": 1, \"current_agent_claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"other_agent_claimed_open_count\": 0, \"other_agent_claimed_weight\": \"diagnostic_only\", \"other_agent_claimed_items\": [], \"blocked_claimed_open_count\": 0, \"blocked_claimed_items\": [], \"executor_excluded_self_count\": 0, \"executor_excluded_self_items\": [], \"executor_exclusion_policy\": \"excluded_agents_cannot_claim_or_execute\", \"removed_continuation_blocked_count\": 0, \"removed_continuation_blocked_items\": [], \"removed_continuation_policy\": \"legacy_review_handoffs_fail_closed_until_repaired\"}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/monitors_warnings": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 2, \"open_count\": 2, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 2, \"advancement\": 0, \"monitor\": 2, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"monitor_due_count\": 1, \"monitor_due_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}], \"watch_only_monitor_count\": 1, \"watch_only_monitor_due_count\": 1, \"watch_only_monitor_due_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 1, \"monitor_schedule_gap_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"executable_backlog_items\": [], \"convergence_open_count\": null, \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"completed_without_successor_count\": 2, \"completed_without_successor_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"todo_succession_warning\": {\"schema_version\": \"todo_succession_warning_v0\", \"reason_code\": \"completed_advancement_without_successor\", \"count\": 2, \"items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"done\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"recommended_action\": \"Review remaining authorized Goal acceptance and the runnable frontier; follow the current quota settlement/replan contract. A summary warning does not authorize terminal action.\"}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/legacy_next": { + "output": "{\"schema_version\": null, \"source_section\": null, \"total_count\": null, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": null, \"deferred_count\": null, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "user/malformed_history": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": \"historical\", \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 1, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": \"2\", \"deferred_count\": null, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"first_executable_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"executable_backlog_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"unclaimed_priority_open_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}, \"claimed_open_count\": 1, \"unclaimed_open_count\": 0}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/large_backlog": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 24, \"open_count\": 24, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 24, \"advancement\": 24, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"first_executable_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"executable_backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "user/lossless_metadata": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 9007199254740993, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 1.0, \"deferred_count\": 0, \"source_completeness\": {\"schema_version\": \"todo_source_completeness_v0\", \"status\": \"invalid\", \"source\": \"structured_todo_projection\", \"role\": null, \"terminal_closure\": \"invalid\"}, \"first_open_items\": [], \"first_executable_items\": [], \"gate_open_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"monitor_schedule_gap_count\": 0, \"monitor_schedule_gap_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"goal_acceptance_contract\": {\"revision\": 9007199254740993, \"ratio\": -0.0}, \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "project_asset/non_dict": { + "output": "null", + "calls": {} + }, + "project_asset/empty": { + "output": "{\"schema_version\": null, \"source_section\": \"project_asset\", \"total_count\": null, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": null, \"first_open_items\": [], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "project_asset/user_only": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 1, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"global_gate\": true}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/agent_scoped": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 2, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 1, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": \"agent-a\"}, \"done_count\": 0, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"first_executable_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"executable_backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"claimed_advancement_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"claimed_monitor_open_items\": [], \"claimed_advancement_open_count\": 2, \"claimed_monitor_open_count\": 0, \"current_agent_claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"current_agent_claimed_advancement_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-a\"}], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"current_agent_claimed_open_count\": 1, \"current_agent_claimed_advancement_count\": 1, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 1, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"claimed_open_count\": 2, \"unclaimed_open_count\": 0, \"claim_scope\": {\"schema_version\": \"agent_claim_scope_v0\", \"agent_id\": \"agent-a\", \"agent_model\": \"peer_v1\", \"selection_order\": \"current_agent_claimed_then_unclaimed\", \"selectable_open_count\": 1, \"current_agent_claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"other_agent_claimed_open_count\": 1, \"other_agent_claimed_weight\": \"diagnostic_only\", \"other_agent_claimed_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"blocked_claimed_open_count\": 1, \"blocked_claimed_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\", \"claimed_by\": \"agent-b\"}], \"executor_excluded_self_count\": 0, \"executor_excluded_self_items\": [], \"executor_exclusion_policy\": \"excluded_agents_cannot_claim_or_execute\", \"removed_continuation_blocked_count\": 0, \"removed_continuation_blocked_items\": [], \"removed_continuation_policy\": \"legacy_review_handoffs_fail_closed_until_repaired\"}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/user_actions": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 3, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"first_open_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"current_agent_claimed_open_items\": [], \"current_agent_claimed_advancement_items\": [], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [], \"current_agent_claimed_open_count\": 0, \"current_agent_claimed_advancement_count\": 0, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 0, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"agent_scope_filter\": {\"schema_version\": \"agent_scoped_user_gate_filter_v0\", \"agent_id\": \"agent-a\", \"policy\": \"user todos scoped to another agent by blocks_agent or claimed_by remain visible but do not block this agent's quota lane\", \"current_agent_blocking_open_count\": 0, \"other_agent_scoped_open_count\": 1}, \"all_open_count\": 3, \"other_agent_scoped_open_count\": 1, \"other_agent_scoped_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_gate\", \"blocks_agent\": \"agent-b\"}], \"user_action_open_count\": 1, \"user_action_items\": [{\"index\": 3, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_3\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\"}], \"user_action_agent_scope_filter\": {\"schema_version\": \"agent_scoped_user_action_filter_v0\", \"agent_id\": \"agent-a\", \"policy\": \"user actions bound to another agent remain diagnostic-only and must not enter this agent's reminder channel\", \"current_agent_user_action_open_count\": 1, \"other_agent_bound_user_action_open_count\": 1}, \"other_agent_bound_user_action_open_count\": 1, \"other_agent_bound_user_action_items\": [{\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"user_action\", \"bound_agent\": \"agent-b\"}]}", + "calls": { + "todo.context.page": 4, + "todo.quota_planning.project": 1 + } + }, + "project_asset/recent_batches": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 0, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"first_open_items\": [], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "project_asset/vision_blockers": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 1, \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": \"agent-a\"}, \"done_count\": 0, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"claimed_advancement_open_count\": 0, \"claimed_monitor_open_count\": 0, \"current_agent_claimed_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"blocked\", \"priority\": \"P1\", \"task_class\": \"blocker\", \"claimed_by\": \"agent-a\", \"reason\": \"Synthetic dependency\"}], \"current_agent_claimed_advancement_items\": [], \"current_agent_claimed_monitor_items\": [], \"claimed_by_others_items\": [], \"current_agent_claimed_open_count\": 1, \"current_agent_claimed_advancement_count\": 0, \"current_agent_claimed_monitor_count\": 0, \"claimed_by_others_count\": 0, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}, \"claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"claim_scope\": {\"schema_version\": \"agent_claim_scope_v0\", \"agent_id\": \"agent-a\", \"agent_model\": \"peer_v1\", \"selection_order\": \"current_agent_claimed_then_unclaimed\", \"selectable_open_count\": 1, \"current_agent_claimed_open_count\": 1, \"unclaimed_open_count\": 0, \"other_agent_claimed_open_count\": 0, \"other_agent_claimed_weight\": \"diagnostic_only\", \"other_agent_claimed_items\": [], \"blocked_claimed_open_count\": 0, \"blocked_claimed_items\": [], \"executor_excluded_self_count\": 0, \"executor_excluded_self_items\": [], \"executor_exclusion_policy\": \"excluded_agents_cannot_claim_or_execute\", \"removed_continuation_blocked_count\": 0, \"removed_continuation_blocked_items\": [], \"removed_continuation_policy\": \"legacy_review_handoffs_fail_closed_until_repaired\"}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/monitors_warnings": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 2, \"open_count\": 2, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 2, \"advancement\": 0, \"monitor\": 2, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"first_executable_items\": [], \"monitor_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"monitor_due_count\": 1, \"monitor_due_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}], \"watch_only_monitor_count\": 1, \"watch_only_monitor_due_count\": 1, \"watch_only_monitor_due_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\", \"next_due_at\": \"2020-01-01T00:00:00Z\", \"watch_only\": true}, {\"index\": 2, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_2\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"continuous_monitor\"}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/legacy_next": { + "output": "{\"schema_version\": null, \"source_section\": \"project_asset\", \"total_count\": \"3\", \"open_count\": \"1\", \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 1, \"monitor\": 0, \"hidden\": 0, \"complete\": false, \"agent_id\": null}, \"done_count\": \"2\", \"first_open_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\"}], \"first_executable_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\"}], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\"}], \"executable_backlog_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\"}], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\", \"task_class\": \"advancement_task\"}], \"claimed_advancement_open_items\": [{\"index\": \"7\", \"text\": \"Synthetic next\", \"claimed_by\": \"agent-a\", \"task_class\": \"advancement_task\"}], \"claimed_monitor_open_items\": [], \"claimed_advancement_open_count\": 1, \"claimed_monitor_open_count\": 0, \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}, \"claimed_open_count\": 1, \"unclaimed_open_count\": 0}", + "calls": { + "todo.quota_planning.project": 1 + } + }, + "project_asset/malformed_history": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": \"historical\", \"open_count\": 1, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 1, \"advancement\": 1, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": \"2\", \"first_open_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"first_executable_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"executable_backlog_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"unclaimed_priority_open_items\": [{\"index\": \"2\", \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": 7, \"task_class\": \"advancement_task\", \"claimed_by\": [\"agent-a\"]}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": null, \"complete\": false, \"ready_by_agent\": {}}, \"claimed_open_count\": 1, \"unclaimed_open_count\": 0}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/large_backlog": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 24, \"open_count\": 24, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 24, \"advancement\": 24, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 0, \"first_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"first_executable_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"executable_backlog_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"unclaimed_priority_open_items\": [{\"index\": 1, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_1\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 10, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_10\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 11, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_11\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 12, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_12\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 13, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_13\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 14, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_14\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 15, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_15\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}, {\"index\": 16, \"text\": \"Synthetic work\", \"todo_id\": \"todo_synthetic_16\", \"status\": \"open\", \"priority\": \"P1\", \"task_class\": \"advancement_task\"}], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.context.page": 1, + "todo.quota_planning.project": 1 + } + }, + "project_asset/lossless_metadata": { + "output": "{\"schema_version\": \"todo_summary_v0\", \"source_section\": \"User Todo\", \"total_count\": 9007199254740993, \"open_count\": 0, \"work_counts\": {\"schema_version\": \"todo_work_counts_v0\", \"open\": 0, \"advancement\": 0, \"monitor\": 0, \"hidden\": 0, \"complete\": true, \"agent_id\": null}, \"done_count\": 1.0, \"first_open_items\": [], \"first_executable_items\": [], \"monitor_open_items\": [], \"monitor_due_count\": 0, \"monitor_due_items\": [], \"watch_only_monitor_count\": 0, \"watch_only_monitor_due_count\": 0, \"watch_only_monitor_due_items\": [], \"non_watch_only_monitor_due_items\": [], \"monitor_capability_blocked_due_count\": 0, \"monitor_capability_blocked_due_items\": [], \"active_next_action_items\": [], \"active_next_action_executable_items\": [], \"backlog_items\": [], \"executable_backlog_items\": [], \"unclaimed_priority_open_items\": [], \"claimed_open_items\": [], \"claimed_advancement_open_items\": [], \"claimed_monitor_open_items\": [], \"deferred_work_counts\": {\"ready\": 0, \"blocked\": 0, \"unknown\": 0, \"complete\": true, \"ready_by_agent\": {}}}", + "calls": { + "todo.quota_planning.project": 1 + } + } +} diff --git a/tests/control_plane/test_quota_planning_transport.py b/tests/control_plane/test_quota_planning_transport.py index d77ab6ee08..f0a6c43ae5 100644 --- a/tests/control_plane/test_quota_planning_transport.py +++ b/tests/control_plane/test_quota_planning_transport.py @@ -62,8 +62,27 @@ def test_current_wire_keeps_legacy_full_source_decisions(owned_runtime, monkeypa def compare(method, params, **options): wire = native(method, params, **options) - legacy = native(method, {**params, "schema_version": "todo_quota_planning_request_v3"}, **options) - assert _decode_quota_planning_wire(wire) == legacy + if "summary_request" in params: + from loopx.control_plane.todos.summary_item import todo_summary_source_items + from loopx.control_plane.todos.todo_semantics import todo_presentation_sort_key + + source = params["summary_request"]["source"]["record"] + items = sorted(todo_summary_source_items(source), key=todo_presentation_sort_key) + selection = params["selection"] + # Exercise the old full-source planning carrier as well as the new + # final-summary carrier, preserving the legacy decision oracle. + planning = project_quota_planning( + source, all_open_items=items, source_open_count=source.get("open_count", len(items)), + agent_identity={"agent_id": selection["agent_id"], "agent_profile": selection["profile"]}, + filter_user_gate_blocks_agent=selection["user_gate_scope"], + available_capabilities=selection["available"], resolve_capacity=True, + current_time=params["current_time"], + ) + assert wire["summary"]["work_counts"] == planning["work_counts"] + assert wire["summary"]["first_open_items"] == planning["lanes"]["display_open_items"][:3] + else: + legacy = native(method, {**params, "schema_version": "todo_quota_planning_request_v3"}, **options) + assert _decode_quota_planning_wire(wire) == legacy return wire monkeypatch.setattr(quota_selection, "effect_runtime_result", compare) diff --git a/tests/control_plane/test_quota_summary_source_references.py b/tests/control_plane/test_quota_summary_source_references.py new file mode 100644 index 0000000000..2ce945e853 --- /dev/null +++ b/tests/control_plane/test_quota_summary_source_references.py @@ -0,0 +1,112 @@ +"""Source copies remain Python values; planning/display rows remain JSON values.""" +import json +import math +from copy import deepcopy + +import pytest + +from loopx.control_plane.todos import quota_selection, quota_summary +from loopx.control_plane.todos.active_state_todo_parser import parse_active_state_todos + + +def test_source_values_and_warning_fields_preserve_python_identity(): + metadata = {"revision": 9007199254740993, "ratio": -0.0, "whole": 1.0} + proof = {"agent_id": "agent-a", "metadata": metadata} + completed = {"index": 1.0, "text": "Completed synthetic work", "status": "done", + "task_class": "advancement_task", "completion_recovery": metadata} + source = {"items": [], "total_count": 9007199254740993, "done_count": 1.0, + "deferred_count": -0.0, "goal_acceptance_contract": metadata, + "advancement_frontier_revision_index": metadata, + "vision_wait_states": [proof, {"agent_id": "agent-b"}], + "completed_without_successor_count": 9007199254740993, + "completed_without_successor_items": [completed]} + result = quota_summary.summarize_user_todos_for_quota(source, agent_identity={"agent_id": "agent-a"}) + assert result["total_count"] == 9007199254740993 + assert type(result["done_count"]) is float + assert math.copysign(1, result["deferred_count"]) == -1 + assert result["goal_acceptance_contract"] is metadata + assert result["advancement_frontier_revision_index"] is metadata + assert result["vision_wait_states"][0] is proof + warning = result["completed_without_successor_items"][0] + assert type(warning["index"]) is float + assert warning["completion_recovery"] is metadata + assert result["completed_without_successor_count"] == 9007199254740993 + assert result["todo_succession_warning"]["count"] == 9007199254740993 + assert json.dumps(result["goal_acceptance_contract"]) == json.dumps(metadata) + + +def test_closure_overlay_preserves_unprojected_source_metadata(): + parsed = parse_active_state_todos( + "## Agent Todo\n- [x] [P1] Complete bounded work.\n" + " \n" + )["agent_todos"] + metadata = {"revision": 9007199254740993, "ratio": -0.0} + parsed["closure_intent"]["metadata"] = metadata + result = quota_summary.summarize_user_todos_for_quota(parsed) + assert result["closure_intent"]["metadata"] is metadata + assert result["closure_intent"]["source"] == "todo_no_followup" + + +def test_planning_values_are_not_restored_from_raw_source(): + source = {"open_count": 9007199254740993, "items": [ + {"index": 1.0, "source_section": "User Todo", "text": "First synthetic work", "status": "open"}, + {"index": 2, "source_section": "User Todo", "text": "Second synthetic work", "status": "open"}, + ]} + result = quota_summary.summarize_user_todos_for_quota(source) + assert result["open_count"] == 9007199254740992 + assert [row["index"] for row in result["first_open_items"]] == [1, 2] + assert type(result["first_open_items"][0]["index"]) is int + assert type(source["items"][0]["index"]) is float + + +@pytest.mark.parametrize("raw,expected", [(None, 1), ("1.0", 1), (" 2_0 ", 20), (-2, 0), (True, 1)]) +def test_warning_integer_codec_does_not_choose_the_count(raw, expected): + source = {"items": [], "completed_without_successor_count": raw, + "completed_without_successor_items": [{"text": "Completed work", "status": "done"}]} + result = quota_summary.summarize_user_todos_for_quota(source) + assert result["completed_without_successor_count"] == expected + + +def wire(): + return {"schema_version": "todo_quota_summary_wire_v1", + "summary": {"work_counts": {}, "first_open_items": [], "first_executable_items": [], + "monitor_open_items": [], "backlog_items": [], "total_count": None}, + "source_copies": [{"source": ["total_count"], "target": ["total_count"]}], + "integer_copies": []} + + +@pytest.mark.parametrize("patch", [ + {"source": ["missing"]}, {"target": []}, {"target": ["missing"]}, + {"source": [True]}, {"target": ["first_open_items", -1]}, +]) +def test_invalid_source_reference_is_rejected_without_mutating_source(patch): + value = wire() + value["source_copies"][0].update(patch) + source = {"total_count": {"nested": 1}} + before = deepcopy(source) + with pytest.raises(RuntimeError, match="invalid TypeScript quota summary wire"): + quota_selection._decode_quota_summary_wire(value, source) + assert source == before + + +def test_source_reference_expansion_is_bounded_before_attachment(monkeypatch): + source = {"total_count": "x" * 1000} + value = wire() + monkeypatch.setattr(quota_selection, "MAX_LOCAL_SNAPSHOT_BYTES", 500) + with pytest.raises(RuntimeError, match="expanded response is oversized"): + quota_selection._decode_quota_summary_wire(value, source) + assert value["summary"]["total_count"] is None + + +def test_repeated_planning_rows_are_independent_mutable_copies(): + item = {"todo_id": "todo_mutable", "index": 1, "text": "Synthetic work", + "status": "open", "required_capabilities": ["synthetic.read"]} + source = {"items": [item], "open_count": 1} + result = quota_summary.summarize_user_todos_for_quota(source) + first = result["first_open_items"][0] + backlog = result["backlog_items"][0] + assert first == backlog + assert first is not backlog + first["required_capabilities"].append("synthetic.write") + assert backlog["required_capabilities"] == ["synthetic.read"] + assert item["required_capabilities"] == ["synthetic.read"] diff --git a/tests/control_plane/test_quota_summary_transaction_characterization.py b/tests/control_plane/test_quota_summary_transaction_characterization.py new file mode 100644 index 0000000000..e4322401cf --- /dev/null +++ b/tests/control_plane/test_quota_summary_transaction_characterization.py @@ -0,0 +1,147 @@ +"""Pinned pre-cutover complete results, including lossless Python metadata. + +Snapshots were captured from 867615e2c before any production changes. Retain +these complete-output snapshots as the transaction parity guard. +""" +import json +from collections import Counter +from datetime import datetime, timezone +from pathlib import Path + +import pytest + +from loopx.control_plane import effect_runtime +from loopx.control_plane.todos import quota_selection, quota_summary + + +def row(number=1, **fields): + return {"todo_id": f"todo_synthetic_{number}", "index": number, + "text": "Synthetic work", "status": "open", "priority": "P1", + "task_class": "advancement_task", **fields} + + +def source(rows=None, **fields): + rows = rows or [] + return {"schema_version": "todo_summary_v0", "source_section": "User Todo", + "total_count": len(rows), "open_count": len(rows), "done_count": 0, + "deferred_count": 0, "items": rows, **fields} + + +def cases(): + return { + "non_dict": (None, {}), + "empty": ({}, {}), + "user_only": (source([row(task_class="user_gate", global_gate=True)]), {}), + "agent_scoped": (source([row(claimed_by="agent-a"), row(2, claimed_by="agent-b")]), + {"agent_identity": {"agent_id": "agent-a"}}), + "user_actions": (source([row(task_class="user_gate", blocks_agent="agent-b"), + row(2, task_class="user_action", bound_agent="agent-b"), + row(3, task_class="user_action")]), + {"agent_identity": {"agent_id": "agent-a"}, + "filter_user_gate_blocks_agent": True}), + "recent_batches": (source(recent_completed_advancement_items=[ + row(i, status="done", text="Completed synthetic work. " * 40) + for i in range(1, 9)]), {}), + "vision_blockers": (source([row(task_class="blocker", status="blocked", + reason="Synthetic dependency", claimed_by="agent-a")], + vision_wait_states=[{"agent_id": "agent-a", "state": "waiting"}, + {"agent_id": "agent-b", "state": "waiting"}]), + {"agent_identity": {"agent_id": "agent-a"}}), + "monitors_warnings": (source([ + row(task_class="continuous_monitor", next_due_at="2020-01-01T00:00:00Z", watch_only=True), + row(2, task_class="continuous_monitor")], + completed_without_successor_count="2", completed_without_successor_items=[row(3, status="done")]), {}), + "legacy_next": ({"next": "Synthetic next", "next_index": "7", "next_claimed_by": "agent-a", + "total": "3", "open": "1", "done": "2"}, {}), + "malformed_history": (source([row(priority=7, index="2", claimed_by=["agent-a"])], + total_count="historical", done_count="2", + deferred_count=None, recent_completed_advancement_items=[None, 7]), {}), + "large_backlog": (source([row(i) for i in range(1, 25)]), {}), + "lossless_metadata": (source(total_count=9007199254740993, done_count=1.0, + goal_acceptance_contract={"revision": 9007199254740993, + "ratio": -0.0}), {}), + } + + +def case_input(name, kind): + value, options = cases()[name] + if kind == "project_asset" and isinstance(value, dict) and "total_count" in value: + value = dict(value) + # Exercise the legacy asset composition, rather than its user-summary delegation. + for old, new in (("total_count", "total"), ("open_count", "open"), ("done_count", "done")): + value[new] = value.pop(old) + return value, options + + +@pytest.fixture +def runtime_calls(monkeypatch): + calls = Counter() + original = effect_runtime.effect_runtime_result + + def counted(operation, *args, **kwargs): + calls[operation] += 1 + return original(operation, *args, **kwargs) + + # quota_selection holds an imported reference; summary_item imports lazily. + monkeypatch.setattr(effect_runtime, "effect_runtime_result", counted) + monkeypatch.setattr(quota_selection, "effect_runtime_result", counted) + monkeypatch.setattr(quota_selection, "now_utc", + lambda: datetime(2026, 10, 1, tzinfo=timezone.utc)) + # Exercise display batching with small synthetic rows, without a large fixture. + monkeypatch.setattr(effect_runtime, "MAX_REQUEST_BYTES", 8192) + return calls + + +@pytest.mark.parametrize("kind", ["user", "project_asset"]) +@pytest.mark.parametrize("name", list(cases())) +def test_complete_pre_cutover_output_and_crossings(name, kind, runtime_calls): + value, options = case_input(name, kind) + project = (quota_summary.summarize_user_todos_for_quota if kind == "user" + else quota_summary.summarize_project_asset_todos_for_quota) + result = project(value, **options) + expected = json.loads(Path(__file__).with_name("quota_summary_transaction_snapshots.json").read_text()) + snapshot = expected[f"{kind}/{name}"] + assert json.dumps(result, sort_keys=False) == snapshot["output"] + assert dict(runtime_calls) == ({"todo.quota_planning.project": 1} if snapshot["calls"] else {}) + if name == "lossless_metadata": + assert result["total_count"] == 9007199254740993 + assert type(result["total_count"]) is int + assert type(result["done_count"]) is float + if name == "large_backlog": + assert len(result["backlog_items"]) == 8 + if name == "legacy_next" and kind == "project_asset": + assert result["first_open_items"][0]["index"] == "7" + + +@pytest.mark.parametrize("kind", ["user", "project_asset"]) +def test_owner_refusal_propagates_without_fallback(kind, monkeypatch): + calls = [] + + def refuse(operation, *args, **kwargs): + calls.append(operation) + raise effect_runtime.EffectRuntimeRejected("synthetic owner refusal") + + monkeypatch.setattr(effect_runtime, "effect_runtime_result", refuse) + monkeypatch.setattr(quota_selection, "effect_runtime_result", refuse) + project = (quota_summary.summarize_user_todos_for_quota if kind == "user" + else quota_summary.summarize_project_asset_todos_for_quota) + with pytest.raises(ValueError, match="synthetic owner refusal"): + project({}) + assert calls == ["todo.quota_planning.project"] + + +def test_plain_javascript_json_transport_cannot_preserve_current_metadata(): + import subprocess + + source_value = cases()["lossless_metadata"][0] + encoded = json.dumps(source_value, sort_keys=False) + transported = subprocess.check_output( + ["node", "-e", "let s='';process.stdin.on('data',c=>s+=c);" + "process.stdin.on('end',()=>process.stdout.write(JSON.stringify(JSON.parse(s))))"], + input=encoded, text=True, + ) + decoded = json.loads(transported) + assert source_value["total_count"] == 9007199254740993 + assert decoded["total_count"] == 9007199254740992 + assert type(source_value["done_count"]) is float + assert type(decoded["done_count"]) is int diff --git a/tests/control_plane_ts/quota_summary_transaction.test.ts b/tests/control_plane_ts/quota_summary_transaction.test.ts new file mode 100644 index 0000000000..39858b6a4f --- /dev/null +++ b/tests/control_plane_ts/quota_summary_transaction.test.ts @@ -0,0 +1,90 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import type {JsonObject} from "../../loopx/control_plane/effect_program.ts"; +import {composeQuotaSummary, prepareQuotaSummary} from "../../loopx/control_plane/todos/quota_selection.ts"; + +function planning(): JsonObject { + return {lanes: { + all_open_items: [], display_open_items: [], executable_items: [], gate_items: [], monitor_items: [], + monitor_due_items: [], watch_only_monitor_items: [], watch_only_monitor_due_items: [], + non_watch_only_monitor_due_items: [], monitor_capability_blocked_due_items: [], monitor_schedule_gap_items: [], + active_next_action_items: [], active_next_action_executable_items: [], claimed_open_items: [], + other_agent_scoped_items: [], user_action_open_items: [], other_agent_bound_user_action_items: [], open_count: 0, + }, resume_planning: {capacity_fields: null, deferred_lanes: {}, resume_blocked_lanes: {resume_blocked_count: 2}}, + work_counts: {open: 0}, source_completeness: {complete: true}, claim_visibility: {}, handoff_lanes: {}, route_lanes: {}, + closure_intent: null}; +} +function request(source: JsonObject, fields: JsonObject = {}): JsonObject { + return {summary_request: {source: {record: source}, source_rows: {}, kind: "user", integer_counts: {source: source.completed_without_successor_count == null ? null : String(source.completed_without_successor_count), warning: null}, ...fields}, + selection: {agent_id: "agent-a", user_gate_scope: false}, handoff_items: []}; +} +function restored(wire: JsonObject, source: JsonObject): JsonObject { + const result = structuredClone(wire.summary) as JsonObject; + for (const copy of wire.source_copies as {source: (string | number)[]; target: (string | number)[]}[]) { + let value: any = source, parent: any = result; + for (const key of copy.source) value = value[key]; + for (const key of copy.target.slice(0, -1)) parent = parent[key]; + parent[copy.target.at(-1)!] = value; + } + return result; +} + +test("source metadata and selected Vision proofs use references; planning counts remain normalized", () => { + const source = {total_count: 17, done_count: 2, goal_acceptance_contract: {ratio: 0}, + vision_wait_states: [{agent_id: "agent-b"}, {agent_id: "agent-a", evidence: {revision: 3}}]}; + const wire = composeQuotaSummary(request(source), planning()); + assert.deepEqual((wire.source_copies as JsonObject[]).map(row => row.source), + [["total_count"], ["done_count"], ["goal_acceptance_contract"], ["vision_wait_states", 1]]); + const result = restored(wire, source); + assert.equal(result.goal_acceptance_contract, source.goal_acceptance_contract); + assert.deepEqual(result.vision_wait_states, [source.vision_wait_states[1]]); + assert.equal(result.open_count, 0); +}); + +test("legacy assets omit user-only closure, warning and blocked-resume lanes", () => { + const source = {total: "4", done: "3", completed_without_successor_count: 2}; + const p = planning(); p.closure_intent = {kind: "no_followup"}; + const result = restored(composeQuotaSummary(request(source, {legacy: true}), p), source); + assert.equal(result.source_section, "project_asset"); + assert.equal(result.total_count, "4"); + assert.equal(result.done_count, "3"); + for (const key of ["closure_intent", "todo_succession_warning", "resume_blocked_count", "gate_open_items", "source_completeness"]) + assert.equal(Object.hasOwn(result, key), false, key); +}); + +test("summary admits one monitor while retaining the complete due count and bounded backlog", () => { + const p = planning(), lanes = p.lanes as JsonObject; + const items = Array.from({length: 20}, (_, index) => ({index, text: "Observe synthetic state"})); + Object.assign(lanes, {monitor_due_items: items, watch_only_monitor_due_items: items, + watch_only_monitor_items: items, display_open_items: items, executable_items: items}); + const source = {convergence_open_count: 3}; + const result = restored(composeQuotaSummary(request(source), p), source); + assert.equal(result.monitor_due_count, 20); + assert.equal((result.monitor_due_items as unknown[]).length, 1); + assert.equal((result.backlog_items as unknown[]).length, 8); + assert.equal((result.first_open_items as unknown[]).length, 3); +}); + +test("warning projection preserves source-only values while normalizing task class and scopes", () => { + const source = {completed_without_successor_count: "2", completed_without_successor_items: [ + {index: 7, text: "Completed work", priority: "P1", status: "done", task_class: "advancement_task", completion_recovery: {revision: 9}}, + ]}; + const result = restored(composeQuotaSummary(request(source), planning()), source); + assert.equal(result.completed_without_successor_count, 2); + const items = result.completed_without_successor_items as JsonObject[]; + assert.equal(items[0]!.completion_recovery, source.completed_without_successor_items[0]!.completion_recovery); + assert.equal(items[0]!.task_class, "advancement_task"); + assert.deepEqual((result.todo_succession_warning as JsonObject).items, items); +}); + +test("source provenance follows lane precedence even when equal identities carry conflicting facts", () => { + const first = {todo_id: "todo_same", index: 1, text: "Preferred source", task_class: "user_gate"}; + const second = {...first, text: "Discarded source", task_class: "advancement_task"}; + const input = request({items: [second], first_open_items: [first]}); + const fact = (payload: JsonObject, gate: boolean) => ({payload, gate, presentation: [1, 999999, "", "todo_same"]}); + (input.summary_request as JsonObject).source_rows = {items: [fact(second, false)], first_open_items: [fact(first, true)]}; + const selected = (prepareQuotaSummary(input).selection as JsonObject).items as JsonObject[]; + assert.equal(selected.length, 1); + assert.equal(selected[0]!.gate, true); + assert.equal((selected[0]!.payload as JsonObject).text, "Preferred source"); +});