Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/reference/protocols/task-graph-projection-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ The source of truth remains:
- run-history evidence and blocker writebacks.

The projection may appear under `attention_queue.items[].task_graph_projection`
in `loopx --format json status`. Full
in `loopx --format json status --include-task-graph`. Default status output
keeps this object on the cold path so the dashboard hot path remains within its
interface budget. Full
`loopx --format json review-packet --goal-id <goal-id>` output may
include the same object for operator review. The handoff-only review-packet
surface should stay compact and omit the graph unless a future interface budget
Expand Down
13 changes: 8 additions & 5 deletions docs/status-data-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,14 @@ card or timeline, but project truth still comes from the registry, active
state, quota guard, and append-only run history.

Rows may also include an optional `task_graph_projection` object with
`schema_version=task_graph_projection_v0`. This is a compact graph-shaped view
over existing todos, gates, leases, run ids, and event-ledger state. It is
read-only and exists only to show dependency, validation, repair, and handoff
relationships that are hard to scan in a flat todo list. It must not introduce a
second scheduler, graph write API, hidden lease store, or alternate task truth.
`schema_version=task_graph_projection_v0`. The default `status` hot path omits
this graph to preserve the dashboard interface budget; callers that need the
graph can request it with `loopx --format json status --include-task-graph`, or
use a full review packet. This is a compact graph-shaped view over existing
todos, gates, leases, run ids, and event-ledger state. It is read-only and
exists only to show dependency, validation, repair, and handoff relationships
that are hard to scan in a flat todo list. It must not introduce a second
scheduler, graph write API, hidden lease store, or alternate task truth.
The protocol is defined in
[`docs/reference/protocols/task-graph-projection-v0.md`](reference/protocols/task-graph-projection-v0.md);
consumers should ignore the field when absent.
Expand Down
3 changes: 3 additions & 0 deletions examples/hot-path-interface-budget-smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,9 @@ def main() -> int:
scan_roots=[project],
limit=5,
)
status_items = status_payload["attention_queue"]["items"]
assert status_items, status_payload
assert "task_graph_projection" not in status_items[0], status_items[0]
quota_payload = build_quota_should_run(status_payload, goal_id=GOAL_ID)
review_packet = build_review_packet(status_payload, goal_id=GOAL_ID, action_kind="codex")
handoff_payload = review_packet_handoff_only_payload(review_packet)
Expand Down
11 changes: 11 additions & 0 deletions loopx/cli_commands/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ def register_status_commands(
"to matching status queue items."
),
)
status_parser.add_argument(
"--include-task-graph",
action="store_true",
help=(
"Include the optional task_graph_projection_v0 on status items. "
"Default status output keeps this graph on the cold path to stay "
"inside the dashboard hot-path budget."
),
)

diagnose_parser = subparsers.add_parser(
"diagnose",
Expand Down Expand Up @@ -208,6 +217,7 @@ def handle_status_command(
runtime_root_override=runtime_root_arg,
scan_roots=_scan_roots(args),
limit=max(0, args.limit),
include_task_graph=args.include_task_graph,
)
if args.agent_id:
attach_agent_lane_next_actions(payload, agent_id=args.agent_id)
Expand Down Expand Up @@ -357,6 +367,7 @@ def handle_review_packet_command(
runtime_root_override=runtime_root_arg,
scan_roots=_scan_roots(args),
limit=max(0, args.limit),
include_task_graph=not args.handoff_only,
)
payload = build_review_packet(
status_payload,
Expand Down
18 changes: 11 additions & 7 deletions loopx/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -8608,6 +8608,7 @@ def build_attention_queue(
history: dict[str, Any],
global_registry: dict[str, Any],
runtime_root: Path | None = None,
include_task_graph: bool = False,
) -> dict[str, Any]:
health_items: list[dict[str, Any]] = []
history_items: list[dict[str, Any]] = []
Expand Down Expand Up @@ -8785,13 +8786,14 @@ def build_attention_queue(
interface_budget_cadence=interface_budget_cadence,
)
normalize_monitor_quiet_attention_display(item)
task_graph_projection = build_task_graph_projection(
item,
goal=goal,
goal_latest_runs=goal_latest_runs,
)
if task_graph_projection:
item["task_graph_projection"] = task_graph_projection
if include_task_graph:
task_graph_projection = build_task_graph_projection(
item,
goal=goal,
goal_latest_runs=goal_latest_runs,
)
if task_graph_projection:
item["task_graph_projection"] = task_graph_projection
attach_goal_channel_projection(
item,
goal=goal,
Expand Down Expand Up @@ -9671,6 +9673,7 @@ def collect_status(
runtime_root_override: str | None,
scan_roots: list[Path],
limit: int,
include_task_graph: bool = False,
) -> dict[str, Any]:
display_limit = max(0, limit)
control_plane_limit = max(display_limit, STATUS_CONTROL_PLANE_CONTEXT_LIMIT)
Expand Down Expand Up @@ -9700,6 +9703,7 @@ def collect_status(
history=history,
global_registry=global_registry,
runtime_root=runtime_root,
include_task_graph=include_task_graph,
)
run_history = build_run_history(history, display_limit=display_limit)
event_ledger_summary = build_event_ledger_summary(history)
Expand Down