Skip to content

feat(LinuxTentacleE2E): Phase 12.L.E.16 — upgrade-events.jsonl format contract pin

Summary

Pins the wire format the server's UI timeline parser consumes from upgrade-events.jsonl. Every E1.h-style success ALREADY emits these events; what's never been pinned is the format contract — server-side parser drops malformed lines silently → operator sees frozen timeline.

Why this matters

Without this test, regressions in any of the following ship invisibly:

  • JSON malformation (unescaped quotes, missing commas, wrong shape)
  • Field renames (msg → message, kind → type)
  • Phase tag drift ("A" → "PhaseA")
  • Missing terminal events (success absent → UI hangs in "in-progress" forever)
  • Out-of-order events (success before scope-exec → broken causality)
  • Non-UTC timestamps (UI ordering by timestamp breaks)

Wire format pinned

{"t":"2026-04-22T02:57:04Z","phase":"A","kind":"method-try","msg":"apt: update"}

(.sh line 206 docstring + line 249 printf)

Test approach

Run E1.h-Linux end-to-end, then PARSE every line of the resulting upgrade-events.jsonl as JSON (using System.Text.Json — the same parser the server uses).

Assertions

  1. Every line is valid JSON (parser throws → assertion fails)
  2. Every event has the four required fields {t, phase, kind, msg}
  3. Phase values are EXACTLY "A" or "B" (not "1", "a", "PhaseA")
  4. Timestamps end with Z (UTC) and parse as DateTimeOffset
  5. Expected kind sequence appears in order:
    • start → method-selected → scope-exec (Phase A)
    • swapped → restart-start → healthz-pass → success (Phase B)
  6. Last event is success (terminal-state contract — UI flips from in-progress → completed only on this kind)

Infrastructure additions

LinuxLifecycleContext:

  • EventsFilePath property — {STATE_DIR}/upgrade-events.jsonl
  • ReadUpgradeEvents() → IReadOnlyList<UpgradeEvent> — parses every line; throws on malformed lines (the throw IS one of the assertions — server-side parser would silently drop that same line)
  • UpgradeEvent record (T, Phase, Kind, Msg) — mirrors the .sh's emit_event JSON shape verbatim

Fidelity tier

🟢 High (Rule 12.4): real prod .sh + real systemd + real bash + real .jsonl file emitted by real emit_event call site. Composes with E1.h's fixture entirely; only adds parse + sequence assertions on top.

Expected runtime: ~5s (same as E1.h + a few ms for parse).

Test plan

  • Linux E2E workflow runs (manual workflow_dispatch after merge)
  • E1uEventsContract_AfterSuccess_AllLinesValidJsonInExpectedOrder passes within ~5s
  • No regression on existing 16 Linux E2E tests

🤖 Generated with Claude Code

Merge request reports

Loading