> 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/apps/warroom/readme_warroom.md).

# @factionos/warroom

Optional Cloudflare Worker and Durable Object backend for FactionOS room federation.

The backend ships today and is covered by Worker tests. The web client panel at `apps/web/src/components/WarRoomPanel.tsx` can use this optional Worker for room creation, join requests, leader approval and rejection, participant presence, Worker health diagnostics, bounded reconnect catch-up summaries, and local disconnect or leave controls. Redacted cockpit event federation is allowlisted through shared protocol validators and sender-excluded remote events.

Core local FactionOS usage does not require Cloudflare credentials or this Worker.

Phase 05 Session 07 closeout validated focused Worker, protocol, and web tests plus app desktop/mobile browser evidence for optional Worker lifecycle and redacted federation. The evidence is recorded in `.spec_system/archive/sessions/phase05-session07-war-room-validation-and-documentation-closeout/`. It does not replace deployed Worker health probes, Cloudflare dashboard review, production-hosted app validation, hosted identity review, or trusted erasure work.

## Phase 05 Baseline

Session 01 records the source-backed War Room baseline in:

* `.spec_system/archive/phases/phase_05/war_room_requirements_trust_baseline.md`
* `.spec_system/archive/phases/phase_05/war_room_payload_redaction_baseline.md`
* `.spec_system/archive/phases/phase_05/war_room_requirement_routing_matrix.md`

Later Worker API work must preserve the current room relay boundary: this package owns the Worker and Durable Object surface, the local server remains a `/warroom` compatibility/status stub, and the web cockpit must treat this Worker as optional external transfer.

## Phase 06 Collaboration Baseline

Phase 06 Session 01 records the broader collaboration and isolation baseline in `.spec_system/archive/phases/phase_06/collaboration_isolation_safety_baseline.md` and routes Worker-owned changes in `.spec_system/archive/phases/phase_06/phase06_requirement_routing_matrix.md`.

Later Worker work must keep room authority, participant roles, leader-only decisions, stale joins, duplicate decisions, sender-excluded broadcasts, bounded catch-up, blocked-field validation, compact diagnostics, and non-hosted identity limits explicit. This package must not become a hosted auth surface, analytics surface, public replay host, remote command executor, Docker executor, local-server proxy, or trusted erasure system.

Phase 06 closeout validates the shipped Worker-owned subset: room-local authority, participant roles, leader decisions with expected revisions and idempotency, safe socket frame validation, sender-excluded broadcasts, bounded catch-up, compact health/errors, and optional external transfer. The evidence is local Worker/protocol/web tests plus local app desktop/mobile Playwright coverage with mocked or same-origin Worker paths. It is not hosted identity, production-hosted validation, public replay hosting, remote execution, certification, or trusted erasure.

## Deploying

The preferred deploy path is the GitHub Actions workflow [`warroom-deploy.yml`](https://github.com/AI-with-Apex-VIP/factionos/tree/main/.github/workflows/warroom-deploy.yml). It runs on pushes to `main` and requires repository secrets for `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID`.

```bash
cd apps/warroom
wrangler login
npm install
npm run deploy
```

Wrangler prints a URL such as `https://factionos-warroom.YOURNAME.workers.dev`. Use that URL, the custom domain, or local Wrangler URL as the optional web Worker URL. Leave the web Worker URL blank for local-only War Room mode.

Only the Worker origin belongs in browser config through `VITE_FACTIONOS_WARROOM_WORKER_URL`. Cloudflare account ids, API tokens, zone ids, tunnel tokens, repository secrets, Wrangler tokens, and Durable Object bindings are deploy-only or Worker-side values. Do not mirror them into `VITE_` variables, Worker health responses, browser diagnostics, logs, replay, exports, archives, public demo assets, or docs examples.

The current deployed endpoints are:

| Surface                     | URL                                                                      |
| --------------------------- | ------------------------------------------------------------------------ |
| Worker custom domain        | `https://warroom.faction-os.com/`                                        |
| Worker custom-domain health | `https://warroom.faction-os.com/health`                                  |
| Worker `workers.dev` URL    | `https://factionos-warroom.apex-web-services-llc-0d4.workers.dev/`       |
| Worker `workers.dev` health | `https://factionos-warroom.apex-web-services-llc-0d4.workers.dev/health` |

The Worker has an application-level fixed-window rate limit enabled by default: 240 requests per 60 seconds per connecting IP. Tune `FACTIONOS_RATE_LIMIT_MAX`, `FACTIONOS_RATE_LIMIT_WINDOW_MS`, and `FACTIONOS_RATE_LIMIT_ENABLED` in `wrangler.toml` or Cloudflare dashboard variables.

The deploy workflow runs a bounded health smoke check after `wrangler deploy`. Set the repository variable `CLOUDFLARE_WARROOM_HEALTH_URL` to override the default custom-domain health URL. The smoke check logs only service, deployment type, and app-level rate-limit state.

Phase 08 production-hosted release smoke is available from the repository root:

```bash
npm run release:hosted-smoke -- --target warroom-worker-custom --target warroom-worker-workers-dev
```

The smoke validates the custom-domain and workers.dev `/health` endpoints with timeouts, compact service metadata, app-level rate-limit metadata, deployment type checks, and sanitized issue codes. It must not print raw health bodies, Cloudflare account ids, zone ids, API tokens, request bodies, room payloads, or local paths. A healthy Worker smoke is not hosted identity, hosted storage, production account behavior, public collaboration safety, analytics consent, or trusted erasure proof.

Phase 08 Session 08 live hosted smoke did not clear deployed Worker release claims. Both Worker targets reported `WORKER_DEPLOYMENT` and `WORKER_HEALTH_RATE_LIMIT`, so deployed Worker validation remains no-claim until an authorized release environment updates the Worker target and reruns smoke successfully.

For WAF protection, prefer Cloudflare managed/OWASP WAF plus a hostname-specific rate-limit rule for `warroom.faction-os.com` when the account plan allows it. As of 2026-05-29, managed/OWASP WAF execution was not entitled on the current account/zone, and the single available zone rate-limit rule slot was already occupied by `Leaked credential check`. Keep the existing leaked-credential rule unless replacing it with a Worker-specific rate limit is explicitly approved.

## Local Dev

```bash
npm run dev
curl --fail --show-error --max-time 8 http://127.0.0.1:8790/health
```

That starts `wrangler dev` on `http://localhost:8790`.

## Endpoints

| Method | Path                                  | Purpose                                                                        |
| ------ | ------------------------------------- | ------------------------------------------------------------------------------ |
| `GET`  | `/`                                   | HTML landing page                                                              |
| `GET`  | `/health`                             | Liveness probe with compact service, time, rate-limit, and deployment metadata |
| `POST` | `/rooms`                              | Create a fresh room and return `{ code, leader }`                              |
| `GET`  | `/rooms/:code`                        | Room snapshot                                                                  |
| `POST` | `/rooms/:code/join`                   | Request to join; leader approval required                                      |
| `POST` | `/rooms/:code/approve`                | Leader approves a pending request                                              |
| `POST` | `/rooms/:code/reject`                 | Leader rejects a pending request                                               |
| `WS`   | `/rooms/:code/socket?participant=:id` | Long-lived participant socket                                                  |

All room lifecycle requests and responses are now typed through `@factionos/protocol`. Error responses use a deterministic envelope:

```json
{
  "error": "invalid_request",
  "message": "Request payload is invalid.",
  "details": {
    "body": "must be a JSON object"
  }
}
```

Stable Worker error codes include `invalid_request`, `invalid_room_code`, `room_not_found`, `room_full`, `pending_approval`, `forbidden_participant`, `stale_join_decision`, `only_leader_can_decide`, `expected_upgrade`, `missing_participant`, `missing_authority`, `invalid_authority`, `expired_authority`, `authority_mismatch`, `stale_room_revision`, `replayed_authority`, `not_found`, `rate_limited`, `invalid_socket_frame`, and `blocked_frame_field`. Rate-limit responses include `Retry-After`, `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers plus a JSON envelope with `retryAfterSeconds`.

## Room Authority

The Worker issues room-local opaque authority for create and join responses. The Durable Object stores token hashes, participant id, role, room code, room revision, generation, issued-at, and expires-at metadata. Raw authority tokens are returned only to the requesting browser and are not persisted in room storage. Snapshot, duplicate join, leader decisions, and socket setup require current authority; stale, expired, malformed, mismatched, replayed, and missing authority inputs fail closed with compact protocol errors.

Leader approve/reject requests include leader authority, an expected room revision, and an idempotency key. Duplicate retries with the same decision key return the stored response with `duplicate: true`; reused keys for a different decision return `replayed_authority`. Non-leader authority returns `only_leader_can_decide`, and stale room revisions return `stale_room_revision` before mutation.

This authority model is stronger than browser id hints, but it remains non-hosted. It proves possession of a Worker-issued room token inside one room; it does not prove a hosted account, real-world identity, organization membership, production auditability, public collaboration safety, or trusted deletion.

Phase 07 Session 03 preserves this boundary in the hosted identity guardrails. Room-local authority is not hosted account identity, SSO, organization membership, analytics consent, production audit proof, public collaboration safety, or trusted erasure. Worker participant ids, display names, colors, roles, online flags, room revisions, authority hashes, and idempotency metadata remain room operational metadata only. They must not be reused as account ids, organization membership, billing authority, analytics consent, public replay consent, push consent, remote-access consent, or deletion proof.

Health responses expose only compact operational metadata:

```json
{
  "ok": true,
  "service": "factionos-warroom",
  "time": "2026-05-30T00:00:00.000Z",
  "rateLimit": { "enabled": true, "max": 240, "windowMs": 60000 },
  "deployment": { "label": "custom-domain", "urlType": "custom-domain" }
}
```

Health responses must not expose Cloudflare account ids, zone ids, tokens, request headers, client IPs, request bodies, room payloads, prompt content, command output, paths, exports, scans, media drafts, logs, or local diagnostics.

The reject route removes a pending participant from the room and broadcasts a `warroom_join_rejected` frame plus a participant snapshot. Duplicate or already resolved approve/reject requests return `stale_join_decision`; non-leaders receive `only_leader_can_decide`.

## Durable Object Behavior

Each room is one Durable Object instance keyed by room code. It:

* Holds participant state with leader, member, observer, and pending roles.
* Caps participants at 16.
* Keeps a bounded ring buffer of the last 100 events for reconnect catch-up.
* Broadcasts accepted safe socket frames to connected peers other than the sender.
* Cleans up stale sockets through heartbeat handling.
* Marks socket participants online on connect and offline on socket close or send failure.

Durable Objects provide single-instance consistency for one room code.

The current socket path accepts only protocol-validated safe frames: `ping`, `warroom_presence`, `warroom_cursor`, `warroom_focus`, `warroom_hero_state`, `warroom_mission_state`, `warroom_room_notice`, `notice_board_message`, and `notice_resolved`. `ping` is ignored and not persisted. Legacy War Room frames are validated, stored in the bounded recent-event buffer, and broadcast as sender-excluded `remote_event` frames. Notice Board relay frames use their own bounded history and are broadcast directly as sender-excluded `notice_board_message` or `notice_resolved` frames.

Session 03 keeps recent-event and catch-up filtering protocol-owned through `parseWarRoomRecentEvent`, `parseWarRoomCatchupFrame`, and `filterSafeWarRoomRecentEvents`. The Worker uses those helpers before persistence, snapshot storage, and catch-up delivery so unsafe legacy entries are dropped and accepted entries preserve insertion order. Catch-up remains capped at 100 safe events, and summaries should expose only counts, timestamps, and safe family labels.

Notice Board relay is also protocol-owned. `notice_board_message` carries a canonical sanitized notice payload through `notice` plus a compatibility `message` alias. `notice_resolved` carries `noticeId`, a matching `messageId` alias, and optional bounded `resolution`, `resolvedAt`, `roomCode`, and embedded safe notice metadata. Reconnecting sockets receive `notice_board_catchup` only when filtered safe Notice Board history exists; the frame includes bounded `notices` and matching `messages` arrays ordered by notice timestamp and id. Unknown notice resolutions are relayed to peers but do not create catch-up records.

The local web/server convergence path treats the local server as canonical for Notice Board state. Safe room notice input from the web panel is converted into a local `POST /notice-board` `announcement` request before it appears in the cockpit board. Worker `notice_board_message`, `notice_resolved`, and `notice_board_catchup` frames are converted back into local Notice Board hydrate/message/resolve events by the web convergence helpers and server bridge. Legacy `warroom_room_notice` frames remain valid War Room room events and keep legacy pending-catch-up behavior; they are not stored in Notice Board relay history unless converted through the canonical local board path.

Notice Board relay history is filtered during hydrate, persistence, and reconnect catch-up through protocol-owned Notice Board validators. Malformed frames, unknown fields, blocked keys, unsafe content values, and oversized catch-up arrays fail closed with compact socket errors before Worker history mutation, persistence, catch-up, diagnostics, logs, or browser consumption. This relay is optional external transfer for explicit coordination notices only. It must not expose raw prompts, transcripts, terminal output, command bodies, file contents, secrets, broad absolute paths, exports, replay buffers, scans, media drafts, diagnostics, logs, backups, quarantined historical content, hosted identity claims, hosted storage claims, analytics claims, public replay claims, production auditability claims, public collaboration safety claims, or trusted erasure claims.

Room snapshots may include compact relay posture and Notice catch-up summaries derived from shared protocol helpers. `relayPosture` reports only labels, counts, relay health, and last activity timestamps for the room notice relay. `noticeCatchup` reports filtered catch-up counts, latest timestamps, and safe family labels. These summaries are designed for command-center collaboration and handoff UI state; they are not raw Worker event history, Notice content archives, authority proof, remote-access proof, hosted identity, production audit evidence, public collaboration safety, or trusted erasure evidence.

Blocked Worker payload categories include prompts, file contents, command bodies, terminal output, transcripts, secret values, broad local paths, exports, replay buffers, media drafts, scan payloads, local diagnostics, and logs.

Phase 08 Session 04 adds Worker room-state erasure endpoints: `POST /rooms/:code/erasure/preview` and `POST /rooms/:code/erasure/confirm`. Preview returns sanitized counts for participants, recent events, authority hash metadata, idempotency metadata, room revision state, and browser-hint adjacency. Confirm requires current room leader authority, expected room revision, the exact phrase `ERASE WORKER WAR ROOM STATE`, and an idempotency key before deleting the Durable Object `room` record.

Confirmed Worker erasure closes active sockets, stores a redacted receipt for duplicate confirms, verifies room absence, and reports labels, counts, statuses, timestamps, docs paths, and synthetic receipt ids only. It must not emit authority tokens, authority hashes, participant secrets, participant names, raw room payloads, request bodies, paths, logs, exports, replay buffers, or diagnostics payloads.

This is not full trusted unified erasure and not hosted identity. Web disconnect closes only the browser socket, and web leave/reset clears only that browser's local room context. Browser hints, local logs, archives, exports, replay buffers, hosted data, production-hosted validation, and final release trusted-erasure wording remain separate no-claim release gates.

`apps/warroom/src/erasureInventory.ts` derives protocol-owned erasure inventory metadata for participants, recent events, authority hash metadata, idempotency metadata, room revisions, and browser-hint adjacency. `apps/warroom/src/roomErasure.ts` owns the redacted room-state erasure response and receipt helpers. Neither helper reads raw room payloads or exposes raw authority tokens or hashes.

## Limits

| Knob                | Value      | Reason                                                                     |
| ------------------- | ---------- | -------------------------------------------------------------------------- |
| `ROOM_CODE_LENGTH`  | 6          | Short enough to share verbally, large enough for practical collision space |
| `MAX_PARTICIPANTS`  | 16         | Bounded room size                                                          |
| `MAX_RECENT_EVENTS` | 100        | Bounded reconnect catch-up                                                 |
| Heartbeat           | 20 seconds | Stale socket cleanup                                                       |

## Integration Boundary

* `apps/warroom` is independent from the local server internals.
* The local server's `/warroom` route is a compatibility/status stub, not the product federation backend.
* The web client handles disabled, invalid URL, unchecked, checking, healthy, connected, unavailable, timeout, rate-limited, bad-response, reconnect, catch-up, and approval states without blocking local cockpit use.
* Federation payloads must be explicit allowlists. They must not expose prompts, file contents, command bodies, terminal output, transcripts, secret values, broad local paths, exports, replay buffers, media drafts, scan payloads, local diagnostics, PID files, spool entries, backups, or local logs.
* Notice Board relay payloads are still optional external transfer. They carry sanitized coordination notices, resolution metadata, and filtered catch-up only. Room-notice input converges through the canonical local Notice Board before it becomes a cockpit notice. Relay frames do not establish hosted identity, hosted storage, analytics, public replay, production auditability, public collaboration safety, or trusted erasure.
* Sender-excluded broadcast and the recent-event catch-up cap are part of the current tested contract and must remain covered as Worker schemas harden.
* Queue, template, lineage, guarded-action, web-control, and CLI-diagnostic work remain separate from room federation. The Worker is not a remote command executor, hosted queue, hosted auth surface, analytics surface, public replay host, or trusted erasure system.

## Phase 07 Hosted Boundary

Phase 07 Session 01 keeps this package as an optional room relay only. Worker vars in `wrangler.toml` are room-relay runtime knobs, not hosted identity, hosted storage, analytics, public replay, remote access, tunnel, or provider credentials. Cloudflare account ids, zone ids, API tokens, tunnel tokens, request headers, client IPs, request bodies, room payloads, prompts, command output, paths, exports, scans, media drafts, logs, and local diagnostics must not appear in Worker health responses, errors, logs, docs examples, or browser summaries.

Hosted identity, public replay hosting, analytics, remote access, hosted diagnostics, production-hosted validation, and full trusted erasure remain scoped release claims. Phase 08 Session 04 records Worker erasure and hosted identity gate evidence, Session 05 records production-hosted Worker smoke tooling, and Session 08 keeps live Worker hosted smoke blocked/no-claim. Room-local authority stays room-scoped bearer proof only.

Phase 07 Session 07 closeout confirmed this boundary holds: no Phase 07 source changed in `apps/warroom`, the Worker remains an optional room relay, and the full suite (2186 passed / 1 skipped) keeps room-local authority distinct from hosted account identity. The Worker is never described as hosted identity, SSO, organization membership, hosted storage, analytics, public replay hosting, or production audit proof. Production-hosted Worker validation remains blocked/no-claim after the Session 08 live smoke run.

The Session 01 release baseline at `.spec_system/archive/phases/phase_08/release_requirements_risk_baseline.md` is not Worker erasure or deployed Worker validation evidence. Session 04 adds scoped Worker room-record erasure evidence, but browser leave/reset, socket disconnect, health checks, deployment metadata, and room-local authority still must not be described as full trusted erasure, hosted identity, or deployed production-hosted validation.

The Session 02 inventory contract at `.spec_system/archive/phases/phase_08/unified_erasure_inventory.md` and `packages/protocol/src/erasure.ts` gives Session 04 the required Worker boundary list. Session 04 implements the room-state deletion path for one Durable Object room record, but full trusted unified erasure remains unavailable for unproven browser, local, hosted, public replay, analytics, push, remote, backup/log/archive, workspace-file, and future surfaces.


---

# 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/apps/warroom/readme_warroom.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.
