> 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-session03-server-routes-and-websocket-parity/spec.md).

# Session Specification

**Session ID**: `phase17-session03-server-routes-and-websocket-parity` **Phase**: 17 - Notice Board Coordination Parity **Status**: Completed **Validated**: 2026-06-05 **Created**: 2026-06-05 **Package**: apps/server, packages/protocol **Package Stack**: TypeScript

***

## 1. Session Overview

This session restores the runtime-facing Notice Board API surface on top of the protocol contracts from Session 01 and the persistent server manager from Session 02. The current server still exposes only the compatibility `/notice`, `/notices`, and `post_notice` paths even though the manager now supports room-scoped list, context, post, resolve, ingest, and filtering behavior.

The work adds the canonical `/notice-board` REST family, keeps compatibility adapters working, and updates WebSocket hydration and client `post_notice` handling to carry expanded Notice Board fields. It intentionally stays out of the web cockpit UI, CLI, hook context, Worker relay, local War Room bridge, and automatic lifecycle posts, which are later Phase 17 sessions.

Notice Board content is coordination data and can still be sensitive developer data. Route validation, WebSocket validation, related-file handling, and event payloads must preserve local-first boundaries and never broaden claims around hosted identity, public collaboration safety, trusted erasure, real executors, or production auditability.

***

## 2. Objectives

