> 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-session02-server-notice-manager-persistence-and-context/implementation-notes.md).

# Implementation Notes

**Session ID**: `phase17-session02-server-notice-manager-persistence-and-context` **Package**: apps/server **Started**: 2026-06-05 19:40 **Last Updated**: 2026-06-05 19:54

***

## Session Progress

| Metric              | Value     |
| ------------------- | --------- |
| Tasks Completed     | 24 / 24   |
| Estimated Remaining | 0 minutes |
| Blockers            | 0         |

***

## Task Log

### 2026-06-05 - Session Start

**Environment verified**:

* [x] Prerequisites confirmed
* [x] Tools available
* [x] Directory structure ready

**Notes**:

* The active session resolved to `phase17-session02-server-notice-manager-persistence-and-context`.
* Package scope resolved from `spec.md` to `apps/server`.
* `check-prereqs.sh --json --env --package apps/server` passed.
* `node`, `npm`, and `jq` were available; Node 26.2.0 is installed through nvm for verification commands.

***

### Task T001 - Verify Notice Board Evidence

**Started**: 2026-06-05 19:38 **Completed**: 2026-06-05 19:40 **Duration**: 2 minutes

**Notes**:

* Reviewed Session 01 Notice Board protocol contracts in `packages/protocol/src/notices.ts`.
* Reviewed current server manager stub and compatibility callers in routes, WebSocket handlers, and mock events.
* Reviewed quarantined historical manager behavior from `EXAMPLES/package-0.4.1/server/dist/noticeBoardManager.js`.

**Files Changed**:

* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/implementation-notes.md` - recorded setup evidence.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

***

### Task T002 - Verify Server Test Setup

**Started**: 2026-06-05 19:38 **Completed**: 2026-06-05 19:40 **Duration**: 2 minutes

**Notes**:

* Reviewed `apps/server/package.json` and root `vitest.config.ts`.
* Confirmed focused tests can be added under `apps/server/tests/**/*.test.ts`.
* Confirmed existing temp directory cleanup and fake timer patterns in server tests.

**Files Changed**:

* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/implementation-notes.md` - recorded server test setup review.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

***

### Task T003 - Create Notice Board Test Scaffold

**Started**: 2026-06-05 19:40 **Completed**: 2026-06-05 19:41 **Duration**: 1 minute

**Notes**:

* Added an isolated temp `FACTIONOS_HOME` helper for persistence tests.
* Added cleanup hooks to restore real timers and remove temporary roots after each test.
* Added focused TODO placeholders for persistence, filtering, context, resolution, ingest, prune, and dedupe behavior.

**Files Changed**:

* `apps/server/tests/noticeBoard.test.ts` - created manager test scaffold.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

***

### Task T004 - Define Manager Options And Store Schema

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added constructor options for storage path, state directory, default room, clock, debounce, context cache, pruning, stale retention, max messages, and error callback.
* Added the local JSON store schema around `messages`.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added options, constants, store schema, and storage path resolution.

**BQC Fixes**:

* State freshness on re-entry: storage path and clock are resolved per manager instance, not at module import time.

***

### Task T005 - Implement Startup Load Fallback

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added startup load from `notice-board.json`.
* Missing, unreadable, malformed, or schema-invalid stores start from an empty message set.
* Added compact persistence error mapping without exposing raw local paths or payload bodies.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added load and persisted store validation.

**BQC Fixes**:

* Failure path completeness: malformed local state maps to `store_read_failed` or `store_malformed`.
* Error information boundaries: persistence errors avoid raw paths and stored content.

***

### Task T006 - Implement Debounced Atomic Save

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added dirty tracking, debounced save scheduling, parent directory creation, atomic temp-file writes, and rename into place.
* Temp files are removed on write failures.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added save scheduling and atomic persistence.

**BQC Fixes**:

* Failure path completeness: write and directory failures are recorded as compact persistence errors.
* Resource cleanup: failed save temp files are removed.

***

### Task T007 - Implement Destroy And Flush Cleanup

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added `flush()` and `destroy()` lifecycle methods.
* Shutdown clears pending debounce and prune timers, flushes dirty state, and clears caches and in-flight auto-post keys.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added timer and cache cleanup.

**BQC Fixes**:

* Resource cleanup: all manager-owned timers are cleared on `destroy()`.

***

### Task T008 - Normalize Notices And Preserve Aliases

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Normalized create, compatibility, and ingested notices through protocol helpers.
* Preserved `body`, `targets`, `postedAt`, and `severity` aliases while storing canonical fields.
* Returned cloned arrays to avoid exposing mutable internal state.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added normalization and cloning helpers.

**BQC Fixes**:

* Contract alignment: stored notices include canonical and compatibility fields from `@factionos/protocol`.
* Trust boundary enforcement: invalid notice values fail through `NoticeBoardValidationError`.

***

### Task T009 - Add Room Scoped Filtering Helpers

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added default local room fallback for local manager operations.
* Added strict room requirement for room-scoped resolution.
* Added safe id validation for room and session boundary fields.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added room resolution and visibility helpers.

