> For the complete documentation index, see [llms.txt](https://faction-os.gitbook.io/faction-os-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase21-session02-shared-expansion-host/spec.md).

# Session Specification

**Session ID**: `phase21-session02-shared-expansion-host` **Phase**: 21 - Bottom Rail Focused Surface Expansion **Status**: Not Started **Created**: 2026-06-29 **Package**: apps/web **Package Stack**: TypeScript

***

## 1. Session Overview

This session creates the shared bottom-rail expansion host that promotes Quest Board, Orchestration, and War Room from compact cockpit cells into one focused working surface. It builds on Session 01's transient `expandedBottomRailSurfaceId` state instead of adding new local booleans or persisted preferences.

This is the next executable Phase 21 session because Sessions 03, 04, 05, and 06 all depend on a common host contract before they can safely change Orchestration entry paths, shortcuts, panel-specific parity, and responsive verification. The host must preserve the existing `ShellSurface` and `SurfaceStateNote` behavior while keeping each panel mounted once.

The implementation should prefer same-instance promotion: the wrapper changes layout and modal semantics when expanded, but it does not render a second `QuestBoard`, `OrchestrationPanel`, or `WarRoomPanel` tree. Panel-specific header/detail popup semantics remain available for later sessions to rename, demote, or route through the shared host.

***

## 2. Objectives

1. Create a reusable bottom-rail expansion host for the three bottom cockpit surfaces.
2. Wire Quest Board, Orchestration, and War Room through the host in `apps/web/src/App.tsx`.
3. Implement explicit open controls, guarded background expansion, backdrop close, close button, Escape close, focus restore, and dialog semantics.
4. Add focused tests proving one-at-a-time expansion, interactive-descendant click guards, and same-instance panel preservation.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase21-session01-expansion-state-foundation` - Provides the transient `BottomRailSurfaceId` union, `expandedBottomRailSurfaceId`, and setter in `useSettingsStore`.

### Required Tools Or Knowledge

* Node 26.2.0+ and npm 11.16.0 workspace commands.
* React 19 component lifecycle and refs.
* Zustand selector usage for transient shell state.
* Testing Library and Vitest component testing patterns in `apps/web/tests`.

### Environment Requirements

* Local repository checkout with npm dependencies installed.
* Happy DOM test environment used by the existing web tests.
* No hosted service, Cloudflare, Worker, or local server credential is required.

***

## 4. Scope

### In Scope (MVP)

* Web cockpit users can expand Quest Board, Orchestration, or War Room through one shell-level host - implemented in `apps/web/src/components/BottomRailExpansionHost.tsx`.
* The bottom rail in `apps/web/src/App.tsx` uses the shared host for all three bottom surfaces while preserving `SurfaceStateNote` loading, offline, empty, and disconnected notes.
* The host provides product-facing explicit open controls and guarded panel-background click expansion with buttons, links, form fields, tabs, editable content, and `[data-no-panel-expand]` excluded from expansion.
* Expanded state provides a backdrop, close button, Escape close, focus restore to the opener, `role="dialog"`, `aria-modal="true"`, `aria-labelledby`, `aria-controls`, stable ids, and stable test ids.
* Tests prove only one bottom-rail surface is expanded at a time and that the host preserves one mounted panel implementation.

### Out Of Scope (Deferred)

* Renaming Orchestration's primary header action or shortcut from details language to Command Center language - Reason: Session 03 owns Orchestration-specific full Command Center entry behavior and Session 04 owns shortcut routing.
* Demoting Quest Board and War Room existing detail portals from primary panel semantics - Reason: Session 05 owns panel-specific parity after the shared host exists.
* Nested overlay priority across retained detail portals, `TerminalRuntimeDrawer`, and `OrchestrationDrawer` - Reason: Session 04 owns overlay-layer ordering; this session implements the base host Escape close.
* Desktop/mobile browser visual tuning and formal accessibility pass - Reason: Session 06 owns responsive and accessibility evidence after all panel paths are wired.
* Backend orchestration, War Room Worker protocol, trusted erasure, hosted identity, or execution semantics - Reason: this is an `apps/web` shell presentation session only.

***

## 5. Technical Approach

### Architecture

Add `BottomRailExpansionHost` under `apps/web/src/components/` and use it from `apps/web/src/App.tsx` around the existing Quest Board, Orchestration, and War Room component instances. The host reads `expandedBottomRailSurfaceId` and `setExpandedBottomRailSurfaceId` from `useSettingsStore`, compares that value to its own `BottomRailSurfaceId`, and applies compact or fixed focused layout classes to the same wrapper.

The App-level wiring should keep `SurfaceStateNote` behavior in the same surface wrapper path so shell metadata remains visible in loading, offline, empty, and disconnected states. The host may receive rendered state-note content or equivalent surface metadata, but compact and expanded presentations must share that same note behavior rather than maintaining separate copies.

The host owns pointer and keyboard mechanics. Explicit open buttons call the store setter. Background clicks open only when the event target is not inside an interactive descendant matching the guard selector. Close button, backdrop click, and Escape set the expanded id back to `null`; Escape listeners are registered only while expanded and cleaned up on unmount or close. Focus is restored to the opener when the host closes.

### Design Patterns

* Same-instance promotion: Preserve local panel state by changing the wrapper's layout and semantics instead of rendering a duplicate panel tree.
* Store-backed singleton state: Use the Session 01 Zustand field so setting one surface id replaces any other expanded surface.
* Guarded shell click handling: Treat explicit controls and non-interactive panel background clicks as launchers while preserving nested button, link, input, tab, and editable behavior.
* Component-isolated contract tests: Exercise host mechanics with small child fixtures, then prove App wiring across the real bottom-rail ids.

***

## 6. Deliverables

### Files To Create

| File                                                  | Purpose                                                                                                                                   | Est. Lines |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/BottomRailExpansionHost.tsx` | Shared bottom-rail host with compact/focused layout, open/close controls, click guard, focus restore, ARIA, and test ids.                 | \~180      |
| `apps/web/tests/BottomRailExpansionHost.test.tsx`     | Focused host tests for open, close, backdrop, Escape, focus restore, one-at-a-time state, interactive guard, and same child preservation. | \~190      |

### Files To Modify

| File                                          | Changes                                                                                                                                           | Est. Lines |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/App.tsx`                        | Import and wire the shared host around Quest Board, Orchestration, and War Room while preserving shell surface notes and bottom-rail layout.      | \~80       |
| `apps/web/tests/CockpitShell.test.tsx`        | Add App-level coverage for all three bottom-rail expand controls, one-at-a-time replacement, close recovery, and no duplicate mocked panel trees. | \~120      |
| `apps/web/tests/MobileAccessibility.test.tsx` | Adjust selectors only if the host wrapper changes existing shell-region queries used by mobile accessibility coverage.                            | \~20       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Quest Board, Orchestration, and War Room each expose a visible shell-level expand control with stable test ids.
* [ ] Panel-background clicks open the matching surface only when the click does not start inside an interactive descendant or `[data-no-panel-expand]`.
* [ ] Expanding one bottom-rail surface replaces any previously expanded surface.
* [ ] Backdrop click, close button, and Escape clear the expanded surface and restore focus to the opener.
* [ ] Expanded surfaces use `role="dialog"`, `aria-modal="true"`, `aria-labelledby`, and `aria-controls` while compact surfaces remain normal cockpit regions.
* [ ] Compact and expanded modes preserve one mounted panel implementation per bottom surface.

### Testing Requirements

* [ ] Component tests cover host open, close, backdrop, Escape, focus restore, one-at-a-time state, guarded nested controls, and same-instance child preservation.
* [ ] App shell tests cover all three bottom-rail surfaces with stable test ids and no duplicate panel rendering.
* [ ] Focused web tests and web typecheck completed.

### Non-Functional Requirements

* [ ] Expansion state remains transient and is not persisted to localStorage.
* [ ] No new hosted-service, backend execution, trusted erasure, or formal accessibility certification claim is introduced.
* [ ] Normal UI rows and labels stay product-facing and do not expose raw command, terminal, provider, token, file-content, diff, or broad absolute-path detail.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] Primary user-facing surfaces contain product-facing copy only.

***

## 8. Implementation Notes

### Working Assumptions

* `apps/web` is the package context: the analysis script, Phase 21 PRD, and Session 02 stub all scope the session to the web cockpit shell.
* Fixed-position same-instance promotion is the implementation path: the Phase 21 PRD and Session 02 stub prefer this approach, and `apps/web/src/App.tsx` currently mounts each bottom panel once directly inside the bottom rail.
* Existing detail portals remain available during this session: Session 03 owns Orchestration primary entry changes and Session 05 owns Quest Board and War Room detail portal demotion, so this session should add the shared shell-level expansion path without deleting those inspectors.

### Conflict Resolutions

* Session 02 says all three bottom cells should be wired through the host, while Sessions 03 and 05 also describe primary panel open path changes. The chosen interpretation is that Session 02 creates the generic host controls and background expansion for all three cells; later sessions revise panel-specific header, shortcut, and inspector semantics.
* Session 02 and Session 04 both mention Escape/backdrop behavior. The chosen interpretation is that Session 02 implements the base host Escape, backdrop, and close-button recovery; Session 04 adds nested overlay-layer precedence for retained details and drawers.

### Key Considerations

* `useSettingsStore` already owns `BottomRailSurfaceId`, `expandedBottomRailSurfaceId`, and `setExpandedBottomRailSurfaceId`; this session should reuse that API and avoid adding another store.
* App-level tests currently mock `OrchestrationPanel`, and may need mock counters for all three bottom panels to prove the host is not rendering duplicate child trees.
* `SurfaceStateNote` is defined inside `App.tsx`; wiring should avoid splitting loading/offline note behavior between compact and expanded modes.

### Potential Challenges

* Fixed positioning from inside the cockpit grid can interact with parent overflow: use `fixed` expanded layout and stable z-index so the focused surface is not clipped by `Layout`.
* Host click handling can steal panel actions if the guard selector is incomplete: cover buttons, links, inputs, textareas, selects, role buttons, role tabs, contenteditable, and `[data-no-panel-expand]`.
* Focus restoration can fail when the opener unmounts or another surface replaces it: store the opener ref defensively and check `isConnected` before focusing.

### Relevant Considerations

* \[P20] **Release evidence is the execution claim source**: This session must prove visible host behavior with tests before claiming the expansion host is ready.
* \[P20] **Do not add action verbs before evidence**: New open/close labels must describe implemented surface behavior only.
* \[P20] **Broad privacy gates are release-critical**: The focused shell must not broaden raw orchestration, Worker, terminal, file, diff, token, provider, or broad-path detail into broad UI rows.
* \[P03] **Stable docs are the current contract**: Documentation updates are deferred until Session 07 because this session adds infrastructure for the interaction rather than the final documented entry path.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Background panel clicks accidentally trigger expansion when users click nested controls.
* Expanded surfaces close without restoring focus or leak Escape listeners after unmount.
* A duplicate panel tree forks local Quest Board, Orchestration, or War Room state.

***

## 9. Testing Strategy

### Unit Tests

* Add `BottomRailExpansionHost` tests using fixture children to prove open control behavior, one-at-a-time replacement through the store, close button, backdrop close, Escape close with listener cleanup, focus restoration, guarded nested-control clicks, and same child preservation.

### Integration Tests

* Extend `CockpitShell.test.tsx` to render `App`, expand each bottom surface, assert `bottom-rail-expanded-quest-board`, `bottom-rail-expanded-orchestration`, and `bottom-rail-expanded-war-room`, verify replacing one expanded surface closes the previous one, and verify mocked panel trees remain single-mounted.
* Update `MobileAccessibility.test.tsx` only if the host wrapper changes existing shell region queries.

### Runtime Verification

* No browser runtime verification is required in this session because Session 06 owns viewport and accessibility browser evidence after all panel-specific paths are complete.

### Edge Cases

* An expanded surface closes when Escape is pressed even if focus is inside the panel.
* Clicking a nested button, link, input, textarea, select, role button, role tab, contenteditable element, or `[data-no-panel-expand]` does not expand the surface.
* Opening a second bottom surface replaces the first without leaving multiple dialogs active.
* Focus restore does not throw if the opener is no longer connected.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase21-session01-expansion-state-foundation`.
* Depended by: `phase21-session03-orchestration-command-center-expansion`, `phase21-session04-shortcut-and-overlay-layering`, `phase21-session05-quest-board-and-war-room-parity`, `phase21-session06-responsive-layout-and-accessibility-pass`, `phase21-session07-final-regression-and-documentation`.

***

## Next Steps

Run the `implement` workflow step to begin implementation.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://faction-os.gitbook.io/faction-os-docs/.spec_system/archive/sessions/phase21-session02-shared-expansion-host/spec.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
