> 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/phase17-session08-local-war-room-bridge-and-room-notice-convergence/spec.md).

# Session Specification

**Session ID**: `phase17-session08-local-war-room-bridge-and-room-notice-convergence` **Phase**: 17 - Notice Board Coordination Parity **Status**: Completed **Created**: 2026-06-05 **Package**: Cross-package (`apps/server`, `apps/web`, `packages/protocol`) **Package Stack**: TypeScript local server, React/Zustand web cockpit, shared protocol contracts

***

## 1. Session Overview

This session connects the canonical local Notice Board to optional War Room relay behavior without turning the local server into a Worker proxy. Sessions 01 through 07 already established the Notice Board data model, manager, routes, local WebSocket events, web store normalization, CLI and hook access, and Worker-side relay/catch-up contracts. The missing path is convergence: local posts and resolutions should forward to an active relay, remote relay events should ingest into the canonical manager once, and local web clients should hydrate after remote catch-up.

The work is intentionally cross-package. `apps/server` owns canonical local state, dedupe, provenance, active-room resolution, and broadcasts. `apps/web` keeps the current War Room panel input usable while routing accepted room notices into canonical Notice Board creation and handling Worker catch-up or relay frames as board data. `packages/protocol` is touched only if small shared helpers are needed to avoid duplicate room-notice-to-announcement logic.

The privacy boundary remains the primary constraint. Notice Board relay is an optional external transfer for explicit coordination messages only. This session must keep raw prompts, transcripts, terminal output, command bodies, file contents, secrets, broad paths, exports, replay buffers, scans, media drafts, diagnostics, logs, backups, quarantined evidence, hosted identity claims, production auditability claims, and trusted erasure claims out of server, web, Worker, diagnostic, replay, export, and log payloads.

***

## 2. Objectives