**BQC Fixes**:

* Trust boundary enforcement: room and session ids are validated before filtering or mutation.

***

### Task T010 - Add Bounded Query Defaults

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added bounded list and context limits, offsets, typed filters, and deterministic ordering.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added query validation and sort helpers.

**BQC Fixes**:

* Contract alignment: manager query behavior matches typed Notice Board list and context contracts.

***

### Task T011 - Replace Compatibility Post

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Replaced in-memory compatibility post with canonical storage, alias preservation, cap enforcement, save scheduling, and context cache invalidation.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - rewrote `post()`.

**BQC Fixes**:

* State freshness on re-entry: every post invalidates cached context.

***

### Task T012 - Implement getMessages And List

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added room, type, since, target session, expiration, include-resolved, offset, and limit filters.
* Compatibility `list()` returns notice arrays for existing route and WebSocket hydration callers.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added canonical list response and compatibility list surface.

**BQC Fixes**:

* Trust boundary enforcement: targeted notices are filtered at the manager boundary when a session target is provided.

***

### Task T013 - Implement Room Scoped Resolve

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added `resolveForRoom()` with room boundary checks, timestamp handling, save scheduling, and cache invalidation.
* Kept compatibility `resolve()` for the local default room.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added resolve behavior.

**BQC Fixes**:

* Trust boundary enforcement: a notice can only resolve through the requested room.

***

### Task T014 - Implement Ingest Dedupe

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added id-based `ingest()` with protocol parsing, alias normalization, cap enforcement, save scheduling, and cache invalidation.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added single notice ingest behavior.

**BQC Fixes**:

* Duplicate action prevention: duplicate ids do not mutate state or schedule saves.

***

### Task T015 - Implement Batch Ingest

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added `ingestBatch()` with all-input validation before mutation, duplicate filtering, and a single mutation/save/cache invalidation when inserts occur.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added batch ingest behavior.

**BQC Fixes**:

* Concurrency safety: batch insert boundaries avoid partial mutation before validation completes.

***

### Task T016 - Implement Session Context

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added `getContextForSession()` with recovered heading, same-author exclusion, target filtering, expiration filtering, last-fetch tracking, and five-second cache behavior.
* Supports both canonical object query responses and recovered string-style calls.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added context generation and cache behavior.

**BQC Fixes**:

* State freshness on re-entry: context recomputation advances last-fetch only when cache misses.

***

### Task T017 - Implement Context Cache Invalidation

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Context cache now invalidates on load, post, ingest, batch ingest, resolve, and prune mutations.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - wired mutation paths through cache invalidation.

**BQC Fixes**:

* State freshness on re-entry: mutation paths cannot serve stale cached context.

***

### Task T018 - Implement AutoPost Dedupe

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added `autoPost()` with same-room, same-author-session, same-type 30-second dedupe.
* Added in-flight key protection around duplicate triggers.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added auto-post behavior.

**BQC Fixes**:

* Duplicate action prevention: recent and in-flight auto-post duplicates return `null`.

***

### Task T019 - Implement Pruning And Cap

**Started**: 2026-06-05 19:41 **Completed**: 2026-06-05 19:46 **Duration**: 5 minutes

**Notes**:

* Added pruning for expired notices, stale non-critical notices, stale resolved notices, and max-message cap enforcement.
* Critical unresolved notices remain until resolved, expired, or explicitly pruned by cap pressure.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - added prune and cap behavior.

**BQC Fixes**:

* Resource cleanup: prune timer is manager-owned and cleared on `destroy()`.

***

### Task T020 - Wire Notice Board Shutdown Cleanup

**Started**: 2026-06-05 19:47 **Completed**: 2026-06-05 19:48 **Duration**: 1 minute

**Notes**:

* Added Notice Board `destroy()` to the server shutdown path after mock stop and WebSocket/HTTP close.
* Used a `finally` block so local Notice Board cleanup still runs if socket or HTTP close callbacks encounter a shutdown edge.

**Files Changed**:

* `apps/server/src/server.ts` - wired Notice Board cleanup into `stop()`.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

**BQC Fixes**:

* Resource cleanup: pending save and prune timers are flushed or cleared during server stop.

***

### Task T022 - Add Persistence And Shutdown Tests

**Started**: 2026-06-05 19:48 **Completed**: 2026-06-05 19:51 **Duration**: 3 minutes

**Notes**:

* Added focused tests for debounced persistence, atomic temp cleanup, restart survival, malformed load fallback, destroy-time flush, and timer cleanup.
* Focused Notice Board test run passed.

**Files Changed**:

* `apps/server/tests/noticeBoard.test.ts` - added persistence and shutdown tests.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

**BQC Fixes**:

* Resource cleanup: tests assert shutdown clears manager-owned timers.

***

### Task T023 - Add Filter, Context, Ingest, Dedupe, And Prune Tests

**Started**: 2026-06-05 19:48 **Completed**: 2026-06-05 19:51 **Duration**: 3 minutes

**Notes**:

