Skip to content

runner: display-only events.jsonl stream for GUI v1 (#175) - #176

Merged
sleegme merged 3 commits into
mainfrom
feat/gui-events
Oct 26, 2026
Merged

sleegme merged 3 commits into
mainfrom
feat/gui-events

Conversation

@sleegme

@sleegme sleegme commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Implements #175 (runner-side GUI v1 event stream).

What

The vNext runner appends one JSON line per runner-dispatched role invocation to events.jsonl in the ledger's directory (created lazily on first append). Display-only: the ledger remains the only source of truth for completion, blockers and promotion.

Line shapes (exactly these fields):

  • {"ts","role","milestone","event":"start"} — immediately before each dispatched invocation.
  • {"ts","role","milestone","event":"end","status","duration_ms"} — after the invocation settles, on success, transport failure, throw and timeout alike, so an actor never stays working because an invocation failed.

Exact lifecycle statuses

Flow role milestone end status
Execution (run) bulldozer delegated milestone id (e.g. one) packet status: DONE / BLOCKED / NEEDS_DEEP
Review (run) zen reviewed milestone id verdict: GO / NO-GO
Planning (plan) piledriver null SUCCESS (advisory envelope carries no status; a packet-level status string, if present, is used verbatim)
Alt (alt) instinct null (the --milestone value is nested in the contract and is not a binding) SUCCESS
Desktop (navi) navi null packet status: OBSERVED / DONE / BLOCKED / NEEDS_CONFIRMATION
Adapter specialists jaguar/puma/bobcat/strix-halo active milestone id packet status/verdict (e.g. READY, ACCEPT)

Transport/timeout failures: when the runner resolves {ok:false}, the end status is the runner error code verbatim (TIMEOUT, SPAWN_ERROR, MODEL_ERROR, INVALID_OUTPUT, EMPTY_RESPONSE, INVALID_RESPONSE_FORMAT, TOOL_PERMISSION_DENIED, EXECUTION_FAILED, PROMPT_TOO_LARGE, RECURSION_DETECTED, ...). When the invocation throws, it is error.code || error.name || 'ERROR' (e.g. ETIMEDOUT, ENOENT). Zen envelope rejections throw plain Error -> Error. Every status string is exactly what the ledger usage entry records for the same invocation (asserted in tests).

recover appends one end line: role: null, duration_ms: null, status INVOCATION_FAILURE (mirroring the ledger record) — it closes the dangling start a killed supervisor left; the ledger records no active role.

Limitations (by design)

  • Native workers inside the AGY process (Jaguar, Puma, Bobcat, Strix Halo, headless Excavator) are invisible to the runner and never produce events; declared delegations are claims, not observed invocations (no events, matching their unverified ledger accounting).
  • No rotation/cleanup; single-writer per-file serialized appends.

Safety

  • Every string passes through scripts/telemetry.mjs redaction (<redacted> secrets, (local path) user paths) before the line is written.
  • Best-effort: an append failure logs events.jsonl append failed: <code> to stderr and never changes the invocation or milestone outcome (covered by tests with an injected throwing log and a real read-only file).
  • No ledger, decision, role or rule semantics changed; spine untouched.

Verification

  • SKIP_LIVE_TESTS=1 node --test tests/*.mjs -> 353 tests, 332 passed, 0 failed, 21 skipped.
  • python3 tests/test_zen_shell_guard.py -> 8 tests OK; python3 tests/test_excavator_shell_guard.py -> 7 tests OK.
  • New: tests/test_events.mjs (emitter schema/redaction/ordering/nonfatal append) and tests/test_runner_events.mjs (integration at the real runner invocation seam: paired start/end, ledger status/duration equality, specialist adapter vs declared delegation, transport + thrown failures, redaction at the seam, null-milestone planning/alt, nonfatal append failure, killed-supervisor recover pairing).
  • Diff audited: no absolute home paths, no real secrets (only synthetic redaction fixtures).

Append one redacted JSON line per runner-dispatched role invocation
start/end to events.jsonl beside the ledger. Emitted at the three
runner invocation wrappers (role, zen, specialist) with the exact
status and duration the ledger usage entry records for the same
invocation, including throw/transport/timeout ends, so an actor never
stays working because an invocation failed. recover appends one
observed end (role null, duration null, INVOCATION_FAILURE) to close
a killed supervisor's dangling start.

Native workers inside AGY are invisible to the runner and never
produce events; declared delegations are claims, not invocations.
Appends are best-effort: a failure warns events.jsonl append failed:
<code> and never changes the milestone outcome. The ledger remains
the only source of truth.
Copilot AI balanced review requested due to automatic review settings October 26, 2026 04:04

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@sleegme sleegme closed this Oct 26, 2026
@sleegme sleegme reopened this Oct 26, 2026
@sleegme
sleegme merged commit 7f95812 into main Oct 26, 2026
3 checks passed
@sleegme
sleegme deleted the feat/gui-events branch October 26, 2026 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants