feat(glass-office): Event stream as the third parity-proven Basement room - #111
Conversation
Rehome the existing realtime feed surface behind its stable events room id with zero pipeline changes: the room reads visibleEvents exactly as before, with no new websocket subscription, buffer, persistence key, filter store, clear/recovery path, or incident model. - EventsPage gains its first component-level parity suite: all six domain chips as live filters with pressed state, summaries, domain tones, deterministic relative time under fake timers, heartbeat visibility through the real onShowRawEventsChange seam in both directions, both honest empty states plus Clear filter, exact twelve-item pagination boundaries with page reset on filter, live-shrink clamping that never leaves a later page blank while matching events exist, JSON expand/collapse with recursive secret redaction across nested objects and arrays, and a pin click proven to mutate no filter, page, disclosure, or heartbeat state. - The suite immediately caught a real production defect: the no-events empty state used a … escape inside a JSX attribute string, which JSX does not process, so users saw the literal characters. The copy now uses the real ellipsis. - The registry-backed pin rides the shared room-row idiom beside the filter chips; Show heartbeats keeps the header slot untouched. Register the hidden-by-default events room-shortcut block. - New p5-events-slice e2e drives real websocket events through the existing test gateway: per-domain markers plus whole-page domain-purity assertions (robust to the live feed's own emissions), heartbeat toggle through the checkbox, end-to-end redaction of secrets that genuinely crossed the wire, thirty-event pagination boundaries on the quiet Mail domain, the 400-event retention cap after a 500-event burst, byte-for-byte config immutability on full-canvas refusal and byte-identical repeat pin with feed state untouched, live mounted-Office sync, exact door return, reload persistence, Basement floor disabled/restored door truth, and 390px proof with a nonzero visible ES mark and horizontal inner-containment for every chip, the checkbox, event rows, JSON payload, and pagination controls, under console-error and requestfailed capture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds Event stream Office pinning and a hidden Office shortcut, with unit and Playwright coverage for realtime feeds, filtering, redaction, pagination, persistence, disabled-floor behavior, and responsive layout. ChangesEvent stream room slice
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant Playwright
participant WebsocketGateway
participant EventsPage
participant OfficeLayout
Playwright->>WebsocketGateway: Emit domain-scoped events
WebsocketGateway-->>EventsPage: Deliver realtime feed rows
Playwright->>EventsPage: Filter, expand payload, and pin room
EventsPage->>OfficeLayout: Persist events shortcut visibility
OfficeLayout-->>EventsPage: Return pin and room state
Playwright->>EventsPage: Reopen pinned room after reload
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/mission-control/e2e/p5-events-slice.spec.ts (1)
440-455: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExact
"400 events"subtitle can flake when a heartbeat lands inside the retained window.The subtitle reflects
filtered.lengthof visible events, and heartbeats are hidden at this point (unchecked at Line 151, reset to default after the reload). If the gateway interleaves aheartbeat.*event into the retained 400-item window, the visible count drops below the cap and this poll times out even though retention is working correctly. Consider asserting the cap as an upper bound, or enabling "Show heartbeats" before polling so the count matches the raw retained buffer.♻️ Suggested loosening of the retention assertion
await expect .poll(async () => (await eventsSubtitle.textContent())?.trim() ?? "", { timeout: 20_000, }) - .toBe("400 events"); + .toMatch(/^(?:39[5-9]|400) events$/);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/mission-control/e2e/p5-events-slice.spec.ts` around lines 440 - 455, Update the retention assertion around eventsSubtitle so it does not require exactly “400 events” when hidden heartbeat events occupy retained slots. Either enable “Show heartbeats” before polling to make the subtitle reflect the raw retained buffer, or change the expectation to assert the visible count is at most 400 while still confirming retention reaches the cap.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/plans/2026-07-23-glass-office-claude-resume.md`:
- Around line 344-347: Align the Event stream identity references between the
focused `@core` P5 plan scenario and its corresponding E2E test contract. Choose
one canonical lamp identifier, ensuring both the plan and selector use the exact
same name, either “B · Event stream” or “BF · Event stream,” so validation
cannot pass against the wrong room identity.
---
Nitpick comments:
In `@apps/mission-control/e2e/p5-events-slice.spec.ts`:
- Around line 440-455: Update the retention assertion around eventsSubtitle so
it does not require exactly “400 events” when hidden heartbeat events occupy
retained slots. Either enable “Show heartbeats” before polling to make the
subtitle reflect the raw retained buffer, or change the expectation to assert
the visible count is at most 400 while still confirming retention reaches the
cap.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d60f16c4-fe2c-4180-9397-bdddcb2d5816
📒 Files selected for processing (8)
apps/mission-control/e2e/p5-events-slice.spec.tsapps/mission-control/src/features/events/EventsPage.test.tsxapps/mission-control/src/features/events/EventsPage.tsxapps/mission-control/src/features/execassOffice/PinRoomToOffice.test.tsxapps/mission-control/src/features/execassOffice/officeBlocks.tsapps/mission-control/src/features/execassOffice/pinToOffice.test.tsapps/mission-control/src/styles.cssdocs/plans/2026-07-23-glass-office-claude-resume.md
Summary
The third P5 slice: the realtime Event stream is rehomed behind its stable Basement room id with the feed pipeline untouched — the room still reads
visibleEventsfrom the existing controller, and there is no new websocket subscription, event buffer, persistence key, filter store, clear/recovery path, or incident severity model anywhere in this diff.EventsPagecomponent parity suite (the page had none): all six domain chips as live filters witharia-pressedstate; summaries, domain tone classes, and deterministic relative time under fake timers; heartbeat visibility through the realonShowRawEventsChangeseam in both directions; both honest empty states plus Clear filter; exact twelve-item pagination boundaries with page reset on filter; live-shrink clamping proving a later page never goes silently blank while matching events exist; JSON expand/collapse with recursive secret redaction across nested objects and arrays; and a pin click proven to mutate no filter, page, disclosure, or heartbeat state."Listening for events…"inside a JSX attribute — JSX attribute strings do not process\uescapes, so users literally saw…on screen. Fixed to the real ellipsis character.eventsroom-shortcut block;PinRoomToOffice roomId="events"rides the shared room-row idiom beside the filter chips, leaving Show heartbeats untouched in the header slot. Shared primitives only — no Events special-casing.p5-events-slice.spec.tsdrives real websocket events through the existing/api/v1/e2e/ws-event/ws-burstgateway hooks, no static DOM fixtures: per-domain marker assertions plus whole-page domain-purity checks (every row carries the filtered domain's tone class) that stay robust to the live feed's own emissions; heartbeat toggle through the checkbox; end-to-end redaction of secrets that genuinely crossed the wire ([REDACTED]present, raw values absent); thirty-event pagination boundaries on the quiet Mail domain; the 400-event retention cap verified after a 500-event burst; byte-for-byte config immutability on full-canvas refusal and a byte-identical repeat pin with the operator's filter and open JSON row untouched; live mounted-Office sync; exact door return; reload persistence; Basement floor disabled/restored door truth with no stale refusal copy; and 390px proof with a nonzero visibleESmark plus horizontal inner-containment for every chip, the checkbox, event rows, the JSON payload, and pagination controls — underconsole.errorandrequestfailedcapture.Validation
From
apps/mission-control/(Playwright viaPLAYWRIGHT_BROWSERS_PATH=Z:\carsinos-codex-work\playwright-browsers):npm run typecheck— PASSnpm run lint— PASSnpm run test:unit -- --run— 471/471 PASS (new EventsPage suite 8/8;eventStream.test.tshelpers untouched and green)npm run build— PASS (pre-existing chunk-size warning only)npx playwright test e2e/p5-events-slice.spec.ts— PASSnpx playwright test e2e/live-feed.spec.ts e2e/reconnect-edge.spec.ts e2e/p5-models-slice.spec.ts— 5/5 PASS (live-feed, incident, recovery, reconnect, and the corrected Models anchors unweakened on this head)npm run test:e2e:core— 39/39 PASSpython3 scripts/validate_execass_contract.py— PASS; contracts untouchedgit diff --check— PASSruntime/qa/p5-events-slice/— enumerated withlsfirst: six, each visually inspected (refusal copy beside the Channel-filtered secret row, pinned desktop with expanded redacted JSON, Office door naming The Basement, disabled/restored door truth, and 390px with the ES mark lit, wrapped chip rows contained, and JSON wrapping inside its row)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests