Skip to content

The e2e run learns to present itself - #43

Merged
gifflet merged 2 commits into
mainfrom
feat/e2e-run-presents-itself
Sep 12, 2026
Merged

The e2e run learns to present itself#43
gifflet merged 2 commits into
mainfrom
feat/e2e-run-presents-itself

Conversation

@gifflet

@gifflet gifflet commented Sep 12, 2026

Copy link
Copy Markdown
Owner

What this is

Dogfood round 16, from the operator's question: is an e2e (needs_service) run adequately presented in the terminal and in the UI, without breaking layout on mobile, tablet and desktop? It was not — the service phase was invisible on both surfaces. The run booted an app, health-polled it, captured evidence and tore it down, and neither the terminal nor the RunDetail timeline said a word about any of it. Two items, each closed by its own regression-guard pass and committed separately.

1. The terminal and the run log — c4e76cf

The boot + health poll was a silent multi-second freeze before → Act with no visible cause — the same sin the per-check timeout work fixed for checks. _ServiceRun now narrates in the Assurance Loop's own stderr idiom:

→ Service… python3 -m http.server "$PORT" (port 55346)
  ✓ healthy at http://127.0.0.1:55346 (0.2s)
→ Act (attempt 1/4)…
→ Verify (2 check(s))…
  · e2e-smoke… ✓ 0.0s
  ✓ all checks passed
→ Evidence… 2 artifact(s) captured
  · service stopped

and emits the matching run-log events — service_started (start command, port), service_ready (ok, base URL, elapsed), service_stopped, and evidence_captured (artifact paths, warning count) — so the UI reads the same story from the same channel. A failed health poll prints ✗ not healthy after Ns and emits service_ready ok=false before the error propagates. Prints and events live together in the one wrapper, so every execute_mandate caller (CLI runs, flows, queue drains) gets both for free; runs without a service are byte-identical. Three new integration tests pin the event sequence, the failure shape, and the evidence payload.

2. RunDetail — c996380

buildTimeline folds the new events into Timeline.service (ready true / false / null-while-polling, base URL, elapsed, stopped), and RunDetail renders a Service strip between the outcome banner and the timeline: the SERVICE label, a healthy/failed/starting… pill in the run-state tones, the base URL in mono, up in 0.2s, stopped after the run. A failed poll renders in the error tone with the start command as the fallback identity. The raw event feed learns the four kinds too, so its timestamps read Service starting → healthy → Act → Verify → Evidence → stopped. Old runs and runs without a service render exactly as before (the strip simply does not exist), and older UIs ignore the new events by construction (the switch's default case). Seven new vitest cases across runEvents and RunDetail.

Layout, verified

Validated against a real needs_service run — a probe project registered into the running UI via the projects API, then deregistered — at 1280px, 834px and 411px: document.scrollWidth == innerWidth at all three (no horizontal overflow), with flex-wrap and anywhere-wrapping on the URL doing the mobile work. The 411px page reads Service → outcome → timeline → scorecard → Evidence → events, all in the existing design system (Pill tones, mono data, panel idiom). The evidence panel itself already existed — the strip gives it the narrative it was missing.

Honest caveat: the physical Android remains disconnected; rounds 15-16 owe an on-device pass when it returns (logged in the friction log both times).

Regression guard, per item

  • Item 1: ruff clean · pytest 2670 (+3) · vitest 676 · build clean — no regressions.
  • Item 2: ruff clean · pytest 2670 · vitest 683 (+7) · build clean — no regressions.

🤖 Generated with Claude Code

A needs_service run booted the app and polled health in complete
silence — a multi-second freeze before '→ Act' with no visible cause,
the same sin the check timeout fixed for checks — and the run log had
no trace of the service at all, so the UI's timeline could not show
the e2e phase either.

_ServiceRun now narrates in the Assurance Loop's own stderr idiom
('→ Service… <start> (port N)', '✓ healthy at <url> (0.2s)',
'· service stopped', and '✗ not healthy after Ns' on a failed poll)
and emits the matching run-log events — service_started,
service_ready (ok/base_url/elapsed_s), service_stopped, plus
evidence_captured after capture: runs (artifact paths + warning
count). Events and prints live together in the wrapper, so every
caller of execute_mandate gets both for free; runs without a service
are byte-identical.

Proved live: the terminal now reads Service → healthy → Act → Verify
(e2e-smoke ✓) → Evidence (2 artifacts) → service stopped → SUCCESS.
The run log now carries service_* events, but the timeline dropped them
on the floor — a needs_service run looked identical to a plain one, and
the only trace of the e2e phase was the artifacts panel at the bottom.

buildTimeline folds them into Timeline.service (start command, port,
ready true/false/null-while-polling, base URL, elapsed, stopped), and
RunDetail renders a Service strip between the outcome and the timeline:
SERVICE · healthy/failed/starting… pill · mono base URL · 'up in 0.2s' ·
'stopped after the run'. flex-wrap plus anywhere-wrapping on the URL
keep it inside 411px without sideways scroll; a failed poll renders in
the error tone with the start command as the fallback identity. The raw
event feed learns the four new kinds too (describeEvent), so the
timestamps read Service starting → healthy → Act → … → Evidence.

Validated live against a real needs_service run (probe project
registered into the running UI, then deregistered) at 1280, 834 and
411px — no horizontal overflow at any width. The physical Android
remains disconnected; on-device validation still owed.
@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
alc Ready Ready Preview Sep 12, 2026 5:32pm UTC

@gifflet
gifflet merged commit 5fba147 into main Sep 12, 2026
5 checks passed
@gifflet
gifflet deleted the feat/e2e-run-presents-itself branch September 12, 2026 17:33
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.

1 participant