> 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-session04-join-approval-presence-and-reconnect-ux/spec.md).

# Session Specification

**Session ID**: `phase05-session04-join-approval-presence-and-reconnect-ux` **Phase**: 05 - War Room Worker Integration **Status**: Complete **Created**: 2026-05-30 **Package**: Cross-package (`apps/web`, `apps/warroom`) **Package Stack**: TypeScript, React 18, Vite, Zustand, Vitest, Cloudflare Workers, Durable Objects

***

## 1. Session Overview

This session turns the first usable War Room lifecycle surface from Session 03 into a resilient participation experience. The web cockpit can already create, join, connect, disconnect, and reset optional Worker room context. Session 04 adds the participation layer around that lifecycle: leader approval, rejection, presence, reconnect, bounded catch-up summaries, retry controls, and leave copy that keeps the local-first boundary explicit.

The Worker already exposes approve, reject, participant-change, pending-join, socket, and bounded catch-up primitives from Sessions 02 and 03. This session consumes and locks those primitives through the web client, Zustand store, panel UI, focused Worker evidence, and browser-oriented tests. It must not turn the local server into a room relay or make Cloudflare required for the cockpit.

The result should make room participation visible without claiming hosted identity, trusted erasure, durable hosted history, or broad cockpit federation. Full redacted cockpit event federation, sender-excluded battlefield overlays, and payload-blocking tests remain Session 05 scope.

***

## 2. Objectives

