> 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/phase05-session03-web-room-lifecycle-and-state-store/spec.md).

# Session Specification

**Session ID**: `phase05-session03-web-room-lifecycle-and-state-store` **Phase**: 05 - War Room Worker Integration **Status**: Complete **Created**: 2026-05-29 **Package**: apps/web **Package Stack**: TypeScript, React 18, Vite, Zustand, Vitest

***

## 1. Session Overview

This session replaces the disabled web War Room stub with the first usable browser lifecycle path for the optional Cloudflare Worker room relay. The Worker and shared protocol contracts were hardened in Session 02; this session consumes those contracts from `apps/web` without changing the local server into a room proxy or implying that Cloudflare is required for core FactionOS use.

The implementation adds a bounded Worker client, local participant identity handling, a War Room Zustand store, and accessible create, join, connect, and disconnect controls in the existing cockpit panel. The panel must clearly show local-only, unavailable, pending, connected, disconnected, invalid input, and rate-limited states while preserving the rest of the cockpit when no Worker URL is configured or the Worker is down.

This is deliberately not the full collaboration UI. Leader approval controls, participant roster detail, reconnect/catch-up UX, ghost overlays, and redacted cockpit event federation remain owned by Sessions 04 and 05.

***

## 2. Objectives

1. Add a typed `apps/web` War Room client that consumes the Session 02 Worker contract for health, room snapshot, create, join, socket URL, and disconnect lifecycle helpers.
2. Add a War Room Zustand store for Worker URL, local participant hint, room code, role, lifecycle state, last safe snapshot, in-flight flags, and bounded error state.
3. Replace the disabled War Room panel with accessible room lifecycle controls that handle create, join, connect, disconnect, validation, loading, empty, unavailable, pending, and connected states.
4. Persist only bounded browser hints and add focused tests for storage recovery, duplicate-action guards, client error mapping, socket cleanup, and component states.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase05-session01-war-room-requirements-and-trust-baseline` - Provides lifecycle vocabulary, trust boundaries, local-first requirements, and transfer minimization rules.
* [x] `phase05-session02-worker-api-hardening-and-client-contract` - Provides shared Worker REST, WebSocket, participant, error, rate-limit, and safe-frame contracts consumed by this session.
* [x] `phase04-session08-media-validation-and-documentation-closeout` - Confirms current local-first, media, browser, and privacy gates before external-transfer UI work resumes.

### Required Tools/Knowledge

* React 18 component patterns in `apps/web/src/components`.
* Zustand store patterns in `apps/web/src/store`.
* Protocol-owned War Room contracts exported from `@factionos/protocol`.
* Vitest and Testing Library patterns under `apps/web/tests`.
* Browser `fetch`, `AbortController`, `WebSocket`, and localStorage failure behavior.

### Environment Requirements

* Node 20+ and npm workspace install are available.
* No Cloudflare credentials are required for implementation or tests.
* Worker integration tests must use mocks or a configured local Worker URL; the rest of the cockpit must remain usable with no Worker URL.

***

## 4. Scope

### In Scope (MVP)

* Local cockpit users can stay in local-only mode when no Worker URL is configured - implemented as visible copy and disabled external-transfer actions without blocking the cockpit.
* Local cockpit users can save bounded Worker URL and participant display hints
  * implemented with normalization, malformed storage recovery, and no raw room events or local session data in persistence.
* Room leaders can create a Worker room - implemented through the protocol create contract, leader participant capture, duplicate-submit guard, and typed error handling.
* Participants can submit a room code and request to join - implemented through local room-code validation, pending state, unavailable state, full-room and not-found copy, and duplicate-submit guard.
* Approved participants can connect or disconnect a room socket - implemented with protocol-backed socket URL helpers, socket cleanup, disconnected state, and no automatic reconnect UI yet.
* The War Room panel exposes accessible lifecycle controls and states - implemented with labels, focus-safe form controls, loading, empty, error, offline, pending, connected, and disconnected states.
* Tests cover Worker client failure mapping, store transitions, persistence safety, duplicate-action prevention, socket cleanup, and component state rendering.

### Out of Scope (Deferred)

* Leader approval and rejection UI - *Reason: Session 04 owns pending-request resolution, stale decisions, non-leader states, and accessible approval UX.*
* Participant roster detail, observer policy, presence list, reconnect, catch-up display, and leave semantics - *Reason: Session 04 owns resilient participation UX beyond the first connect/disconnect path.*
* Redacted hero, mission, replay, export, media, scan, command, transcript, or prompt federation - *Reason: Session 05 owns the explicit federation allowlist and sensitive-payload blocking tests.*
* Hosted accounts, hosted persistence, analytics, public replay hosting, inbound commands, remote execution, Docker isolation, or unified erasure - *Reason: later phases own these surfaces and threat models.*
* Turning local server `/warroom` into a Worker proxy - *Reason: Phase 05 keeps room traffic on the separate Worker surface unless a future PRD adds a proxy threat model.*

***

## 5. Technical Approach

### Architecture

Add `apps/web/src/lib/warRoomClient.ts` as the browser boundary for Worker REST and WebSocket operations. It should import protocol-owned types and constants from `@factionos/protocol`, normalize Worker base URLs, apply request timeouts, map deterministic Worker error envelopes into safe UI failures, validate response shape before returning success, and avoid reusing the local server auth token or local `/api` proxy.

Add `apps/web/src/lib/warRoomIdentity.ts` for bounded participant and Worker URL hints. The persisted snapshot should contain only non-sensitive fields such as `workerUrl`, `participantId`, and `participantName`, with size limits, malformed JSON recovery, URL validation, and a clear reset path. It must not store room events, socket frames, prompts, paths, exports, replay buffers, scan payloads, diagnostics, or local server auth tokens.

Add `apps/web/src/store/useWarRoomStore.ts` to own lifecycle state. The store should expose actions for setting hints, creating a room, joining a room, connecting, disconnecting, clearing errors, and resetting local room context. It should retain the last safe room snapshot for display, guard duplicate mutations while a request is in flight, clean up sockets on disconnect or reset, and reduce network/socket failures into bounded error state.

Update `apps/web/src/components/WarRoomPanel.tsx` to consume the store and replace the stub with real form controls. The panel should remain dense and operational: Worker URL input, participant name input, create and join flows, room code display/input, pending and connected summaries, disconnect/reset controls, and local-only/unavailable copy should all fit inside the existing bottom-rail surface without overlapping mobile or desktop content.

### Design Patterns

* Protocol-first consumption: Import shared War Room contracts instead of duplicating event and error strings.
* Boundary validation: Validate Worker URL, room code, participant hint, response shape, and socket participant before mutation.
* Local-first fallback: Missing Worker configuration is a normal state, not an app error.
* Duplicate-action guard: Every create, join, connect, disconnect, and reset path must ignore or disable repeated triggers while in flight.
* Scoped socket lifecycle: Every acquired socket must be closed or detached on disconnect, reset, or component/store teardown.
* Bounded persistence: Store only browser hints needed to re-enter a room context; no room event stream or sensitive local state persists.
* Honest staging: Approval, reconnect, catch-up, and federation copy should be visible as later-session scope, not implied as shipped.

### Technology Stack

* TypeScript 5.9.3 in `apps/web`.
* React 18 and existing Tailwind utility styling.
* Zustand 4.5.4 for the War Room store.
* `@factionos/protocol` workspace dependency for War Room contracts.
* Vitest 4.1.7, Testing Library, and happy-dom for focused tests.
* Browser `fetch`, `AbortController`, `WebSocket`, and localStorage APIs.

***

## 6. Deliverables

### Files to Create

| File                                     | Purpose                                                                                                               | Est. Lines |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/warRoomClient.ts`      | Worker REST/WebSocket client, URL normalization, timeout handling, response validation, and safe failure mapping.     | \~220      |
| `apps/web/src/lib/warRoomIdentity.ts`    | Bounded local participant and Worker URL persistence helpers with malformed storage recovery.                         | \~140      |
| `apps/web/src/lib/warRoomUi.ts`          | Lifecycle copy, tone, and state-derivation helpers for the panel and tests.                                           | \~120      |
| `apps/web/src/store/useWarRoomStore.ts`  | Zustand lifecycle store for Worker URL, participant hint, room snapshot, socket, in-flight flags, and errors.         | \~300      |
| `apps/web/tests/warRoomClient.test.ts`   | Client tests for success, timeout, HTTP envelopes, malformed responses, and socket URL behavior.                      | \~180      |
| `apps/web/tests/warRoomIdentity.test.ts` | Persistence tests for bounded hints, malformed storage, invalid URL, and reset behavior.                              | \~150      |
| `apps/web/tests/warRoomStore.test.ts`    | Store tests for create, join, pending, connect, disconnect, unavailable states, duplicate guards, and socket cleanup. | \~240      |
| `apps/web/tests/WarRoomPanel.test.tsx`   | Component tests for local-only, validation, create, join, pending, connected, disconnected, and unavailable UI.       | \~260      |

