Skip to content

feat(glass-office): registry-driven tour, mobile shell law, and a11y polish - #119

Merged
EmergentKnowledgeGroup merged 3 commits into
mainfrom
codex/glass-office-final-polish
Jul 27, 2026
Merged

feat(glass-office): registry-driven tour, mobile shell law, and a11y polish#119
EmergentKnowledgeGroup merged 3 commits into
mainfrom
codex/glass-office-final-polish

Conversation

@EmergentKnowledgeGroup

@EmergentKnowledgeGroup EmergentKnowledgeGroup commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Scope

Final P6 whole-building polish for Glass Office. This PR completes the registry-driven guided tour, plain-language quick guides, 390px shell/Office/Window behavior, focus and accessibility sweep, reduced motion, and zoom/long-copy/resilience proof. It extends the resolved elevator registry, existing controllers, and shared shell; it adds no backend authority, alternate navigation system, or fabricated facts.

Product behavior

  • Builds one tour stop per resolved floor using stable room IDs, followed by Help/Docs, Config, and command palette stops. Hidden or unavailable floors are skipped; targets that disappear recover honestly.
  • Preserves conventional room navigation and direct Help/Docs, Config, and Basement Setup access.
  • Preserves the fixed desktop 6-column × 4-row Office canvas. At narrow widths, Office becomes a stacked feed with Needs You first without mutating persisted layout; Reef and Chatter summarize before disclosure.
  • Announces current room and incident posture without color alone, removes motion under prefers-reduced-motion, ignores elevator shortcuts in editable fields, and gives Settings, command palette, and tour real focus trap/restoration behavior.

Hostile QA corrections

  • Fixed Settings focus escape through controls inside closed disclosures and added real-browser forward/reverse trap plus exact-invoker restoration proof.
  • Fixed mobile/200%-zoom title and action occlusion. Narrow-layout toasts now participate in shell flow instead of floating over header or bottom controls.
  • Replaced the scroll-relative Office ordering assertion with one immutable layout snapshot and added desktop 6×4 plus byte-identical persisted-layout proof.
  • Strengthened viewport-bottom, center-hit occlusion, mark/badge, long-copy, and connected keyboard-focus restoration assertions.
  • Added exact one-request / one-response / one-console-error capability failure proof with honest loading, partial facts, retry, and recovery at 390px.
  • Unmounted the AppShell test root correctly and replaced the deprecated Playwright typing call.

Security and authority boundary

  • No contract, Rust backend, authentication, credential, policy, payment, or multi-user behavior changed.
  • No secrets or personal data were added.
  • Pinning and responsive presentation remain configuration-only; backend facts remain authoritative.

Validation on final correction head

  • npm run typecheck — PASS
  • npm run lint -- --max-warnings=0 — PASS
  • npm run test:unit -- --run841/841 PASS
  • npm run build — PASS
  • npm run test:e2e:core50/50 PASS in 7.5 minutes
  • cargo run -q -p carsinos-protocol --bin generate_execass_contract -- --check — PASS
  • python scripts/validate_execass_contract.py — PASS
  • git diff --check — PASS
  • Contracts untouched; only the preserved root node_modules/ remains untracked.

Regenerated desktop, 390px, 200%-zoom, and deliberate partial-error artifacts under runtime/qa/p6-polish/ were visually inspected. Checkpoint track: GLASS_OFFICE_P6_CROSS_FLOOR WORK.

Summary by CodeRabbit

  • New Features
    • Guided tours are now generated from the resolved elevator floors, landing on the appropriate room and including consistent Help/Docs, Config, and Command palette steps.
    • Improved narrow-viewport behavior with responsive elevator/feed layout updates.
  • Accessibility
    • Added focus-management for Settings and Command palette dialogs, including Escape-to-close and focus restoration.
    • Guided tour overlay now traps keyboard Tab focus and shows clearer “missing stop” messaging.
    • Enhanced navigation/status ARIA labeling across the shell.
  • Bug Fixes
    • Improved tour target visibility handling and geometry-related resilience at narrow widths/high zoom.
  • Tests
    • Added/expanded unit, component, and Playwright end-to-end coverage for guided tours, dialogs, focus behavior, and responsive layouts.