1. Add a local server Notice Board relay bridge that can forward local posts and resolutions and ingest remote message, resolution, and catch-up frames.
2. Record bounded debug provenance for remotely ingested notices while deduping by notice id and preserving standalone local-room behavior.
3. Hydrate connected local web clients after remote catch-up ingestion and propagate remote resolutions through canonical `notice_resolved` events.
4. Keep the web War Room room-notice form usable by converting accepted safe room notices into sanitized canonical `announcement` notices.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase17-session02-server-notice-manager-persistence-and-context` - provides canonical room-scoped storage, ingest, batch ingest, resolution, filtering, and context behavior.
* [x] `phase17-session03-server-routes-and-websocket-parity` - provides canonical `/notice-board` routes plus local `notice_board_message`, `notice_board_hydrate`, and `notice_resolved` events.
* [x] `phase17-session04-web-store-and-cockpit-notice-board` - provides web Notice Board normalization, visibility filtering, and resolved-state merge behavior.
* [x] `phase17-session07-war-room-worker-relay-and-catchup` - provides Worker and protocol support for Notice Board relay, resolution relay, bounded catch-up, and safe room notice frames.

### Required Tools/Knowledge

* Node 26.2.0 or newer with npm workspaces.
* Existing Notice Board manager and route behavior in `apps/server`.
* Existing War Room web socket client, store, federation helpers, and panel behavior in `apps/web`.
* Shared Notice Board and War Room contracts in `packages/protocol`.
* Phase 05 and Phase 06 War Room optional-transfer and redaction boundaries.

### Environment Requirements

* Work from the repository root.
* Use package-relative monorepo paths from the repo root.
* Keep all generated and edited files ASCII-only with Unix LF line endings.
* Use fake bridge senders, fake WebSocket clients, and local HTTP test servers in tests; do not require Cloudflare credentials or a live Worker.

***

## 4. Scope

### In Scope (MVP)

* Local server can forward canonical Notice Board posts to an injected or configured relay client when connected - implemented as an in-process bridge, not a local `/warroom` proxy route.
* Local server can forward canonical Notice Board resolutions to the relay when connected - implemented with duplicate-trigger prevention and explicit failure handling.
* Local server can ingest remote `notice_board_message` frames into the canonical Notice Board manager once by id - preserving room scope and broadcasting accepted notices locally.
* Local server can ingest remote `notice_resolved` frames in the active room - preserving explicit error mapping for unknown, wrong-room, or malformed resolution inputs.
* Local server can ingest remote `notice_board_catchup` arrays with dedupe by id, bounded batch size, deterministic ordering, and one local hydration broadcast after accepted changes.
* Debug provenance for remote notices records source, ingested time, and source machine or participant id when available without storing raw Worker payloads.
* Standalone local room behavior continues when no War Room relay is connected.
* The web War Room panel preserves its input affordance while accepted room notices create sanitized canonical `announcement` notices through the local server.
* Web Worker catch-up and remote relay frames merge into Notice Board state without duplicate notices or local-store-only truth.
* Focused server and web tests cover local-to-remote send, remote ingest, catch-up dedupe, resolution, provenance, standalone mode, sanitizer blocking, and room-notice conversion.

### Out of Scope (Deferred)

* Worker-side relay implementation - Reason: completed in Session 07.
* CLI and hook commands - Reason: completed in Sessions 05 and 06.
* Automatic mission lifecycle posts - Reason: Session 09 owns status and completion auto-posts.
* Broad Notice Board rendering changes - Reason: Session 04 completed the cockpit board UI.
* Local server Worker room create/join/approve proxy routes - Reason: current docs require the local `/warroom` route to remain a compatibility/status stub and Worker room APIs to stay a separate surface.
* Hosted identity, hosted storage, public replay hosting, analytics capture, public collaboration safety, production auditability, and trusted unified erasure - Reason: these remain explicit no-claims.

***

## 5. Technical Approach

### Architecture

Introduce a narrow server-side Notice Board bridge in `apps/server/src/lib`. The bridge should accept a `NoticeBoard`, `Broadcaster`, active-room resolver, clock, optional relay sender, and optional connected-state snapshot. Route and WebSocket producers continue to create canonical notices through the manager; after a successful local post or resolution, they notify the bridge to forward safe relay frames when connected. Remote Worker frames flow through the bridge into the canonical manager, then out to local clients through existing `notice_board_message`, `notice_board_hydrate`, and `notice_resolved` events.

Keep local server War Room boundaries intact. This session may add an in-process bridge adapter and tests, but it must not add local `/rooms/*` or `/warroom/*` proxy routes, persist Worker room authority in local server state, reuse `FACTIONOS_AUTH_TOKEN` as Worker authority, or imply hosted collaboration. The bridge should degrade to no-op send behavior when no relay connection exists.

Update web behavior around the existing War Room panel. Accepted `warroom_room_notice` input should still validate with the safe Worker contract, then also create a canonical `announcement` notice by calling the local `/notice-board` route with local auth headers. Incoming Worker `notice_board_message`, `notice_resolved`, and `notice_board_catchup` frames should merge through existing Notice Board helpers or request local hydration, not become a separate remote-only notice feed.

### Design Patterns

* Canonical local state: server `NoticeBoard` remains source of truth for local notices, filtering, resolution, dedupe, context, and hydration.
* Injected bridge dependency: relay send behavior is tested through a fake sender and can be no-op when disconnected.
* Fail-closed external input handling: remote frames are schema validated and mapped to compact errors before manager mutation.
* Bounded provenance: record only source labels, source machine or participant id, notice id, and ingested timestamp.
* Additive compatibility: keep `/notice`, `/notices`, `post_notice`, `warroom_room_notice`, and existing web panel state while routing accepted data through canonical notices.

### Technology Stack

* TypeScript in `apps/server`, `apps/web`, and `packages/protocol`.
* Express local REST routes and local WebSocket broadcaster.
* React and Zustand for the web cockpit state.
* Vitest with existing fake server, fake socket, and happy-dom test patterns.
* No new runtime dependencies.

***

## 6. Deliverables

### Files to Create

| File                                              | Purpose                                                                                                          | Est. Lines |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/server/src/lib/warRoomNoticeBridge.ts`      | Server bridge for relay send, remote ingest, catch-up dedupe, resolution, provenance, and local hydration events | \~260      |
| `apps/server/tests/warRoomNoticeBridge.test.ts`   | Focused server bridge tests for send, ingest, dedupe, catch-up, resolution, provenance, and standalone behavior  | \~360      |
| `apps/web/src/lib/noticeBoardApi.ts`              | Browser helper for authenticated local `/notice-board` creation with timeout and compact failure mapping         | \~180      |
| `apps/web/src/lib/warRoomNoticeConvergence.ts`    | Web helper for safe room notice to canonical announcement conversion and Worker Notice Board frame merging       | \~220      |
| `apps/web/tests/warRoomNoticeConvergence.test.ts` | Focused web tests for sanitizer, conversion, catch-up merge, resolution merge, and blocked payloads              | \~260      |

### Files to Modify

| File                                                 | Changes                                                                                                                                      | Est. Lines |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/server/src/routes/noticeBoard.ts`              | Notify bridge after canonical local post and resolution; preserve existing REST responses and local emits                                    | \~80       |
| `apps/server/src/ws/handlers.ts`                     | Route `post_notice` through bridge-aware canonical post path and preserve active-room hydration                                              | \~80       |
| `apps/server/src/server.ts`                          | Instantiate the Notice Board bridge with no-op standalone defaults and inject it into route/WebSocket dependencies                           | \~80       |
| `apps/server/src/managers/noticeBoard.ts`            | Add bounded provenance support or read-only debug accessor if bridge needs manager-owned storage                                             | \~120      |
| `apps/web/src/store/useWarRoomStore.ts`              | Route room notice sends through canonical Notice Board creation and merge Worker Notice Board relay frames with duplicate-trigger protection | \~180      |
| `apps/web/src/lib/warRoomFederation.ts`              | Reuse or export sanitized room-notice conversion helpers without weakening blocked-field validation                                          | \~80       |
| `apps/web/tests/WarRoomPanel.test.tsx`               | Assert room notice send still works, blocked input remains blocked, and accepted input posts canonical announcement                          | \~80       |
| `apps/web/tests/warRoomStore.test.ts`                | Assert duplicate sends are guarded and Worker Notice Board frames merge or trigger hydration safely                                          | \~100      |
| `packages/protocol/src/warroom.ts`                   | Add small exported helper only if shared room-notice conversion requires protocol-owned vocabulary                                           | \~40       |
| `packages/protocol/tests/warroomNoticeRelay.test.ts` | Extend protocol coverage only if a shared helper is added                                                                                    | \~40       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Local Notice Board posts forward through the relay sender when connected and remain local-only when no relay is connected.
* [ ] Local Notice Board resolutions forward through the relay sender when connected and remain local-only when no relay is connected.
* [ ] Remote `notice_board_message` frames ingest into the canonical manager exactly once by notice id.
* [ ] Remote `notice_resolved` frames resolve only the active-room notice and emit canonical local `notice_resolved` events.
* [ ] Remote `notice_board_catchup` frames dedupe by id and trigger one local `notice_board_hydrate` after accepted changes.
* [ ] Remote provenance exposes source, ingested time, and source machine or participant id only when debug output is requested.
* [ ] Web room notices still validate through `warroom_room_notice` rules and accepted messages create sanitized canonical `announcement` notices.
* [ ] Standalone local Notice Board behavior still works without a Worker URL, room connection, relay sender, or Worker credentials.

### Testing Requirements

* [ ] Unit tests written and passing for server bridge send, ingest, dedupe, catch-up, resolution, provenance, and standalone behavior.
* [ ] Web tests written and passing for room notice conversion, canonical post, blocked input, duplicate-trigger prevention, catch-up merge, and resolution merge.
* [ ] Focused package tests run for touched server, web, and protocol files.
* [ ] Manual testing completed for accepted and blocked War Room notice input.

### Non-Functional Requirements

* [ ] Optional Worker relay remains an external-transfer path for coordination notices only.
* [ ] Local server `/warroom` remains a compatibility/status stub, not a room relay or Worker proxy.
* [ ] No raw prompts, transcripts, terminal output, command bodies, file contents, secrets, broad paths, exports, replay buffers, scans, media drafts, diagnostics, logs, backups, or quarantined evidence are shared or logged.
* [ ] Bridge send and ingest paths are bounded, deterministic, and idempotency-aware.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] No new runtime dependencies.

***

## 8. Implementation Notes

### Key Considerations

* The local server must stay the canonical Notice Board owner. Worker relay is optional and must not create a second source of truth.
* The server README and API docs still prohibit local Worker proxy routes; this session should add bridge behavior inside the runtime only.
* Session 07 already made Worker relay frames safe and sender-excluded, so this session should consume those contracts instead of redefining Worker payloads.
* Web room-notice input should preserve current UX state, duplicate-send guard, blocked-input copy, and disconnected-room feedback.

### Potential Challenges

* Active-room ambiguity: Use the active War Room code when connected and the existing local default room id when standalone.
* Duplicate remote ingest: Deduplicate by notice id before broadcast and batch catch-up hydration.
* Resolution race: Treat unknown remote resolutions as no-op or compact failure without creating placeholder notices.
* Boundary drift: Keep bridge send/injest logic separate from local route proxying and document no-claim behavior in test names and comments.

### Relevant Considerations

* \[P03-packages/protocol] **Protocol leads cross-package work**: Use shared Notice Board and War Room contracts before wiring server or web behavior.
* \[P06-apps/warroom+apps/web] **War Room federation is optional and redacted**: Relay only explicit coordination notices and do not imply hosted identity, public collaboration safety, production auditability, certification, or full erasure.
* \[P07] **Redaction is boundary-specific**: Keep minimization explicit across REST, WebSocket, Worker, replay, export, log, and diagnostic boundaries.
* \[P03-apps/server] **Local server boundary must stay conservative**: Preserve loopback-first local APIs, optional auth, CORS/WS origin checks, request validation, rate limits, body-size caps, and unavailable states.
* \[P03] **Stable docs are the current contract**: Treat `EXAMPLES/` as evidence only and align implementation with current README and API docs.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Remote catch-up can create duplicate notices or repeated hydration storms if batch ingest is not idempotent.
* Room notice sends can double-post if web Worker send and local Notice Board post are not guarded under the same in-flight state.
* Relay boundaries can leak sensitive payloads if remote frames, provenance, or failure messages carry raw Worker payloads instead of compact labels.

***

## 9. Testing Strategy

### Unit Tests

* Test server bridge local send and resolution forwarding with fake sender and disconnected no-op behavior.
* Test server bridge remote message ingest, duplicate id rejection, catch-up dedupe, bounded hydration, and provenance.
* Test web helper conversion from `warroom_room_notice` to canonical `announcement` notice and blocked input handling.
* Test web store handling for Worker Notice Board message, catch-up, and resolution frames.

### Integration Tests

* Start a local test server with fake bridge sender, post through `/notice-board`, and assert local response, local event, and outbound relay frame.
* Resolve through `/notice-board/:id/resolve` and assert local response, local event, and outbound relay frame.
* Render the War Room panel with mocked local Notice Board API and Worker socket, send a room notice, and assert canonical announcement creation plus duplicate-trigger prevention.

### Manual Testing

* With no Worker configured, post and resolve notices locally and verify the board still updates.
* With a mocked or local Worker connection, send a safe War Room panel notice and verify it appears as an `announcement` in the Notice Board.
* Attempt blocked room notice content with URL, broad path, command-like text, or token-like text and verify no canonical notice is posted.

### Edge Cases

* Empty catch-up arrays.
* Catch-up arrays containing duplicate ids.
* Remote notices with a room code different from the active room.
* Unknown remote resolution id.
* Disconnected relay sender during a local post.
* Worker socket connected while local server auth token is configured.
* Reopened War Room panel after a failed send.

***

## 10. Dependencies

### External Libraries

* No new runtime dependencies.

### Other Sessions

* **Depends on**: `phase17-session02-server-notice-manager-persistence-and-context`, `phase17-session03-server-routes-and-websocket-parity`, `phase17-session04-web-store-and-cockpit-notice-board`, `phase17-session07-war-room-worker-relay-and-catchup`
* **Depended by**: `phase17-session09-automatic-mission-lifecycle-posts`, `phase17-session10-validation-documentation-and-handoff`

***

## 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/phase17-session08-local-war-room-bridge-and-room-notice-convergence/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.