* Added tests for message cap, room/type/since/target/expiration/resolution filters, context cache and last-fetch behavior, ingest and batch ingest dedupe, auto-post dedupe, and pruning behavior.
* Focused Notice Board test run passed.

**Files Changed**:

* `apps/server/tests/noticeBoard.test.ts` - added manager behavior tests.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

**BQC Fixes**:

* Duplicate action prevention: ingest, batch ingest, and auto-post duplicate tests now cover no-mutation paths.
* State freshness on re-entry: context cache and last-fetch behavior are covered.

***

### Task T021 - Preserve Compatibility Callers

**Started**: 2026-06-05 19:51 **Completed**: 2026-06-05 19:53 **Duration**: 2 minutes

**Notes**:

* Kept compatibility `post()`, `list()`, and `resolve()` surfaces for current routes, WebSocket hydration, and mock event generation.
* Adjusted WebSocket `post_notice` handling to tolerate the protocol union where current compatibility clients may provide `body` and canonical clients may provide `content`.
* Added Notice Board server options and temp Notice Board stores in route, WebSocket, and auth tests so persistent state cannot leak across test servers.
* Compatibility suites passed with 32 tests across manager, REST, WebSocket, and auth coverage.

**Files Changed**:

* `apps/server/src/managers/noticeBoard.ts` - preserved compatibility manager methods.
* `apps/server/src/ws/handlers.ts` - preserved current and canonical post body compatibility.
* `apps/server/src/server.ts` - exposed Notice Board options for deterministic test isolation.
* `apps/server/tests/routes.test.ts` - isolated Notice Board test state.
* `apps/server/tests/websocket.test.ts` - isolated Notice Board test state.
* `apps/server/tests/authBoundaries.test.ts` - isolated Notice Board test state.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked task complete.

**BQC Fixes**:

* State freshness on re-entry: persistent Notice Board state is isolated per server test lifecycle.
* Contract alignment: WebSocket post handling accepts both protocol-compatible body shapes.

***

### Task T024 - Run Final Verification Gates

**Started**: 2026-06-05 19:53 **Completed**: 2026-06-05 19:54 **Duration**: 1 minute

**Notes**:

* Ran final formatting/lint checks for all touched server code and tests.
* Ran server package typecheck.
* Ran focused Notice Board, REST route, WebSocket, and auth compatibility tests.
* Ran ASCII and CRLF validation across touched code, tests, and session files.

**Files Changed**:

* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/tasks.md` - marked final task and completion checklist complete.
* `.spec_system/specs/phase17-session02-server-notice-manager-persistence-and-context/implementation-notes.md` - recorded verification evidence.

**Verification**:

* `npx biome check apps/server/src/managers/noticeBoard.ts apps/server/src/server.ts apps/server/src/ws/handlers.ts apps/server/tests/noticeBoard.test.ts apps/server/tests/routes.test.ts apps/server/tests/websocket.test.ts apps/server/tests/authBoundaries.test.ts` - passed.
* `npm --workspace apps/server run typecheck` - passed.
* `npx vitest run apps/server/tests/noticeBoard.test.ts apps/server/tests/routes.test.ts apps/server/tests/websocket.test.ts apps/server/tests/authBoundaries.test.ts --project node` - passed, 32 tests.
* `rg --pcre2 -n "[^\\x00-\\x7F]" ...` - passed with no matches.
* `rg -nU $'\\r' ...` - passed with no matches.

***

## Blockers & Solutions

### Blocker 1: Persistent State Cross-Test Leakage

**Description**: Route and WebSocket suites initially shared the default local Notice Board persistence root, so notices from one server test could appear in another. **Impact**: A WebSocket malformed-message compatibility assertion saw prior route notices. **Resolution**: Added `noticeBoard` options to `createFactionOsServer` and passed temp state directories from route, WebSocket, and auth test harnesses. **Time Lost**: 5 minutes

***

## Design Decisions

### Decision 1: Keep Persistence And Filtering In NoticeBoard

**Context**: Session 02 owns the manager behavior, while routes and relay behavior are deferred. **Options Considered**:

1. Put persistence and filtering in routes - spreads state behavior across future sessions.
2. Keep persistence, filtering, context, pruning, and cache invalidation in the manager - centralizes the state boundary.

**Chosen**: Keep behavior in `NoticeBoard`. **Rationale**: Later route, WebSocket, CLI, hook, and relay sessions can share one validated manager boundary.

### Decision 2: Inject Notice Board Options Through ServerOptions

**Context**: Persistent state is production behavior but tests need isolated local roots. **Options Considered**:

1. Mutate `FACTIONOS_HOME` globally in tests - simple but risks cross-test process coupling.
2. Add `noticeBoard` options to `createFactionOsServer` - explicit and instance-scoped.

**Chosen**: Add `noticeBoard` options. **Rationale**: Server tests can isolate state without weakening the production default of local persistence under `FACTIONOS_HOME` or `~/.factionos`.

***


---

# 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-session02-server-notice-manager-persistence-and-context/implementation-notes.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.
