fix(investigation): persist large results and require graph links
Full-network pressure comparisons exceeded the worker limit before saved-result previews could run. Preserve complete calculation results and keep read-time summaries and pagination. Incremental graph publication accepted isolated nodes after flow-authoring rules were lost. Require new steps to connect explicitly while retaining historical snapshots and status-only patches. Regression tests reproduce both failures on the previous code.
This commit is contained in:
@@ -93,8 +93,8 @@ async def execute_child(input_path: str, output_path: str):
|
||||
category = 'EXECUTION_CONTEXT_UNAVAILABLE'
|
||||
payload = {'status': 'failed', 'error': {'code': category}}
|
||||
encoded = json.dumps(payload, allow_nan=False)
|
||||
if len(encoded.encode()) > 8 * 1024 * 1024:
|
||||
encoded = json.dumps({'status': 'failed', 'error': {'code': 'RESULT_TOO_LARGE'}})
|
||||
# Keep the complete calculation for persistence. MCP result reads apply
|
||||
# their own summary/page budgets after the result has been saved.
|
||||
Path(output_path).write_text(encoded)
|
||||
|
||||
|
||||
@@ -212,8 +212,6 @@ class CalculationWorker:
|
||||
terminal = {'status': 'timed_out', 'error': {'code': 'EXECUTION_TIMEOUT'}}
|
||||
elif process.returncode is not None:
|
||||
try:
|
||||
if output_path.stat().st_size > 8 * 1024 * 1024:
|
||||
raise ValueError('Result exceeds persistence limit')
|
||||
terminal = json.loads(output_path.read_text())
|
||||
except (OSError, ValueError):
|
||||
terminal = {'status': 'failed', 'error': {'code': 'CHILD_PROCESS_FAILED'}}
|
||||
|
||||
@@ -39,6 +39,7 @@ def update_investigation_graph(
|
||||
))
|
||||
|
||||
nodes = {node.node_id: node.model_copy(deep=True) for node in previous.node_refs} if previous else {}
|
||||
saved_ids = set(nodes)
|
||||
require(len({node.node_id for node in update.nodes}) == len(update.nodes),
|
||||
"GRAPH_NODE_DUPLICATE", "Graph update contains duplicate node ids", status=422)
|
||||
for node in update.nodes:
|
||||
@@ -81,6 +82,26 @@ def update_investigation_graph(
|
||||
edges.append(edge.model_copy(deep=True))
|
||||
require(len(nodes) <= 100 and len(edges) <= 200, "GRAPH_CAPACITY_EXCEEDED",
|
||||
"Investigation graph exceeds 100 nodes or 200 edges; existing paths were retained", status=422)
|
||||
# Validate only newly added steps. Historical snapshots and status-only
|
||||
# patches stay valid, even if an earlier publisher omitted relationships.
|
||||
new_ids = set(nodes) - saved_ids
|
||||
if new_ids and len(nodes) > 1:
|
||||
neighbours = {node_id: set() for node_id in nodes}
|
||||
for edge in edges:
|
||||
neighbours[edge.source].add(edge.target)
|
||||
neighbours[edge.target].add(edge.source)
|
||||
connected = set(saved_ids) or {next(iter(nodes))}
|
||||
pending = list(connected)
|
||||
while pending:
|
||||
for node_id in neighbours[pending.pop()] - connected:
|
||||
connected.add(node_id)
|
||||
pending.append(node_id)
|
||||
missing = sorted(new_ids - connected)
|
||||
require(not missing, "GRAPH_RELATION_REQUIRED",
|
||||
"Add explicit edges connecting these new steps to the investigation narrative: "
|
||||
+ ", ".join(missing)
|
||||
+ ". Describe branches, parallel findings or retries; edges do not schedule execution.",
|
||||
status=422)
|
||||
lines = [source or "flowchart TD"]
|
||||
for node in nodes.values():
|
||||
if in_source(node.node_id):
|
||||
|
||||
Reference in New Issue
Block a user