EmergentKnowledgeGroup and others added 2 commits July 26, 2026 23:53
…polish

Final P6 cross-floor polish slice. No new navigation mechanism, no
fabricated backend facts; every change extends the resolved elevator
registry, existing controllers, and shared shell.

Guided tour
- Replace legacy tab-button GUIDED_TOUR_STEPS with buildGuidedTourSteps,
  a pure composer over the resolved elevator registry: one owner-language
  stop per floor (by stable room id, default-room fallback), then the
  Help/Docs, Config, and command-palette shell stops. Hidden or
  capability-disabled floors and rooms can never become stops.
- Anchor each floor section with data-tour-id="floor-<id>"; the overlay
  spotlights the real section, walks by stable room id (fails closed on
  unknown ids), shows honest recovery copy when a stop is off/hidden
  (zero-rect aware), traps Tab, and restores focus to the launcher (or an
  equivalent visible launcher when the invoker unmounted mid-tour).

Quick guides
- Rewrite the Office ("Your desk") and Window quick guides in plain,
  glance-able owner language. Help/Docs, Config, Setup, and conventional
  room navigation remain the direct path; the tour is never the only way.

390px mobile shell law
- Fit the elevator to the 52px rail (lamp + room marks, no overflow past
  the viewport). The Office becomes a stacked scrollable feed with Needs
  You first without mutating the stored arrangement (arrange mode shows
  true order); the fixed desktop 6x4 canvas is unchanged. Reef and Office
  Chatter summarize before disclosure at narrow widths via one shared
  useNarrowViewport hook.

Accessibility
- Add useDialogFocus (focus-in, Tab trap, exact-invoker restore) and apply
  it to Settings and the command palette, both now role="dialog"
  aria-modal labeled. aria-current marks the active room; the posture pill
  is an announced status; rail/topbar actions have accessible names; the
  live-feed scroll respects prefers-reduced-motion.

Proof
- New e2e/p6-final-polish.spec.ts: elevator tour walk, launcher focus
  restore, reduced-motion, hidden-target honesty, 390px unclipped chrome
  and mark/badge non-overlap, stacked Office feed, Window summaries, 200%
  zoom, editable-field keyboard guard, and long-copy incident band, all
  with exact console/page/request failure accounting. Rewrite the core
  tour spec to the elevator model. New unit suites for buildGuidedTourSteps,
  GuidedTourOverlay, useDialogFocus, mobile Office ordering, and Window
  summaries.

Local gates: typecheck, zero-warning lint, unit 840/840, build, core E2E
49/49, ExecAss generated contract --check, independent validator, and
git diff --check all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR rebuilds guided tours from resolved elevator floors, adds accessible focus management for dialogs and tours, introduces responsive mobile shell behavior, updates help copy and styling, and adds mounted and browser-based validation for geometry, keyboard behavior, hostile content, and incident recovery.

Changes

Mission Control final polish

