diff --git a/apps/fabro-web/app/test-fixtures/petri/command.json b/apps/fabro-web/app/test-fixtures/petri/command.json new file mode 100644 index 000000000..3f14ddb55 --- /dev/null +++ b/apps/fabro-web/app/test-fixtures/petri/command.json @@ -0,0 +1,3013 @@ +{ + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "projection": { + "title": "Run one command", + "spec": { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Command", + "nodes": { + "say": { + "id": "say", + "attrs": { + "script": { + "String": "echo hello from petri" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + }, + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "say", + "attrs": {} + }, + { + "from": "say", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Run one command" + } + } + }, + "graph_source": "digraph Command {\n graph [goal=\"Run one command\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n say [shape=parallelogram, script=\"echo hello from petri\"]\n start -> say -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "a65150b821e21c843ede6b06fe0ed2bc6af498746a3c6883f1ee4328ef6d5c55", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c0d89c0b36f18d693a61729efcca4e4763204f6faaa458cf66e2468050622e84", + "engine": { + "kind": "petri", + "graph": { + "blob": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa", + "digest": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa" + } + } + }, + "web_url": "http://localhost:3000/runs/01M2SD6BARCTFZJGSKBDFR90KS", + "start": { + "start_time": "2026-09-18T04:42:59.346Z" + }, + "status": { + "kind": "succeeded", + "reason": "completed" + }, + "status_updated_at": "2026-09-18T04:42:59.522Z", + "last_event_at": "2026-09-18T04:42:59.532Z", + "pending_control": null, + "checkpoints": [], + "conclusion": { + "timestamp": "2026-09-18T04:42:59.522Z", + "status": "succeeded", + "timing": { + "wall_time_ms": 176, + "inference_time_ms": 0, + "tool_time_ms": 42, + "active_time_ms": 42 + }, + "total_retries": 0, + "diff": {} + }, + "sandbox": { + "kind": "planned", + "plan": { + "provider": "local" + } + }, + "pull_request": null, + "superseded_by": null, + "pending_interviews": {}, + "stages": { + "start@1": { + "first_event_seq": 62, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.412Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN is not a Git repository; the workspace starts empty\n", + "output_bytes": 130, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.349Z", + "handler": "start", + "graph_visit": 1, + "timing": { + "wall_time_ms": 10, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "exit@1": { + "first_event_seq": 168, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.455Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.455Z", + "handler": "exit", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "say@1": { + "first_event_seq": 125, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.455Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "hello from petri\n", + "output_bytes": 17, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.412Z", + "handler": "command", + "graph_visit": 1, + "timing": { + "wall_time_ms": 42, + "inference_time_ms": 0, + "tool_time_ms": 42, + "active_time_ms": 42 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + } + } + }, + "stream": [ + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 1, + "kind": "platform", + "id": "1", + "recorded_at": 1789706579288, + "item": { + "seq": 1, + "recorded_at": 1789706579288, + "record": { + "kind": "run.created", + "spec": { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Command", + "nodes": { + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + }, + "say": { + "id": "say", + "attrs": { + "script": { + "String": "echo hello from petri" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "say", + "attrs": {} + }, + { + "from": "say", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Run one command" + } + } + }, + "graph_source": "digraph Command {\n graph [goal=\"Run one command\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n say [shape=parallelogram, script=\"echo hello from petri\"]\n start -> say -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "a65150b821e21c843ede6b06fe0ed2bc6af498746a3c6883f1ee4328ef6d5c55", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c0d89c0b36f18d693a61729efcca4e4763204f6faaa458cf66e2468050622e84", + "engine": { + "kind": "petri", + "graph": { + "blob": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa", + "digest": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa" + } + } + }, + "title": "Run one command", + "web_url": "http://localhost:3000/runs/01M2SD6BARCTFZJGSKBDFR90KS" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 2, + "kind": "platform", + "id": "2", + "recorded_at": 1789706579330, + "item": { + "seq": 2, + "recorded_at": 1789706579330, + "record": { + "kind": "run.lifecycle", + "transition": "submitted", + "status": { + "kind": "submitted" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 3, + "kind": "platform", + "id": "3", + "recorded_at": 1789706579333, + "item": { + "seq": 3, + "recorded_at": 1789706579333, + "record": { + "kind": "run.lifecycle", + "transition": "start_requested", + "source": "start" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 4, + "kind": "platform", + "id": "4", + "recorded_at": 1789706579333, + "item": { + "seq": 4, + "recorded_at": 1789706579333, + "record": { + "kind": "run.lifecycle", + "transition": "runnable", + "status": { + "kind": "runnable" + }, + "source": "start_requested" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 5, + "kind": "platform", + "id": "5", + "recorded_at": 1789706579334, + "item": { + "seq": 5, + "recorded_at": 1789706579334, + "record": { + "kind": "run.lifecycle", + "transition": "starting", + "status": { + "kind": "starting" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 6, + "kind": "platform", + "id": "6", + "recorded_at": 1789706579334, + "item": { + "seq": 6, + "recorded_at": 1789706579334, + "record": { + "kind": "run.lifecycle", + "transition": "running", + "status": { + "kind": "running" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 7, + "kind": "petri", + "id": "coordinator/0/0", + "recorded_at": 1789706579346, + "item": { + "id": { + "log": "coordinator", + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579346, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579346, + "body": { + "event": "run.started", + "format_version": 5, + "key": "01M2SD6BARCTFZJGSKBDFR90KS", + "root": 0, + "middleware_chain": [ + "circuit-breaker" + ] + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 8, + "kind": "petri", + "id": "coordinator/1/0", + "recorded_at": 1789706579347, + "item": { + "id": { + "log": "coordinator", + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579347, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579347, + "body": { + "event": "graph.registered", + "digest": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 9, + "kind": "petri", + "id": "coordinator/2/0", + "recorded_at": 1789706579348, + "item": { + "id": { + "log": "coordinator", + "seq": 2, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579348, + "record": { + "seq": 2, + "origin": "external", + "recorded_at": 1789706579348, + "body": { + "event": "invocation.declared", + "invocation": 0, + "call": null, + "graph": "0ff5a9360b8cadf9a13c7a024104c2a2e0ce0244589fc81f00a0afc76ab756fa", + "context": {}, + "secret_bindings": "none", + "sandbox": "isolated" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 10, + "kind": "petri", + "id": "coordinator/3/0", + "recorded_at": 1789706579348, + "item": { + "id": { + "log": "coordinator", + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579348, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579348, + "body": { + "event": "execution.declared", + "execution": 0, + "invocation": 0, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 11, + "kind": "petri", + "id": "execution 0/0/0", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579349, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579349, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 12, + "kind": "petri", + "id": "execution 0/1/0", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579349, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579349, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 13, + "kind": "petri", + "id": "execution 0/1/1", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579349, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 2, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 14, + "kind": "petri", + "id": "execution 0/1/2", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579349, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 15, + "kind": "petri", + "id": "execution 0/2/0", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579349, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579349, + "body": { + "event": "token.emitted", + "edge": 2, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 16, + "kind": "petri", + "id": "execution 0/3/0", + "recorded_at": 1789706579349, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579349, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579349, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 17, + "kind": "petri", + "id": "execution 0/4/0", + "recorded_at": 1789706579401, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579401, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579401, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 18, + "kind": "petri", + "id": "execution 0/4/1", + "recorded_at": 1789706579401, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579401, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 19, + "kind": "petri", + "id": "execution 0/5/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stderr", + "line": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpj0wBpN is not a Git repository; the workspace starts empty" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 20, + "kind": "petri", + "id": "execution 0/6/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 10 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 21, + "kind": "petri", + "id": "execution 0/6/1", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 10 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 22, + "kind": "petri", + "id": "execution 0/7/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 0 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 23, + "kind": "petri", + "id": "execution 0/7/1", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + ] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 24, + "kind": "petri", + "id": "execution 0/7/2", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 25, + "kind": "petri", + "id": "execution 0/8/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 8, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 8, + "origin": "core", + "recorded_at": 1789706579412, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 1, + "group": 0, + "edge": 0 + } + }, + "derived": { + "target": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 26, + "kind": "petri", + "id": "execution 0/9/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 9, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "say", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 9, + "origin": "core", + "recorded_at": 1789706579412, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 27, + "kind": "petri", + "id": "execution 0/10/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 10, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 10, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 2, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 28, + "kind": "petri", + "id": "execution 0/11/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 11, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "step.started", + "firing": 2, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 29, + "kind": "petri", + "id": "execution 0/11/1", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 30, + "kind": "petri", + "id": "execution 0/12/0", + "recorded_at": 1789706579427, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579427, + "record": { + "seq": 12, + "origin": "external", + "recorded_at": 1789706579427, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "log": { + "stream": "stdout", + "line": "hello from petri" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 31, + "kind": "petri", + "id": "execution 0/13/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 13, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "step.finished", + "firing": 2, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "hello from petri\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 42 + }, + "context_updates": { + "command.output": "hello from petri\n", + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 32, + "kind": "petri", + "id": "execution 0/13/1", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "hello from petri\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 42 + }, + "context_updates": { + "command.output": "hello from petri\n", + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 33, + "kind": "petri", + "id": "execution 0/14/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 14, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 2, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 1 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 34, + "kind": "petri", + "id": "execution 0/14/1", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 1, + "generation": 0, + "payload": { + "exit_status": 0, + "stdout": "hello from petri\n", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + ] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 35, + "kind": "petri", + "id": "execution 0/14/2", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 36, + "kind": "petri", + "id": "execution 0/15/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 15, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 15, + "origin": "core", + "recorded_at": 1789706579455, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 2, + "group": 0, + "edge": 1 + } + }, + "derived": { + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 37, + "kind": "petri", + "id": "execution 0/16/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "say", + "kind": "attractor/command", + "meta": { + "label": "say", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 16, + "origin": "core", + "recorded_at": 1789706579455, + "body": { + "event": "token.emitted", + "edge": 1, + "generation": 0, + "payload": { + "exit_status": 0, + "stdout": "hello from petri\n", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 38, + "kind": "petri", + "id": "execution 0/17/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 17, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 17, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 3, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 39, + "kind": "petri", + "id": "execution 0/18/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 18, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 18, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "step.started", + "firing": 3, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 40, + "kind": "petri", + "id": "execution 0/18/1", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 18, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 41, + "kind": "petri", + "id": "execution 0/19/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 19, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "step.finished", + "firing": 3, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 42, + "kind": "petri", + "id": "execution 0/19/1", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 43, + "kind": "petri", + "id": "execution 0/20/0", + "recorded_at": 1789706579455, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 20, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579455, + "record": { + "seq": 20, + "origin": "external", + "recorded_at": 1789706579455, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 3, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 44, + "kind": "petri", + "id": "coordinator/4/0", + "recorded_at": 1789706579456, + "item": { + "id": { + "log": "coordinator", + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579456, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579456, + "body": { + "event": "execution.finished", + "execution": 0, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 45, + "kind": "petri", + "id": "coordinator/5/0", + "recorded_at": 1789706579456, + "item": { + "id": { + "log": "coordinator", + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579456, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579456, + "body": { + "event": "invocation.finished", + "invocation": 0, + "result": { + "status": "success", + "failure": null, + "final_execution": 0, + "output": null, + "context": { + "command.output": "hello from petri\n", + "failure_class": "", + "internal.run_id": "petri" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 46, + "kind": "petri", + "id": "coordinator/6/0", + "recorded_at": 1789706579522, + "item": { + "id": { + "log": "coordinator", + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579522, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579522, + "body": { + "event": "run.finished", + "status": "success" + } + } + } + }, + { + "run_id": "01M2SD6BARCTFZJGSKBDFR90KS", + "stream_seq": 47, + "kind": "platform", + "id": "7", + "recorded_at": 1789706579532, + "item": { + "seq": 7, + "recorded_at": 1789706579532, + "record": { + "kind": "run.lifecycle", + "transition": "succeeded", + "status": { + "kind": "succeeded", + "reason": "completed" + } + } + } + } + ] +} \ No newline at end of file diff --git a/apps/fabro-web/app/test-fixtures/petri/gate.json b/apps/fabro-web/app/test-fixtures/petri/gate.json new file mode 100644 index 000000000..01b2e7a7d --- /dev/null +++ b/apps/fabro-web/app/test-fixtures/petri/gate.json @@ -0,0 +1,4271 @@ +{ + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "projection": { + "title": "Ask before running", + "spec": { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Gate", + "nodes": { + "no": { + "id": "no", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/no" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "yes": { + "id": "yes", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/yes" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + }, + "gate": { + "id": "gate", + "attrs": { + "shape": { + "String": "hexagon" + }, + "label": { + "String": "Go?" + }, + "question_type": { + "String": "yes_no" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "gate", + "attrs": {} + }, + { + "from": "gate", + "to": "yes", + "attrs": { + "label": { + "String": "[Y] Yes" + } + } + }, + { + "from": "gate", + "to": "no", + "attrs": { + "label": { + "String": "[N] No" + } + } + }, + { + "from": "yes", + "to": "exit", + "attrs": {} + }, + { + "from": "no", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Ask before running" + } + } + }, + "graph_source": "digraph Gate {\n graph [goal=\"Ask before running\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n gate [shape=hexagon, label=\"Go?\", question_type=\"yes_no\"]\n yes [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/yes\"]\n no [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/no\"]\n start -> gate\n gate -> yes [label=\"[Y] Yes\"]\n gate -> no [label=\"[N] No\"]\n yes -> exit\n no -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "3ec107957ebbb3305da5c0aab203a827cc07cc645ac5ea831a294cdc0a541531", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c123e9d2a4d52bcefab60c09ca1bc1ec280ba5d765b062eda931e8ae66bac3ea", + "engine": { + "kind": "petri", + "graph": { + "blob": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020", + "digest": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020" + } + } + }, + "web_url": "http://localhost:3000/runs/01M2SD6BB066XN12A42XHFBC5D", + "start": { + "start_time": "2026-09-18T04:42:59.342Z" + }, + "status": { + "kind": "succeeded", + "reason": "completed" + }, + "status_updated_at": "2026-09-18T04:42:59.530Z", + "last_event_at": "2026-09-18T04:42:59.534Z", + "pending_control": null, + "checkpoints": [], + "conclusion": { + "timestamp": "2026-09-18T04:42:59.530Z", + "status": "succeeded", + "timing": { + "wall_time_ms": 188, + "inference_time_ms": 0, + "tool_time_ms": 34, + "active_time_ms": 34 + }, + "total_retries": 0, + "diff": {} + }, + "sandbox": { + "kind": "planned", + "plan": { + "provider": "local" + } + }, + "pull_request": null, + "superseded_by": null, + "pending_interviews": {}, + "stages": { + "start@1": { + "first_event_seq": 50, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.392Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px is not a Git repository; the workspace starts empty\n", + "output_bytes": 130, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.345Z", + "handler": "start", + "graph_visit": 1, + "timing": { + "wall_time_ms": 22, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "exit@1": { + "first_event_seq": 187, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.482Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.482Z", + "handler": "exit", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "gate@1": { + "first_event_seq": 97, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.447Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "waiting for an answer: Go?\n", + "output_bytes": 27, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.392Z", + "handler": "human", + "graph_visit": 1, + "timing": { + "wall_time_ms": 54, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "no@1": { + "first_event_seq": 152, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.482Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.447Z", + "handler": "command", + "graph_visit": 1, + "timing": { + "wall_time_ms": 34, + "inference_time_ms": 0, + "tool_time_ms": 34, + "active_time_ms": 34 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + } + } + }, + "stream": [ + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 1, + "kind": "platform", + "id": "1", + "recorded_at": 1789706579296, + "item": { + "seq": 1, + "recorded_at": 1789706579296, + "record": { + "kind": "run.created", + "spec": { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Gate", + "nodes": { + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + }, + "gate": { + "id": "gate", + "attrs": { + "label": { + "String": "Go?" + }, + "shape": { + "String": "hexagon" + }, + "question_type": { + "String": "yes_no" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + }, + "yes": { + "id": "yes", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/yes" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "no": { + "id": "no", + "attrs": { + "shape": { + "String": "parallelogram" + }, + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/no" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "gate", + "attrs": {} + }, + { + "from": "gate", + "to": "yes", + "attrs": { + "label": { + "String": "[Y] Yes" + } + } + }, + { + "from": "gate", + "to": "no", + "attrs": { + "label": { + "String": "[N] No" + } + } + }, + { + "from": "yes", + "to": "exit", + "attrs": {} + }, + { + "from": "no", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Ask before running" + } + } + }, + "graph_source": "digraph Gate {\n graph [goal=\"Ask before running\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n gate [shape=hexagon, label=\"Go?\", question_type=\"yes_no\"]\n yes [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/yes\"]\n no [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp2whQsw/no\"]\n start -> gate\n gate -> yes [label=\"[Y] Yes\"]\n gate -> no [label=\"[N] No\"]\n yes -> exit\n no -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "3ec107957ebbb3305da5c0aab203a827cc07cc645ac5ea831a294cdc0a541531", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c123e9d2a4d52bcefab60c09ca1bc1ec280ba5d765b062eda931e8ae66bac3ea", + "engine": { + "kind": "petri", + "graph": { + "blob": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020", + "digest": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020" + } + } + }, + "title": "Ask before running", + "web_url": "http://localhost:3000/runs/01M2SD6BB066XN12A42XHFBC5D" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 2, + "kind": "platform", + "id": "2", + "recorded_at": 1789706579335, + "item": { + "seq": 2, + "recorded_at": 1789706579335, + "record": { + "kind": "run.lifecycle", + "transition": "submitted", + "status": { + "kind": "submitted" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 3, + "kind": "platform", + "id": "3", + "recorded_at": 1789706579338, + "item": { + "seq": 3, + "recorded_at": 1789706579338, + "record": { + "kind": "run.lifecycle", + "transition": "start_requested", + "source": "start" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 4, + "kind": "platform", + "id": "4", + "recorded_at": 1789706579339, + "item": { + "seq": 4, + "recorded_at": 1789706579339, + "record": { + "kind": "run.lifecycle", + "transition": "runnable", + "status": { + "kind": "runnable" + }, + "source": "start_requested" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 5, + "kind": "platform", + "id": "5", + "recorded_at": 1789706579340, + "item": { + "seq": 5, + "recorded_at": 1789706579340, + "record": { + "kind": "run.lifecycle", + "transition": "starting", + "status": { + "kind": "starting" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 6, + "kind": "platform", + "id": "6", + "recorded_at": 1789706579340, + "item": { + "seq": 6, + "recorded_at": 1789706579340, + "record": { + "kind": "run.lifecycle", + "transition": "running", + "status": { + "kind": "running" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 7, + "kind": "petri", + "id": "coordinator/0/0", + "recorded_at": 1789706579342, + "item": { + "id": { + "log": "coordinator", + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579342, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579342, + "body": { + "event": "run.started", + "format_version": 5, + "key": "01M2SD6BB066XN12A42XHFBC5D", + "root": 0, + "middleware_chain": [ + "circuit-breaker" + ] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 8, + "kind": "petri", + "id": "coordinator/1/0", + "recorded_at": 1789706579343, + "item": { + "id": { + "log": "coordinator", + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579343, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579343, + "body": { + "event": "graph.registered", + "digest": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 9, + "kind": "petri", + "id": "coordinator/2/0", + "recorded_at": 1789706579343, + "item": { + "id": { + "log": "coordinator", + "seq": 2, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579343, + "record": { + "seq": 2, + "origin": "external", + "recorded_at": 1789706579343, + "body": { + "event": "invocation.declared", + "invocation": 0, + "call": null, + "graph": "9a44afdc3c2f9b780b22be7a709443239b1bf3b0ed3f4558e6266b3482a8f020", + "context": {}, + "secret_bindings": "none", + "sandbox": "isolated" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 10, + "kind": "petri", + "id": "coordinator/3/0", + "recorded_at": 1789706579343, + "item": { + "id": { + "log": "coordinator", + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579343, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579343, + "body": { + "event": "execution.declared", + "execution": 0, + "invocation": 0, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 11, + "kind": "petri", + "id": "execution 0/0/0", + "recorded_at": 1789706579344, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579344, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579344, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 12, + "kind": "petri", + "id": "execution 0/1/0", + "recorded_at": 1789706579345, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579345, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579345, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 13, + "kind": "petri", + "id": "execution 0/1/1", + "recorded_at": 1789706579345, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579345, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 5, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 14, + "kind": "petri", + "id": "execution 0/1/2", + "recorded_at": 1789706579345, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579345, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 15, + "kind": "petri", + "id": "execution 0/2/0", + "recorded_at": 1789706579345, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579345, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579345, + "body": { + "event": "token.emitted", + "edge": 5, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 16, + "kind": "petri", + "id": "execution 0/3/0", + "recorded_at": 1789706579345, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579345, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579345, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 17, + "kind": "petri", + "id": "execution 0/4/0", + "recorded_at": 1789706579370, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579370, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579370, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 18, + "kind": "petri", + "id": "execution 0/4/1", + "recorded_at": 1789706579370, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579370, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 19, + "kind": "petri", + "id": "execution 0/5/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579392, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stderr", + "line": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp7qg1px is not a Git repository; the workspace starts empty" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 20, + "kind": "petri", + "id": "execution 0/6/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579392, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 22 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 21, + "kind": "petri", + "id": "execution 0/6/1", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 22 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 22, + "kind": "petri", + "id": "execution 0/7/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579392, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 0 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 23, + "kind": "petri", + "id": "execution 0/7/1", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 24, + "kind": "petri", + "id": "execution 0/7/2", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 25, + "kind": "petri", + "id": "execution 0/8/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 8, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "record": { + "seq": 8, + "origin": "core", + "recorded_at": 1789706579392, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 1, + "group": 0, + "edge": 0 + } + }, + "derived": { + "target": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 26, + "kind": "petri", + "id": "execution 0/9/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 9, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "gate", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579392, + "record": { + "seq": 9, + "origin": "core", + "recorded_at": 1789706579392, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 27, + "kind": "petri", + "id": "execution 0/10/0", + "recorded_at": 1789706579393, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 10, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579393, + "record": { + "seq": 10, + "origin": "external", + "recorded_at": 1789706579393, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 2, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 28, + "kind": "petri", + "id": "execution 0/11/0", + "recorded_at": 1789706579393, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579393, + "record": { + "seq": 11, + "origin": "external", + "recorded_at": 1789706579393, + "body": { + "event": "step.started", + "firing": 2, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 29, + "kind": "petri", + "id": "execution 0/11/1", + "recorded_at": 1789706579393, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579393, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 30, + "kind": "petri", + "id": "execution 0/12/0", + "recorded_at": 1789706579393, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579393, + "record": { + "seq": 12, + "origin": "external", + "recorded_at": 1789706579393, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "$question": { + "id": "gate#2", + "text": "Go?", + "options": [ + { + "key": "Y", + "label": "[Y] Yes" + }, + { + "key": "N", + "label": "[N] No" + } + ], + "default": "Y", + "freeform": false, + "sensitive": false, + "kind": "yes_no" + } + } + } + } + }, + "derived": { + "parsed": { + "kind": "question", + "question": { + "id": "gate#2", + "text": "Go?", + "options": [ + { + "key": "Y", + "label": "[Y] Yes" + }, + { + "key": "N", + "label": "[N] No" + } + ], + "default": "Y", + "freeform": false, + "sensitive": false, + "kind": "yes_no" + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 31, + "kind": "petri", + "id": "execution 0/12/1", + "recorded_at": 1789706579393, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579393, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_answer" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 32, + "kind": "petri", + "id": "execution 0/13/0", + "recorded_at": 1789706579397, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579397, + "record": { + "seq": 13, + "origin": "external", + "recorded_at": 1789706579397, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "log": { + "stream": "stdout", + "line": "waiting for an answer: Go?" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 33, + "kind": "platform", + "id": "7", + "recorded_at": 1789706579446, + "item": { + "seq": 7, + "recorded_at": 1789706579446, + "record": { + "kind": "interview.answered", + "question": "gate#2", + "principal": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 34, + "kind": "petri", + "id": "execution 0/14/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 14, + "origin": "external", + "recorded_at": 1789706579447, + "body": { + "event": "control.requested", + "firing": 2, + "ctl": { + "deliver": { + "$answer": { + "question": "gate#2", + "choice": "N" + } + } + } + } + }, + "derived": { + "deliverable": true, + "answer": { + "question": "gate#2", + "choice": "N" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 35, + "kind": "petri", + "id": "execution 0/14/1", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 36, + "kind": "petri", + "id": "execution 0/15/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 15, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 15, + "origin": "external", + "recorded_at": 1789706579447, + "body": { + "event": "step.finished", + "firing": 2, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "preferred_label": "No", + "suggested_next_ids": [ + "no" + ], + "choice": "N", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 54 + }, + "context_updates": { + "failure_class": "", + "human.gate.gate.answer": "no", + "human.gate.gate.label": "[N] No", + "human.gate.gate.question": "Go?", + "human.gate.label": "[N] No", + "human.gate.selected": "N" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 37, + "kind": "petri", + "id": "execution 0/15/1", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 15, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "preferred_label": "No", + "suggested_next_ids": [ + "no" + ], + "choice": "N", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 54 + }, + "context_updates": { + "failure_class": "", + "human.gate.gate.answer": "no", + "human.gate.gate.label": "[N] No", + "human.gate.gate.question": "Go?", + "human.gate.label": "[N] No", + "human.gate.selected": "N" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 38, + "kind": "petri", + "id": "execution 0/16/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 16, + "origin": "external", + "recorded_at": 1789706579447, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 2, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 2 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 39, + "kind": "petri", + "id": "execution 0/16/1", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 2, + "generation": 0, + "payload": { + "preferred_label": "No", + "suggested_next_ids": [ + "no" + ], + "choice": "N", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 40, + "kind": "petri", + "id": "execution 0/16/2", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 41, + "kind": "petri", + "id": "execution 0/17/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 17, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 17, + "origin": "core", + "recorded_at": 1789706579447, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 2, + "group": 0, + "edge": 2 + } + }, + "derived": { + "target": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 42, + "kind": "petri", + "id": "execution 0/18/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 18, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "gate", + "kind": "attractor/human", + "meta": { + "label": "Go?", + "shape": "hexagon", + "kind": "human", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "edges": { + "1": { + "to": "yes", + "label": "[Y] Yes" + }, + "2": { + "to": "no", + "label": "[N] No" + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 18, + "origin": "core", + "recorded_at": 1789706579447, + "body": { + "event": "token.emitted", + "edge": 2, + "generation": 0, + "payload": { + "preferred_label": "No", + "suggested_next_ids": [ + "no" + ], + "choice": "N", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 43, + "kind": "petri", + "id": "execution 0/19/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 19, + "origin": "external", + "recorded_at": 1789706579447, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 3, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 44, + "kind": "petri", + "id": "execution 0/20/0", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 20, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "record": { + "seq": 20, + "origin": "external", + "recorded_at": 1789706579447, + "body": { + "event": "step.started", + "firing": 3, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 45, + "kind": "petri", + "id": "execution 0/20/1", + "recorded_at": 1789706579447, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 20, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579447, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 46, + "kind": "petri", + "id": "execution 0/21/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 21, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 21, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "step.finished", + "firing": 3, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 34 + }, + "context_updates": { + "command.output": "", + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 47, + "kind": "petri", + "id": "execution 0/21/1", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 21, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 34 + }, + "context_updates": { + "command.output": "", + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 48, + "kind": "petri", + "id": "execution 0/22/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 22, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 22, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 3, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 4 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 49, + "kind": "petri", + "id": "execution 0/22/1", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 22, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 4, + "generation": 0, + "payload": { + "exit_status": 0, + "stdout": "", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 3 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 50, + "kind": "petri", + "id": "execution 0/22/2", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 22, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 51, + "kind": "petri", + "id": "execution 0/23/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 23, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 23, + "origin": "core", + "recorded_at": 1789706579482, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 3, + "group": 0, + "edge": 4 + } + }, + "derived": { + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 52, + "kind": "petri", + "id": "execution 0/24/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 24, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "no", + "kind": "attractor/command", + "meta": { + "label": "no", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "4": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 24, + "origin": "core", + "recorded_at": 1789706579482, + "body": { + "event": "token.emitted", + "edge": 4, + "generation": 0, + "payload": { + "exit_status": 0, + "stdout": "", + "outcome": "succeeded", + "failure_class": "" + }, + "from": 3 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 53, + "kind": "petri", + "id": "execution 0/25/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 25, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 25, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 4, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 54, + "kind": "petri", + "id": "execution 0/26/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 26, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 26, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "step.started", + "firing": 4, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 55, + "kind": "petri", + "id": "execution 0/26/1", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 26, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 56, + "kind": "petri", + "id": "execution 0/27/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 27, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "step.finished", + "firing": 4, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 57, + "kind": "petri", + "id": "execution 0/27/1", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 58, + "kind": "petri", + "id": "execution 0/28/0", + "recorded_at": 1789706579482, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 28, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579482, + "record": { + "seq": 28, + "origin": "external", + "recorded_at": 1789706579482, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 4, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 59, + "kind": "petri", + "id": "coordinator/4/0", + "recorded_at": 1789706579483, + "item": { + "id": { + "log": "coordinator", + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579483, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579483, + "body": { + "event": "execution.finished", + "execution": 0, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 60, + "kind": "petri", + "id": "coordinator/5/0", + "recorded_at": 1789706579483, + "item": { + "id": { + "log": "coordinator", + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579483, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579483, + "body": { + "event": "invocation.finished", + "invocation": 0, + "result": { + "status": "success", + "failure": null, + "final_execution": 0, + "output": null, + "context": { + "command.output": "", + "failure_class": "", + "human.gate.gate.answer": "no", + "human.gate.gate.label": "[N] No", + "human.gate.gate.question": "Go?", + "human.gate.label": "[N] No", + "human.gate.selected": "N", + "internal.run_id": "petri" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 61, + "kind": "petri", + "id": "coordinator/6/0", + "recorded_at": 1789706579530, + "item": { + "id": { + "log": "coordinator", + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579530, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579530, + "body": { + "event": "run.finished", + "status": "success" + } + } + } + }, + { + "run_id": "01M2SD6BB066XN12A42XHFBC5D", + "stream_seq": 62, + "kind": "platform", + "id": "8", + "recorded_at": 1789706579534, + "item": { + "seq": 8, + "recorded_at": 1789706579534, + "record": { + "kind": "run.lifecycle", + "transition": "succeeded", + "status": { + "kind": "succeeded", + "reason": "completed" + } + } + } + } + ] +} \ No newline at end of file diff --git a/apps/fabro-web/app/test-fixtures/petri/hello.json b/apps/fabro-web/app/test-fixtures/petri/hello.json new file mode 100644 index 000000000..16efba292 --- /dev/null +++ b/apps/fabro-web/app/test-fixtures/petri/hello.json @@ -0,0 +1,4387 @@ +{ + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "projection": { + "title": "Say hello and demonstrate a basic Fabro workflow", + "spec": { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {}, + "engine": "petri" + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": "gpt-5.4", + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Hello", + "nodes": { + "exit": { + "id": "exit", + "attrs": { + "label": { + "String": "Exit" + }, + "shape": { + "String": "Msquare" + } + } + }, + "greet": { + "id": "greet", + "attrs": { + "label": { + "String": "Greet" + }, + "prompt": { + "String": "Add a haiku to the README" + } + } + }, + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + }, + "label": { + "String": "Start" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "greet", + "attrs": {} + }, + { + "from": "greet", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "rankdir": { + "String": "LR" + }, + "goal": { + "String": "Say hello and demonstrate a basic Fabro workflow" + } + } + }, + "graph_source": "digraph Hello {\n graph [goal=\"Say hello and demonstrate a basic Fabro workflow\"]\n rankdir=LR\n\n start [shape=Mdiamond, label=\"Start\"]\n exit [shape=Msquare, label=\"Exit\"]\n\n greet [label=\"Greet\", prompt=\"Add a haiku to the README\"]\n\n start -> greet -> exit\n}\n", + "workflow_slug": "workflow", + "workflow_version_id": "170dd4ba80b17475c7c2ad832fe0765d26ed889b45f4c923e8cc590fa56ceee2", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c1d31000e7e8b33773f19288456ca595123b7657264a3fc00434a30f36ef2fd0", + "engine": { + "kind": "petri", + "graph": { + "blob": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647", + "digest": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647" + } + } + }, + "web_url": "http://localhost:3000/runs/01M2SD6BB8VBFYDZK0A45HGAAQ", + "start": { + "start_time": "2026-09-18T04:42:59.351Z" + }, + "status": { + "kind": "succeeded", + "reason": "completed" + }, + "status_updated_at": "2026-09-18T04:42:59.704Z", + "last_event_at": "2026-09-18T04:42:59.708Z", + "pending_control": null, + "checkpoints": [], + "conclusion": { + "timestamp": "2026-09-18T04:42:59.704Z", + "status": "succeeded", + "timing": { + "wall_time_ms": 353, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + }, + "total_retries": 0, + "diff": {} + }, + "sandbox": { + "kind": "planned", + "plan": { + "provider": "local" + } + }, + "pull_request": null, + "superseded_by": null, + "pending_interviews": {}, + "stages": { + "greet@1": { + "first_event_seq": 126, + "prompt": null, + "response": "A haiku, added.", + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.662Z" + }, + "provider_used": { + "mode": "agent", + "provider": "openai", + "model": "gpt-5.4" + }, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "A haiku, added.\n", + "output_bytes": 16, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.429Z", + "handler": "agent", + "graph_visit": 1, + "timing": { + "wall_time_ms": 232, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + }, + "model": { + "provider": "openai", + "model_id": "gpt-5.4" + }, + "agent": { + "root_session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "route": { + "provider": "openai", + "model": "gpt-5.4" + }, + "activity": "ended", + "usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + }, + "messages": 1, + "descendants": {}, + "context_window": { + "provider": "openai", + "model": "gpt-5.4", + "context_window_tokens": 1050000, + "input_tokens": 1, + "usage_percent": 0.00009523809523809524, + "count_method": "response_usage_scaled_breakdown", + "staleness": "live", + "generated_at": "2026-09-18T04:42:59.661Z", + "breakdown": [ + { + "category": "system_prompt", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "tools", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "conversation", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "other", + "tokens": 1, + "usage_percent": 0.00009523809523809524 + } + ], + "warnings": [] + }, + "tools": {}, + "retries": 0, + "mcp_servers": {}, + "skills": { + "available": [], + "activated": [] + }, + "subagent_counts": { + "spawned": 0, + "turns_started": 0, + "completed": 0, + "failed": 0, + "closed": 0 + }, + "todos": {}, + "subagents": [], + "compactions": [], + "failovers": [], + "files_touched": [], + "last_file_touched": null, + "prompts": 1, + "prompt": { + "completed": true, + "usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + }, + "messages": 1, + "context_window": { + "provider": "openai", + "model": "gpt-5.4", + "context_window_tokens": 1050000, + "input_tokens": 1, + "usage_percent": 0.00009523809523809524, + "count_method": "response_usage_scaled_breakdown", + "staleness": "live", + "generated_at": "2026-09-18T04:42:59.661Z", + "breakdown": [ + { + "category": "system_prompt", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "tools", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "conversation", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "other", + "tokens": 1, + "usage_percent": 0.00009523809523809524 + } + ], + "warnings": [] + }, + "tool_calls": 0, + "retries": 0, + "failovers": 0, + "descendants": {}, + "subagents": { + "spawned": 0, + "turns_started": 0, + "completed": 0, + "failed": 0, + "closed": 0 + }, + "compactions": [], + "files_touched": [], + "last_file_touched": null + } + }, + "state": "succeeded" + }, + "start@1": { + "first_event_seq": 62, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.429Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG is not a Git repository; the workspace starts empty\n", + "output_bytes": 130, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.365Z", + "handler": "start", + "graph_visit": 1, + "timing": { + "wall_time_ms": 17, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "exit@1": { + "first_event_seq": 359, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.662Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.662Z", + "handler": "exit", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + } + } + }, + "stream": [ + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 1, + "kind": "platform", + "id": "1", + "recorded_at": 1789706579304, + "item": { + "seq": 1, + "recorded_at": 1789706579304, + "record": { + "kind": "run.created", + "spec": { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {}, + "engine": "petri" + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": "gpt-5.4", + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Hello", + "nodes": { + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + }, + "label": { + "String": "Start" + } + } + }, + "greet": { + "id": "greet", + "attrs": { + "label": { + "String": "Greet" + }, + "prompt": { + "String": "Add a haiku to the README" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "label": { + "String": "Exit" + }, + "shape": { + "String": "Msquare" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "greet", + "attrs": {} + }, + { + "from": "greet", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "rankdir": { + "String": "LR" + }, + "goal": { + "String": "Say hello and demonstrate a basic Fabro workflow" + } + } + }, + "graph_source": "digraph Hello {\n graph [goal=\"Say hello and demonstrate a basic Fabro workflow\"]\n rankdir=LR\n\n start [shape=Mdiamond, label=\"Start\"]\n exit [shape=Msquare, label=\"Exit\"]\n\n greet [label=\"Greet\", prompt=\"Add a haiku to the README\"]\n\n start -> greet -> exit\n}\n", + "workflow_slug": "workflow", + "workflow_version_id": "170dd4ba80b17475c7c2ad832fe0765d26ed889b45f4c923e8cc590fa56ceee2", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "c1d31000e7e8b33773f19288456ca595123b7657264a3fc00434a30f36ef2fd0", + "engine": { + "kind": "petri", + "graph": { + "blob": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647", + "digest": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647" + } + } + }, + "title": "Say hello and demonstrate a basic Fabro workflow", + "web_url": "http://localhost:3000/runs/01M2SD6BB8VBFYDZK0A45HGAAQ" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 2, + "kind": "platform", + "id": "2", + "recorded_at": 1789706579341, + "item": { + "seq": 2, + "recorded_at": 1789706579341, + "record": { + "kind": "run.lifecycle", + "transition": "submitted", + "status": { + "kind": "submitted" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 3, + "kind": "platform", + "id": "3", + "recorded_at": 1789706579346, + "item": { + "seq": 3, + "recorded_at": 1789706579346, + "record": { + "kind": "run.lifecycle", + "transition": "start_requested", + "source": "start" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 4, + "kind": "platform", + "id": "4", + "recorded_at": 1789706579347, + "item": { + "seq": 4, + "recorded_at": 1789706579347, + "record": { + "kind": "run.lifecycle", + "transition": "runnable", + "status": { + "kind": "runnable" + }, + "source": "start_requested" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 5, + "kind": "platform", + "id": "5", + "recorded_at": 1789706579348, + "item": { + "seq": 5, + "recorded_at": 1789706579348, + "record": { + "kind": "run.lifecycle", + "transition": "starting", + "status": { + "kind": "starting" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 6, + "kind": "platform", + "id": "6", + "recorded_at": 1789706579349, + "item": { + "seq": 6, + "recorded_at": 1789706579349, + "record": { + "kind": "run.lifecycle", + "transition": "running", + "status": { + "kind": "running" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 7, + "kind": "petri", + "id": "coordinator/0/0", + "recorded_at": 1789706579351, + "item": { + "id": { + "log": "coordinator", + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579351, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579351, + "body": { + "event": "run.started", + "format_version": 5, + "key": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "root": 0, + "middleware_chain": [ + "circuit-breaker" + ] + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 8, + "kind": "petri", + "id": "coordinator/1/0", + "recorded_at": 1789706579352, + "item": { + "id": { + "log": "coordinator", + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579352, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579352, + "body": { + "event": "graph.registered", + "digest": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 9, + "kind": "petri", + "id": "coordinator/2/0", + "recorded_at": 1789706579353, + "item": { + "id": { + "log": "coordinator", + "seq": 2, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579353, + "record": { + "seq": 2, + "origin": "external", + "recorded_at": 1789706579353, + "body": { + "event": "invocation.declared", + "invocation": 0, + "call": null, + "graph": "c863cb5271554b25115dec3bb6cbcdb9790298a21fb837973a43d0fa658f9647", + "context": {}, + "secret_bindings": "none", + "sandbox": "isolated" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 10, + "kind": "petri", + "id": "coordinator/3/0", + "recorded_at": 1789706579355, + "item": { + "id": { + "log": "coordinator", + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579355, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579355, + "body": { + "event": "execution.declared", + "execution": 0, + "invocation": 0, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 11, + "kind": "petri", + "id": "execution 0/0/0", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579365, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579365, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 12, + "kind": "petri", + "id": "execution 0/1/0", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579365, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579365, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 13, + "kind": "petri", + "id": "execution 0/1/1", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579365, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 2, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 14, + "kind": "petri", + "id": "execution 0/1/2", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579365, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 15, + "kind": "petri", + "id": "execution 0/2/0", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579365, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579365, + "body": { + "event": "token.emitted", + "edge": 2, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 16, + "kind": "petri", + "id": "execution 0/3/0", + "recorded_at": 1789706579365, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579365, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579365, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 17, + "kind": "petri", + "id": "execution 0/4/0", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579412, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 18, + "kind": "petri", + "id": "execution 0/4/1", + "recorded_at": 1789706579412, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579412, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 19, + "kind": "petri", + "id": "execution 0/5/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stderr", + "line": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmp9wt8EG is not a Git repository; the workspace starts empty" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 20, + "kind": "petri", + "id": "execution 0/6/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 17 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 21, + "kind": "petri", + "id": "execution 0/6/1", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 17 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 22, + "kind": "petri", + "id": "execution 0/7/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 0 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 23, + "kind": "petri", + "id": "execution 0/7/1", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": { + "from": "start", + "fidelity": null, + "thread_id": null + }, + "from": 1 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 24, + "kind": "petri", + "id": "execution 0/7/2", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 25, + "kind": "petri", + "id": "execution 0/8/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 8, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 8, + "origin": "core", + "recorded_at": 1789706579429, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 1, + "group": 0, + "edge": 0 + } + }, + "derived": { + "target": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 26, + "kind": "petri", + "id": "execution 0/9/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 9, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "Start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 5, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "greet", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 9, + "origin": "core", + "recorded_at": 1789706579429, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": { + "from": "start", + "fidelity": null, + "thread_id": null + }, + "from": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 27, + "kind": "petri", + "id": "execution 0/10/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 10, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 10, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 2, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 28, + "kind": "petri", + "id": "execution 0/11/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 11, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "step.started", + "firing": 2, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 29, + "kind": "petri", + "id": "execution 0/11/1", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 30, + "kind": "petri", + "id": "execution 0/12/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 12, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "attractor.thread", + "node": "greet", + "firing": 2, + "attempt": 1, + "fidelity": "compact", + "fidelity_source": "default", + "thread": "start", + "thread_source": "previous", + "reused": false, + "backend": "api" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 31, + "kind": "petri", + "id": "execution 0/13/0", + "recorded_at": 1789706579429, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579429, + "record": { + "seq": 13, + "origin": "external", + "recorded_at": 1789706579429, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "attractor.fallback.plan", + "node": "greet", + "firing": 2, + "attempt": 1, + "requested": { + "provider": "openai", + "model": "gpt-5.4" + }, + "routes": [ + { + "position": 0, + "provider": "openai", + "model": "gpt-5.4", + "reasoning_effort": null, + "speed": null + } + ], + "notices": [] + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 32, + "kind": "petri", + "id": "execution 0/14/0", + "recorded_at": 1789706579469, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579469, + "record": { + "seq": 14, + "origin": "external", + "recorded_at": 1789706579469, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 1, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "SessionStarted": { + "provider": "openai", + "model": "gpt-5.4" + } + }, + "timestamp": "2026-09-18T04:42:59.469Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 33, + "kind": "petri", + "id": "execution 0/15/0", + "recorded_at": 1789706579619, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 15, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579619, + "record": { + "seq": 15, + "origin": "external", + "recorded_at": 1789706579619, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 2, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "MemoryLoaded": { + "profile": "openai", + "files": [], + "total_loaded_bytes": 0, + "budget_bytes": 32768 + } + }, + "timestamp": "2026-09-18T04:42:59.618Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 34, + "kind": "petri", + "id": "execution 0/16/0", + "recorded_at": 1789706579619, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579619, + "record": { + "seq": 16, + "origin": "external", + "recorded_at": 1789706579619, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 3, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "SkillsDiscovered": { + "profile": "openai", + "source_dirs": [ + "/Users/bhelmkamp/.fabro/skills", + "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/fabro-test-01M2SD6B98NK5D5A3TKW8EGZBH/storage/scratch/20260918-01M2SD6BB8VBFYDZK0A45HGAAQ/petri/scopes/invocation-0-scope-0/work/.fabro/skills", + "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/fabro-test-01M2SD6B98NK5D5A3TKW8EGZBH/storage/scratch/20260918-01M2SD6BB8VBFYDZK0A45HGAAQ/petri/scopes/invocation-0-scope-0/work/skills" + ], + "skills": [], + "skipped": [] + } + }, + "timestamp": "2026-09-18T04:42:59.618Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 35, + "kind": "petri", + "id": "execution 0/17/0", + "recorded_at": 1789706579619, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 17, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579619, + "record": { + "seq": 17, + "origin": "external", + "recorded_at": 1789706579619, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "attractor.skills", + "node": "greet", + "firing": 2, + "attempt": 1, + "scope": 0, + "dirs": [ + { + "path": "/Users/bhelmkamp/.fabro/skills", + "source": "configured" + }, + { + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/fabro-test-01M2SD6B98NK5D5A3TKW8EGZBH/storage/scratch/20260918-01M2SD6BB8VBFYDZK0A45HGAAQ/petri/scopes/invocation-0-scope-0/work/.fabro/skills", + "source": "project_fabro" + }, + { + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/fabro-test-01M2SD6B98NK5D5A3TKW8EGZBH/storage/scratch/20260918-01M2SD6BB8VBFYDZK0A45HGAAQ/petri/scopes/invocation-0-scope-0/work/skills", + "source": "project" + } + ] + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 36, + "kind": "petri", + "id": "execution 0/18/0", + "recorded_at": 1789706579660, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 18, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579660, + "record": { + "seq": 18, + "origin": "external", + "recorded_at": 1789706579660, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 4, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "UserInput": { + "text": "Goal: Say hello and demonstrate a basic Fabro workflow\n\n\nAdd a haiku to the README" + } + }, + "timestamp": "2026-09-18T04:42:59.660Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 37, + "kind": "petri", + "id": "execution 0/19/0", + "recorded_at": 1789706579660, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579660, + "record": { + "seq": 19, + "origin": "external", + "recorded_at": 1789706579660, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 5, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "LlmRequestStarted": { + "requested_model": "gpt-5.4" + } + }, + "timestamp": "2026-09-18T04:42:59.660Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 38, + "kind": "petri", + "id": "execution 0/20/0", + "recorded_at": 1789706579661, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 20, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579661, + "record": { + "seq": 20, + "origin": "external", + "recorded_at": 1789706579661, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 6, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "LlmFirstOutput": { + "kind": "text" + } + }, + "timestamp": "2026-09-18T04:42:59.661Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 39, + "kind": "petri", + "id": "execution 0/21/0", + "recorded_at": 1789706579661, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 21, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579661, + "record": { + "seq": 21, + "origin": "external", + "recorded_at": 1789706579661, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 7, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "TextDelta": { + "delta": "A haiku, added." + } + }, + "timestamp": "2026-09-18T04:42:59.661Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 40, + "kind": "petri", + "id": "execution 0/22/0", + "recorded_at": 1789706579661, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 22, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579661, + "record": { + "seq": 22, + "origin": "external", + "recorded_at": 1789706579661, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 8, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": { + "AssistantMessage": { + "text": "A haiku, added.", + "model": "gpt-5.4", + "usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + }, + "tool_call_count": 0, + "context_window": { + "provider": "openai", + "model": "gpt-5.4", + "context_window_tokens": 1050000, + "input_tokens": 1, + "usage_percent": 0.00009523809523809524, + "count_method": "response_usage_scaled_breakdown", + "staleness": "live", + "generated_at": "2026-09-18T04:42:59.661Z", + "breakdown": [ + { + "category": "system_prompt", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "tools", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "conversation", + "tokens": 0, + "usage_percent": 0.0 + }, + { + "category": "other", + "tokens": 1, + "usage_percent": 0.00009523809523809524 + } + ], + "warnings": [] + } + } + }, + "timestamp": "2026-09-18T04:42:59.661Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 41, + "kind": "petri", + "id": "execution 0/23/0", + "recorded_at": 1789706579661, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 23, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579661, + "record": { + "seq": 23, + "origin": "external", + "recorded_at": 1789706579661, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 9, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": "ProcessingEnd", + "timestamp": "2026-09-18T04:42:59.661Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 42, + "kind": "petri", + "id": "execution 0/24/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 24, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 24, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "log": { + "stream": "stdout", + "line": "A haiku, added." + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 43, + "kind": "petri", + "id": "execution 0/25/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 25, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 25, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "step.progress.recorded", + "firing": 2, + "ev": { + "custom": { + "kind": "pebble", + "firing": 2, + "attempt": 1, + "scope": 0, + "node": "greet", + "event": { + "seq": 10, + "stream_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7", + "event": "SessionEnded", + "timestamp": "2026-09-18T04:42:59.662Z", + "session_id": "ses_b2d59043-342c-4c7c-a638-0ffec24e94d7" + } + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 44, + "kind": "petri", + "id": "execution 0/26/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 26, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 26, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "step.finished", + "firing": 2, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "text": "A haiku, added.", + "turns": 1, + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 232, + "custom": { + "pebble.compaction_usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "pebble.compactions": 0, + "pebble.inference_ms": 0, + "pebble.prompts": 1, + "pebble.subagents": { + "spawned": 0, + "turns_started": 0, + "completed": 0, + "failed": 0, + "closed": 0, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "sessions": {} + }, + "pebble.tool_ms": 0, + "pebble.usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + } + } + }, + "context_updates": { + "failure_class": "", + "last_response": "A haiku, added.", + "last_stage": "greet", + "response.greet": "A haiku, added." + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 45, + "kind": "petri", + "id": "execution 0/26/1", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 26, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "text": "A haiku, added.", + "turns": 1, + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 232, + "custom": { + "pebble.compaction_usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "pebble.compactions": 0, + "pebble.inference_ms": 0, + "pebble.prompts": 1, + "pebble.subagents": { + "spawned": 0, + "turns_started": 0, + "completed": 0, + "failed": 0, + "closed": 0, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "sessions": {} + }, + "pebble.tool_ms": 0, + "pebble.usage": { + "tokens": { + "input": 1, + "output": 5, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + }, + "cost": { + "usd_micros": 77, + "source": "catalog" + } + } + } + }, + "context_updates": { + "failure_class": "", + "last_response": "A haiku, added.", + "last_stage": "greet", + "response.greet": "A haiku, added." + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 46, + "kind": "petri", + "id": "execution 0/27/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 27, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 2, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 1 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 47, + "kind": "petri", + "id": "execution 0/27/1", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 1, + "generation": 0, + "payload": { + "text": "A haiku, added.", + "turns": 1, + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + ] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 48, + "kind": "petri", + "id": "execution 0/27/2", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 49, + "kind": "petri", + "id": "execution 0/28/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 28, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 28, + "origin": "core", + "recorded_at": 1789706579662, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 2, + "group": 0, + "edge": 1 + } + }, + "derived": { + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 50, + "kind": "petri", + "id": "execution 0/29/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 29, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "greet", + "kind": "attractor/agent", + "meta": { + "label": "Greet", + "shape": "box", + "kind": "agent", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "1": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 29, + "origin": "core", + "recorded_at": 1789706579662, + "body": { + "event": "token.emitted", + "edge": 1, + "generation": 0, + "payload": { + "text": "A haiku, added.", + "turns": 1, + "outcome": "succeeded", + "failure_class": "" + }, + "from": 2 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 51, + "kind": "petri", + "id": "execution 0/30/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 30, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 30, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 3, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 52, + "kind": "petri", + "id": "execution 0/31/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 31, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "step.started", + "firing": 3, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 53, + "kind": "petri", + "id": "execution 0/31/1", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 54, + "kind": "petri", + "id": "execution 0/32/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 32, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 32, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "step.finished", + "firing": 3, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 55, + "kind": "petri", + "id": "execution 0/32/1", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 32, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 56, + "kind": "petri", + "id": "execution 0/33/0", + "recorded_at": 1789706579662, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 33, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "Exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 6, + "column": 5 + } + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579662, + "record": { + "seq": 33, + "origin": "external", + "recorded_at": 1789706579662, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 3, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 57, + "kind": "petri", + "id": "coordinator/4/0", + "recorded_at": 1789706579663, + "item": { + "id": { + "log": "coordinator", + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579663, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579663, + "body": { + "event": "execution.finished", + "execution": 0, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 58, + "kind": "petri", + "id": "coordinator/5/0", + "recorded_at": 1789706579663, + "item": { + "id": { + "log": "coordinator", + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579663, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579663, + "body": { + "event": "invocation.finished", + "invocation": 0, + "result": { + "status": "success", + "failure": null, + "final_execution": 0, + "output": null, + "context": { + "failure_class": "", + "internal.run_id": "petri", + "last_response": "A haiku, added.", + "last_stage": "greet", + "response.greet": "A haiku, added." + } + } + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 59, + "kind": "petri", + "id": "coordinator/6/0", + "recorded_at": 1789706579704, + "item": { + "id": { + "log": "coordinator", + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579704, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579704, + "body": { + "event": "run.finished", + "status": "success" + } + } + } + }, + { + "run_id": "01M2SD6BB8VBFYDZK0A45HGAAQ", + "stream_seq": 60, + "kind": "platform", + "id": "7", + "recorded_at": 1789706579708, + "item": { + "seq": 7, + "recorded_at": 1789706579708, + "record": { + "kind": "run.lifecycle", + "transition": "succeeded", + "status": { + "kind": "succeeded", + "reason": "completed" + } + } + } + } + ] +} \ No newline at end of file diff --git a/apps/fabro-web/app/test-fixtures/petri/parallel.json b/apps/fabro-web/app/test-fixtures/petri/parallel.json new file mode 100644 index 000000000..78b4b6e07 --- /dev/null +++ b/apps/fabro-web/app/test-fixtures/petri/parallel.json @@ -0,0 +1,8824 @@ +{ + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "projection": { + "title": "Run two branches", + "spec": { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Parallel", + "nodes": { + "merge": { + "id": "merge", + "attrs": { + "shape": { + "String": "tripleoctagon" + } + } + }, + "fork": { + "id": "fork", + "attrs": { + "shape": { + "String": "component" + } + } + }, + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + }, + "a": { + "id": "a", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/a.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo a" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "b": { + "id": "b", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/b.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo b" + }, + "shape": { + "String": "parallelogram" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "fork", + "attrs": {} + }, + { + "from": "fork", + "to": "a", + "attrs": {} + }, + { + "from": "fork", + "to": "b", + "attrs": {} + }, + { + "from": "a", + "to": "merge", + "attrs": {} + }, + { + "from": "b", + "to": "merge", + "attrs": {} + }, + { + "from": "merge", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Run two branches" + } + } + }, + "graph_source": "digraph Parallel {\n graph [goal=\"Run two branches\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n fork [shape=component]\n a [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/a.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo a\"]\n b [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/b.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo b\"]\n merge [shape=tripleoctagon]\n start -> fork\n fork -> a\n fork -> b\n a -> merge\n b -> merge\n merge -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "b02110236c53803c783fee27d6b79152d0d03492b21e03b64597965b32ac679a", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "1d9fd68facbbeca32d1df0c69f8208cbdc8550b91348edef9948d3e204877840", + "engine": { + "kind": "petri", + "graph": { + "blob": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1", + "digest": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1" + }, + "children": [ + { + "blob": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9", + "digest": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9" + }, + { + "blob": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623", + "digest": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623" + } + ] + } + }, + "web_url": "http://localhost:3000/runs/01M2SD6BBAZRP67N0E6V66627X", + "start": { + "start_time": "2026-09-18T04:42:59.361Z" + }, + "status": { + "kind": "succeeded", + "reason": "completed" + }, + "status_updated_at": "2026-09-18T04:42:59.582Z", + "last_event_at": "2026-09-18T04:42:59.587Z", + "pending_control": null, + "checkpoints": [], + "conclusion": { + "timestamp": "2026-09-18T04:42:59.582Z", + "status": "succeeded", + "timing": { + "wall_time_ms": 221, + "inference_time_ms": 0, + "tool_time_ms": 187, + "active_time_ms": 187 + }, + "total_retries": 0, + "diff": {} + }, + "sandbox": { + "kind": "planned", + "plan": { + "provider": "local" + } + }, + "pull_request": null, + "superseded_by": null, + "pending_interviews": {}, + "stages": { + "start@1": { + "first_event_seq": 98, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.440Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD is not a Git repository; the workspace starts empty\n", + "output_bytes": 130, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.403Z", + "handler": "start", + "graph_visit": 1, + "timing": { + "wall_time_ms": 15, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "a@1": { + "first_event_seq": 139, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.540Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "parallel_branch_id": "fork@1:0", + "output": "a\n", + "output_bytes": 2, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.444Z", + "handler": "command", + "graph_visit": 1, + "timing": { + "wall_time_ms": 96, + "inference_time_ms": 0, + "tool_time_ms": 96, + "active_time_ms": 96 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "merge@1": { + "first_event_seq": 236, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.541Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.541Z", + "handler": "parallel.fan_in", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "b@1": { + "first_event_seq": 141, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.538Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "parallel_branch_id": "fork@1:1", + "output": "b\n", + "output_bytes": 2, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.446Z", + "handler": "command", + "graph_visit": 1, + "timing": { + "wall_time_ms": 91, + "inference_time_ms": 0, + "tool_time_ms": 91, + "active_time_ms": 91 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "exit@1": { + "first_event_seq": 236, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.541Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": null, + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.541Z", + "handler": "exit", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + }, + "fork@1": { + "first_event_seq": 135, + "prompt": null, + "response": null, + "completion": { + "outcome": "succeeded", + "notes": null, + "failure_reason": null, + "timestamp": "2026-09-18T04:42:59.440Z" + }, + "provider_used": null, + "diff": null, + "script_invocation": null, + "script_timing": null, + "parallel_results": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": {} + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": {} + } + ], + "output": null, + "live_streaming": false, + "termination": "exited", + "started_at": "2026-09-18T04:42:59.440Z", + "handler": "parallel", + "graph_visit": 1, + "timing": { + "wall_time_ms": 0, + "inference_time_ms": 0, + "tool_time_ms": 0, + "active_time_ms": 0 + }, + "usage": { + "tokens": { + "input": 0, + "output": 0, + "reasoning": 0, + "cache_read": 0, + "cache_write": 0 + } + }, + "state": "succeeded" + } + } + }, + "stream": [ + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 1, + "kind": "platform", + "id": "1", + "recorded_at": 1789706579306, + "item": { + "seq": 1, + "recorded_at": 1789706579306, + "record": { + "kind": "run.created", + "spec": { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "settings": { + "project": { + "name": null, + "description": null, + "metadata": {} + }, + "workflow": { + "name": null, + "description": null, + "graph": "workflow.fabro", + "metadata": {} + }, + "run": { + "goal": null, + "working_dir": null, + "metadata": {}, + "inputs": {}, + "model": { + "provider": null, + "name": null, + "fallbacks": {}, + "controls": { + "reasoning_effort": null, + "speed": null + } + }, + "git": { + "author": null + }, + "prepare": { + "steps": [], + "timeout_ms": 300000 + }, + "execution": { + "mode": "normal", + "approval": "prompt" + }, + "checkpoint": { + "exclude_globs": [], + "skip_git_hooks": false, + "commit_timeout_ms": 30000 + }, + "clone": { + "enabled": true, + "depth": 100 + }, + "run_branch": { + "enabled": true, + "push": true + }, + "environment": { + "id": "local", + "provider": "local", + "image": { + "docker": null, + "dockerfile": null + }, + "resources": { + "cpu": null, + "memory": null, + "disk": null + }, + "network": { + "mode": "allow_all", + "allow": [] + }, + "lifecycle": { + "preserve": false, + "stop_on_terminal": true, + "auto_stop": null + }, + "labels": {}, + "env": {} + }, + "notifications": {}, + "interviews": { + "provider": null, + "slack": null + }, + "agent": { + "fabro_tools": false, + "mcps": {} + }, + "hooks": [], + "scm": { + "provider": null, + "owner": null, + "repository": null, + "github": null + }, + "pull_request": null, + "artifacts": { + "include": [] + }, + "integrations": { + "github": { + "permissions": {} + } + } + } + }, + "graph": { + "name": "Parallel", + "nodes": { + "a": { + "id": "a", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/a.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo a" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "exit": { + "id": "exit", + "attrs": { + "shape": { + "String": "Msquare" + } + } + }, + "merge": { + "id": "merge", + "attrs": { + "shape": { + "String": "tripleoctagon" + } + } + }, + "fork": { + "id": "fork", + "attrs": { + "shape": { + "String": "component" + } + } + }, + "b": { + "id": "b", + "attrs": { + "script": { + "String": "touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/b.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo b" + }, + "shape": { + "String": "parallelogram" + } + } + }, + "start": { + "id": "start", + "attrs": { + "shape": { + "String": "Mdiamond" + } + } + } + }, + "edges": [ + { + "from": "start", + "to": "fork", + "attrs": {} + }, + { + "from": "fork", + "to": "a", + "attrs": {} + }, + { + "from": "fork", + "to": "b", + "attrs": {} + }, + { + "from": "a", + "to": "merge", + "attrs": {} + }, + { + "from": "b", + "to": "merge", + "attrs": {} + }, + { + "from": "merge", + "to": "exit", + "attrs": {} + } + ], + "attrs": { + "goal": { + "String": "Run two branches" + } + } + }, + "graph_source": "digraph Parallel {\n graph [goal=\"Run two branches\"]\n start [shape=Mdiamond]\n exit [shape=Msquare]\n fork [shape=component]\n a [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/a.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo a\"]\n b [shape=parallelogram, script=\"touch /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/b.started; while [ ! -f /var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpFS7rMT/go ]; do sleep 0.05; done; echo b\"]\n merge [shape=tripleoctagon]\n start -> fork\n fork -> a\n fork -> b\n a -> merge\n b -> merge\n merge -> exit\n}", + "workflow_slug": "workflow", + "workflow_version_id": "b02110236c53803c783fee27d6b79152d0d03492b21e03b64597965b32ac679a", + "target": { + "kind": "folder", + "path": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD" + }, + "source_directory": "/private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD", + "provenance": { + "server": { + "version": "0.357.0-nightly.0" + }, + "subject": { + "kind": "user", + "identity": { + "issuer": "fabro:dev", + "subject": "dev" + }, + "login": "dev", + "auth_method": "dev_token" + } + }, + "spec_blob": "1d9fd68facbbeca32d1df0c69f8208cbdc8550b91348edef9948d3e204877840", + "engine": { + "kind": "petri", + "graph": { + "blob": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1", + "digest": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1" + }, + "children": [ + { + "blob": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9", + "digest": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9" + }, + { + "blob": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623", + "digest": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623" + } + ] + } + }, + "title": "Run two branches", + "web_url": "http://localhost:3000/runs/01M2SD6BBAZRP67N0E6V66627X" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 2, + "kind": "platform", + "id": "2", + "recorded_at": 1789706579346, + "item": { + "seq": 2, + "recorded_at": 1789706579346, + "record": { + "kind": "run.lifecycle", + "transition": "submitted", + "status": { + "kind": "submitted" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 3, + "kind": "platform", + "id": "3", + "recorded_at": 1789706579349, + "item": { + "seq": 3, + "recorded_at": 1789706579349, + "record": { + "kind": "run.lifecycle", + "transition": "start_requested", + "source": "start" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 4, + "kind": "platform", + "id": "4", + "recorded_at": 1789706579350, + "item": { + "seq": 4, + "recorded_at": 1789706579350, + "record": { + "kind": "run.lifecycle", + "transition": "runnable", + "status": { + "kind": "runnable" + }, + "source": "start_requested" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 5, + "kind": "platform", + "id": "5", + "recorded_at": 1789706579352, + "item": { + "seq": 5, + "recorded_at": 1789706579352, + "record": { + "kind": "run.lifecycle", + "transition": "starting", + "status": { + "kind": "starting" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 6, + "kind": "platform", + "id": "6", + "recorded_at": 1789706579353, + "item": { + "seq": 6, + "recorded_at": 1789706579353, + "record": { + "kind": "run.lifecycle", + "transition": "running", + "status": { + "kind": "running" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 7, + "kind": "petri", + "id": "coordinator/0/0", + "recorded_at": 1789706579361, + "item": { + "id": { + "log": "coordinator", + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579361, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579361, + "body": { + "event": "run.started", + "format_version": 5, + "key": "01M2SD6BBAZRP67N0E6V66627X", + "root": 0, + "middleware_chain": [ + "circuit-breaker" + ] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 8, + "kind": "petri", + "id": "coordinator/1/0", + "recorded_at": 1789706579370, + "item": { + "id": { + "log": "coordinator", + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579370, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579370, + "body": { + "event": "graph.registered", + "digest": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 9, + "kind": "petri", + "id": "coordinator/2/0", + "recorded_at": 1789706579392, + "item": { + "id": { + "log": "coordinator", + "seq": 2, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579392, + "record": { + "seq": 2, + "origin": "external", + "recorded_at": 1789706579392, + "body": { + "event": "graph.registered", + "digest": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 10, + "kind": "petri", + "id": "coordinator/3/0", + "recorded_at": 1789706579401, + "item": { + "id": { + "log": "coordinator", + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579401, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579401, + "body": { + "event": "graph.registered", + "digest": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 11, + "kind": "petri", + "id": "coordinator/4/0", + "recorded_at": 1789706579401, + "item": { + "id": { + "log": "coordinator", + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0 + }, + "recorded_at": 1789706579401, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579401, + "body": { + "event": "invocation.declared", + "invocation": 0, + "call": null, + "graph": "be8fcd9ad28e9aa25b3414a0ec2a30de544589200b6d248d1f2d812be9bcaaa1", + "context": {}, + "secret_bindings": "none", + "sandbox": "isolated" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 12, + "kind": "petri", + "id": "coordinator/5/0", + "recorded_at": 1789706579402, + "item": { + "id": { + "log": "coordinator", + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579402, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579402, + "body": { + "event": "execution.declared", + "execution": 0, + "invocation": 0, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 13, + "kind": "petri", + "id": "execution 0/0/0", + "recorded_at": 1789706579402, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579402, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579402, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": {}, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 14, + "kind": "petri", + "id": "execution 0/1/0", + "recorded_at": 1789706579403, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579403, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579403, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 15, + "kind": "petri", + "id": "execution 0/1/1", + "recorded_at": 1789706579403, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579403, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 8, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 16, + "kind": "petri", + "id": "execution 0/1/2", + "recorded_at": 1789706579403, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579403, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 17, + "kind": "petri", + "id": "execution 0/2/0", + "recorded_at": 1789706579403, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579403, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579403, + "body": { + "event": "token.emitted", + "edge": 8, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 18, + "kind": "petri", + "id": "execution 0/3/0", + "recorded_at": 1789706579403, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579403, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579403, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 19, + "kind": "petri", + "id": "execution 0/4/0", + "recorded_at": 1789706579425, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579425, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579425, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 20, + "kind": "petri", + "id": "execution 0/4/1", + "recorded_at": 1789706579425, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579425, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 21, + "kind": "petri", + "id": "execution 0/5/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stderr", + "line": "checkout: /private/var/folders/nm/bd2dwzy52t1ckn3tklsfmy1c0000gn/T/.tmpGZ9DbD is not a Git repository; the workspace starts empty" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 22, + "kind": "petri", + "id": "execution 0/6/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 15 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 23, + "kind": "petri", + "id": "execution 0/6/1", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 15 + }, + "context_updates": { + "failure_class": "", + "internal.run_id": "petri" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 24, + "kind": "petri", + "id": "execution 0/7/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 0 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 25, + "kind": "petri", + "id": "execution 0/7/1", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 26, + "kind": "petri", + "id": "execution 0/7/2", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 7, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 27, + "kind": "petri", + "id": "execution 0/8/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 8, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 8, + "origin": "core", + "recorded_at": 1789706579440, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 1, + "group": 0, + "edge": 0 + } + }, + "derived": { + "target": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 28, + "kind": "petri", + "id": "execution 0/9/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 9, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 0, + "name": "start", + "kind": "attractor/stage", + "meta": { + "label": "start", + "shape": "Mdiamond", + "kind": "start", + "classes": [], + "span": { + "line": 3, + "column": 5 + }, + "admission_hooks": "step", + "edges": { + "0": { + "to": "fork", + "label": null + } + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 9, + "origin": "core", + "recorded_at": 1789706579440, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": { + "outcome": "succeeded", + "failure_class": "" + }, + "from": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 29, + "kind": "petri", + "id": "execution 0/10/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 10, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 10, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 2, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 30, + "kind": "petri", + "id": "execution 0/11/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 11, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "step.started", + "firing": 2, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 31, + "kind": "petri", + "id": "execution 0/11/1", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 11, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 32, + "kind": "petri", + "id": "execution 0/12/0", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "record": { + "seq": 12, + "origin": "external", + "recorded_at": 1789706579440, + "body": { + "event": "step.finished", + "firing": 2, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "metrics": { + "duration_ms": 0 + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 33, + "kind": "petri", + "id": "execution 0/12/1", + "recorded_at": 1789706579440, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 12, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579440, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "metrics": { + "duration_ms": 0 + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 34, + "kind": "petri", + "id": "coordinator/6/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "coordinator", + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "invocation.declared", + "invocation": 1, + "call": { + "parent": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + }, + "graph": "7d5e762205c2e2501b2f0707633a54af15dc4b31f1a39e8ef998c00b3b6144e9", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "secret_bindings": "inherit", + "sandbox": { + "inherited": { + "lease": 0 + } + }, + "admission": { + "gate": "fork@0", + "max_parallel": 4 + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 35, + "kind": "petri", + "id": "execution 0/13/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 13, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 2, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 6 + } + }, + { + "group": 1, + "draw": null, + "trace": [], + "decision": { + "emit": 7 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + } + }, + { + "group": 1, + "target": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 36, + "kind": "petri", + "id": "execution 0/13/1", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 6, + "generation": 0, + "payload": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 2 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 37, + "kind": "petri", + "id": "execution 0/13/2", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 38, + "kind": "petri", + "id": "execution 0/13/3", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 3 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 7, + "generation": 0, + "payload": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 2 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 39, + "kind": "petri", + "id": "execution 0/13/4", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 13, + "index": 4 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 40, + "kind": "petri", + "id": "execution 0/14/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 14, + "origin": "core", + "recorded_at": 1789706579441, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 2, + "group": 0, + "edge": 6 + } + }, + "derived": { + "target": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 41, + "kind": "petri", + "id": "execution 0/14/1", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 14, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "fork.started", + "occurrence": { + "execution": 0, + "fork": 2, + "firing": 2, + "visit": 1, + "generation": 0 + }, + "branches": [ + { + "fork": 2, + "index": 0 + }, + { + "fork": 2, + "index": 1 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 42, + "kind": "petri", + "id": "execution 0/15/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 15, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 15, + "origin": "core", + "recorded_at": 1789706579441, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 2, + "group": 1, + "edge": 7 + } + }, + "derived": { + "target": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 43, + "kind": "petri", + "id": "execution 0/16/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 16, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 16, + "origin": "core", + "recorded_at": 1789706579441, + "body": { + "event": "token.emitted", + "edge": 6, + "generation": 0, + "payload": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 2 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 44, + "kind": "petri", + "id": "execution 0/17/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 17, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "firing": 2, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "fork", + "branches": 2 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 17, + "origin": "core", + "recorded_at": 1789706579441, + "body": { + "event": "token.emitted", + "edge": 7, + "generation": 0, + "payload": { + "snapshot": { + "failure_class": "", + "internal.run_id": "petri" + }, + "nodes": null, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 2 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 45, + "kind": "petri", + "id": "execution 0/18/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 18, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 18, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 3, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 46, + "kind": "petri", + "id": "execution 0/19/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 19, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "step.started", + "firing": 3, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 47, + "kind": "petri", + "id": "execution 0/19/1", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 19, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 48, + "kind": "petri", + "id": "execution 0/20/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 20, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 20, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 4, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 49, + "kind": "petri", + "id": "execution 0/21/0", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 21, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579441, + "record": { + "seq": 21, + "origin": "external", + "recorded_at": 1789706579441, + "body": { + "event": "step.started", + "firing": 4, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 50, + "kind": "petri", + "id": "execution 0/21/1", + "recorded_at": 1789706579441, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 21, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579441, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 51, + "kind": "petri", + "id": "coordinator/7/0", + "recorded_at": 1789706579443, + "item": { + "id": { + "log": "coordinator", + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579443, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579443, + "body": { + "event": "invocation.declared", + "invocation": 2, + "call": { + "parent": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + }, + "graph": "0f987262db67036c3e0b2027300af948919860f2cde4f4937ccf5277f07ad623", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "secret_bindings": "inherit", + "sandbox": { + "inherited": { + "lease": 0 + } + }, + "admission": { + "gate": "fork@0", + "max_parallel": 4 + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 52, + "kind": "petri", + "id": "coordinator/8/0", + "recorded_at": 1789706579443, + "item": { + "id": { + "log": "coordinator", + "seq": 8, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579443, + "record": { + "seq": 8, + "origin": "external", + "recorded_at": 1789706579443, + "body": { + "event": "execution.declared", + "execution": 1, + "invocation": 1, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 53, + "kind": "petri", + "id": "execution 0/22/0", + "recorded_at": 1789706579443, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 22, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579443, + "record": { + "seq": 22, + "origin": "external", + "recorded_at": 1789706579443, + "body": { + "event": "step.progress.recorded", + "firing": 3, + "ev": { + "custom": { + "fork": "fork", + "occurrence": { + "fork": "fork", + "firing": 2 + }, + "branch": "a", + "index": 0, + "item_label": null, + "kind": "attractor.parallel.branch.started", + "invocation": 1 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 54, + "kind": "petri", + "id": "coordinator/9/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "coordinator", + "seq": 9, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 9, + "origin": "external", + "recorded_at": 1789706579444, + "body": { + "event": "execution.declared", + "execution": 2, + "invocation": 2, + "predecessor": null, + "start": { + "entry": "graph_entries", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + }, + "middleware_state": { + "circuit-breaker": [ + 1, + { + "loop_signatures": {}, + "restart_signatures": {}, + "pending": {} + } + ] + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 55, + "kind": "petri", + "id": "execution 1/0/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579444, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 56, + "kind": "petri", + "id": "execution 1/1/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579444, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 57, + "kind": "petri", + "id": "execution 1/1/1", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579444, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 58, + "kind": "petri", + "id": "execution 1/1/2", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579444, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 59, + "kind": "petri", + "id": "execution 1/2/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579444, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 60, + "kind": "petri", + "id": "execution 1/3/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579444, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 61, + "kind": "petri", + "id": "execution 1/4/0", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579444, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579444, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 62, + "kind": "petri", + "id": "execution 1/4/1", + "recorded_at": 1789706579444, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579444, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 63, + "kind": "petri", + "id": "execution 0/23/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 23, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 23, + "origin": "external", + "recorded_at": 1789706579446, + "body": { + "event": "step.progress.recorded", + "firing": 4, + "ev": { + "custom": { + "fork": "fork", + "occurrence": { + "fork": "fork", + "firing": 2 + }, + "branch": "b", + "index": 1, + "item_label": null, + "kind": "attractor.parallel.branch.started", + "invocation": 2 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 64, + "kind": "petri", + "id": "execution 2/0/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 0, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 0, + "origin": "external", + "recorded_at": 1789706579446, + "body": { + "event": "execution.started", + "entry": "graph_entries", + "context": { + "failure_class": "", + "internal.run_id": "petri" + }, + "prior_firings": {}, + "execution_index": 0, + "max_executions": 32 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 65, + "kind": "petri", + "id": "execution 2/1/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 1, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 1, + "origin": "external", + "recorded_at": 1789706579446, + "body": { + "event": "admission.decided", + "decision_id": "execution_start", + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 66, + "kind": "petri", + "id": "execution 2/1/1", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 1, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 0, + "generation": 0, + "payload": null, + "from": 0 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 67, + "kind": "petri", + "id": "execution 2/1/2", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 1, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 68, + "kind": "petri", + "id": "execution 2/2/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 2, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 2, + "origin": "core", + "recorded_at": 1789706579446, + "body": { + "event": "token.emitted", + "edge": 0, + "generation": 0, + "payload": null, + "from": 0 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 69, + "kind": "petri", + "id": "execution 2/3/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 3, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 3, + "origin": "external", + "recorded_at": 1789706579446, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 1, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 70, + "kind": "petri", + "id": "execution 2/4/0", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 4, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "record": { + "seq": 4, + "origin": "external", + "recorded_at": 1789706579446, + "body": { + "event": "step.started", + "firing": 1, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 71, + "kind": "petri", + "id": "execution 2/4/1", + "recorded_at": 1789706579446, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 4, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579446, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 72, + "kind": "platform", + "id": "7", + "recorded_at": 1789706579470, + "item": { + "seq": 7, + "recorded_at": 1789706579470, + "record": { + "kind": "run.notice", + "level": "info", + "code": "test.between_branches", + "message": "recorded while both branches ran" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 73, + "kind": "petri", + "id": "execution 2/5/0", + "recorded_at": 1789706579512, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579512, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579512, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stdout", + "line": "b" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 74, + "kind": "petri", + "id": "execution 1/5/0", + "recorded_at": 1789706579517, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 5, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579517, + "record": { + "seq": 5, + "origin": "external", + "recorded_at": 1789706579517, + "body": { + "event": "step.progress.recorded", + "firing": 1, + "ev": { + "log": { + "stream": "stdout", + "line": "a" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 75, + "kind": "petri", + "id": "coordinator/10/0", + "recorded_at": 1789706579538, + "item": { + "id": { + "log": "coordinator", + "seq": 10, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579538, + "record": { + "seq": 10, + "origin": "external", + "recorded_at": 1789706579538, + "body": { + "event": "execution.finished", + "execution": 2, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 76, + "kind": "petri", + "id": "execution 2/6/0", + "recorded_at": 1789706579538, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579538, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579538, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "b\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 91 + }, + "context_updates": { + "command.output": "b\n", + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 77, + "kind": "petri", + "id": "execution 2/6/1", + "recorded_at": 1789706579538, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579538, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "b\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 91 + }, + "context_updates": { + "command.output": "b\n", + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 78, + "kind": "petri", + "id": "execution 2/7/0", + "recorded_at": 1789706579538, + "item": { + "id": { + "log": "execution", + "execution": 2, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "subject": { + "node": { + "id": 0, + "name": "b", + "kind": "attractor/command", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 1 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579538, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579538, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 79, + "kind": "petri", + "id": "coordinator/11/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "coordinator", + "seq": 11, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 2, + "execution": 2, + "parent": { + "execution": 0, + "firing": 4, + "attempt": 1, + "slot": "branch:fork@2:1:b" + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 11, + "origin": "external", + "recorded_at": 1789706579539, + "body": { + "event": "invocation.finished", + "invocation": 2, + "result": { + "status": "success", + "failure": null, + "final_execution": 2, + "output": { + "exit_status": 0, + "stdout": "b\n", + "outcome": "succeeded", + "failure_class": "" + }, + "context": { + "command.output": "b\n", + "failure_class": "", + "internal.run_id": "petri" + }, + "updates": { + "command.output": "b\n", + "failure_class": "" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 80, + "kind": "petri", + "id": "execution 0/24/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 24, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 24, + "origin": "external", + "recorded_at": 1789706579539, + "body": { + "event": "step.progress.recorded", + "firing": 4, + "ev": { + "custom": { + "fork": "fork", + "occurrence": { + "fork": "fork", + "firing": 2 + }, + "branch": "b", + "index": 1, + "item_label": null, + "kind": "attractor.parallel.branch.completed", + "invocation": 2, + "status": "succeeded", + "disposition": "completed", + "started": true, + "duration_ms": 98 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 81, + "kind": "petri", + "id": "execution 0/25/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 25, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 25, + "origin": "external", + "recorded_at": 1789706579539, + "body": { + "event": "step.finished", + "firing": 4, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "metrics": { + "duration_ms": 98 + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 82, + "kind": "petri", + "id": "execution 0/25/1", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 25, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "metrics": { + "duration_ms": 98 + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 83, + "kind": "petri", + "id": "execution 0/26/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 26, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 26, + "origin": "external", + "recorded_at": 1789706579539, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 4, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 5 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 84, + "kind": "petri", + "id": "execution 0/27/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 27, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 27, + "origin": "core", + "recorded_at": 1789706579539, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 4, + "group": 0, + "edge": 5 + } + }, + "derived": { + "target": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 85, + "kind": "petri", + "id": "execution 0/28/0", + "recorded_at": 1789706579539, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 28, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579539, + "record": { + "seq": 28, + "origin": "core", + "recorded_at": 1789706579539, + "body": { + "event": "token.emitted", + "edge": 5, + "generation": 0, + "payload": { + "index": 1, + "value": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 4 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 86, + "kind": "petri", + "id": "execution 1/6/0", + "recorded_at": 1789706579540, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 6, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579540, + "record": { + "seq": 6, + "origin": "external", + "recorded_at": 1789706579540, + "body": { + "event": "step.finished", + "firing": 1, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "a\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 96 + }, + "context_updates": { + "command.output": "a\n", + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 87, + "kind": "petri", + "id": "execution 1/6/1", + "recorded_at": 1789706579540, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 6, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579540, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "exit_status": 0, + "stdout": "a\n", + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 96 + }, + "context_updates": { + "command.output": "a\n", + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 88, + "kind": "petri", + "id": "execution 1/7/0", + "recorded_at": 1789706579540, + "item": { + "id": { + "log": "execution", + "execution": 1, + "seq": 7, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "subject": { + "node": { + "id": 0, + "name": "a", + "kind": "attractor/command", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "command", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch_role": { + "fork": 2, + "index": 0 + } + } + }, + "firing": 1, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579540, + "record": { + "seq": 7, + "origin": "external", + "recorded_at": 1789706579540, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 1, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 89, + "kind": "petri", + "id": "coordinator/12/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "coordinator", + "seq": 12, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 12, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "execution.finished", + "execution": 1, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 90, + "kind": "petri", + "id": "coordinator/13/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "coordinator", + "seq": 13, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 1, + "execution": 1, + "parent": { + "execution": 0, + "firing": 3, + "attempt": 1, + "slot": "branch:fork@2:0:a" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 13, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "invocation.finished", + "invocation": 1, + "result": { + "status": "success", + "failure": null, + "final_execution": 1, + "output": { + "exit_status": 0, + "stdout": "a\n", + "outcome": "succeeded", + "failure_class": "" + }, + "context": { + "command.output": "a\n", + "failure_class": "", + "internal.run_id": "petri" + }, + "updates": { + "command.output": "a\n", + "failure_class": "" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 91, + "kind": "petri", + "id": "execution 0/29/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 29, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 29, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.progress.recorded", + "firing": 3, + "ev": { + "custom": { + "fork": "fork", + "occurrence": { + "fork": "fork", + "firing": 2 + }, + "branch": "a", + "index": 0, + "item_label": null, + "kind": "attractor.parallel.branch.completed", + "invocation": 1, + "status": "succeeded", + "disposition": "completed", + "started": true, + "duration_ms": 100 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 92, + "kind": "petri", + "id": "execution 0/30/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 30, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 30, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.finished", + "firing": 3, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "metrics": { + "duration_ms": 100 + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 93, + "kind": "petri", + "id": "execution 0/30/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 30, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "metrics": { + "duration_ms": 100 + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 94, + "kind": "petri", + "id": "execution 0/31/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 31, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 3, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 4 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 95, + "kind": "petri", + "id": "execution 0/31/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "branch.completed", + "occurrence": { + "execution": 0, + "fork": 2, + "firing": 2, + "visit": 1, + "generation": 0 + }, + "result": { + "branch": { + "fork": 2, + "index": 0 + }, + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "status": "success", + "payload": { + "index": 0, + "value": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 96, + "kind": "petri", + "id": "execution 0/31/2", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 1 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "branch.completed", + "occurrence": { + "execution": 0, + "fork": 2, + "firing": 2, + "visit": 1, + "generation": 0 + }, + "result": { + "branch": { + "fork": 2, + "index": 1 + }, + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "status": "success", + "payload": { + "index": 1, + "value": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 97, + "kind": "petri", + "id": "execution 0/31/3", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 3 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "fork.completed", + "occurrence": { + "execution": 0, + "fork": 2, + "firing": 2, + "visit": 1, + "generation": 0 + }, + "fork": { + "id": 2, + "name": "fork", + "kind": "attractor/fork", + "meta": { + "label": "fork", + "shape": "component", + "kind": "parallel", + "classes": [], + "span": { + "line": 5, + "column": 5 + } + } + }, + "results": [ + { + "branch": { + "fork": 2, + "index": 0 + }, + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "status": "success", + "payload": { + "index": 0, + "value": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + } + }, + { + "branch": { + "fork": 2, + "index": 1 + }, + "node": { + "id": 4, + "name": "b", + "kind": "attractor/branch", + "meta": { + "label": "b", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 7, + "column": 5 + }, + "edges": { + "2": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "b", + "index": 1 + }, + "synthetic": true + } + }, + "firing": 4, + "status": "success", + "payload": { + "index": 1, + "value": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + } + } + ], + "disposition": "joined" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 98, + "kind": "petri", + "id": "execution 0/31/4", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 4 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 4, + "generation": 0, + "payload": { + "index": 0, + "value": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 3 + }, + { + "edge": 5, + "generation": 0, + "payload": { + "index": 1, + "value": { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 4 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 99, + "kind": "petri", + "id": "execution 0/31/5", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 31, + "index": 5 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 100, + "kind": "petri", + "id": "execution 0/32/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 32, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 32, + "origin": "core", + "recorded_at": 1789706579541, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 3, + "group": 0, + "edge": 4 + } + }, + "derived": { + "target": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 101, + "kind": "petri", + "id": "execution 0/33/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 33, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 3, + "name": "a", + "kind": "attractor/branch", + "meta": { + "label": "a", + "shape": "parallelogram", + "kind": "parallel.branch", + "classes": [], + "span": { + "line": 6, + "column": 5 + }, + "edges": { + "1": { + "to": "merge", + "label": null + } + }, + "branch": { + "fork": "fork", + "target": "a", + "index": 0 + }, + "synthetic": true + } + }, + "firing": 3, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "member", + "fork": 2, + "index": 0 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 33, + "origin": "core", + "recorded_at": 1789706579541, + "body": { + "event": "token.emitted", + "edge": 4, + "generation": 0, + "payload": { + "index": 0, + "value": { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + "occurrence": { + "fork": "fork", + "firing": 2 + } + }, + "from": 3 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 102, + "kind": "petri", + "id": "execution 0/34/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 34, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 34, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 5, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 103, + "kind": "petri", + "id": "execution 0/35/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 35, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 35, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.started", + "firing": 5, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 104, + "kind": "petri", + "id": "execution 0/35/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 35, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 105, + "kind": "petri", + "id": "execution 0/36/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 36, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 36, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.progress.recorded", + "firing": 5, + "ev": { + "custom": { + "kind": "attractor.parallel.completed", + "node": "merge", + "fork": "fork", + "occurrence": { + "fork": "fork", + "firing": 2 + }, + "branch_count": 2, + "success_count": 2, + "failure_count": 0, + "status": "succeeded" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 106, + "kind": "petri", + "id": "execution 0/37/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 37, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 37, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.finished", + "firing": 5, + "attempt": 1, + "outcome": { + "status": "success", + "output": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ], + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "parallel.branch_count": 2, + "parallel.results": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ] + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 107, + "kind": "petri", + "id": "execution 0/37/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 37, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ], + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "parallel.branch_count": 2, + "parallel.results": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ] + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 108, + "kind": "petri", + "id": "execution 0/38/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 38, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 38, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 5, + "attempt": 1 + } + }, + "groups": [ + { + "group": 0, + "draw": null, + "trace": [], + "decision": { + "emit": 3 + } + } + ] + } + }, + "derived": { + "groups": [ + { + "group": 0, + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + } + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 109, + "kind": "petri", + "id": "execution 0/38/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 38, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "visit.started", + "inputs": [ + { + "edge": 3, + "generation": 0, + "payload": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ], + "from": 5 + } + ] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 110, + "kind": "petri", + "id": "execution 0/38/2", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 38, + "index": 2 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "wait.state.changed", + "state": "awaiting_admission" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 111, + "kind": "petri", + "id": "execution 0/39/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 39, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 39, + "origin": "core", + "recorded_at": 1789706579541, + "body": { + "event": "route.applied", + "kind": "edge", + "firing": 5, + "group": 0, + "edge": 3 + } + }, + "derived": { + "target": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "transition": "Continue", + "back": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 112, + "kind": "petri", + "id": "execution 0/40/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 40, + "index": 0 + }, + "origin": "core", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 5, + "name": "merge", + "kind": "attractor/fan_in", + "meta": { + "label": "merge", + "shape": "tripleoctagon", + "kind": "parallel.fan_in", + "classes": [], + "span": { + "line": 8, + "column": 5 + }, + "edges": { + "3": { + "to": "exit", + "label": null + } + } + } + }, + "firing": 5, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "join", + "fork": 2 + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 40, + "origin": "core", + "recorded_at": 1789706579541, + "body": { + "event": "token.emitted", + "edge": 3, + "generation": 0, + "payload": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ], + "from": 5 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 113, + "kind": "petri", + "id": "execution 0/41/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 41, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 41, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "admission.decided", + "decision_id": { + "attempt_start": { + "firing": 6, + "attempt": 1 + } + }, + "decision": "admit", + "trace": [] + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 114, + "kind": "petri", + "id": "execution 0/42/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 42, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 42, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.started", + "firing": 6, + "attempt": 1 + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 115, + "kind": "petri", + "id": "execution 0/42/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 42, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "wait.state.changed", + "state": "running" + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 116, + "kind": "petri", + "id": "execution 0/43/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 43, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 43, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "step.finished", + "firing": 6, + "attempt": 1, + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + } + } + }, + "derived": { + "final": true, + "exhausted": false + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 117, + "kind": "petri", + "id": "execution 0/43/1", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 43, + "index": 1 + }, + "origin": "derived", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "derived": { + "event": "visit.completed", + "outcome": { + "status": "success", + "output": { + "outcome": "succeeded", + "failure_class": "" + }, + "metrics": { + "duration_ms": 0 + }, + "context_updates": { + "failure_class": "" + } + }, + "executed": true, + "attempts": 1 + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 118, + "kind": "petri", + "id": "execution 0/44/0", + "recorded_at": 1789706579541, + "item": { + "id": { + "log": "execution", + "execution": 0, + "seq": 44, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "subject": { + "node": { + "id": 1, + "name": "exit", + "kind": "attractor/stage", + "meta": { + "label": "exit", + "shape": "Msquare", + "kind": "exit", + "classes": [], + "span": { + "line": 4, + "column": 5 + } + } + }, + "firing": 6, + "visit": 1, + "attempt": 1, + "generation": 0, + "branch": { + "role": "none" + } + }, + "recorded_at": 1789706579541, + "record": { + "seq": 44, + "origin": "external", + "recorded_at": 1789706579541, + "body": { + "event": "routing.resolved", + "decision_id": { + "route": { + "firing": 6, + "attempt": 1 + } + }, + "groups": [] + } + }, + "derived": { + "groups": [] + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 119, + "kind": "petri", + "id": "coordinator/14/0", + "recorded_at": 1789706579542, + "item": { + "id": { + "log": "coordinator", + "seq": 14, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579542, + "record": { + "seq": 14, + "origin": "external", + "recorded_at": 1789706579542, + "body": { + "event": "execution.finished", + "execution": 0, + "exit": { + "terminal": { + "status": "success" + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 120, + "kind": "petri", + "id": "coordinator/15/0", + "recorded_at": 1789706579542, + "item": { + "id": { + "log": "coordinator", + "seq": 15, + "index": 0 + }, + "origin": "external", + "context": { + "invocation": 0, + "execution": 0 + }, + "recorded_at": 1789706579542, + "record": { + "seq": 15, + "origin": "external", + "recorded_at": 1789706579542, + "body": { + "event": "invocation.finished", + "invocation": 0, + "result": { + "status": "success", + "failure": null, + "final_execution": 0, + "output": null, + "context": { + "failure_class": "", + "internal.run_id": "petri", + "parallel.branch_count": 2, + "parallel.results": [ + { + "id": "a", + "index": 0, + "status": "succeeded", + "context_updates": { + "command.output": "a\n" + } + }, + { + "id": "b", + "index": 1, + "status": "succeeded", + "context_updates": { + "command.output": "b\n" + } + } + ] + } + } + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 121, + "kind": "petri", + "id": "coordinator/16/0", + "recorded_at": 1789706579582, + "item": { + "id": { + "log": "coordinator", + "seq": 16, + "index": 0 + }, + "origin": "external", + "context": {}, + "recorded_at": 1789706579582, + "record": { + "seq": 16, + "origin": "external", + "recorded_at": 1789706579582, + "body": { + "event": "run.finished", + "status": "success" + } + } + } + }, + { + "run_id": "01M2SD6BBAZRP67N0E6V66627X", + "stream_seq": 122, + "kind": "platform", + "id": "8", + "recorded_at": 1789706579587, + "item": { + "seq": 8, + "recorded_at": 1789706579587, + "record": { + "kind": "run.lifecycle", + "transition": "succeeded", + "status": { + "kind": "succeeded", + "reason": "completed" + } + } + } + } + ] +} \ No newline at end of file diff --git a/docs/public/api-reference/fabro-api.yaml b/docs/public/api-reference/fabro-api.yaml index 25ba828cf..fb1eaf3fd 100644 --- a/docs/public/api-reference/fabro-api.yaml +++ b/docs/public/api-reference/fabro-api.yaml @@ -2970,23 +2970,40 @@ paths: tags: [Run Internals] summary: List Run Events description: | - Returns a paginated JSON list of stored run events. Ascending order - uses `since_seq` as an inclusive cursor. Descending order uses + Returns a paginated JSON list of the run's events. The shape depends + on the engine the run was created for (`RunSpec.engine`). + + For a legacy run (`engine.kind = legacy`): stored run events in the + legacy envelope (`PaginatedEventList`). Ascending order uses + `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. + + For a Petri run (`engine.kind = petri`): the run stream + (`PaginatedRunStreamList`), one ordered delivery of Petri's own + `RunEvent`s and Fabro's platform records in the `RunStreamItem` + envelope, in `stream_seq` order. The cursor is `after`: the last + `stream_seq` the client saw, exclusive; the first page is `after=0`. + `since_seq`, `before_seq` and `order` are not accepted for a Petri + run. A client that reconnects resumes from its last `stream_seq` and + deduplicates by each item's `id`; every item is delivered once, in + order, with no gap. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/SinceSeq" - $ref: "#/components/parameters/EventLimit" - $ref: "#/components/parameters/BeforeSeq" - $ref: "#/components/parameters/EventOrder" + - $ref: "#/components/parameters/StreamAfter" responses: "200": - description: Paginated list of run events + description: Paginated list of run events, in the run engine's envelope content: application/json: schema: - $ref: "#/components/schemas/PaginatedEventList" + oneOf: + - $ref: "#/components/schemas/PaginatedEventList" + - $ref: "#/components/schemas/PaginatedRunStreamList" "400": description: Invalid cursor and order combination headers: @@ -3097,10 +3114,25 @@ paths: operationId: attachRunEvents tags: [Run Internals] summary: Attach Run Events - description: Opens an ordered server-sent event stream starting at `since_seq`, replaying persisted events and continuing with live updates while the run remains active. + description: | + Opens an ordered server-sent event stream, replaying persisted items + and continuing with live updates while the run remains active. Each + `data:` frame is one JSON object in the run engine's envelope. + + For a legacy run the frames are `EventEnvelope`s and the stream + starts at `since_seq` (inclusive; the next unseen event when omitted). + It ends after `run.completed` or `run.failed`. + + For a Petri run the frames are `RunStreamItem`s and the stream + starts after `after` (the last `stream_seq` the client saw; `0` + replays the whole run; the next unseen item when omitted). It ends + once the run is no longer active and every committed item has been + sent. A reconnecting client passes its last `stream_seq` as `after` + and deduplicates by `id`. parameters: - $ref: "#/components/parameters/RunId" - $ref: "#/components/parameters/SinceSeq" + - $ref: "#/components/parameters/StreamAfter" responses: "200": description: Server-sent event stream @@ -6290,6 +6322,20 @@ components: default: 100 example: 100 + StreamAfter: + name: after + in: query + required: false + description: | + Run stream cursor for a Petri run: the last `stream_seq` the client + saw, exclusive. `0` starts at the first item. + schema: + type: integer + format: uint64 + minimum: 0 + default: 0 + example: 42 + QuestionId: name: qid in: path @@ -10869,6 +10915,99 @@ components: meta: $ref: "#/components/schemas/PaginationMeta" + RunStreamItemKind: + description: Which item shape a run stream item carries. + type: string + enum: [petri, platform] + + RunStreamItem: + description: | + One item of a Petri run's stream: a Petri `RunEvent` or a Fabro + platform record in Fabro's envelope. + + `stream_seq` is the durable per-run delivery sequence the projector + assigned when the item's record was committed: dense, strictly + increasing within the run, and the cursor for `after`. `id` is the + item's own identity, kept beside the cursor so a client deduplicates + by it: for a Petri event the `EventId` as `//` + (`coordinator/3/0`, `execution 1/23/0`); for a platform record its + `seq`. Petri's `EventId` is per log and has no platform variant, so + it is never the cursor. + + A `petri` item is a Petri `RunEvent` passed through unchanged: + `{id: {log, execution?, seq, index}, origin, recorded_at, + observed_at?, context: {invocation, execution, parent?}, subject?, + record?, derived?}`. Its vocabulary is Petri's public event contract + (`crates/core/execution/EVENTS.md` in the Petri repository), not + Fabro's: the recorded event's name is `record.body.event` + (`.`, e.g. `visit.started`, `step.finished`, + `run.finished`), a derived view event's is `derived.event`, and the + stage a subject names is `(context.execution, subject.firing)` with + `subject.node.name` and `subject.visit` as its display label. The + server reports the contract version it serves in + `PaginatedRunStreamList.event_contract_version`. + + A `platform` item is a stored platform record: `{seq, recorded_at, + record: {kind, ...}, position?: {execution, firing}}`. `record.kind` + is one of `run.created`, `run.lifecycle`, `run.title`, `run.parent`, + `run.archived`, `run.unarchived`, `run.superseded`, `run.notice`, + `interview.answered`, `run.branch`, `git.identity`, `checkpoint`, + `pull_request.created`, `notification.sent`, `run.paired`. + type: object + required: + - run_id + - stream_seq + - kind + - id + - recorded_at + - item + properties: + run_id: + type: string + stream_seq: + type: integer + format: uint64 + minimum: 0 + description: The delivery sequence; the cursor. + kind: + $ref: "#/components/schemas/RunStreamItemKind" + id: + type: string + description: The item's own identity, for deduplication. + recorded_at: + type: integer + format: uint64 + minimum: 0 + description: Milliseconds since the Unix epoch when the item's record was appended. + item: + type: object + additionalProperties: true + description: The Petri `RunEvent` or the stored platform record, unchanged. + + PaginatedRunStreamList: + description: | + One page of a Petri run's stream, in `stream_seq` order. + `event_contract_version` is Petri's `EVENT_CONTRACT_VERSION` the + server was built against: the version of the event contract every + `petri` item follows. + type: object + required: + - data + - meta + - event_contract_version + properties: + data: + type: array + items: + $ref: "#/components/schemas/RunStreamItem" + meta: + $ref: "#/components/schemas/PaginationMeta" + event_contract_version: + type: integer + format: uint32 + minimum: 0 + example: 3 + AppendEventResponse: description: Assigned sequence number for an appended event. type: object @@ -12712,6 +12851,58 @@ components: oneOf: - $ref: "#/components/schemas/ForkSourceRef" - type: "null" + engine: + $ref: "#/components/schemas/RunEngine" + description: | + The engine the run was created for, with what it admitted. + Absent in a spec written before the field existed, which means + the legacy executor. + + RunEngine: + description: | + The engine a run was created for. `legacy` is the in-process + executor; `petri` names the Petri workflow engine and carries what + Petri admitted at create time. + oneOf: + - type: object + required: [kind] + properties: + kind: + type: string + enum: [legacy] + - allOf: + - type: object + required: [kind] + properties: + kind: + type: string + enum: [petri] + - $ref: "#/components/schemas/PetriAdmission" + + PetriAdmission: + description: | + What Petri admitted for a run at create time: the lowered root graph + and the pre-lowered child graphs, every one persisted in the blob + store before the run exists. + type: object + required: [graph] + properties: + graph: + $ref: "#/components/schemas/PetriGraphRef" + children: + type: array + items: + $ref: "#/components/schemas/PetriGraphRef" + + PetriGraphRef: + description: An admitted graph in the blob store, verified by digest on load. + type: object + required: [blob, digest] + properties: + blob: + $ref: "#/components/schemas/BlobHash" + digest: + type: string UpdateRunParentRequest: type: object diff --git a/lib/apps/fabro-server/src/server/handler/events.rs b/lib/apps/fabro-server/src/server/handler/events.rs index ec8fc93fa..6fe7b3ed7 100644 --- a/lib/apps/fabro-server/src/server/handler/events.rs +++ b/lib/apps/fabro-server/src/server/handler/events.rs @@ -1,12 +1,17 @@ use std::sync::Arc; +use std::time::Duration; use axum::extract::DefaultBodyLimit; +use fabro_api::types::PaginatedRunStreamList; +use fabro_petri::petri::EVENT_CONTRACT_VERSION; use fabro_types::run_event::MAX_RUN_EVENT_BODY_BYTES; use fabro_types::{ RunEventDetailContent, RunEventDetailContentKind, RunEventDetailEnvelope, - RunEventDetailResponse, + RunEventDetailResponse, RunStreamItem, }; use fabro_workflow::event::build_redacted_event_payload; +use tokio::sync::broadcast::error::RecvError; +use tokio::time::{self, Instant}; use super::super::{ ApiError, AppState, AppendEventResponse, BroadcastStream, Event, EventBody, EventEnvelope, @@ -70,9 +75,12 @@ struct RunEventListParams { #[serde(default)] before_seq: Option, #[serde(default)] - order: EventSequenceOrder, + order: Option, #[serde(default)] limit: Option, + /// The run stream cursor of a Petri run: the last `stream_seq` seen. + #[serde(default)] + after: Option, } impl RunEventListParams { @@ -80,12 +88,21 @@ impl RunEventListParams { self.since_seq.unwrap_or(1).max(1) } + fn order(&self) -> EventSequenceOrder { + self.order.unwrap_or_default() + } + fn limit(&self) -> usize { self.limit.unwrap_or(100).clamp(1, 1000) } fn cursor_error(&self) -> Option<&'static str> { - match self.order { + if self.after.is_some() && (self.since_seq.is_some() || self.before_seq.is_some()) { + return Some( + "after is the run stream cursor and cannot be combined with since_seq or before_seq.", + ); + } + match self.order() { EventSequenceOrder::Asc if self.before_seq.is_some() => { Some("before_seq requires order=desc.") } @@ -95,12 +112,27 @@ impl RunEventListParams { _ => None, } } + + /// Why the parameters do not address a Petri run's stream, if they do + /// not: the legacy cursors have no meaning there. + fn stream_cursor_error(&self) -> Option<&'static str> { + if self.since_seq.is_some() || self.before_seq.is_some() || self.order.is_some() { + return Some( + "this run executes on Petri; its events are a run stream addressed by `after` \ + (the last stream_seq seen), not by since_seq, before_seq or order.", + ); + } + None + } } #[derive(serde::Deserialize)] struct AttachParams { #[serde(default)] since_seq: Option, + /// The run stream cursor of a Petri run: the last `stream_seq` seen. + #[serde(default)] + after: Option, } #[derive(serde::Deserialize)] @@ -256,9 +288,25 @@ async fn list_run_events( } let limit = params.limit(); + match run_is_petri(&state, &id).await { + Ok(true) => { + if let Some(detail) = params.stream_cursor_error() { + return ApiError::bad_request(detail).into_response(); + } + return list_run_stream(&state, id, params.after.unwrap_or(0), limit).await; + } + Ok(false) => {} + Err(response) => return response, + } + if params.after.is_some() { + return ApiError::bad_request( + "after is the run stream cursor of a Petri run; this run's events use since_seq.", + ) + .into_response(); + } match state.stores.runs.open_run_reader(&id).await { Ok(run_store) => { - let events = match params.order { + let events = match params.order() { EventSequenceOrder::Asc => { run_store .list_events_from_with_limit(params.since_seq(), limit) @@ -291,6 +339,171 @@ async fn list_run_events( } } +/// Whether the run executes on Petri, from its stored spec; the canonical +/// 404 when there is no such run. +async fn run_is_petri(state: &AppState, id: &RunId) -> Result { + let projection = state + .load_run_projection(id) + .await + .map_err(IntoResponse::into_response)?; + Ok(projection.spec.engine.is_petri()) +} + +/// One page of a Petri run's stream past `after`. +async fn list_run_stream(state: &AppState, id: RunId, after: u64, limit: usize) -> Response { + match state + .petri_projector + .stream_after(id, after, limit.saturating_add(1)) + .await + { + Ok(mut items) => { + let has_more = items.len() > limit; + items.truncate(limit); + Json(PaginatedRunStreamList { + data: items, + meta: PaginationMeta { + has_more, + total: None, + }, + event_contract_version: EVENT_CONTRACT_VERSION, + }) + .into_response() + } + Err(err) => { + ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response() + } + } +} + +fn sse_event_from_stream_item(item: &RunStreamItem) -> Option { + let data = serde_json::to_string(item).ok()?; + let data = redact_jsonl_line(&data); + Some(Event::default().data(data)) +} + +/// How many stream items one read takes while attached. +const STREAM_ATTACH_BATCH_LIMIT: usize = 256; + +/// How long an attached reader waits for a commit signal before it re-reads +/// its cursor anyway: a signal is a wake-up, never the source of facts. +const STREAM_ATTACH_POLL: Duration = Duration::from_secs(1); + +/// How long an attached reader keeps following a run whose projection is +/// already terminal, waiting for the platform record of the terminal +/// lifecycle transition that ends the stream; after that it ends anyway. +const STREAM_ATTACH_TERMINAL_GRACE: Duration = Duration::from_secs(15); + +/// Whether the item ends an attached stream: the platform record of the +/// run's terminal lifecycle transition, which Fabro writes after the engine +/// recorded the run's finish. The analog of the legacy stream's +/// `run.completed` and `run.failed`. +fn stream_item_is_terminal(item: &RunStreamItem) -> bool { + if item.kind != fabro_types::RunStreamItemKind::Platform { + return false; + } + let record = &item.item["record"]; + record["kind"].as_str() == Some("run.lifecycle") + && matches!( + record["transition"].as_str(), + Some("succeeded" | "failed" | "dead") + ) +} + +/// The live stream of a Petri run from `after` (the last `stream_seq` the +/// client saw; `None` starts at the next unseen item), as server-sent +/// events. Every committed item past the cursor is sent once, in order, +/// and the stream ends once the run is no longer active and every +/// committed item is out. +async fn attach_run_stream(state: Arc, id: RunId, after: Option) -> Response { + let cursor = match after { + Some(after) => after, + None => match state.petri_projector.stream_head(id).await { + Ok(head) => head.unwrap_or(0), + Err(err) => { + return ApiError::new(StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) + .into_response(); + } + }, + }; + let (sender, receiver) = mpsc::unbounded_channel(); + let shutdown = state.shutdown_token(); + tokio::spawn(async move { + // Subscribed before the first read, so a pass that commits between + // the read and the wait is not missed. + let mut committed = state.petri_projector.subscribe(); + let mut cursor = cursor; + // Set once the projection is terminal: the stream then ends at the + // terminal lifecycle record, or when the grace runs out. + let mut terminal_deadline: Option = None; + loop { + // Drain everything committed past the cursor. + let mut drained = false; + while !drained { + let Ok(items) = state + .petri_projector + .stream_after(id, cursor, STREAM_ATTACH_BATCH_LIMIT) + .await + else { + return; + }; + drained = items.len() < STREAM_ATTACH_BATCH_LIMIT; + for item in items { + cursor = item.stream_seq; + let terminal = stream_item_is_terminal(&item); + if let Some(sse_event) = sse_event_from_stream_item(&item) { + if sender + .send(Ok::(sse_event)) + .is_err() + { + return; + } + } + if terminal { + return; + } + } + } + + // The run's status is read after the drain, so an item + // committed with the finish is already out. Once terminal, the + // stream keeps following for the terminal lifecycle record, + // which Fabro writes after the engine's finish, for a bounded + // time. + if terminal_deadline.is_none() { + let active = match state.stores.runs.load_run_projection(&id).await { + Ok(Some(projection)) => run_projection_is_active(&projection), + Ok(None) | Err(_) => false, + }; + if !active { + terminal_deadline = Some(Instant::now() + STREAM_ATTACH_TERMINAL_GRACE); + } + } + if terminal_deadline.is_some_and(|deadline| Instant::now() >= deadline) { + return; + } + + // Wait for the projector to commit more of this run, or poll. + loop { + tokio::select! { + biased; + () = shutdown.cancelled() => return, + signal = committed.recv() => match signal { + Ok(run_id) if run_id == id => break, + Ok(_) => {} + Err(RecvError::Lagged(_)) => break, + Err(RecvError::Closed) => return, + }, + () = time::sleep(STREAM_ATTACH_POLL) => break, + } + } + } + }); + + Sse::new(UnboundedReceiverStream::new(receiver)) + .keep_alive(KeepAlive::default()) + .into_response() +} + async fn list_run_stage_events( RequireRunStageScoped(id, stage_id): RequireRunStageScoped, State(state): State>, @@ -446,6 +659,11 @@ async fn attach_run_events( Ok(id) => id, Err(response) => return response, }; + match run_is_petri(&state, &id).await { + Ok(true) => return attach_run_stream(state, id, params.after).await, + Ok(false) => {} + Err(response) => return response, + } let Ok(run_store) = state.stores.runs.open_run_reader(&id).await else { return ApiError::not_found("Run not found.").into_response(); }; diff --git a/lib/apps/fabro-server/tests/it/scenario/mod.rs b/lib/apps/fabro-server/tests/it/scenario/mod.rs index a58db82af..15ce45a22 100644 --- a/lib/apps/fabro-server/tests/it/scenario/mod.rs +++ b/lib/apps/fabro-server/tests/it/scenario/mod.rs @@ -2,6 +2,7 @@ mod archive; mod dry_run; mod lifecycle; mod petri; +mod petri_stream; mod run_completion; mod sse; mod usage; diff --git a/lib/apps/fabro-server/tests/it/scenario/petri.rs b/lib/apps/fabro-server/tests/it/scenario/petri.rs index 3816fbde9..365755a23 100644 --- a/lib/apps/fabro-server/tests/it/scenario/petri.rs +++ b/lib/apps/fabro-server/tests/it/scenario/petri.rs @@ -105,14 +105,14 @@ const PARALLEL_DOT: &str = r#"digraph Parallel { merge -> exit }"#; -const PLAIN_SETTINGS: &str = "_version = 1\n\n[workflow]\ngraph = \"workflow.fabro\"\n"; +pub(super) const PLAIN_SETTINGS: &str = "_version = 1\n\n[workflow]\ngraph = \"workflow.fabro\"\n"; const PETRI_SETTINGS: &str = "_version = 1\n\n[workflow]\ngraph = \"workflow.fabro\"\nengine = \"petri\"\n"; /// The host plugin as Petri's lookup finds it: the override variable, else /// the executable on `PATH`. `None`, after saying so, when the test should /// skip; a panic when the environment forbids a skip. -fn host_plugin() -> Option { +pub(super) fn host_plugin() -> Option { let found = env::var_os(HOST_PLUGIN_OVERRIDE) .map(PathBuf::from) .or_else(|| { @@ -132,7 +132,7 @@ fn host_plugin() -> Option { /// Register a version whose entrypoint is `workflow.fabro`, with the given /// files beside it. -async fn register_version(app: &axum::Router, files: &[(&str, &str)]) -> String { +pub(super) async fn register_version(app: &axum::Router, files: &[(&str, &str)]) -> String { let entrypoint = WorkflowPath::new("workflow.fabro").expect("entrypoint path is valid"); let files = files .iter() @@ -150,7 +150,7 @@ async fn register_version(app: &axum::Router, files: &[(&str, &str)]) -> String .to_string() } -fn intent(version_id: &str, workspace: &std::path::Path) -> serde_json::Value { +pub(super) fn intent(version_id: &str, workspace: &std::path::Path) -> serde_json::Value { serde_json::json!({ "workflow_version_id": version_id, "target": {"kind": "folder", "path": workspace}, @@ -187,7 +187,11 @@ async fn petri_outcome(state: &AppState, run_id: &str) -> engine::RunOutcome { } /// The run's projected state once its projector settled. -async fn settled_state(state: &AppState, app: &axum::Router, run_id: &str) -> serde_json::Value { +pub(super) async fn settled_state( + state: &AppState, + app: &axum::Router, + run_id: &str, +) -> serde_json::Value { let id: RunId = run_id.parse().expect("the run id parses"); state.test_petri_projector().settle(id).await; let req = Request::builder() @@ -335,6 +339,7 @@ async fn the_hello_bundle_runs_on_petri_when_the_version_names_the_engine() { .any(|request| request["model"] == OPENAI_MODEL), "the prompt stage should have called the twin, got {logs}" ); + super::petri_stream::capture_settled(&state, &app, &run_id, "hello").await; } /// A command-only bundle runs on Petri when the server's setting names the @@ -379,6 +384,7 @@ async fn a_command_bundle_runs_on_petri_under_the_server_setting() { ); let stream = petri_stream_len(&state, &run_id).await; assert!(stream > 0, "the run's stream holds its events"); + super::petri_stream::capture_settled(&state, &app, &run_id, "command").await; } /// A parallel bundle with two command branches runs on Petri through the @@ -685,4 +691,5 @@ async fn a_human_gate_is_answered_through_the_questions_api() { record.principal.is_some(), "the answering principal: {record:?}" ); + super::petri_stream::capture_settled(&state, &app, &run_id, "gate").await; } diff --git a/lib/apps/fabro-server/tests/it/scenario/petri_stream.rs b/lib/apps/fabro-server/tests/it/scenario/petri_stream.rs new file mode 100644 index 000000000..3aab3d53b --- /dev/null +++ b/lib/apps/fabro-server/tests/it/scenario/petri_stream.rs @@ -0,0 +1,421 @@ +//! The run stream of a Petri run through the server: `GET /runs/{id}/events` +//! pages it by `after`, `GET /runs/{id}/attach` follows it live, and a +//! client that disconnects mid-run and reconnects from its last +//! `stream_seq` receives every item once, in order, with no gap and no +//! duplicate, including a platform record Fabro recorded between two +//! concurrent child executions' events. +//! +//! The runs execute in the server process under the handler-registry test +//! override and take their host scope through the sandbox-driver host +//! plugin, so the tests skip, and say why, when the executable is not +//! found (see `petri.rs`). +//! +//! With `FABRO_CAPTURE_PETRI_FIXTURES` set, a scenario also writes its +//! settled projection and full stream as JSON under the web app's test +//! fixtures (`apps/fabro-web/app/test-fixtures/petri/`), which the web +//! app's rendering tests read. + +#![expect( + clippy::disallowed_methods, + reason = "the tests locate the plugin executable and the capture switch through the process environment" +)] +#![expect(clippy::print_stderr, reason = "a skipped test says why on its stderr")] + +use std::collections::BTreeSet; +use std::env; +use std::sync::Arc; +use std::time::Duration; + +use axum::body::Body; +use axum::http::{Request, StatusCode}; +use fabro_server::server::AppState; +use fabro_store::platform_records::{PlatformRecord, PlatformRecordStore, RunNoticeRecord}; +use fabro_types::run_event::RunNoticeLevel; +use fabro_types::{RunId, RunStreamItem, RunStreamItemKind}; +use http_body_util::BodyExt; +use tokio::time::timeout; +use tower::ServiceExt; + +use super::petri::{PLAIN_SETTINGS, host_plugin, intent, register_version, settled_state}; +use crate::helpers::{ + api, create_and_start_run_from_intent, repo_root, response_json, run_json, settings_from_toml, + test_app_state_with_options, test_app_with_scheduler, wait_for_run_status, +}; + +const CAPTURE_ENV: &str = "FABRO_CAPTURE_PETRI_FIXTURES"; +const FRAME_TIMEOUT: Duration = Duration::from_secs(20); + +/// Two command branches that announce they started and wait for a release +/// marker, so a test can act between their events. +fn gated_parallel_dot(markers: &std::path::Path) -> String { + let dir = markers.display(); + format!( + r#"digraph Parallel {{ + graph [goal="Run two branches"] + start [shape=Mdiamond] + exit [shape=Msquare] + fork [shape=component] + a [shape=parallelogram, script="touch {dir}/a.started; while [ ! -f {dir}/go ]; do sleep 0.05; done; echo a"] + b [shape=parallelogram, script="touch {dir}/b.started; while [ ! -f {dir}/go ]; do sleep 0.05; done; echo b"] + merge [shape=tripleoctagon] + start -> fork + fork -> a + fork -> b + a -> merge + b -> merge + merge -> exit +}}"# + ) +} + +/// One page of the run's stream past `after`. +async fn stream_page( + app: &axum::Router, + run_id: &str, + after: u64, + limit: usize, +) -> serde_json::Value { + let req = Request::builder() + .method("GET") + .uri(api(&format!( + "/runs/{run_id}/events?after={after}&limit={limit}" + ))) + .body(Body::empty()) + .expect("events request should build"); + let response = app + .clone() + .oneshot(req) + .await + .expect("events request routes"); + response_json( + response, + StatusCode::OK, + format!("GET /api/v1/runs/{run_id}/events?after={after}&limit={limit}"), + ) + .await +} + +/// Every item of the run's stream, paged through the listing endpoint. +pub(super) async fn list_stream( + app: &axum::Router, + run_id: &str, + page_limit: usize, +) -> Vec { + let mut after = 0; + let mut items = Vec::new(); + loop { + let page = stream_page(app, run_id, after, page_limit).await; + let data: Vec = + serde_json::from_value(page["data"].clone()).expect("stream items decode"); + let has_more = page["meta"]["has_more"] + .as_bool() + .expect("has_more is a bool"); + assert_eq!( + page["event_contract_version"].as_u64(), + Some(3), + "the server reports Petri's contract version: {page}" + ); + let Some(last) = data.last() else { + assert!(!has_more, "an empty page is the last"); + break; + }; + after = last.stream_seq; + items.extend(data); + if !has_more { + break; + } + } + items +} + +/// An attached reader of the run's stream that stops reading when `until` +/// says so, as a client that lost its connection would: the frames it saw +/// so far come back. +struct Attached { + body: Body, + pending: String, +} + +impl Attached { + async fn open(app: &axum::Router, run_id: &str, after: u64) -> Self { + let req = Request::builder() + .method("GET") + .uri(api(&format!("/runs/{run_id}/attach?after={after}"))) + .body(Body::empty()) + .expect("attach request should build"); + let response = app + .clone() + .oneshot(req) + .await + .expect("attach request routes"); + assert_eq!(response.status(), StatusCode::OK); + assert!( + response + .headers() + .get("content-type") + .and_then(|value| value.to_str().ok()) + .is_some_and(|value| value.contains("text/event-stream")), + "an SSE response" + ); + Self { + body: response.into_body(), + pending: String::new(), + } + } + + /// The next item on the stream, or `None` once the server ended it. + async fn next(&mut self) -> Option { + loop { + if let Some(end) = self.pending.find("\n\n") { + let frame = self.pending[..end].to_string(); + self.pending.drain(..end + 2); + let data = frame + .lines() + .filter_map(|line| line.strip_prefix("data:")) + .map(str::trim) + .collect::>() + .join("\n"); + if data.is_empty() { + continue; + } + return Some(serde_json::from_str(&data).expect("a stream item frame decodes")); + } + let frame = timeout(FRAME_TIMEOUT, self.body.frame()) + .await + .expect("the attached stream keeps sending or ends"); + match frame { + Some(Ok(frame)) => { + if let Some(data) = frame.data_ref() { + self.pending.push_str(&String::from_utf8_lossy(data)); + } + } + Some(Err(err)) => panic!("the attached stream failed: {err}"), + None => return None, + } + } + } +} + +fn petri_name(item: &RunStreamItem) -> Option<&str> { + (item.kind == RunStreamItemKind::Petri) + .then(|| item.name()) + .flatten() +} + +/// The subject's node name, for a node that is a stage of its own: the +/// `parallel.branch` delegate the fork's execution holds for each branch +/// shares the branch's name and is not one. +fn subject_node(item: &RunStreamItem) -> Option<&str> { + let node = &item.item["subject"]["node"]; + if node["meta"]["kind"].as_str() == Some("parallel.branch") { + return None; + } + node["name"].as_str() +} + +fn wait_for_marker(path: &std::path::Path) { + let deadline = std::time::Instant::now() + Duration::from_secs(20); + while !path.exists() { + assert!( + std::time::Instant::now() < deadline, + "{} never appeared", + path.display() + ); + std::thread::sleep(Duration::from_millis(20)); + } +} + +/// A client attached to a two-branch parallel run disconnects once both +/// branches have started, Fabro records a platform notice while they run, +/// the client reconnects from its last `stream_seq`, and the union of what +/// it saw is the whole stream: every item once, in `stream_seq` order, no +/// gap, no duplicate, with the notice between the branches' events. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn a_reconnecting_client_receives_every_stream_item_once_in_order() { + if host_plugin().is_none() { + return; + } + let workspace = tempfile::tempdir().expect("workspace tempdir"); + let markers = tempfile::tempdir().expect("marker tempdir"); + let settings = settings_from_toml( + "_version = 1\n\n[run.environment]\nid = \"local\"\n\n[server.execution]\nengine = \ + \"petri\"\n", + ); + let state = test_app_state_with_options(settings, 5); + let app = test_app_with_scheduler(Arc::clone(&state)); + + let dot = gated_parallel_dot(markers.path()); + let version_id = register_version(&app, &[ + ("workflow.fabro", &dot), + ("workflow.toml", PLAIN_SETTINGS), + ]) + .await; + let run_id = + create_and_start_run_from_intent(&app, intent(&version_id, workspace.path())).await; + let id: RunId = run_id.parse().expect("the run id parses"); + + // First connection: from the start of the run until both branches + // have a `visit.started` on the stream, then drop it. + let mut first = Attached::open(&app, &run_id, 0).await; + let mut seen_first: Vec = Vec::new(); + let mut started: BTreeSet = BTreeSet::new(); + while started.len() < 2 { + let item = first + .next() + .await + .expect("the stream runs until both branches started"); + if petri_name(&item) == Some("visit.started") { + if let Some(node @ ("a" | "b")) = subject_node(&item) { + started.insert(node.to_string()); + } + } + seen_first.push(item); + } + let last_seen = seen_first + .last() + .map(|item| item.stream_seq) + .expect("something was seen"); + drop(first); + + // Both branch scripts are running: record a platform fact between + // their events, as a checkpoint or a notice would be, then let them go. + wait_for_marker(&markers.path().join("a.started")); + wait_for_marker(&markers.path().join("b.started")); + let platform = PlatformRecordStore::new(state.test_petri_view_pool()); + let notice = platform + .append( + &id, + &PlatformRecord::RunNotice(RunNoticeRecord { + level: RunNoticeLevel::Info, + code: "test.between_branches".to_string(), + message: "recorded while both branches ran".to_string(), + }), + None, + ) + .await + .expect("the notice appends"); + state.test_petri_projector().signal(id); + state.test_petri_projector().settle(id).await; + std::fs::write(markers.path().join("go"), b"").expect("the release marker writes"); + + // Second connection: resume from the last stream_seq seen and read to + // the end of the stream, which the server closes once the run is done. + let mut second = Attached::open(&app, &run_id, last_seen).await; + let mut seen_second: Vec = Vec::new(); + while let Some(item) = second.next().await { + seen_second.push(item); + } + let status = wait_for_run_status(&app, &run_id, &["succeeded", "failed"]).await; + let run = run_json(&app, &run_id).await; + assert_eq!(status, "succeeded", "run: {run}"); + let projection = settled_state(&state, &app, &run_id).await; + assert_eq!(projection["status"]["kind"], "succeeded", "{projection}"); + + // The union is the whole stream, once each, in order, with no gap. + let mut union = seen_first; + union.extend(seen_second); + let seqs: Vec = union.iter().map(|item| item.stream_seq).collect(); + let expected: Vec = (1..=seqs.len() as u64).collect(); + assert_eq!( + seqs, expected, + "stream_seq is dense and strictly increasing" + ); + let ids: BTreeSet<&str> = union.iter().map(|item| item.id.as_str()).collect(); + assert_eq!(ids.len(), union.len(), "every item identity appears once"); + for item in &union { + assert_eq!(item.run_id, id); + assert!(item.recorded_at > 0, "{item:?}"); + } + + // The same stream, paged through the listing endpoint with small + // pages, is item for item what the attached client saw. + let listed = list_stream(&app, &run_id, 7).await; + assert_eq!(listed, union, "the listing pages the same stream"); + + // The notice sits between the branches' events. + let notice_seq = union + .iter() + .find(|item| item.kind == RunStreamItemKind::Platform && item.id == notice.seq.to_string()) + .map(|item| item.stream_seq) + .expect("the notice is on the stream"); + let branch_seqs = |name: &str| -> Vec { + union + .iter() + .filter(|item| { + petri_name(item) == Some(name) && matches!(subject_node(item), Some("a" | "b")) + }) + .map(|item| item.stream_seq) + .collect() + }; + let starts = branch_seqs("visit.started"); + let ends = branch_seqs("visit.completed"); + assert_eq!(starts.len(), 2, "{starts:?}"); + assert_eq!(ends.len(), 2, "{ends:?}"); + assert!( + starts.iter().all(|seq| *seq < notice_seq) && ends.iter().all(|seq| *seq > notice_seq), + "the notice ({notice_seq}) is between the branch starts {starts:?} and ends {ends:?}" + ); + let finished = union + .iter() + .filter(|item| petri_name(item) == Some("run.finished")) + .count(); + assert_eq!(finished, 1, "the stream ends with the run's finish"); + + // The legacy cursors are refused for a Petri run; the stream cursor is + // refused for nothing else. + let req = Request::builder() + .method("GET") + .uri(api(&format!("/runs/{run_id}/events?since_seq=1"))) + .body(Body::empty()) + .expect("events request should build"); + let response = app + .clone() + .oneshot(req) + .await + .expect("events request routes"); + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + capture_fixture(&app, &run_id, "parallel", &projection).await; +} + +/// Write the run's settled projection and its whole stream under the web +/// app's test fixtures, when the capture switch is set. +pub(super) async fn capture_fixture( + app: &axum::Router, + run_id: &str, + name: &str, + projection: &serde_json::Value, +) { + if env::var_os(CAPTURE_ENV).is_none() { + return; + } + let stream = list_stream(app, run_id, 1000).await; + let fixture = serde_json::json!({ + "run_id": run_id, + "projection": projection, + "stream": stream, + }); + let dir = repo_root().join("apps/fabro-web/app/test-fixtures/petri"); + std::fs::create_dir_all(&dir).expect("the fixture directory creates"); + let path = dir.join(format!("{name}.json")); + std::fs::write( + &path, + serde_json::to_string_pretty(&fixture).expect("the fixture serializes"), + ) + .expect("the fixture writes"); + eprintln!("captured {}", path.display()); +} + +/// Helpers the other Petri scenarios use to capture their fixtures. +pub(super) async fn capture_settled( + state: &AppState, + app: &axum::Router, + run_id: &str, + name: &str, +) { + if env::var_os(CAPTURE_ENV).is_none() { + return; + } + let projection = settled_state(state, app, run_id).await; + capture_fixture(app, run_id, name, &projection).await; +} diff --git a/lib/components/fabro-petri/src/petri.rs b/lib/components/fabro-petri/src/petri.rs index 726edac63..e4464cca0 100644 --- a/lib/components/fabro-petri/src/petri.rs +++ b/lib/components/fabro-petri/src/petri.rs @@ -3,6 +3,11 @@ //! depending on the Petri packages themselves. Only this crate names them in //! its `Cargo.toml`. +use petri_execution::events; pub use petri_store::{ Access, Digest, ExecutionId, LogId, OwnerId, Record, RunKey, RunLogs, RunStore, StoreError, }; + +/// The version of Petri's public event contract this build serves on the +/// run stream: every `petri` item of `GET /runs/{id}/events` follows it. +pub const EVENT_CONTRACT_VERSION: u32 = events::EVENT_CONTRACT_VERSION; diff --git a/lib/components/fabro-petri/src/projector.rs b/lib/components/fabro-petri/src/projector.rs index 3215a842b..2e304e9b2 100644 --- a/lib/components/fabro-petri/src/projector.rs +++ b/lib/components/fabro-petri/src/projector.rs @@ -46,13 +46,13 @@ use std::time::Duration; use fabro_db::DbPool; use fabro_store::platform_records::{PlatformRecordStore, StoredPlatformRecord, now_ms}; use fabro_store::{RunProjection, RunSummaryStore}; -use fabro_types::RunId; +use fabro_types::{RunId, RunStreamItem, RunStreamItemKind}; use fabro_util::error::collect_chain; use petri_execution::events::{self, EventId, EventSource, RunEvent}; use petri_execution::{Access, RunKey, RunStore as _, inspect}; use petri_store::StoreError; use serde::{Deserialize, Serialize}; -use tokio::sync::Mutex as AsyncMutex; +use tokio::sync::{Mutex as AsyncMutex, broadcast}; use tokio::time; use tracing::{debug, info, warn}; @@ -147,17 +147,21 @@ struct Slot { /// the server both are the one database; a test may hand it the run /// summary store's own pool for the views. pub struct Projector { - records: DbPool, - pool: DbPool, - store: SqliteRunStore, - platform: PlatformRecordStore, - slots: Mutex>, + records: DbPool, + pool: DbPool, + store: SqliteRunStore, + platform: PlatformRecordStore, + slots: Mutex>, /// One pass at a time per run: a signalled pass and the startup pass /// over the same run never interleave their reads and writes. - passes: Mutex>>>, + passes: Mutex>>>, /// Test-only: stop the next pass after its reads, before its view /// transaction, as a crash there would. - fault: AtomicBool, + fault: AtomicBool, + /// Sent after each committed pass that wrote stream rows: the run whose + /// stream grew. A wake-up for the stream's readers, never a source of + /// facts; a reader that lags re-reads from its cursor. + committed: broadcast::Sender, } impl std::fmt::Debug for Projector { @@ -180,9 +184,42 @@ impl Projector { slots: Mutex::default(), passes: Mutex::default(), fault: AtomicBool::new(false), + committed: broadcast::channel(COMMIT_SIGNAL_CAPACITY).0, }) } + /// A receiver that learns which run's stream grew after each committed + /// pass. A receiver that falls behind gets `Lagged` and treats it as a + /// wake-up for every run it follows. + #[must_use] + pub fn subscribe(&self) -> broadcast::Receiver { + self.committed.subscribe() + } + + /// The run's stream past the cursor: up to `limit` items with + /// `stream_seq > after`, in `stream_seq` order, each in Fabro's + /// envelope. `after = 0` reads from the first item. + pub async fn stream_after( + &self, + run_id: RunId, + after: u64, + limit: usize, + ) -> Result, ProjectError> { + stream_after(&self.pool, run_id, after, limit).await + } + + /// The last delivery sequence the run's view holds, or `None` when no + /// pass has committed a view for it. + pub async fn stream_head(&self, run_id: RunId) -> Result, ProjectError> { + let head: Option = + sqlx::query_scalar("SELECT stream_seq FROM petri_projection WHERE run_id = ?") + .bind(run_id.to_string()) + .fetch_optional(&self.pool) + .await + .map_err(ProjectError::Database)?; + Ok(head.map(|head| u64::try_from(head).unwrap_or(0))) + } + /// Schedule a pass for the run. A pass already running for it runs once /// more when it ends; any number of signals in between coalesce. pub fn signal(self: &Arc, run_id: RunId) { @@ -471,6 +508,10 @@ impl Projector { stream_seq, "Petri projection pass committed" ); + if !rows.is_empty() { + // No receiver is not an error: nobody follows the stream. + let _ = self.committed.send(run_id); + } Ok(PassReport { run_id, skipped: false, @@ -658,6 +699,52 @@ struct StreamRow { event_json: String, } +/// How many commit signals a slow reader may fall behind before it is told +/// it lagged and re-reads from its cursor. +const COMMIT_SIGNAL_CAPACITY: usize = 1024; + +/// The run's stream past the cursor, read from the view tables: up to +/// `limit` rows with `stream_seq > after`, in order, in Fabro's envelope. +pub async fn stream_after( + views: &DbPool, + run_id: RunId, + after: u64, + limit: usize, +) -> Result, ProjectError> { + let rows: Vec<(i64, String, String, String)> = sqlx::query_as( + "SELECT stream_seq, item_kind, item_id, event_json FROM petri_stream WHERE run_id = ? AND \ + stream_seq > ? ORDER BY stream_seq LIMIT ?", + ) + .bind(run_id.to_string()) + .bind(column(after)) + .bind(i64::try_from(limit).unwrap_or(i64::MAX)) + .fetch_all(views) + .await + .map_err(ProjectError::Database)?; + rows.into_iter() + .map(|(stream_seq, item_kind, item_id, event_json)| { + let item: serde_json::Value = + serde_json::from_str(&event_json).map_err(ProjectError::Encode)?; + let kind = match item_kind.as_str() { + "platform" => RunStreamItemKind::Platform, + _ => RunStreamItemKind::Petri, + }; + let recorded_at = item + .get("recorded_at") + .and_then(serde_json::Value::as_u64) + .unwrap_or(0); + Ok(RunStreamItem { + run_id, + stream_seq: u64::try_from(stream_seq).unwrap_or(0), + kind, + id: item_id, + recorded_at, + item, + }) + }) + .collect() +} + /// A Petri event id as the stream names it: `//`. #[must_use] pub fn event_id_text(id: &EventId) -> String { diff --git a/lib/foundation/fabro-api/build.rs b/lib/foundation/fabro-api/build.rs index 1834074df..1580c2020 100644 --- a/lib/foundation/fabro-api/build.rs +++ b/lib/foundation/fabro-api/build.rs @@ -658,6 +658,11 @@ fn main() { &[], ), ("EventEnvelope", "fabro_types::EventEnvelope", &[]), + ("RunStreamItem", "fabro_types::RunStreamItem", &[]), + ("RunStreamItemKind", "fabro_types::RunStreamItemKind", &[]), + ("RunEngine", "fabro_types::RunEngine", &[]), + ("PetriAdmission", "fabro_types::PetriAdmission", &[]), + ("PetriGraphRef", "fabro_types::PetriGraphRef", &[]), ("PullRequest", "fabro_types::PullRequest", &[]), ("PullRequestLink", "fabro_types::PullRequestLink", &[]), ( diff --git a/lib/foundation/fabro-api/src/lib.rs b/lib/foundation/fabro-api/src/lib.rs index 7fa81a11e..0fa5c0abf 100644 --- a/lib/foundation/fabro-api/src/lib.rs +++ b/lib/foundation/fabro-api/src/lib.rs @@ -52,25 +52,25 @@ pub mod types { ModelTestMode, ModelUsage, PairId, PairMessageId, PairMessageRecord, PairMessageRequest, PairRecord, PairStartRequest, PairStatus, PairTarget, PairTranscriptEntry, PairTranscriptResponse, ParallelBranchId, ParallelBranchResult, PendingInterviewRecord, - PermissionLevel, Principal, Provider, PullRequest, PullRequestCreation, - PullRequestCreationId, PullRequestCreationStatus, PullRequestDetails, + PermissionLevel, PetriAdmission, PetriGraphRef, Principal, Provider, PullRequest, + PullRequestCreation, PullRequestCreationId, PullRequestCreationStatus, PullRequestDetails, PullRequestDetailsStatus, PullRequestDetailsUnavailableReason, PullRequestLink, PullRequestMeta, PullRequestResponse, QuestionType, RepositoryRef, ReviewTarget, - ReviewTargetKind, Run, RunApproval, RunApprovalState, RunClientProvenance, RunEvent, - RunEventDetailContentKind, RunEventDetailResponse, RunFailure, RunIntent, RunIntentArgs, - RunPairStatusResponse, RunProjection, RunProvenance, RunRunnableSource, RunSandbox, - RunSandboxFailure, RunSandboxInstance, RunSandboxKind, RunSandboxPlan, RunSandboxRuntime, - RunServerProvenance, RunSessionMetadata, RunSize, RunTarget, SandboxDetails, SandboxInfo, - SandboxListMeta, SandboxListResponse, SandboxProviderKind, SandboxProviderLookupError, - SandboxService, SandboxServiceListResponse, SecretMetadata, SecretType, ServerSettings, - SessionDetail, SessionId, SessionStatus, SessionSummary, SessionTurn, - SkillActivationSource, SkillSummary, StageCompletion, StageContextWindow, - StageContextWindowUnavailableReason, StageHandler, StageId, StageInferenceProjection, - StageModelUsage, StageOutcome, StageProjection, StageState, StageToolBatchProjection, - SystemActorKind, SystemIntegrationStatus, SystemIntegrationsResponse, TodoListProjection, - ToolCategory, ToolSource, ToolSummary, TurnId, UpdateVariableRequest, UserPrincipal, - Variable, VariableListResponse, WorkflowPath, WorkflowSettings, WorkflowVersion, - WorkflowVersionId, + ReviewTargetKind, Run, RunApproval, RunApprovalState, RunClientProvenance, RunEngine, + RunEvent, RunEventDetailContentKind, RunEventDetailResponse, RunFailure, RunIntent, + RunIntentArgs, RunPairStatusResponse, RunProjection, RunProvenance, RunRunnableSource, + RunSandbox, RunSandboxFailure, RunSandboxInstance, RunSandboxKind, RunSandboxPlan, + RunSandboxRuntime, RunServerProvenance, RunSessionMetadata, RunSize, RunStreamItem, + RunStreamItemKind, RunTarget, SandboxDetails, SandboxInfo, SandboxListMeta, + SandboxListResponse, SandboxProviderKind, SandboxProviderLookupError, SandboxService, + SandboxServiceListResponse, SecretMetadata, SecretType, ServerSettings, SessionDetail, + SessionId, SessionStatus, SessionSummary, SessionTurn, SkillActivationSource, SkillSummary, + StageCompletion, StageContextWindow, StageContextWindowUnavailableReason, StageHandler, + StageId, StageInferenceProjection, StageModelUsage, StageOutcome, StageProjection, + StageState, StageToolBatchProjection, SystemActorKind, SystemIntegrationStatus, + SystemIntegrationsResponse, TodoListProjection, ToolCategory, ToolSource, ToolSummary, + TurnId, UpdateVariableRequest, UserPrincipal, Variable, VariableListResponse, WorkflowPath, + WorkflowSettings, WorkflowVersion, WorkflowVersionId, }; pub use lithos_llm::catalog::{ModelHandle, ProviderId}; pub use lithos_llm::types::{ diff --git a/lib/foundation/fabro-api/tests/run_engine_round_trip.rs b/lib/foundation/fabro-api/tests/run_engine_round_trip.rs new file mode 100644 index 000000000..914ae56cf --- /dev/null +++ b/lib/foundation/fabro-api/tests/run_engine_round_trip.rs @@ -0,0 +1,57 @@ +use std::any::{TypeId, type_name}; + +use fabro_api::types::{ + PetriAdmission as ApiPetriAdmission, PetriGraphRef as ApiPetriGraphRef, + RunEngine as ApiRunEngine, +}; +use fabro_types::{PetriAdmission, PetriGraphRef, RunEngine}; +use serde_json::json; + +#[test] +fn run_engine_reuses_canonical_types() { + assert_same_type::(); + assert_same_type::(); + assert_same_type::(); +} + +#[test] +fn the_legacy_engine_round_trips_as_its_kind_alone() { + let value = json!({ "kind": "legacy" }); + let engine: RunEngine = serde_json::from_value(value.clone()).unwrap(); + assert!(engine.is_legacy()); + assert_eq!(serde_json::to_value(&engine).unwrap(), value); +} + +#[test] +fn the_petri_engine_round_trips_with_its_admission_flattened() { + let value = json!({ + "kind": "petri", + "graph": { + "blob": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "digest": "sha256:root" + }, + "children": [ + { + "blob": "3cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", + "digest": "sha256:child" + } + ] + }); + let engine: RunEngine = serde_json::from_value(value.clone()).unwrap(); + let admission = engine + .petri() + .expect("a Petri engine carries its admission"); + assert_eq!(admission.graph.digest, "sha256:root"); + assert_eq!(admission.children.len(), 1); + assert_eq!(serde_json::to_value(&engine).unwrap(), value); +} + +fn assert_same_type() { + assert_eq!( + TypeId::of::(), + TypeId::of::(), + "{} should be the same type as {}", + type_name::(), + type_name::() + ); +} diff --git a/lib/foundation/fabro-api/tests/run_stream_item_round_trip.rs b/lib/foundation/fabro-api/tests/run_stream_item_round_trip.rs new file mode 100644 index 000000000..3147c9646 --- /dev/null +++ b/lib/foundation/fabro-api/tests/run_stream_item_round_trip.rs @@ -0,0 +1,74 @@ +use std::any::{TypeId, type_name}; + +use fabro_api::types::{ + RunStreamItem as ApiRunStreamItem, RunStreamItemKind as ApiRunStreamItemKind, +}; +use fabro_types::{RunStreamItem, RunStreamItemKind, fixtures}; +use serde_json::json; + +#[test] +fn run_stream_item_reuses_canonical_types() { + assert_same_type::(); + assert_same_type::(); +} + +#[test] +fn a_petri_item_round_trips_with_its_event_unchanged() { + let value = json!({ + "run_id": fixtures::RUN_1.to_string(), + "stream_seq": 12, + "kind": "petri", + "id": "execution 1/23/0", + "recorded_at": 1_789_323_217_459_u64, + "item": { + "id": { "log": "execution", "execution": 1, "seq": 23, "index": 0 }, + "origin": "core", + "recorded_at": 1_789_323_217_459_u64, + "context": { "invocation": 0, "execution": 1 }, + "subject": { + "node": { "id": 4, "name": "review", "kind": "attractor/agent", "meta": { "kind": "agent" } }, + "firing": 3, "visit": 1, "attempt": 1, "generation": 0, "branch": { "role": "none" } + }, + "record": { + "seq": 23, "origin": "core", "recorded_at": 1_789_323_217_459_u64, + "body": { "event": "route.applied", "kind": "jump", "firing": 3, "target": 7 } + }, + "derived": { "target": { "id": 7, "name": "finalize", "kind": "attractor/command", "meta": { "kind": "command" } } } + } + }); + let item: RunStreamItem = serde_json::from_value(value.clone()).unwrap(); + assert_eq!(item.kind, RunStreamItemKind::Petri); + assert_eq!(item.name(), Some("route.applied")); + assert_eq!(serde_json::to_value(&item).unwrap(), value); +} + +#[test] +fn a_platform_item_round_trips_with_its_record_unchanged() { + let value = json!({ + "run_id": fixtures::RUN_1.to_string(), + "stream_seq": 13, + "kind": "platform", + "id": "4", + "recorded_at": 1_789_323_217_500_u64, + "item": { + "seq": 4, + "recorded_at": 1_789_323_217_500_u64, + "record": { "kind": "checkpoint", "execution": 1, "firing": 3, "git_commit_sha": "abc123" }, + "position": { "execution": 1, "firing": 3 } + } + }); + let item: RunStreamItem = serde_json::from_value(value.clone()).unwrap(); + assert_eq!(item.kind, RunStreamItemKind::Platform); + assert_eq!(item.name(), Some("checkpoint")); + assert_eq!(serde_json::to_value(&item).unwrap(), value); +} + +fn assert_same_type() { + assert_eq!( + TypeId::of::(), + TypeId::of::(), + "{} should be the same type as {}", + type_name::(), + type_name::() + ); +} diff --git a/lib/foundation/fabro-client/src/client.rs b/lib/foundation/fabro-client/src/client.rs index 03f16e479..2a2fa9c4d 100644 --- a/lib/foundation/fabro-client/src/client.rs +++ b/lib/foundation/fabro-client/src/client.rs @@ -15,7 +15,7 @@ use fabro_types::{ ArtifactUpload, BlobHash, EventEnvelope, Model, ModelTestMode, PairId, PairMessageRecord, PairMessageRequest, PairRecord, PairStartRequest, PairTranscriptResponse, Run, RunEvent, RunEventDetailResponse, RunId, RunPairStatusResponse, RunProjection, RunSessionMetadata, - SessionId, StageId, WorkflowVersion, WorkflowVersionId, + RunStreamItem, SessionId, StageId, WorkflowVersion, WorkflowVersionId, }; use fabro_util::exit::{ErrorExt, ExitClass}; use futures::future::BoxFuture; @@ -56,6 +56,24 @@ pub struct RunEventStream { buffered_events: VecDeque, } +/// The live stream of a Petri run, as `GET /runs/{id}/attach` serves it: +/// one `RunStreamItem` per `data:` frame, in `stream_seq` order. +pub struct RunStreamItemStream { + stream: progenitor_client::ByteStream, + pending_bytes: Vec, + buffered_items: VecDeque, +} + +/// One page of a Petri run's stream. +#[derive(Debug, Clone)] +pub struct RunStreamPage { + pub items: Vec, + pub has_more: bool, + /// Petri's `EVENT_CONTRACT_VERSION` the server serves; `None` when the + /// page was empty and the server reported no version beside it. + pub event_contract_version: Option, +} + type HttpByteStream = Pin> + Send>>; pub struct SessionEventStream { @@ -186,6 +204,42 @@ impl RunEventStream { } } +impl RunStreamItemStream { + #[must_use] + pub fn new(stream: progenitor_client::ByteStream) -> Self { + Self { + stream, + pending_bytes: Vec::new(), + buffered_items: VecDeque::new(), + } + } + + pub async fn next_item(&mut self) -> Result> { + loop { + if let Some(item) = self.buffered_items.pop_front() { + return Ok(Some(item)); + } + + if let Some(chunk) = self.stream.next().await { + let chunk = chunk.map_err(anyhow::Error::new)?; + self.pending_bytes.extend_from_slice(&chunk); + self.buffer_sse_items(false)?; + } else { + self.buffer_sse_items(true)?; + return Ok(self.buffered_items.pop_front()); + } + } + } + + fn buffer_sse_items(&mut self, finalize: bool) -> Result<()> { + for payload in sse::drain_sse_payloads(&mut self.pending_bytes, finalize) { + self.buffered_items + .push_back(serde_json::from_str(&payload)?); + } + Ok(()) + } +} + impl SessionEventStream { #[must_use] pub fn new(stream: HttpByteStream) -> Self { @@ -1813,7 +1867,15 @@ impl Client { request.send().await }) .await?; - let parsed = response.into_inner(); + let parsed = match response.into_inner() { + types::ListRunEventsResponse::EventList(page) => page, + types::ListRunEventsResponse::RunStreamList(_) => { + bail!( + "run {run_id} executes on Petri; its events are served as a run stream \ + (list_run_stream)" + ); + } + }; let events = parsed .data .into_iter() @@ -1822,6 +1884,84 @@ impl Client { Ok((events, parsed.meta.has_more)) } + /// One page of a Petri run's stream: up to `limit` items with + /// `stream_seq > after`, in order. + pub async fn list_run_stream_page( + &self, + run_id: &RunId, + after: u64, + limit: Option, + ) -> Result { + let response = self + .send_api(|client| async move { + let mut request = client.list_run_events().id(run_id.to_string()).after(after); + let page_limit = limit.map(|limit| limit.min(1000)); + if let Some(limit) = page_limit.and_then(non_zero_u64_from_usize) { + request = request.limit(limit); + } + request.send().await + }) + .await?; + match response.into_inner() { + types::ListRunEventsResponse::RunStreamList(page) => Ok(RunStreamPage { + items: page.data, + has_more: page.meta.has_more, + event_contract_version: Some(page.event_contract_version), + }), + // An empty page decodes as either list; a legacy page with + // items is a run that does not execute on Petri. + types::ListRunEventsResponse::EventList(page) if page.data.is_empty() => { + Ok(RunStreamPage { + items: Vec::new(), + has_more: page.meta.has_more, + event_contract_version: None, + }) + } + types::ListRunEventsResponse::EventList(_) => { + bail!("run {run_id} executes on the legacy engine; its events are not a run stream") + } + } + } + + /// Every item of a Petri run's stream past `after`, page by page. + pub async fn list_run_stream(&self, run_id: &RunId, after: u64) -> Result> { + let mut cursor = after; + let mut all = Vec::new(); + loop { + let page = self.list_run_stream_page(run_id, cursor, None).await?; + let Some(last) = page.items.last() else { + break; + }; + cursor = last.stream_seq; + let has_more = page.has_more; + all.extend(page.items); + if !has_more { + break; + } + } + Ok(all) + } + + /// The live stream of a Petri run from `after` (the last `stream_seq` + /// seen; `Some(0)` replays the whole run; `None` starts at the next + /// unseen item). + pub async fn attach_run_stream( + &self, + run_id: &RunId, + after: Option, + ) -> Result { + let response = self + .send_api(|client| async move { + let mut request = client.attach_run_events().id(run_id.to_string()); + if let Some(after) = after { + request = request.after(after); + } + request.send().await + }) + .await?; + Ok(RunStreamItemStream::new(response.into_inner())) + } + pub async fn attach_run_events( &self, run_id: &RunId, diff --git a/lib/foundation/fabro-client/src/lib.rs b/lib/foundation/fabro-client/src/lib.rs index e65e02560..d85fb6c47 100644 --- a/lib/foundation/fabro-client/src/lib.rs +++ b/lib/foundation/fabro-client/src/lib.rs @@ -12,7 +12,8 @@ pub use auth_store::{ AuthEntry, AuthStore, AuthStoreError, DevTokenEntry, LockError, OAuthEntry, StoredSubject, }; pub use client::{ - Client, RunEventStream, SessionEventStream, TransportConnector, apply_bearer_token_auth, + Client, RunEventStream, RunStreamItemStream, RunStreamPage, SessionEventStream, + TransportConnector, apply_bearer_token_auth, }; pub use credential::{Credential, CredentialFallback}; pub use error::{ diff --git a/lib/foundation/fabro-types/src/lib.rs b/lib/foundation/fabro-types/src/lib.rs index be945029a..543c02c62 100644 --- a/lib/foundation/fabro-types/src/lib.rs +++ b/lib/foundation/fabro-types/src/lib.rs @@ -35,6 +35,7 @@ pub mod run_id; pub mod run_intent; pub mod run_projection; pub mod run_sandbox; +pub mod run_stream; pub mod run_summary; pub mod run_title; pub mod sandbox_details; @@ -152,6 +153,7 @@ pub use run_sandbox::{ RunSandbox, RunSandboxFailure, RunSandboxInstance, RunSandboxKind, RunSandboxPlan, RunSandboxRuntime, }; +pub use run_stream::{RunStreamItem, RunStreamItemKind, petri_event_name}; pub use run_summary::{ AskFabro, AskFabroUnavailableReason, AutomationRef, ResolvedAutomationGitWorkflowSource, Run, RunApproval, RunApprovalState, RunError, RunLifecycle, RunLinks, RunModel, RunOrigin, diff --git a/lib/foundation/fabro-types/src/run_stream.rs b/lib/foundation/fabro-types/src/run_stream.rs new file mode 100644 index 000000000..dee4fa7b5 --- /dev/null +++ b/lib/foundation/fabro-types/src/run_stream.rs @@ -0,0 +1,168 @@ +//! The run stream: one ordered delivery of a Petri run's public events and +//! Fabro's platform records, as `GET /runs/{id}/events` and the attach +//! stream serve them for a run that executes on Petri. +//! +//! Each item is a Petri `RunEvent` (Petri's event contract, passed through +//! as JSON) or a stored platform record (Fabro's own fact about the run: +//! its lifecycle before and after the engine, a checkpoint with its commit, +//! a pull request), in one Fabro envelope. The envelope carries: +//! +//! - `stream_seq`, the durable per-run delivery sequence the projector assigned +//! when the item's record was committed. It is the cursor: a client resumes +//! from the last `stream_seq` it saw. It is dense and strictly increasing +//! within a run. +//! - `id`, the item's own identity, kept beside the cursor so a client +//! deduplicates by it: for a Petri event the `EventId` as +//! `//` (`coordinator/3/0`, `execution 1/23/0`), for a +//! platform record its `seq`. Petri's `EventId` is per log and has no +//! platform variant, so it is never the cursor. +//! - `kind`, which of the two the item is. +//! - `recorded_at`, when the item's record was appended, in milliseconds since +//! the Unix epoch; the same field both item shapes carry. +//! - `item`, the Petri `RunEvent` or the stored platform record, unchanged. + +use serde::{Deserialize, Serialize}; + +use crate::RunId; + +/// Which of the two item shapes a stream item carries. +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + strum::Display, + strum::EnumString, + strum::IntoStaticStr, +)] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum RunStreamItemKind { + /// A Petri `RunEvent`: `{id, origin, recorded_at, context, subject, + /// record, derived}` under Petri's event contract. + Petri, + /// A stored platform record: `{seq, recorded_at, record: {kind, ...}, + /// position?}`. + Platform, +} + +/// One item of a Petri run's stream, in Fabro's envelope. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RunStreamItem { + pub run_id: RunId, + /// The delivery sequence: the cursor. + pub stream_seq: u64, + pub kind: RunStreamItemKind, + /// The item's own identity, for deduplication. + pub id: String, + /// Milliseconds since the Unix epoch when the item's record was + /// appended. + pub recorded_at: u64, + /// The Petri `RunEvent` or the stored platform record, as JSON. + pub item: serde_json::Value, +} + +impl RunStreamItem { + /// The `.` name of a Petri event, or the `kind` of a + /// platform record: what a listing shows and a filter matches on. + #[must_use] + pub fn name(&self) -> Option<&str> { + match self.kind { + RunStreamItemKind::Petri => petri_event_name(&self.item), + RunStreamItemKind::Platform => self + .item + .get("record") + .and_then(|record| record.get("kind")) + .and_then(serde_json::Value::as_str), + } + } +} + +/// The `.` name of a Petri `RunEvent` value: the recorded +/// body's `event` tag, or a view event's tag under `derived`. +#[must_use] +pub fn petri_event_name(event: &serde_json::Value) -> Option<&str> { + event + .get("record") + .and_then(|record| record.get("body")) + .and_then(|body| body.get("event")) + .and_then(serde_json::Value::as_str) + .or_else(|| { + event + .get("derived") + .and_then(|derived| derived.get("event")) + .and_then(serde_json::Value::as_str) + }) +} + +#[cfg(test)] +mod tests { + use serde_json::json; + + use super::{RunStreamItem, RunStreamItemKind, petri_event_name}; + use crate::fixtures; + + #[test] + fn kind_names_are_lowercase_in_both_directions() { + assert_eq!(RunStreamItemKind::Petri.to_string(), "petri"); + assert_eq!( + "platform".parse::(), + Ok(RunStreamItemKind::Platform) + ); + assert_eq!( + serde_json::to_value(RunStreamItemKind::Platform).expect("kind serializes"), + json!("platform") + ); + } + + #[test] + fn a_petri_item_is_named_by_its_recorded_event_tag() { + let item = RunStreamItem { + run_id: fixtures::RUN_1, + stream_seq: 4, + kind: RunStreamItemKind::Petri, + id: "coordinator/3/0".to_string(), + recorded_at: 1_789_323_217_366, + item: json!({ + "id": {"log": "coordinator", "seq": 3, "index": 0}, + "record": {"seq": 3, "body": {"event": "execution.declared"}} + }), + }; + assert_eq!(item.name(), Some("execution.declared")); + assert_eq!( + petri_event_name(&json!({"origin": "derived", "derived": {"event": "visit.started"}})), + Some("visit.started") + ); + } + + #[test] + fn a_platform_item_is_named_by_its_record_kind() { + let item = RunStreamItem { + run_id: fixtures::RUN_1, + stream_seq: 5, + kind: RunStreamItemKind::Platform, + id: "2".to_string(), + recorded_at: 1_789_323_217_400, + item: json!({"seq": 2, "record": {"kind": "run.notice", "level": "info"}}), + }; + assert_eq!(item.name(), Some("run.notice")); + } + + #[test] + fn the_envelope_round_trips_as_json() { + let value = json!({ + "run_id": fixtures::RUN_1.to_string(), + "stream_seq": 7, + "kind": "platform", + "id": "3", + "recorded_at": 1_789_323_217_400_u64, + "item": {"seq": 3, "recorded_at": 1_789_323_217_400_u64, "record": {"kind": "checkpoint", "execution": 1, "firing": 2}} + }); + let item: RunStreamItem = serde_json::from_value(value.clone()).expect("item decodes"); + assert_eq!(serde_json::to_value(&item).expect("item encodes"), value); + } +} diff --git a/lib/packages/fabro-api-client/src/.openapi-generator/FILES b/lib/packages/fabro-api-client/src/.openapi-generator/FILES index 0d0b0f64d..4828ce8f6 100644 --- a/lib/packages/fabro-api-client/src/.openapi-generator/FILES +++ b/lib/packages/fabro-api-client/src/.openapi-generator/FILES @@ -216,6 +216,7 @@ models/interview-option.ts models/interview-provider-settings.ts models/interview-question-record.ts models/link-run-pull-request-request.ts +models/list-run-events200-response.ts models/llm-output-kind.ts models/llm-retry-classification-after.ts models/llm-retry-classification-never.ts @@ -271,6 +272,7 @@ models/paginated-run-commit-list.ts models/paginated-run-file-list.ts models/paginated-run-list.ts models/paginated-run-stage-list.ts +models/paginated-run-stream-list.ts models/paginated-saved-query-list.ts models/paginated-session-list.ts models/paginated-workflow-list-response.ts @@ -296,7 +298,9 @@ models/pending-interview-record.ts models/pending-reason.ts models/permission-level.ts models/petri-access.ts +models/petri-admission.ts models/petri-append-request.ts +models/petri-graph-ref.ts models/petri-open-request.ts models/petri-open-response.ts models/petri-record-list.ts @@ -383,6 +387,9 @@ models/run-commit.ts models/run-commits-meta.ts models/run-control-action.ts models/run-diff.ts +models/run-engine-one-of.ts +models/run-engine-one-of1.ts +models/run-engine.ts models/run-environment-settings.ts models/run-error.ts models/run-event-detail-response-content.ts @@ -442,6 +449,8 @@ models/run-status-starting.ts models/run-status-submitted.ts models/run-status-succeeded.ts models/run-status.ts +models/run-stream-item-kind.ts +models/run-stream-item.ts models/run-superseded-by-props.ts models/run-target.ts models/run-timestamps.ts diff --git a/lib/packages/fabro-api-client/src/api/run-internals-api.ts b/lib/packages/fabro-api-client/src/api/run-internals-api.ts index ba15825ed..a4cd73b6d 100644 --- a/lib/packages/fabro-api-client/src/api/run-internals-api.ts +++ b/lib/packages/fabro-api-client/src/api/run-internals-api.ts @@ -30,6 +30,8 @@ import type { CommandLogResponse } from '../models'; // @ts-ignore import type { ErrorResponse } from '../models'; // @ts-ignore +import type { ListRunEvents200Response } from '../models'; +// @ts-ignore import type { PaginatedEventList } from '../models'; // @ts-ignore import type { PaginatedRunStageList } from '../models'; @@ -161,14 +163,15 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config }; }, /** - * Opens an ordered server-sent event stream starting at `since_seq`, replaying persisted events and continuing with live updates while the run remains active. + * Opens an ordered server-sent event stream, replaying persisted items and continuing with live updates while the run remains active. Each `data:` frame is one JSON object in the run engine\'s envelope. For a legacy run the frames are `EventEnvelope`s and the stream starts at `since_seq` (inclusive; the next unseen event when omitted). It ends after `run.completed` or `run.failed`. For a Petri run the frames are `RunStreamItem`s and the stream starts after `after` (the last `stream_seq` the client saw; `0` replays the whole run; the next unseen item when omitted). It ends once the run is no longer active and every committed item has been sent. A reconnecting client passes its last `stream_seq` as `after` and deduplicates by `id`. * @summary Attach Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - attachRunEvents: async (id: string, sinceSeq?: number, options: RawAxiosRequestConfig = {}): Promise => { + attachRunEvents: async (id: string, sinceSeq?: number, after?: number, options: RawAxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists('attachRunEvents', 'id', id) const localVarPath = `/api/v1/runs/{id}/attach` @@ -194,6 +197,10 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config localVarQueryParameter['since_seq'] = sinceSeq; } + if (after !== undefined) { + localVarQueryParameter['after'] = after; + } + localVarHeaderParameter['Accept'] = 'text/event-stream,application/json'; setSearchParams(localVarUrlObj, localVarQueryParameter); @@ -615,17 +622,18 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config }; }, /** - * Returns a paginated JSON list of stored run events. Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. + * Returns a paginated JSON list of the run\'s events. The shape depends on the engine the run was created for (`RunSpec.engine`). For a legacy run (`engine.kind = legacy`): stored run events in the legacy envelope (`PaginatedEventList`). Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. For a Petri run (`engine.kind = petri`): the run stream (`PaginatedRunStreamList`), one ordered delivery of Petri\'s own `RunEvent`s and Fabro\'s platform records in the `RunStreamItem` envelope, in `stream_seq` order. The cursor is `after`: the last `stream_seq` the client saw, exclusive; the first page is `after=0`. `since_seq`, `before_seq` and `order` are not accepted for a Petri run. A client that reconnects resumes from its last `stream_seq` and deduplicates by each item\'s `id`; every item is delivered once, in order, with no gap. * @summary List Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. * @param {number} [limit] Maximum number of events to return. * @param {number} [beforeSeq] Exclusive upper event sequence cursor for descending order. Omit on the first descending request to start from the newest event. * @param {ListRunEventsOrderEnum} [order] Event sequence order. `since_seq` is valid only with `asc`; `before_seq` is valid only with `desc`. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - listRunEvents: async (id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, options: RawAxiosRequestConfig = {}): Promise => { + listRunEvents: async (id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, after?: number, options: RawAxiosRequestConfig = {}): Promise => { // verify required parameter 'id' is not null or undefined assertParamExists('listRunEvents', 'id', id) const localVarPath = `/api/v1/runs/{id}/events` @@ -663,6 +671,10 @@ export const RunInternalsApiAxiosParamCreator = function (configuration?: Config localVarQueryParameter['order'] = order; } + if (after !== undefined) { + localVarQueryParameter['after'] = after; + } + localVarHeaderParameter['Accept'] = 'application/json'; setSearchParams(localVarUrlObj, localVarQueryParameter); @@ -1276,15 +1288,16 @@ export const RunInternalsApiFp = function(configuration?: Configuration) { return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, /** - * Opens an ordered server-sent event stream starting at `since_seq`, replaying persisted events and continuing with live updates while the run remains active. + * Opens an ordered server-sent event stream, replaying persisted items and continuing with live updates while the run remains active. Each `data:` frame is one JSON object in the run engine\'s envelope. For a legacy run the frames are `EventEnvelope`s and the stream starts at `since_seq` (inclusive; the next unseen event when omitted). It ends after `run.completed` or `run.failed`. For a Petri run the frames are `RunStreamItem`s and the stream starts after `after` (the last `stream_seq` the client saw; `0` replays the whole run; the next unseen item when omitted). It ends once the run is no longer active and every committed item has been sent. A reconnecting client passes its last `stream_seq` as `after` and deduplicates by `id`. * @summary Attach Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.attachRunEvents(id, sinceSeq, options); + async attachRunEvents(id: string, sinceSeq?: number, after?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.attachRunEvents(id, sinceSeq, after, options); const localVarOperationServerIndex = configuration?.serverIndex ?? 0; const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.attachRunEvents']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); @@ -1417,18 +1430,19 @@ export const RunInternalsApiFp = function(configuration?: Configuration) { return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); }, /** - * Returns a paginated JSON list of stored run events. Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. + * Returns a paginated JSON list of the run\'s events. The shape depends on the engine the run was created for (`RunSpec.engine`). For a legacy run (`engine.kind = legacy`): stored run events in the legacy envelope (`PaginatedEventList`). Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. For a Petri run (`engine.kind = petri`): the run stream (`PaginatedRunStreamList`), one ordered delivery of Petri\'s own `RunEvent`s and Fabro\'s platform records in the `RunStreamItem` envelope, in `stream_seq` order. The cursor is `after`: the last `stream_seq` the client saw, exclusive; the first page is `after=0`. `since_seq`, `before_seq` and `order` are not accepted for a Petri run. A client that reconnects resumes from its last `stream_seq` and deduplicates by each item\'s `id`; every item is delivered once, in order, with no gap. * @summary List Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. * @param {number} [limit] Maximum number of events to return. * @param {number} [beforeSeq] Exclusive upper event sequence cursor for descending order. Omit on the first descending request to start from the newest event. * @param {ListRunEventsOrderEnum} [order] Event sequence order. `since_seq` is valid only with `asc`; `before_seq` is valid only with `desc`. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.listRunEvents(id, sinceSeq, limit, beforeSeq, order, options); + async listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, after?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listRunEvents(id, sinceSeq, limit, beforeSeq, order, after, options); const localVarOperationServerIndex = configuration?.serverIndex ?? 0; const localVarOperationServerBasePath = operationServerMap['RunInternalsApi.listRunEvents']?.[localVarOperationServerIndex]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); @@ -1639,15 +1653,16 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b return localVarFp.appendRunEvent(id, runEvent, options).then((request) => request(axios, basePath)); }, /** - * Opens an ordered server-sent event stream starting at `since_seq`, replaying persisted events and continuing with live updates while the run remains active. + * Opens an ordered server-sent event stream, replaying persisted items and continuing with live updates while the run remains active. Each `data:` frame is one JSON object in the run engine\'s envelope. For a legacy run the frames are `EventEnvelope`s and the stream starts at `since_seq` (inclusive; the next unseen event when omitted). It ends after `run.completed` or `run.failed`. For a Petri run the frames are `RunStreamItem`s and the stream starts after `after` (the last `stream_seq` the client saw; `0` replays the whole run; the next unseen item when omitted). It ends once the run is no longer active and every committed item has been sent. A reconnecting client passes its last `stream_seq` as `after` and deduplicates by `id`. * @summary Attach Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig): AxiosPromise { - return localVarFp.attachRunEvents(id, sinceSeq, options).then((request) => request(axios, basePath)); + attachRunEvents(id: string, sinceSeq?: number, after?: number, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.attachRunEvents(id, sinceSeq, after, options).then((request) => request(axios, basePath)); }, /** * Streams a ZIP archive with the latest captured version of each artifact path. Stage order, retry number, and then stage ID determine the latest version, matching the artifacts page. Captures from the graph\'s boundary nodes are excluded, identified by their `start` and `exit` handler type rather than by node name. The archive streams, so the response status is sent before the first artifact is read. A failure after that point aborts the transfer rather than returning `500`. The ZIP central directory is written last, so a truncated download does not open as a valid archive. @@ -1750,18 +1765,19 @@ export const RunInternalsApiFactory = function (configuration?: Configuration, b return localVarFp.listRunArtifacts(id, options).then((request) => request(axios, basePath)); }, /** - * Returns a paginated JSON list of stored run events. Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. + * Returns a paginated JSON list of the run\'s events. The shape depends on the engine the run was created for (`RunSpec.engine`). For a legacy run (`engine.kind = legacy`): stored run events in the legacy envelope (`PaginatedEventList`). Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. For a Petri run (`engine.kind = petri`): the run stream (`PaginatedRunStreamList`), one ordered delivery of Petri\'s own `RunEvent`s and Fabro\'s platform records in the `RunStreamItem` envelope, in `stream_seq` order. The cursor is `after`: the last `stream_seq` the client saw, exclusive; the first page is `after=0`. `since_seq`, `before_seq` and `order` are not accepted for a Petri run. A client that reconnects resumes from its last `stream_seq` and deduplicates by each item\'s `id`; every item is delivered once, in order, with no gap. * @summary List Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. * @param {number} [limit] Maximum number of events to return. * @param {number} [beforeSeq] Exclusive upper event sequence cursor for descending order. Omit on the first descending request to start from the newest event. * @param {ListRunEventsOrderEnum} [order] Event sequence order. `since_seq` is valid only with `asc`; `before_seq` is valid only with `desc`. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, options?: RawAxiosRequestConfig): AxiosPromise { - return localVarFp.listRunEvents(id, sinceSeq, limit, beforeSeq, order, options).then((request) => request(axios, basePath)); + listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, after?: number, options?: RawAxiosRequestConfig): AxiosPromise { + return localVarFp.listRunEvents(id, sinceSeq, limit, beforeSeq, order, after, options).then((request) => request(axios, basePath)); }, /** * Returns the ordered list of stages in a run\'s workflow graph with their current status and timing. Stages are bounded by the workflow graph size, typically fewer than 20. @@ -1933,15 +1949,16 @@ export class RunInternalsApi extends BaseAPI { } /** - * Opens an ordered server-sent event stream starting at `since_seq`, replaying persisted events and continuing with live updates while the run remains active. + * Opens an ordered server-sent event stream, replaying persisted items and continuing with live updates while the run remains active. Each `data:` frame is one JSON object in the run engine\'s envelope. For a legacy run the frames are `EventEnvelope`s and the stream starts at `since_seq` (inclusive; the next unseen event when omitted). It ends after `run.completed` or `run.failed`. For a Petri run the frames are `RunStreamItem`s and the stream starts after `after` (the last `stream_seq` the client saw; `0` replays the whole run; the next unseen item when omitted). It ends once the run is no longer active and every committed item has been sent. A reconnecting client passes its last `stream_seq` as `after` and deduplicates by `id`. * @summary Attach Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - public attachRunEvents(id: string, sinceSeq?: number, options?: RawAxiosRequestConfig) { - return RunInternalsApiFp(this.configuration).attachRunEvents(id, sinceSeq, options).then((request) => request(this.axios, this.basePath)); + public attachRunEvents(id: string, sinceSeq?: number, after?: number, options?: RawAxiosRequestConfig) { + return RunInternalsApiFp(this.configuration).attachRunEvents(id, sinceSeq, after, options).then((request) => request(this.axios, this.basePath)); } /** @@ -2054,18 +2071,19 @@ export class RunInternalsApi extends BaseAPI { } /** - * Returns a paginated JSON list of stored run events. Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. + * Returns a paginated JSON list of the run\'s events. The shape depends on the engine the run was created for (`RunSpec.engine`). For a legacy run (`engine.kind = legacy`): stored run events in the legacy envelope (`PaginatedEventList`). Ascending order uses `since_seq` as an inclusive cursor. Descending order uses `before_seq` as an exclusive cursor and starts at the newest event when `before_seq` is omitted. For a Petri run (`engine.kind = petri`): the run stream (`PaginatedRunStreamList`), one ordered delivery of Petri\'s own `RunEvent`s and Fabro\'s platform records in the `RunStreamItem` envelope, in `stream_seq` order. The cursor is `after`: the last `stream_seq` the client saw, exclusive; the first page is `after=0`. `since_seq`, `before_seq` and `order` are not accepted for a Petri run. A client that reconnects resumes from its last `stream_seq` and deduplicates by each item\'s `id`; every item is delivered once, in order, with no gap. * @summary List Run Events * @param {string} id Unique run identifier (ULID). * @param {number} [sinceSeq] First event sequence number to include. * @param {number} [limit] Maximum number of events to return. * @param {number} [beforeSeq] Exclusive upper event sequence cursor for descending order. Omit on the first descending request to start from the newest event. * @param {ListRunEventsOrderEnum} [order] Event sequence order. `since_seq` is valid only with `asc`; `before_seq` is valid only with `desc`. + * @param {number} [after] Run stream cursor for a Petri run: the last `stream_seq` the client saw, exclusive. `0` starts at the first item. * @param {*} [options] Override http request option. * @throws {RequiredError} */ - public listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, options?: RawAxiosRequestConfig) { - return RunInternalsApiFp(this.configuration).listRunEvents(id, sinceSeq, limit, beforeSeq, order, options).then((request) => request(this.axios, this.basePath)); + public listRunEvents(id: string, sinceSeq?: number, limit?: number, beforeSeq?: number, order?: ListRunEventsOrderEnum, after?: number, options?: RawAxiosRequestConfig) { + return RunInternalsApiFp(this.configuration).listRunEvents(id, sinceSeq, limit, beforeSeq, order, after, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/lib/packages/fabro-api-client/src/models/index.ts b/lib/packages/fabro-api-client/src/models/index.ts index 897027f9d..99bc052b1 100644 --- a/lib/packages/fabro-api-client/src/models/index.ts +++ b/lib/packages/fabro-api-client/src/models/index.ts @@ -186,6 +186,7 @@ export * from './interview-option'; export * from './interview-provider-settings'; export * from './interview-question-record'; export * from './link-run-pull-request-request'; +export * from './list-run-events200-response'; export * from './llm-output-kind'; export * from './llm-retry-classification'; export * from './llm-retry-classification-after'; @@ -241,6 +242,7 @@ export * from './paginated-run-commit-list'; export * from './paginated-run-file-list'; export * from './paginated-run-list'; export * from './paginated-run-stage-list'; +export * from './paginated-run-stream-list'; export * from './paginated-saved-query-list'; export * from './paginated-session-list'; export * from './paginated-workflow-list-response'; @@ -266,7 +268,9 @@ export * from './pending-interview-record'; export * from './pending-reason'; export * from './permission-level'; export * from './petri-access'; +export * from './petri-admission'; export * from './petri-append-request'; +export * from './petri-graph-ref'; export * from './petri-open-request'; export * from './petri-open-response'; export * from './petri-record'; @@ -354,6 +358,9 @@ export * from './run-commit-person'; export * from './run-commits-meta'; export * from './run-control-action'; export * from './run-diff'; +export * from './run-engine'; +export * from './run-engine-one-of'; +export * from './run-engine-one-of1'; export * from './run-environment-settings'; export * from './run-error'; export * from './run-event'; @@ -413,6 +420,8 @@ export * from './run-status-running'; export * from './run-status-starting'; export * from './run-status-submitted'; export * from './run-status-succeeded'; +export * from './run-stream-item'; +export * from './run-stream-item-kind'; export * from './run-superseded-by-props'; export * from './run-target'; export * from './run-timestamps'; diff --git a/lib/packages/fabro-api-client/src/models/list-run-events200-response.ts b/lib/packages/fabro-api-client/src/models/list-run-events200-response.ts new file mode 100644 index 000000000..ed35f86ed --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/list-run-events200-response.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { PaginatedEventList } from './paginated-event-list'; +// May contain unused imports in some cases +// @ts-ignore +import type { PaginatedRunStreamList } from './paginated-run-stream-list'; +// May contain unused imports in some cases +// @ts-ignore +import type { PaginationMeta } from './pagination-meta'; +// May contain unused imports in some cases +// @ts-ignore +import type { RunStreamItem } from './run-stream-item'; + +/** + * @type ListRunEvents200Response + */ +export type ListRunEvents200Response = PaginatedEventList | PaginatedRunStreamList; diff --git a/lib/packages/fabro-api-client/src/models/paginated-run-stream-list.ts b/lib/packages/fabro-api-client/src/models/paginated-run-stream-list.ts new file mode 100644 index 000000000..878abf91c --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/paginated-run-stream-list.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { PaginationMeta } from './pagination-meta'; +// May contain unused imports in some cases +// @ts-ignore +import type { RunStreamItem } from './run-stream-item'; + +/** + * One page of a Petri run\'s stream, in `stream_seq` order. `event_contract_version` is Petri\'s `EVENT_CONTRACT_VERSION` the server was built against: the version of the event contract every `petri` item follows. + */ +export interface PaginatedRunStreamList { + 'data': Array; + 'meta': PaginationMeta; + 'event_contract_version': number; +} diff --git a/lib/packages/fabro-api-client/src/models/petri-admission.ts b/lib/packages/fabro-api-client/src/models/petri-admission.ts new file mode 100644 index 000000000..744c46a97 --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/petri-admission.ts @@ -0,0 +1,26 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { PetriGraphRef } from './petri-graph-ref'; + +/** + * What Petri admitted for a run at create time: the lowered root graph and the pre-lowered child graphs, every one persisted in the blob store before the run exists. + */ +export interface PetriAdmission { + 'graph': PetriGraphRef; + 'children'?: Array; +} diff --git a/lib/packages/fabro-api-client/src/models/petri-graph-ref.ts b/lib/packages/fabro-api-client/src/models/petri-graph-ref.ts new file mode 100644 index 000000000..3eb77a1ea --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/petri-graph-ref.ts @@ -0,0 +1,26 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * An admitted graph in the blob store, verified by digest on load. + */ +export interface PetriGraphRef { + /** + * Content-addressed SHA-256 hash of a stored blob. Hex input is case-insensitive; Fabro emits the canonical lowercase form. + */ + 'blob': string; + 'digest': string; +} diff --git a/lib/packages/fabro-api-client/src/models/run-engine-one-of.ts b/lib/packages/fabro-api-client/src/models/run-engine-one-of.ts new file mode 100644 index 000000000..86bf37439 --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/run-engine-one-of.ts @@ -0,0 +1,25 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +export interface RunEngineOneOf { + 'kind': RunEngineOneOfKindEnum; +} + +export const RunEngineOneOfKindEnum = { + LEGACY: 'legacy' +} as const; + +export type RunEngineOneOfKindEnum = typeof RunEngineOneOfKindEnum[keyof typeof RunEngineOneOfKindEnum]; diff --git a/lib/packages/fabro-api-client/src/models/run-engine-one-of1.ts b/lib/packages/fabro-api-client/src/models/run-engine-one-of1.ts new file mode 100644 index 000000000..e4ab32ac8 --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/run-engine-one-of1.ts @@ -0,0 +1,26 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { PetriAdmission } from './petri-admission'; +// May contain unused imports in some cases +// @ts-ignore +import type { PetriGraphRef } from './petri-graph-ref'; + +/** + * @type RunEngineOneOf1 + */ +export type RunEngineOneOf1 = PetriAdmission; diff --git a/lib/packages/fabro-api-client/src/models/run-engine.ts b/lib/packages/fabro-api-client/src/models/run-engine.ts new file mode 100644 index 000000000..c8f4929c8 --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/run-engine.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { PetriGraphRef } from './petri-graph-ref'; +// May contain unused imports in some cases +// @ts-ignore +import type { RunEngineOneOf } from './run-engine-one-of'; +// May contain unused imports in some cases +// @ts-ignore +import type { RunEngineOneOf1 } from './run-engine-one-of1'; + +/** + * @type RunEngine + * The engine a run was created for. `legacy` is the in-process executor; `petri` names the Petri workflow engine and carries what Petri admitted at create time. + */ +export type RunEngine = RunEngineOneOf | RunEngineOneOf1; diff --git a/lib/packages/fabro-api-client/src/models/run-spec.ts b/lib/packages/fabro-api-client/src/models/run-spec.ts index 6c05283aa..b8e169a99 100644 --- a/lib/packages/fabro-api-client/src/models/run-spec.ts +++ b/lib/packages/fabro-api-client/src/models/run-spec.ts @@ -24,6 +24,9 @@ import type { ForkSourceRef } from './fork-source-ref'; import type { GitContext } from './git-context'; // May contain unused imports in some cases // @ts-ignore +import type { RunEngine } from './run-engine'; +// May contain unused imports in some cases +// @ts-ignore import type { RunProvenance } from './run-provenance'; // May contain unused imports in some cases // @ts-ignore @@ -54,4 +57,8 @@ export interface RunSpec { 'spec_blob'?: string | null; 'git'?: GitContext | null; 'fork_source_ref'?: ForkSourceRef | null; + /** + * The engine the run was created for, with what it admitted. Absent in a spec written before the field existed, which means the legacy executor. + */ + 'engine'?: RunEngine; } diff --git a/lib/packages/fabro-api-client/src/models/run-stream-item-kind.ts b/lib/packages/fabro-api-client/src/models/run-stream-item-kind.ts new file mode 100644 index 000000000..f81e14391 --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/run-stream-item-kind.ts @@ -0,0 +1,26 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * Which item shape a run stream item carries. + */ + +export const RunStreamItemKind = { + PETRI: 'petri', + PLATFORM: 'platform' +} as const; + +export type RunStreamItemKind = typeof RunStreamItemKind[keyof typeof RunStreamItemKind]; diff --git a/lib/packages/fabro-api-client/src/models/run-stream-item.ts b/lib/packages/fabro-api-client/src/models/run-stream-item.ts new file mode 100644 index 000000000..b73e6120b --- /dev/null +++ b/lib/packages/fabro-api-client/src/models/run-stream-item.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Fabro Run API + * HTTP API for managing Fabro workflow run executions. + * + * The version of the OpenAPI document: 0.2.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { RunStreamItemKind } from './run-stream-item-kind'; + +/** + * One item of a Petri run\'s stream: a Petri `RunEvent` or a Fabro platform record in Fabro\'s envelope. `stream_seq` is the durable per-run delivery sequence the projector assigned when the item\'s record was committed: dense, strictly increasing within the run, and the cursor for `after`. `id` is the item\'s own identity, kept beside the cursor so a client deduplicates by it: for a Petri event the `EventId` as `//` (`coordinator/3/0`, `execution 1/23/0`); for a platform record its `seq`. Petri\'s `EventId` is per log and has no platform variant, so it is never the cursor. A `petri` item is a Petri `RunEvent` passed through unchanged: `{id: {log, execution?, seq, index}, origin, recorded_at, observed_at?, context: {invocation, execution, parent?}, subject?, record?, derived?}`. Its vocabulary is Petri\'s public event contract (`crates/core/execution/EVENTS.md` in the Petri repository), not Fabro\'s: the recorded event\'s name is `record.body.event` (`.`, e.g. `visit.started`, `step.finished`, `run.finished`), a derived view event\'s is `derived.event`, and the stage a subject names is `(context.execution, subject.firing)` with `subject.node.name` and `subject.visit` as its display label. The server reports the contract version it serves in `PaginatedRunStreamList.event_contract_version`. A `platform` item is a stored platform record: `{seq, recorded_at, record: {kind, ...}, position?: {execution, firing}}`. `record.kind` is one of `run.created`, `run.lifecycle`, `run.title`, `run.parent`, `run.archived`, `run.unarchived`, `run.superseded`, `run.notice`, `interview.answered`, `run.branch`, `git.identity`, `checkpoint`, `pull_request.created`, `notification.sent`, `run.paired`. + */ +export interface RunStreamItem { + 'run_id': string; + /** + * The delivery sequence; the cursor. + */ + 'stream_seq': number; + 'kind': RunStreamItemKind; + /** + * The item\'s own identity, for deduplication. + */ + 'id': string; + /** + * Milliseconds since the Unix epoch when the item\'s record was appended. + */ + 'recorded_at': number; + /** + * The Petri `RunEvent` or the stored platform record, unchanged. + */ + 'item': { [key: string]: any; }; +}