1. Add leader-facing approval and rejection controls for pending participants, including duplicate-decision guards, stale-state handling, and non-leader unavailable states.
2. Render a participant roster with leader, member, observer, pending, online, offline, and local-participant state that is not color-only.
3. Implement reconnect, retry, caught-up, disconnected, and leave presentation around the existing Worker socket lifecycle with cleanup for acquired resources.
4. Display bounded catch-up summaries without exposing raw event payloads, prompts, paths, commands, replay buffers, exports, scan data, media drafts, diagnostics, or secrets.
5. Cover approval, presence, reconnect, catch-up, leave, and accessibility behavior with focused Worker, store, client, helper, and component tests.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase05-session01-war-room-requirements-and-trust-baseline` - Provides lifecycle vocabulary, participant trust boundaries, approval authority, reconnect, catch-up, and local-first requirements.
* [x] `phase05-session02-worker-api-hardening-and-client-contract` - Provides Worker create, join, approve, reject, socket, error envelope, participant, safe-frame, and catch-up contracts.
* [x] `phase05-session03-web-room-lifecycle-and-state-store` - Provides the web client, persisted bounded hints, Zustand room lifecycle store, socket connect path, and local-only panel controls.
* [x] `phase04-session08-media-validation-and-documentation-closeout` - Confirms the current local-first, media, browser, and privacy posture before optional external-transfer UI expands.

### Required Tools/Knowledge

* React 18 component patterns in `apps/web/src/components`.
* Zustand store patterns and test injection hooks in `apps/web/src/store`.
* Protocol-owned War Room contracts exported from `@factionos/protocol`.
* Cloudflare Worker and Durable Object behavior in `apps/warroom/src/index.ts`.
* Vitest, Testing Library, happy-dom, and local Worker socket test fixtures.

### Environment Requirements

* Node 20+ and npm workspace install are available.
* No Cloudflare credentials are required for implementation or tests.
* Tests must use mocks, fake Worker sockets, or package-local Worker fixtures.
* Core local cockpit behavior must remain usable with no Worker URL configured.

***

## 4. Scope

### In Scope (MVP)

* Room leaders can review pending join requests and approve or reject them - implemented through typed Worker client helpers, store actions, in-flight guards, stale-state feedback, and visible non-leader unavailable copy.
* Pending and rejected participants can see their state without blank panels - implemented through socket frame handling, snapshot revalidation, and bounded status copy.
* Participants can inspect the room roster - implemented with role labels, online/offline status, local-participant marker, and accessible labels that do not depend on color alone.
* The web socket lifecycle shows reconnect, retry, disconnected, caught-up, and permanently unavailable states - implemented with bounded retry policy, cleanup on disconnect/reset/unmount, and explicit failure mapping.
* Bounded catch-up is visible as safe summary information - implemented with counts, timestamps, and event families only, never raw event payload bodies.
* Leave and disconnect controls are clear about local reset semantics - implemented without claiming trusted deletion of Worker room state, browser hints, logs, archives, exports, or future hosted data.
* Focused tests cover approval permissions, duplicate actions, stale decisions, roster states, reconnect, catch-up summaries, and accessibility-facing panel behavior.

### Out of Scope (Deferred)

* Full redacted cockpit event federation and ghost battlefield overlays - *Reason: Session 05 owns the event allowlist, sender-excluded cockpit updates, blocked-payload tests, and overlay UX.*
* Hosted accounts, hosted identity proof, durable hosted history, public replay storage, analytics, inbound commands, real executors, or mobile certification - *Reason: later phases own these threat models and validation levels.*
* Unified erasure across local browser hints, Worker room storage, archives, exports, replay buffers, logs, backups, and hosted data - *Reason: Phase 08 owns trusted erasure.*
* Worker deployment diagnostics, custom-domain health checks, CORS runbook, and rate-limit operations - *Reason: Session 06 owns deployment environment and diagnostics.*
* Phase closeout documentation and end-to-end evidence retention - *Reason: Session 07 owns Phase 05 validation and documentation closeout.*

***

## 5. Technical Approach

### Architecture

Keep protocol contracts as the shared boundary, then add web-facing client and store behavior. `apps/web/src/lib/warRoomClient.ts` should gain approve and reject helpers that post `WarRoomJoinDecisionRequest` payloads to the Worker, validate `WarRoomJoinDecisionResponse`, and map non-leader, stale, rate-limited, room-not-found, and unavailable responses into safe UI failures.

Add helper-owned derivation for participant and approval UI. A new `apps/web/src/lib/warRoomPresence.ts` should convert snapshots and socket frames into sorted roster rows, pending-decision rows, local-participant labels, safe catch-up summaries, and accessibility copy. This keeps the panel dense while making role, presence, and catch-up behavior testable outside React.

Extend `apps/web/src/store/useWarRoomStore.ts` as the participation state owner. The store should track approval in-flight state per requester, recent decision failures, reconnect attempts, caught-up summaries, and leave/reset state. It should handle `warroom_join_pending`, `warroom_join_approved`, `warroom_join_rejected`, `warroom_participant_change`, `warroom_pending_catchup`, and socket close/error events without showing raw event payload data.

Update `apps/web/src/components/WarRoomPanel.tsx` by composing focused roster and approval subcomponents. The panel should remain compact and operational in the existing cockpit rail while exposing approval controls, roster state, reconnect/retry, catch-up summary, disconnect, and leave/reset controls with clear labels and disabled states while actions are in flight.

Use `apps/warroom/tests/warroom.test.ts` and `apps/warroom/README_warroom.md` to lock the Worker-side behavior this session relies on. Source changes in the Worker runtime should be limited to fixes discovered while adding focused evidence; the primary implementation surface is the web cockpit.

### Design Patterns

* Protocol-first consumption: Reuse shared War Room request, response, role, lifecycle, socket frame, and error contracts.
* Boundary validation: Validate decision payloads, room code, requester id, approver id, snapshots, and socket frames before mutating UI state.
* Duplicate-action guard: Disable or ignore repeated approve, reject, retry, reconnect, disconnect, and leave actions while a request is active.
* Scoped socket lifecycle: Close or detach acquired sockets on reconnect, disconnect, leave, reset, hydration, and component teardown.
* Bounded catch-up display: Show counts and safe event families only; never render raw Worker event bodies or local cockpit payloads.
* Local-first fallback: Missing Worker configuration, Worker outage, rejected joins, stale decisions, and failed catch-up must not block the rest of the cockpit.
* Honest deletion copy: Leave/reset is a local room-context action, not trusted erasure.

### Technology Stack

* TypeScript 5.9.3 in `apps/web` and `apps/warroom`.
* React 18 and existing Tailwind utility styling in `apps/web`.
* Zustand 4.5.4 for War Room store state.
* Cloudflare Worker and Durable Object contract in `apps/warroom`.
* `@factionos/protocol` workspace dependency for shared War Room contracts.
* Vitest 4.1.7, Testing Library, happy-dom, and fake WebSocket fixtures.

***

## 6. Deliverables

### Files to Create

| File                                               | Purpose                                                                                     | Est. Lines |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/warRoomPresence.ts`              | Pure roster, pending-decision, reconnect, and catch-up summary helpers.                     | \~180      |
| `apps/web/src/components/WarRoomRoster.tsx`        | Accessible participant roster with role, online/offline, pending, and local-user treatment. | \~180      |
| `apps/web/src/components/WarRoomApprovalQueue.tsx` | Leader approval/rejection queue with guarded actions and stale/non-leader feedback.         | \~180      |
| `apps/web/tests/warRoomPresence.test.ts`           | Helper tests for roster sorting, local labels, pending rows, and catch-up redaction.        | \~180      |