Layer / File(s) Summary
Resolved-floor guided tour flow
apps/mission-control/src/glass/guidedTour.ts, apps/mission-control/src/App.tsx, apps/mission-control/src/app/GuidedTourOverlay.tsx, apps/mission-control/e2e/core.spec.ts
Guided-tour steps derive from resolved elevator floors, target stable room IDs, clamp shrinking step lists, report unavailable targets, trap focus, and validate the updated seven-step flow.
Dialog focus and accessibility
apps/mission-control/src/app/useDialogFocus.ts, apps/mission-control/src/app/AppShell.tsx, apps/mission-control/src/ui/CommandPalette.tsx, apps/mission-control/src/app/*test.tsx
Settings and command-palette dialogs gain modal semantics, focus trapping, focus restoration, and accessible labels; navigation and status controls gain additional ARIA attributes.
Responsive office and window shell
apps/mission-control/src/app/useNarrowViewport.ts, apps/mission-control/src/features/execassOffice/*, apps/mission-control/src/features/glassWindow/*, apps/mission-control/src/styles.css
Narrow viewports prioritize “Needs You,” collapse Chatter into a summary, and receive responsive elevator, toast, tour-missing, and chatter styling with corresponding tests.
P6 browser resilience coverage
apps/mission-control/e2e/p6-final-polish.spec.ts, docs/plans/2026-07-23-glass-office-claude-resume.md
End-to-end coverage checks tour behavior, mobile geometry, keyboard truth, long content, incident-band recovery, provider failure recovery, gateway state synchronization, and browser failures.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant MissionControl
  participant ElevatorRegistry
  participant GuidedTourOverlay
  Browser->>MissionControl: start guided tour
  MissionControl->>ElevatorRegistry: read resolved floors
  ElevatorRegistry-->>MissionControl: return floors and rooms
  MissionControl->>GuidedTourOverlay: render generated step
  GuidedTourOverlay->>MissionControl: select stable room target
  MissionControl-->>Browser: update spotlight and progress
Loading

Possibly related PRs

Suggested reviewers: professahx

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main changes: registry-driven tour, mobile shell behavior, and accessibility polish.
Description check ✅ Passed The description covers scope, behavior, validation, and security, though it doesn't follow the template headings exactly.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/glass-office-final-polish

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (3)
apps/mission-control/e2e/p6-final-polish.spec.ts (2)

189-195: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

expectWithinViewport doesn't check the bottom edge.

Only left/top/right are asserted, so an element extending below the fold passes. If that's intentional (vertical scrolling is expected), a brief comment or a name like expectHorizontallyWithinViewport would prevent the helper from being read as full containment proof.

🤖 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/p6-final-polish.spec.ts` around lines 189 - 195,
Update expectWithinViewport to assert that box.y + box.height does not exceed
viewport!.height + 0.5, completing the viewport containment check. If the helper
is intentionally limited to horizontal containment because vertical scrolling is
expected, rename it to expectHorizontallyWithinViewport instead.

481-483: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use pressSequentially() instead of type() here. locator.type() is deprecated in Playwright, and this test needs per-character input semantics.

🤖 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/p6-final-polish.spec.ts` around lines 481 - 483,
Replace the deprecated type() call on askInput in the input interaction flow
with pressSequentially(), preserving the "24b" value and per-character input
behavior.
apps/mission-control/src/App.tsx (1)

879-891: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Guard against redundant re-navigation on unrelated re-renders.

guidedTourSteps is recomputed via useMemo(..., [elevatorFloors]); if elevatorFloors (returned by useResolvedElevator, not shown here) isn't itself memoized/stable across unrelated re-renders, this effect will re-fire selectAvailableRoom(step.roomId) on every such render even though the current step hasn't changed — potentially re-triggering room-selection side effects repeatedly while the tour sits on one step.

A cheap guard using the already-computed resolvedActiveRoomId would make this effect resilient regardless of upstream memoization:

♻️ Proposed guard
   useEffect(() => {
     if (!guidedTourOpen) {
       return;
     }
     const step = guidedTourSteps[guidedTourStep];
-    if (step?.roomId) {
+    if (step?.roomId && step.roomId !== resolvedActiveRoomId) {
       selectAvailableRoom(step.roomId);
     }
-  }, [guidedTourOpen, guidedTourStep, guidedTourSteps, selectAvailableRoom]);
+  }, [guidedTourOpen, guidedTourStep, guidedTourSteps, resolvedActiveRoomId, selectAvailableRoom]);

Please confirm whether useResolvedElevator memoizes its output; if it already does, this guard is still a cheap, harmless safety net.

🤖 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/src/App.tsx` around lines 879 - 891, Update the
guided-tour navigation effect around guidedTourOpen and guidedTourStep to call
selectAvailableRoom only when step.roomId differs from the already-resolved
active room, using resolvedActiveRoomId as the guard. Preserve the existing
behavior for missing room IDs and unavailable rooms, and include the active-room
value in the effect dependencies as needed.
🤖 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 `@apps/mission-control/e2e/p6-final-polish.spec.ts`:
- Around line 311-320: Strengthen the focus validation in the `page.evaluate`
result and its assertions so the restored active element must be a connected,
keyboard-focusable element rather than `document.body`. Preserve the
detached-element check while explicitly rejecting body focus and validating
focusability.
- Around line 377-403: Update the block measurement loop around blockBoxes to
convert each boundingBox() result from viewport-relative to document-absolute
coordinates by incorporating the page scroll offsets, while preserving the
existing visibility and positive-size assertions. Use these absolute boxes for
the needs-you ordering and stacked-layout checks so scrolling between
measurements cannot affect comparisons.

In `@apps/mission-control/src/app/AppShell.test.tsx`:
- Around line 594-612: Update the AppShell test teardown to retain the rendered
React root and call root.unmount() inside act during afterEach before clearing
document.body, ensuring component effect cleanup runs. Preserve the existing
global stubbing cleanup after unmounting.

---

Nitpick comments:
In `@apps/mission-control/e2e/p6-final-polish.spec.ts`:
- Around line 189-195: Update expectWithinViewport to assert that box.y +
box.height does not exceed viewport!.height + 0.5, completing the viewport
containment check. If the helper is intentionally limited to horizontal
containment because vertical scrolling is expected, rename it to
expectHorizontallyWithinViewport instead.
- Around line 481-483: Replace the deprecated type() call on askInput in the
input interaction flow with pressSequentially(), preserving the "24b" value and
per-character input behavior.

In `@apps/mission-control/src/App.tsx`:
- Around line 879-891: Update the guided-tour navigation effect around
guidedTourOpen and guidedTourStep to call selectAvailableRoom only when
step.roomId differs from the already-resolved active room, using
resolvedActiveRoomId as the guard. Preserve the existing behavior for missing
room IDs and unavailable rooms, and include the active-room value in the effect
dependencies as needed.
🪄 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: 0cc8e49b-8e29-407d-bf47-f68c27453142

📥 Commits

Reviewing files that changed from the base of the PR and between f4fc22f and 3d257e3.

📒 Files selected for processing (20)
  • apps/mission-control/e2e/core.spec.ts
  • apps/mission-control/e2e/p6-final-polish.spec.ts
  • apps/mission-control/src/App.tsx
  • apps/mission-control/src/app/AppShell.test.tsx
  • apps/mission-control/src/app/AppShell.tsx
  • apps/mission-control/src/app/GuidedTourOverlay.test.tsx
  • apps/mission-control/src/app/GuidedTourOverlay.tsx
  • apps/mission-control/src/app/TabHelpBanner.tsx
  • apps/mission-control/src/app/useDialogFocus.test.tsx
  • apps/mission-control/src/app/useDialogFocus.ts
  • apps/mission-control/src/app/useNarrowViewport.ts
  • apps/mission-control/src/features/execassOffice/ExecassOfficePanel.test.tsx
  • apps/mission-control/src/features/execassOffice/ExecassOfficePanel.tsx
  • apps/mission-control/src/features/glassWindow/GlassWindowExperiential.test.tsx
  • apps/mission-control/src/features/glassWindow/GlassWindowPage.tsx
  • apps/mission-control/src/glass/guidedTour.test.ts
  • apps/mission-control/src/glass/guidedTour.ts
  • apps/mission-control/src/styles.css
  • apps/mission-control/src/ui/CommandPalette.tsx
  • docs/plans/2026-07-23-glass-office-claude-resume.md

Comment thread apps/mission-control/e2e/p6-final-polish.spec.ts
Comment thread apps/mission-control/e2e/p6-final-polish.spec.ts Outdated
Comment thread apps/mission-control/src/app/AppShell.test.tsx
@EmergentKnowledgeGroup

Copy link
Copy Markdown
Owner Author

Hostile QA correction pushed once at 8ebd183. All three actionable review findings and all three nits were reproduced/classified and corrected; independent QA also found and fixed the closed-disclosure Settings focus escape and the narrow/zoom toast occlusion. Final local packet: typecheck PASS, zero-warning lint PASS, unit 841/841, build PASS, core E2E 50/50, both ExecAss contract checks PASS, diff-check PASS, contracts untouched. Fresh desktop/390/200%-zoom/partial-error artifacts were inspected. No manual CodeRabbit re-review was requested; this head is now in the ordinary incremental review and CI loop.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
apps/mission-control/e2e/p6-final-polish.spec.ts (2)

665-672: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hoist the topbar measurement out of the badge loop.

expectVisibleNonZeroRect(page, ".mc-topbar") re-runs its full visibility/hit-test probe on every badge. Measure once before the loop so every comparison uses one layout snapshot, matching the discipline used at Lines 477-479.

♻️ Single measurement
+  const zoomTopbarWithIncident = await expectVisibleNonZeroRect(
+    page,
+    ".mc-topbar",
+  );
   for (const badge of await zoomBadges.all()) {
     if (!(await badge.isVisible())) continue;
     const box = await badge.boundingBox();
     expect(box).not.toBeNull();
-    expectContained(box!, await expectVisibleNonZeroRect(page, ".mc-topbar"));
+    expectContained(box!, zoomTopbarWithIncident);
     expectNoOverlap(zoomTitleWithIncident, box!);
     await expectWithinViewport(page, box!);
   }
🤖 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/p6-final-polish.spec.ts` around lines 665 - 672,
Measure the visible non-zero rectangle for “.mc-topbar” once before the loop
over zoomBadges, then reuse that stored rectangle in each expectContained call.
Keep the badge visibility, bounding-box, overlap, and viewport assertions
unchanged.

846-852: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exact-count poll only proves arrival, not stability.

expect.poll(...).toEqual({console: 1, requests: 1, responses: 1}) resolves the moment the counters first match and returns immediately. A duplicate 503 or console error arriving a tick later is never observed, which undercuts the "exact failure accounting" claim in the test title. Re-assert the counters after the subsequent recovery step so overshoot is caught.

♻️ Re-assert after recovery
   await expect(partialProvider).toContainText("streaming");
+  expect({
+    console: injectedConsoleErrors,
+    requests: injectedRequests,
+    responses: injectedResponses,
+  }).toEqual({ console: 1, requests: 1, responses: 1 });
   expect(unexpectedErrors).toEqual([]);
🤖 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/p6-final-polish.spec.ts` around lines 846 - 852,
Update the exact failure-count assertions in the test around the
injectedConsoleErrors, injectedRequests, and injectedResponses poll: retain the
initial poll for arrival, then re-assert the same exact counts after the
subsequent recovery step so any later duplicate 503 or console error causes the
test to fail.
🤖 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.

Nitpick comments:
In `@apps/mission-control/e2e/p6-final-polish.spec.ts`:
- Around line 665-672: Measure the visible non-zero rectangle for “.mc-topbar”
once before the loop over zoomBadges, then reuse that stored rectangle in each
expectContained call. Keep the badge visibility, bounding-box, overlap, and
viewport assertions unchanged.
- Around line 846-852: Update the exact failure-count assertions in the test
around the injectedConsoleErrors, injectedRequests, and injectedResponses poll:
retain the initial poll for arrival, then re-assert the same exact counts after
the subsequent recovery step so any later duplicate 503 or console error causes
the test to fail.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dced79a4-ac88-4014-b8ab-912fc5ed9391

📥 Commits

Reviewing files that changed from the base of the PR and between 3d257e3 and 8ebd183.

📒 Files selected for processing (8)
  • apps/mission-control/e2e/p6-final-polish.spec.ts
  • apps/mission-control/src/App.tsx
  • apps/mission-control/src/app/AppShell.test.tsx
  • apps/mission-control/src/app/AppShell.tsx
  • apps/mission-control/src/app/GuidedTourOverlay.tsx
  • apps/mission-control/src/app/useDialogFocus.test.tsx
  • apps/mission-control/src/app/useDialogFocus.ts
  • apps/mission-control/src/styles.css
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/mission-control/src/app/useDialogFocus.test.tsx
  • apps/mission-control/src/app/AppShell.test.tsx
  • apps/mission-control/src/App.tsx
  • apps/mission-control/src/app/GuidedTourOverlay.tsx
  • apps/mission-control/src/app/useDialogFocus.ts
  • apps/mission-control/src/app/AppShell.tsx

@EmergentKnowledgeGroup
EmergentKnowledgeGroup merged commit 8b532a5 into main Jul 27, 2026
5 checks passed
@EmergentKnowledgeGroup
EmergentKnowledgeGroup deleted the codex/glass-office-final-polish branch July 27, 2026 10:01
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