> 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/phases/phase_18/session_02_server_suggestion_manager_and_persistence.md).

# Session 02: Server Suggestion Manager And Persistence

**Session ID**: `phase18-session02-server-suggestion-manager-and-persistence` **Package**: apps/server **Status**: Not Started **Estimated Tasks**: \~12-25 **Estimated Duration**: 2-4 hours

***

## Objective

Implement a server-side SuggestionManager that owns all Quest Board state, dismissed-ID tracking, freshness windows, and debounced atomic disk persistence, emitting `suggestion_update` snapshots through a single path.

***

## Scope

### In Scope (MVP)

* SuggestionManager holding idle suggestions, codebase issues, session summaries, analysis result, and project scan state using Session 01 types
* Suggestion IDs, session/hero linkage, created-at timestamps, and a per-session idle-suggestion cap
* Accept/dismiss state transitions with dismissed suggestion-ID and issue-ID sets, capped at 100 entries with FIFO eviction, persisted to disk
* Incremental issue APIs: add with dedupe by type+filePath+line, queries by type and severity, clear by type
* Persistence to `suggestions.json` under the FactionOS home directory: debounced (\~1s) saves, atomic tmp-plus-rename writes, load-from-disk on startup, and a destroy/flush path wired into server shutdown
* Freshness windows: analysis result 30 minutes, project scan and codebase scan 24 hours
* `getSummary` with counts and severity buckets
* Single `emitUpdate` path that builds the `suggestion_update` snapshot
* Unit tests for state transitions, dedupe, caps, freshness, persistence round-trip, and corrupt-file recovery

### Out of Scope

* REST routes and WebSocket wiring (Session 03)
* Generation engines and scanners (Sessions 04-08)

***

## Prerequisites

* [ ] Session 01 protocol contracts merged
* [ ] Existing server lifecycle shutdown hooks identified for flush wiring

***

## Deliverables

1. SuggestionManager module with full state, action, and query surface
2. Atomic, debounced persistence with startup load and shutdown flush
3. Dismissed-ID tracking with caps and persistence
4. Unit test suite covering manager behavior and persistence edge cases

***

## Success Criteria

* [ ] Accept/dismiss state and dismissed-ID sets survive a server restart
* [ ] Saves are atomic (no partial files) and debounced under rapid updates
* [ ] Freshness predicates report stale analysis/scan state at the correct boundaries
* [ ] Server test suite passes with new coverage included

***

## Historical Evidence (EXAMPLES References)

Preserved from the 2026-06-07 parity audit (full audit in `PRD_phase_18.md` Appendix A). Evidence only; never import, copy, or transform historical code.

* `EXAMPLES/package-0.4.1/server/dist/suggestionManager.js:1` - the authoritative manager evidence:
  * Persistence: `loadFromDisk`, `saveToDisk` (debounced \~1s), `doSave` (atomic `suggestions.json.tmp` plus `rename` swap), `destroy()` flushing a pending save on shutdown.
  * State fields: `idleSuggestions`, `codebaseIssues`, `sessionSummaries`, `analysisResult`, `projectScan`; constructor fields carry suggestion IDs, session IDs, and created-at timestamps.
  * `setIdleSuggestions` with `MAX_SUGGESTIONS_PER_SESSION=1` (historical per-session cap value).
  * Incremental issue APIs: `addCodebaseIssue` (dedupes by `type`+`filePath`+`line`), `getIssuesByType`, `getIssuesBySeverity`, `clearIssuesByType` (first audit pass only saw bulk `setCodebaseIssues`).
  * Dismissals: `dismissSuggestion`, `dismissIssue`, `static MAX_DISMISSED=100` with FIFO eviction via `capDismissedSet`; `dismissedSuggestionIds` and `dismissedIssueIds` both persist to disk.
  * Freshness: `isAnalysisFresh` (30 minutes, `1800*1e3`), `isProjectScanFresh` and `isCodebaseScanFresh` (24 hours, `1440*60*1e3`); `setAnalysisResult` and `setProjectScan` enforce them.
  * Summary and snapshot: `getSummary` (counts plus severity buckets), `emitUpdate` / `getCurrentState` building the `suggestion_update` snapshot; `setSessionSummary` for session follow-ups.
  * Noise filtering hook: `setAnalysisResult` and `loadFromDisk` both apply the analysis noise filter (filter itself lands in Session 05).
* `EXAMPLES/1st-pass-artifacts/skills/factionos-guide/references/troubleshooting.md:144` and `EXAMPLES/1st-pass-artifacts/skills/factionos-guide/references/troubleshooting.md:247`
  * documents the `~/.factionos/suggestions.json` persistence location and behavior.

## Current-Code Touchpoints (Audit Snapshot 2026-06-07)

* `apps/web/src/store/useGameStore.ts:216` - Quest Board state is browser store memory plus event hydration today; no server-side suggestion persistence exists anywhere in the current codebase.


---

# 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/phases/phase_18/session_02_server_suggestion_manager_and_persistence.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.