### Files to Modify

| File                                       | Changes                                                                                                     | Est. Lines |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/WarRoomPanel.tsx` | Replace disabled stub with accessible lifecycle forms, status summaries, error states, and action guards.   | \~260      |
| `apps/web/src/lib/cockpitShell.ts`         | Update War Room surface metadata and boundary copy from deferred stub to optional Worker lifecycle surface. | \~40       |
| `apps/web/README_web.md`                   | Document the Phase 05 web lifecycle boundary, local-only fallback, and remaining Session 04-05 deferrals.   | \~35       |
| `apps/web/tests/CockpitShell.test.tsx`     | Update shell expectations from disabled stub to local-only Worker lifecycle surface.                        | \~60       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Users can remain in local-only mode with no Worker URL and the cockpit remains fully usable.
* [ ] Users can configure a bounded Worker URL and participant display hint without persisting raw room events or local sensitive state.
* [ ] Users can create a room when a Worker endpoint is configured, and the UI records the returned room code and leader participant.
* [ ] Users can request to join a room with a valid code and see pending, room-not-found, full-room, rate-limited, unavailable, and invalid-code states.
* [ ] Approved participants can connect to and disconnect from a Worker socket, with socket cleanup on disconnect, reset, and failed transitions.
* [ ] The panel exposes loading, empty, error, offline, pending, connected, disconnected, and local-only states without blank panels or raw error output.

### Testing Requirements

* [ ] Unit tests cover Worker client success paths, timeout, offline, HTTP envelope mapping, response validation, and socket URL creation.
* [ ] Unit tests cover persistence normalization, malformed storage recovery, invalid Worker URL rejection, and reset behavior.
* [ ] Store tests cover lifecycle transitions, duplicate-action guards, in-flight state reset, socket cleanup, and unavailable Worker handling.
* [ ] Component tests cover accessible controls and visible state copy across local-only, create, join, pending, connected, disconnected, and error flows.

### Non-Functional Requirements

* [ ] Worker federation remains optional external transfer and is not required for local server, mission, hero, replay, export, scan, media, settings, or orchestration workflows.
* [ ] Browser persistence contains only bounded non-sensitive hints.
* [ ] User-facing Worker errors do not echo raw request bodies, prompts, command bodies, terminal output, tokens, URLs, stack traces, local paths, exports, replay fragments, scan roots, media drafts, or diagnostics.
* [ ] UI controls remain keyboard, pointer, screen-reader, reduced-motion, and mobile-friendly within the existing cockpit shell.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] Focused web tests and typecheck pass for the changed files.

***

## 8. Implementation Notes

### Key Considerations

* Do not send local server auth headers to the Worker. The local loopback token is not Worker participant authority.
* Treat participant ids, display names, colors, and roles as untrusted display hints until future signed-room authority exists.
* Store `workerUrl`, participant id, and participant name only after normalization. Avoid storing room snapshots unless the implementation keeps them in memory only.
* Keep approve, reject, reconnect, catch-up, leave, and federation controls as explicit later-session boundaries.
* Do not update public demo behavior in this session; the public demo must not connect to real Worker rooms.

### Potential Challenges

* Worker URL configuration can drift into Session 06 diagnostics: keep this session to a user-entered or imported URL hint and basic health/unavailable behavior.
* Socket tests in happy-dom may need a small mock WebSocket implementation: keep it local to web tests and avoid browser-only globals leaking across tests.
* The bottom-rail panel is compact: use stable form layout, wrapped labels, and small status rows so text does not overlap at mobile widths.
* Existing shell tests assert the disabled stub: update them to assert honest local-only copy and avoid claiming approval, reconnect, or federation is shipped.

### Relevant Considerations

* \[P03-apps/warroom+apps/web] **War Room federation is still separate**: this session wires only browser lifecycle controls to the separate Worker surface and keeps the local server as a status stub.
* \[P03] **Redaction is boundary-specific**: web state and storage must minimize Worker-bound and persisted data; local redaction rules do not automatically make data safe to federate.
* \[P00] **Hosted services are optional**: the cockpit must work without Cloudflare credentials, hosted accounts, hosted storage, analytics, or public replay hosting.
* \[P02-apps/web] **Responsive and accessibility debt**: new form controls need labels, disabled states, focus behavior, visible errors, and mobile-safe layout.
* \[P03-packages/protocol] **Protocol leads cross-package work**: use the Session 02 shared contracts instead of duplicating Worker error and room shapes in web code.

### Behavioral Quality Focus

Checklist active: Yes

Top behavioral risks for this session:

* Duplicate create, join, connect, or disconnect clicks causing inconsistent store state or repeated Worker calls.
* Worker outage, rate-limit, malformed response, invalid room, full room, or socket failure leaving a blank panel or stale in-flight state.
* Browser storage corruption or private-mode failures breaking the whole cockpit instead of falling back to local-only mode.
* Socket objects surviving disconnect, reset, or test cleanup and continuing to mutate stale room state.
* UI copy implying approval, presence, reconnect, catch-up, ghost overlays, or cockpit event federation is already shipped.

***

## 9. Testing Strategy

### Unit Tests

* Test Worker client URL normalization, request timeout, offline mapping, HTTP envelope mapping, response validation, rate-limit metadata, and socket URL generation.
* Test identity persistence for defaults, valid hints, malformed JSON, invalid URL, oversize participant names, missing localStorage, and reset.
* Test War Room store transitions for local-only, unavailable, create, join, pending, connected, disconnected, failed socket, duplicate in-flight actions, and socket cleanup.

### Integration Tests

* Test `WarRoomPanel` with mocked store/client dependencies for local-only, create-room success, join pending, invalid room code, unavailable Worker, connected socket, disconnect, and reset states.
* Update cockpit shell tests to assert the War Room surface remains visible and honest without the disabled-stub wording.

### Manual Testing

* Run focused web tests for the new War Room client, identity, store, panel, and shell cases.
* Run `npm --workspace apps/web run typecheck`.
* Optionally run the app against a local `apps/warroom` Wrangler dev URL to smoke create, join, connect, and disconnect behavior.

### Edge Cases

* Missing Worker URL, invalid URL scheme, trailing slash Worker URL, and malformed room code.
* Worker offline, timeout, bad JSON, unexpected success body, rate-limit envelope, room not found, room full, pending approval, and forbidden participant errors.
* Duplicate submit while request is in flight, disconnect while connect is in flight, reset while socket is open, and component unmount during async work.
* Corrupt localStorage, storage quota or private-mode throws, oversized names, unsafe participant id characters, and stale room code after storage reset.
* Socket open, message, error, close, and cleanup paths without auto-reconnect or catch-up UI in this session.

***

## 10. Dependencies

### External Libraries

* `@factionos/protocol`: existing workspace dependency for War Room contracts, constants, and error envelopes.
* `zustand`: existing web state store dependency.
* `react` and `react-dom`: existing component runtime.
* `vitest` and Testing Library: existing web test tooling.

### Other Sessions

* **Depends on**: `phase05-session01-war-room-requirements-and-trust-baseline`, `phase05-session02-worker-api-hardening-and-client-contract`, `phase04-session08-media-validation-and-documentation-closeout`
* **Depended by**: `phase05-session04-join-approval-presence-and-reconnect-ux`, `phase05-session05-federation-event-redaction-and-cockpit-integration`, `phase05-session06-deployment-environment-and-diagnostics`, `phase05-session07-war-room-validation-and-documentation-closeout`

***

## Next Steps

Run the implement workflow step to begin AI-led 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/phase05-session03-web-room-lifecycle-and-state-store/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.