1. Add canonical `GET /notice-board`, `GET /notice-board/context`, `POST /notice-board`, and `POST /notice-board/:id/resolve` routes.
2. Preserve compatibility behavior for `GET /notices`, `POST /notice`, and WebSocket `post_notice`.
3. Emit canonical `notice_board_hydrate`, `notice_board_message`, and `notice_resolved` frames with compatibility keys where needed.
4. Add route, WebSocket, and protocol regression tests proving real-mode, no-mock Notice Board parity.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase17-session01-protocol-notice-contract-parity` - provides expanded Notice Board contracts, helpers, REST shapes, and event payload types.
* [x] `phase17-session02-server-notice-manager-persistence-and-context` - provides local persistence, room filtering, context lookup, resolution, pruning, dedupe, and compatibility manager methods.

### Required Tools/Knowledge

* Node 26.2.0 or newer with npm workspaces.
* Express 5 route patterns and existing server route mounting.
* `ws` server handler patterns in `apps/server/src/ws/handlers.ts`.
* Protocol Notice Board helpers in `packages/protocol/src/notices.ts`.
* Server validation helper style in `apps/server/src/lib/requestValidation.ts`.
* Focused Vitest coverage under `apps/server/tests` and `packages/protocol/tests`.

### 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.
* Run server route and WebSocket tests with `FACTIONOS_MOCK=false` behavior.

***

## 4. Scope

### In Scope (MVP)

* Local clients can list active-room notices through `GET /notice-board` - validate `type`, `since`, `forSession`, `limit`, `offset`, `includeResolved`, `roomCode`, and `debug=1`, then return `{ messages, total }`.
* Existing clients can keep listing notices through `GET /notices` - adapt the same manager list to `{ notices }`.
* Agent and human clients can fetch bounded session context through `GET /notice-board/context?sessionId=<id>` - return `{ context }` from the manager and preserve same-author, target, unresolved, and room filtering.
* Canonical clients can post expanded notices through `POST /notice-board` - require `type` and `content`, validate recovered notice type values, cap content at 2000 characters, normalize author metadata, tags, targets, priority, parent id, and related files.
* Existing clients can keep posting through `POST /notice` - adapt `body`, `severity`, and `targets` into canonical manager input while preserving old response fields.
* Operators can resolve notices through `POST /notice-board/:id/resolve` - resolve only in the active room, emit `notice_resolved`, and return `{ success: true }`.
* New WebSocket clients receive active-room Notice Board hydration - send canonical `messages` and compatibility `notices` arrays without replacing persisted notices with mock-only data.
* WebSocket `post_notice` accepts expanded Notice Board fields - preserve current `body`, `severity`, and `targets` behavior while accepting `content`, `noticeType`, `priority`, `tags`, author metadata, target ids, parent id, related files, room code, and expiration.
* Route and WebSocket tests prove canonical post, list, context, hydrate, compatibility post/list, WebSocket post, resolve, and safe related-file behavior in real mode.

### Out of Scope (Deferred)

* Web cockpit store or component rendering - Reason: Session 04 owns web store normalization and Notice Board UI.
* CLI notice commands - Reason: Session 05 owns user-facing CLI post/list commands.
* Hook context fetching and provider skill parity - Reason: Session 06 owns agent hook context access.
* Worker Notice Board relay and catch-up - Reason: Session 07 owns Worker relay behavior.
* Local server to War Room bridge convergence - Reason: Session 08 owns room notice convergence.
* Automatic mission status and completion posts - Reason: Session 09 owns lifecycle auto-post integration.
* Stable documentation handoff - Reason: Session 10 owns validation, documentation, and final phase handoff.

***

## 5. Technical Approach

### Architecture

Create a dedicated `apps/server/src/routes/noticeBoard.ts` router for the canonical route family and compatibility adapters. Mount it from `apps/server/src/server.ts` alongside the existing local API routes, then remove Notice Board route ownership from `apps/server/src/routes/heroes.ts` so notice behavior is centralized in one module.

Keep request validation compact and fail-closed. Route code should convert Express query and body input into protocol-backed `NoticeBoardListQuery`, `NoticeBoardContextQuery`, `NoticeBoardCreateRequest`, and `NoticeBoardResolveRequest` values before calling the manager. Validation errors should use the existing `invalid_request` envelope and must not echo raw paths, request bodies, tokens, prompts, command output, or local filesystem details.

Update `apps/server/src/ws/clientMessageValidation.ts` to accept the expanded `ClientPostNotice` shape already owned by the protocol package, and update `apps/server/src/ws/handlers.ts` to pass canonical fields through to the manager. Hydration and broadcast frames should include both canonical and compatibility payload keys during the migration: `messages` plus `notices` for hydrate, and `message` plus `notice` for post and resolve payloads where the event type supports them.

### Design Patterns

* Route-module ownership: keep Notice Board API behavior out of the generic read router.
* Protocol-backed validation: consume protocol constants and helper types instead of duplicating recovered notice vocabularies.
* Compatibility adapter: canonical route behavior leads, old `/notice`, `/notices`, and `post_notice` inputs are normalized into the same manager.
* Boundary-first event emission: emit bounded Notice values and ids only, never raw request bodies or local path details.
* Focused real-mode tests: start the local server with `mock: false` and temporary Notice Board storage for route and WebSocket coverage.

### Technology Stack

* TypeScript in `apps/server` and `packages/protocol`.
* Express 5 route handlers.
* `ws` WebSocket server handlers.
* Vitest tests through the root configuration.
* Package typecheck through `npm --workspace apps/server run typecheck` and `npm --workspace packages/protocol run typecheck`.

***

## 6. Deliverables

### Files to Create

| File                                          | Purpose                                                  | Est. Lines |
| --------------------------------------------- | -------------------------------------------------------- | ---------- |
| `apps/server/src/routes/noticeBoard.ts`       | Canonical Notice Board routes and compatibility adapters | \~260      |
| `apps/server/tests/noticeBoardRoutes.test.ts` | Real-mode canonical and compatibility route coverage     | \~260      |

### Files to Modify

| File                                            | Changes                                                                                  | Est. Lines |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------- |
| `apps/server/src/server.ts`                     | Mount Notice Board router in local and `/api` route groups                               | \~10       |
| `apps/server/src/routes/heroes.ts`              | Remove legacy notice route ownership after router extraction                             | \~40       |
| `apps/server/src/ws/clientMessageValidation.ts` | Validate expanded `post_notice` fields with bounded arrays and enum checks               | \~120      |
| `apps/server/src/ws/handlers.ts`                | Hydrate active-room notices and pass expanded `post_notice` input through to the manager | \~70       |
| `apps/server/tests/routes.test.ts`              | Adjust legacy route assertions if Notice Board routes move to dedicated coverage         | \~40       |
| `apps/server/tests/websocket.test.ts`           | Add hydrate, expanded post, compatibility post, and resolve broadcast assertions         | \~180      |
| `packages/protocol/src/events.ts`               | Confirm or adjust client and server Notice Board event shapes consumed by server runtime | \~30       |
| `packages/protocol/tests/events.test.ts`        | Lock expanded event, hydrate, resolve, and `post_notice` compatibility shapes            | \~90       |
| `packages/protocol/tests/rest.test.ts`          | Lock canonical route response and compatibility route type contracts                     | \~40       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] `GET /notice-board` returns `{ messages, total }` with bounded filters for type, since, forSession, limit, offset, includeResolved, roomCode, and debug provenance.
* [ ] `GET /notices` still returns `{ notices }` using the same stored active room messages.
* [ ] `GET /notice-board/context?sessionId=<id>` returns only relevant unresolved active-room context for that session.
* [ ] `POST /notice-board` stores canonical notices and emits `notice_board_message`.
* [ ] `POST /notice` still accepts `body`, `severity`, and `targets`, stores a canonical notice, and emits `notice_board_message`.
* [ ] `POST /notice-board/:id/resolve` resolves only in the active room, emits `notice_resolved`, and returns `{ success: true }`.
* [ ] WebSocket connect hydration includes active-room notices with both `notices` and `messages` keys.
* [ ] WebSocket `post_notice` accepts expanded fields and preserves old compatibility fields.
* [ ] Unsafe related files are rejected or dropped before storage.
* [ ] Canonical and compatibility route behavior works with `FACTIONOS_MOCK` disabled.

### Testing Requirements

* [ ] Focused canonical route tests written and passing.
* [ ] Existing compatibility route tests updated and passing.
* [ ] WebSocket hydration, post, and resolve tests written and passing.
* [ ] Protocol event and REST compatibility tests passing.
* [ ] Server and protocol package typechecks passing.

### Non-Functional Requirements

* [ ] Route and WebSocket validation preserve loopback/local auth, CORS, rate-limit, and body-size boundaries already mounted by the server.
* [ ] Notice Board payloads do not introduce raw prompts, transcripts, terminal output, file contents, secrets, command bodies, absolute paths, logs, exports, replay buffers, scans, media drafts, diagnostics, backups, or quarantined historical content.
* [ ] Related-file handling accepts only safe repository- or worktree-relative paths and blocks absolute, parent traversal, URL-like, Windows absolute, and empty path segments.
* [ ] No route or event implies hosted identity, public collaboration safety, production auditability, real executors, or trusted unified erasure.

### Quality Gates

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

***

## 8. Implementation Notes

### Key Considerations

* `NoticeBoard.getMessages`, `getContextForSession`, `post`, `resolveForRoom`, and compatibility `list`/`resolve` already exist from Session 02.
* `packages/protocol/src/events.ts` already includes canonical and compatibility keys for Notice Board server events; this session should keep server runtime aligned with those contracts.
* `ClientPostNotice` is already expanded in protocol, but server-side WebSocket validation currently accepts only `body`, `severity`, and `targets`.
* Current route tests cover `/notice` and `/notices` inside `routes.test.ts`; canonical route coverage should live in a dedicated Notice Board route test.
* The local server currently has only a `/warroom` compatibility/status stub. Worker relay forwarding remains deferred; this session should preserve room codes and emit local events without claiming Worker parity.

### Potential Challenges

* Duplicate route ownership: Mount the dedicated Notice Board router once for both root and `/api` route groups and remove the legacy route handlers from `readRouter`.
* Query validation drift: Convert string query values to typed manager query options before calling `getMessages`.
* Related-file boundary handling: Protocol rejects unsafe relative path shapes, but the route layer still needs project/worktree boundary checks before storage.
* Event compatibility drift: Broadcast both canonical and compatibility keys during migration so Session 04 can consume either shape.
* Real-mode test isolation: Use temporary Notice Board state directories and server `mock: false` so persisted hydration is deterministic.

### Relevant Considerations

* \[P03-packages/protocol] **Protocol leads cross-package work**: Server route and WebSocket behavior must consume the Session 01 Notice Board contracts instead of redefining notice vocabulary.
* \[P03-apps/server] **Local server boundary must stay conservative**: Keep request validation, local auth, CORS, rate limits, body caps, and compact errors intact.
* \[P06-apps/warroom+apps/web] **War Room federation is optional and redacted**: Room-scoped notices must not imply hosted identity, public collaboration safety, production auditability, certification, or full erasure.
* \[P07] **Redaction is boundary-specific**: Route, WebSocket, Worker, CLI, hook, replay, export, log, and diagnostic boundaries need explicit minimization.
* \[P03] **Stable docs are the current contract**: Current source and stable docs are authority; quarantined `EXAMPLES/` remains evidence only.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Invalid route or WebSocket inputs mutating manager state.
* Compatibility posts diverging from canonical post behavior.
* Related-file values leaking absolute paths or traversal payloads.
* Hydration sending stale, mock-only, resolved, or wrong-room notices.
* Duplicate client triggers creating duplicate posts or resolution frames.

***

## 9. Testing Strategy

### Unit Tests

* Validate protocol event and REST type contracts for Notice Board hydrate, message, resolve, canonical list/context/create/resolve responses, and expanded `post_notice` client messages.
* Validate WebSocket client message parsing for canonical and compatibility `post_notice` inputs, invalid enum values, invalid arrays, and oversized content.

### Integration Tests

* Start the local server with `mock: false` and a temporary Notice Board state directory.
* Test canonical post, list, context, and resolve route behavior.
* Test compatibility `/notice` and `/notices` adapters.
* Test WebSocket hydration from persisted notices and expanded `post_notice` broadcast behavior.

### Manual Testing

* Run a local server with `FACTIONOS_MOCK=false`, post a canonical notice with `curl`, list it through both canonical and compatibility routes, connect a WebSocket client, and resolve the notice.

### Edge Cases

* Empty or invalid `type`, `content`, `severity`, `priority`, `authorType`, `targetSessionIds`, `targets`, `tags`, and `relatedFiles`.
* `limit`, `offset`, `since`, `includeResolved`, and `debug` query values that are absent, malformed, or out of bounds.
* Targeted notices that should not appear for unrelated sessions.
* Resolved notices excluded by default and included only when requested.
* Room-specific resolve attempts against a notice from another room.
* Unsafe related files such as absolute paths, parent traversal, URL-like values, Windows absolute paths, and empty segments.

***

## 10. Dependencies

### External Libraries

* Express 5.2.1: route handling.
* `ws` 8.21.0: WebSocket server integration.
* Vitest: focused server and protocol tests through the root test config.

### Internal Packages

* `@factionos/protocol`: Notice Board types, constants, REST contracts, and event contracts.
* `apps/server`: Notice Board manager, routes, WebSocket handlers, security middleware, and tests.

### Other Sessions

* **Depends on**: `phase17-session01-protocol-notice-contract-parity`, `phase17-session02-server-notice-manager-persistence-and-context`.
* **Depended by**: `phase17-session04-web-store-and-cockpit-notice-board`, `phase17-session05-cli-notice-commands`, `phase17-session06-hook-context-and-provider-skill-parity`, `phase17-session07-war-room-worker-relay-and-catchup`, `phase17-session08-local-war-room-bridge-and-room-notice-convergence`, `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-session03-server-routes-and-websocket-parity/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.