### Files to Modify

| File                                       | Changes                                                                                                         | Est. Lines |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/warRoomClient.ts`        | Add approve/reject helpers, response validation, and safe error mapping.                                        | \~120      |
| `apps/web/src/store/useWarRoomStore.ts`    | Add approval actions, roster/pending synchronization, reconnect policy, catch-up summaries, and leave behavior. | \~260      |
| `apps/web/src/lib/warRoomUi.ts`            | Add copy for decision errors, non-leader states, reconnect, caught-up, leave, and safe catch-up summaries.      | \~100      |
| `apps/web/src/components/WarRoomPanel.tsx` | Wire approval queue, participant roster, retry, reconnect, caught-up, disconnect, and leave controls.           | \~180      |
| `apps/web/tests/warRoomTestUtils.ts`       | Extend fake socket helpers for participant changes, catch-up, server close, and reconnect cases.                | \~90       |
| `apps/web/tests/warRoomClient.test.ts`     | Cover approve/reject helpers, stale decision, non-leader, rate-limit, and bad response mapping.                 | \~120      |
| `apps/web/tests/warRoomStore.test.ts`      | Cover approval, rejection, stale state, participant changes, reconnect, catch-up, leave, and duplicate guards.  | \~220      |
| `apps/web/tests/WarRoomPanel.test.tsx`     | Cover approval queue, roster accessibility, reconnect/catch-up, rejected state, and non-leader copy.            | \~240      |
| `apps/warroom/tests/warroom.test.ts`       | Add focused Worker evidence for approval, rejection, stale decisions, roster snapshots, and catch-up bounds.    | \~140      |
| `apps/web/README_web.md`                   | Document Session 04 shipped boundary and remaining Session 05 deferrals.                                        | \~45       |
| `apps/warroom/README_warroom.md`           | Clarify reject, disconnect-only leave, participant presence, and catch-up behavior.                             | \~35       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Leaders can approve or reject pending joins, and non-leaders cannot make join decisions.
* [ ] Duplicate approve or reject triggers are prevented while in flight and stale decisions surface bounded feedback.
* [ ] Pending, approved, rejected, connected, reconnecting, caught-up, disconnected, unavailable, and left states are visible without blank panels.
* [ ] Participant roster rows show leader, member, observer, pending, online/offline, and local-participant state with text labels.
* [ ] Reconnect and retry controls preserve local room context, clean up old sockets, and stop after bounded failures.
* [ ] Catch-up summaries stay bounded and never render raw Worker event payloads or local sensitive data.
* [ ] Leave/reset copy does not claim trusted deletion of Worker room data, browser hints, local logs, archives, exports, replay buffers, or future hosted data.

### Testing Requirements

* [ ] Worker tests cover approve, reject, stale decision, non-leader decision, participant snapshot, and bounded catch-up evidence.
* [ ] Client tests cover approve/reject success, stale decision, non-leader, rate-limit, unavailable, malformed response, and safe error mapping.
* [ ] Store tests cover approval actions, socket frame handling, presence updates, reconnect retry, catch-up summaries, leave cleanup, and duplicate guards.
* [ ] Component tests cover approval queue controls, roster accessibility, pending/rejected copy, reconnect/catch-up states, and unavailable Worker feedback.

### Non-Functional Requirements

* [ ] Worker federation remains optional external transfer and does not block local server, mission, hero, replay, export, scan, media, settings, or orchestration workflows.
* [ ] User-facing errors do not echo request bodies, prompts, command bodies, terminal output, tokens, URLs with secrets, broad paths, exports, replay fragments, scan roots, media drafts, or diagnostics.
* [ ] UI controls remain keyboard, pointer, screen-reader, reduced-motion, and mobile-friendly inside the existing cockpit shell.
* [ ] No new hosted auth, hosted storage, analytics, public replay hosting, inbound command, executor, or erasure claim is introduced.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] Focused web and Worker tests pass.
* [ ] Package or workspace typecheck passes for changed TypeScript packages.

***

## 8. Implementation Notes

### Key Considerations

* The session is cross-package because the web UI consumes Worker behavior and should lock Worker evidence, but most code changes should remain in `apps/web`.
* The Worker already exposes `/approve`, `/reject`, participant change frames, and bounded catch-up frames. Prefer client, store, UI, and test additions over Worker runtime churn unless a contract gap appears.
* Observer role exists in protocol, but Worker route behavior does not yet assign observer participants. Display observer safely if present in snapshots, and document broader observer policy as deferred if no creation path exists.
* Leave is local UI semantics today. Socket close marks participants offline; it does not remove all Worker room storage or provide trusted deletion.

### Potential Challenges

* Stale decision races: Revalidate snapshots after approve/reject and map stale join decisions to bounded feedback without clearing unrelated room state.
* Socket churn: Ensure reconnect closes old sockets and cannot leave duplicate event listeners active after retry, disconnect, reset, or unmount.
* Catch-up leakage: Treat catch-up frames as summary inputs only until Session 05 owns redacted cockpit event integration.
* Panel density: Keep roster and approval controls readable in the existing rail without overlapping text or controls on mobile widths.

### Relevant Considerations

* \[P03-apps/warroom+apps/web] **War Room federation is still separate**: This session implements participant UX while keeping Worker federation optional and separate from local server behavior.
* \[P03] **Redaction is boundary-specific**: Approval, presence, reconnect, and catch-up copy must not treat Worker-safe metadata as export-safe, replay-safe, log-safe, or public-share-safe.
* \[P00] **Hosted services are optional**: The cockpit must remain useful with no Cloudflare credentials, hosted accounts, hosted storage, analytics, or public client tokens.
* \[P03] **Local-first boundary is architectural**: Worker failures must degrade to visible unavailable/local-only states without breaking local workflows.
* \[P02-apps/web] **Responsive and accessibility debt**: New War Room controls need labels, focus behavior, text alternatives, mobile reachability, and reduced-motion-safe status indicators.
* \[P03] **Unified erasure still missing**: Leave/reset copy must avoid trusted deletion claims until Phase 08.

### Behavioral Quality Focus

Checklist active: Yes

Top behavioral risks for this session:

* Duplicate or stale approval decisions can create misleading room state if UI and Worker errors are not synchronized.
* Reconnect logic can leak sockets or event listeners if cleanup is not tied to reset, disconnect, leave, unmount, and failed retry paths.
* Catch-up presentation can accidentally expose raw event data before Session 05's redacted federation allowlist is implemented.

***

## 9. Testing Strategy

### Unit Tests

* Test `warRoomClient` approve/reject helpers for success, stale decisions, non-leader decisions, rate limits, malformed responses, and Worker unavailable failures.
* Test `warRoomPresence` helper output for roster sorting, local participant markers, role labels, online/offline copy, pending queue derivation, and catch-up summary redaction.
* Test `useWarRoomStore` approval, rejection, socket frame synchronization, reconnect retries, catch-up summary state, leave cleanup, and duplicate in-flight guards.

### Integration Tests

* Extend `apps/warroom/tests/warroom.test.ts` to verify approve, reject, stale-decision, non-leader decision, participant-change, and bounded catch-up behavior remains stable.
* Extend `WarRoomPanel` component tests to verify approval queue controls, roster accessibility labels, pending/rejected states, reconnect/catch-up states, leave copy, and unavailable Worker feedback.

### Manual Testing

* In the local web app, save a Worker URL, create a room as leader, join as a second participant through mocked or local Worker behavior, approve/reject the join, disconnect, reconnect, and leave/reset.
* Verify no panel state claims hosted identity, trusted erasure, broad federation, public replay storage, analytics, or local server room relay.

### Edge Cases

* Non-leader attempts to approve or reject a pending join.
* Pending participant is approved, rejected, or removed before the UI decision resolves.
* Duplicate approve, reject, retry, disconnect, and leave clicks while in flight.
* Worker goes offline during snapshot revalidation or reconnect.
* Socket closes during catch-up or sends malformed frames.
* Catch-up includes remote events whose raw payload must not be displayed.
* Room has 16 participants, zero participants in a snapshot, unknown observer role source, or no Worker URL configured.

***

## 10. Dependencies

### External Libraries

* React 18: existing web component runtime.
* Zustand 4.5.4: existing War Room store state management.
* Vitest 4.1.7: focused unit and package tests.
* Testing Library and happy-dom: web component behavior tests.
* Cloudflare Worker and Durable Objects: existing `apps/warroom` runtime.

### Other Sessions

* **Depends on**: `phase05-session01-war-room-requirements-and-trust-baseline`, `phase05-session02-worker-api-hardening-and-client-contract`, `phase05-session03-web-room-lifecycle-and-state-store`.
* **Depended by**: `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-session04-join-approval-presence-and-reconnect-ux/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.
