Commit 1a8f99c2ea80e01d133b3877f563b713aac1f19d

Authored by graphlemon
1 parent ebbc1623

graphlemon: auto-commit uncommitted changes for judgment-e93a0c64d8fe-main-checkout-drift

src/task_query.py
... ... @@ -13,6 +13,8 @@ forcing the frontend to make N more round trips.
13 13  
14 14 import json
15 15  
  16 +from src import work_graph_plan
  17 +
16 18 _SORT_COLUMNS = ("created_at", "updated_at", "goal_text", "status")
17 19  
18 20  
... ... @@ -274,6 +276,29 @@ def _loop_back_events_for_run(conn, run_id):
274 276 return events
275 277  
276 278  
  279 +def _display_graph_manifest(graph_manifest, nodes):
  280 + """v_task_detail's to-do tree/DAG (renderTodoTree/renderGraphVisualizerPanel
  281 + in frontend/app.js) render straight off graph_manifest.nodes, in array
  282 + order -- but work_graph_run.graph_manifest itself deliberately never
  283 + includes the planning call that produced it (work_graph_plan.py's
  284 + _record_planning_node docstring: run_graph()/fork/append-mode all read
  285 + that column too and must only ever see real, executable nodes). This
  286 + prepends a display-only node for that planning call -- sourced from the
  287 + real work_node_execution row _record_planning_node already wrote (same
  288 + node_exec_id, same log, same output_payload every other node gets) --
  289 + so it shows up as the first, clickable entry in both views without the
  290 + persisted manifest itself ever changing. Runs from before this feature
  291 + existed have no such row and come back unchanged."""
  292 + if graph_manifest is None:
  293 + return None
  294 + if not any(n["node_id"] == work_graph_plan.PLANNING_NODE_ID for n in nodes):
  295 + return graph_manifest
  296 + planning_node = {
  297 + "node_id": work_graph_plan.PLANNING_NODE_ID, "artifact_type": "graph_manifest", "depends_on": [],
  298 + }
  299 + return {"nodes": [planning_node] + graph_manifest["nodes"], "edges": graph_manifest.get("edges", [])}
  300 +
  301 +
277 302 def _work_nodes_for_run(conn, run_id):
278 303 # input_schema_ref/output_schema_ref/quota_limit_type/quota_wait_started_at
279 304 # added for U-026's hover tooltip + waiting_for_quota display (02-V §2.7:
... ...
src/test_e2e_pipeline.py
... ... @@ -775,13 +775,17 @@ class ReviewPlannerOutputWithRetriesTest(PipelineTestBase):
775 775 # Both attempts' nodes exist in the SAME run's work_node_execution,
776 776 # and the first attempt's already-'done' node was skipped (not
777 777 # re-executed) the second time around -- exactly 2 trigger_org_
778   - # node_structured calls total, not 3.
  778 + # node_structured calls total, not 3. "__planning__" is the fresh
  779 + # (first) plan_work_graph() call's own synthetic node
  780 + # (work_graph_plan._record_planning_node) -- only the fresh branch
  781 + # records one, so the re-plan (append_to_run_id) doesn't add a
  782 + # second.
779 783 node_ids = {
780 784 row[0] for row in self.conn.execute(
781 785 "SELECT node_id FROM work_node_execution WHERE run_id = ?", (shared_run_id,)
782 786 ).fetchall()
783 787 }
784   - self.assertEqual(node_ids, {"sdd", "sdd_v2"})
  788 + self.assertEqual(node_ids, {"__planning__", "sdd", "sdd_v2"})
785 789 self.assertEqual(mock_trigger_structured.call_count, 2)
786 790  
787 791 # The final PASS'd artifact is the SECOND attempt's content.
... ...