The e2e run learns to present itself - #43
Merged
Merged
Conversation
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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 —
c4e76cfThe boot + health poll was a silent multi-second freeze before
→ Actwith no visible cause — the same sin the per-check timeout work fixed for checks._ServiceRunnow narrates in the Assurance Loop's own stderr idiom:and emits the matching run-log events —
service_started(start command, port),service_ready(ok, base URL, elapsed),service_stopped, andevidence_captured(artifact paths, warning count) — so the UI reads the same story from the same channel. A failed health poll prints✗ not healthy after Nsand emitsservice_ready ok=falsebefore the error propagates. Prints and events live together in the one wrapper, so everyexecute_mandatecaller (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 —
c996380buildTimelinefolds the new events intoTimeline.service(ready true / false / null-while-polling, base URL, elapsed, stopped), and RunDetail renders a Service strip between the outcome banner and the timeline: theSERVICElabel, ahealthy/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 acrossrunEventsandRunDetail.Layout, verified
Validated against a real
needs_servicerun — a probe project registered into the running UI via the projects API, then deregistered — at 1280px, 834px and 411px:document.scrollWidth == innerWidthat all three (no horizontal overflow), withflex-wrapand 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
ruffclean · pytest 2670 (+3) · vitest 676 · build clean — no regressions.ruffclean · pytest 2670 · vitest 683 (+7) · build clean — no regressions.🤖 Generated with Claude Code