> 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/phase02-session06-settings-replay-notifications-and-scan-ux/spec.md).

# Session Specification

**Session ID**: `phase02-session06-settings-replay-notifications-and-scan-ux` **Phase**: 02 - Product Surface and 2D Battlefield Completion **Status**: Completed **Created**: 2026-05-29 **Package**: Cross-cutting (`apps/web`, `apps/server`, docs) **Package Stack**: React 18.3.1, Vite 6.4.2, TypeScript 5.9.3, Zustand, Express 4, ws 8.21.0, Vitest 4.1.7, Testing Library, happy-dom 20.9.0, Node.js 20, Biome 2.4.16

***

## 1. Session Overview

This session hardens the privacy-sensitive auxiliary cockpit surfaces that sit around the main hero and battlefield workflows: settings, replay, browser notifications, local session export, and codebase scan feedback. Sessions 02 through 05 made the primary cockpit, mission, battlefield, asset, and demo flows coherent. Session 06 closes the remaining Phase 02 UX gap before the phase validation and documentation closeout session can run.

The work is cross-cutting because the main user-facing changes live in `apps/web`, while export and scan behavior depend on server contracts in `apps/server` and stable documentation under `docs/`. The session should preserve the Phase 01 redaction posture for replay links, exports, LLM scans, localStorage, notifications, and failure messages.

The expected outcome is a clearer local-first control surface: settings recover from malformed persisted values, notification states explain browser permission outcomes, replay and share links communicate redacted local-only behavior, exports surface local-server dependency and privacy headers, and scan-root failures explain `FACTIONOS_SCAN_ROOTS` and approved-root boundaries without exposing sensitive absolute paths in broad user-facing output.

***

## 2. Objectives

1. Make settings, notification, replay, export, and scan controls explicit, accessible, and resilient to malformed storage or unavailable browser APIs.
2. Preserve Phase 01 privacy boundaries for replay-share links, export downloads, scan-root errors, local auth headers, and localStorage values.
3. Add focused web and server tests for malformed settings, notification permission states, replay/share edge cases, export failure copy, and scan-root UX.
4. Update stable docs so shipped local behavior, deferred erasure work, and scan/export/replay boundaries are accurate before Session 07 validation.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase02-session01-product-surface-requirements-reconciliation` - Provides Phase 02 PRD, UX PRD, and product surface gap matrix rows for Session 06.
* [x] `phase02-session02-cockpit-shell-and-navigation-cohesion` - Provides controlled settings drawer, shell controls, command palette, and shortcut routing.
* [x] `phase02-session03-hero-and-mission-workflow-completion` - Provides replayable mission and permission context that must stay redacted in replay/export surfaces.
* [x] `phase02-session04-battlefield-state-and-interaction-polish` - Provides reduced-motion and accessible interaction expectations that settings must preserve.
* [x] `phase02-session05-battlefield-asset-and-public-demo-parity` - Provides public demo and stable documentation parity constraints; Session 06 must not alter public demo scope.

### Required Tools/Knowledge

* Node.js 20 and npm workspace scripts from the root lockfile.
* Vitest, Testing Library, happy-dom, and focused workspace test commands.
* Existing Zustand store patterns in `apps/web/src/store/useSettingsStore.ts` and `apps/web/src/store/useGameStore.ts`.
* Existing redaction helpers in `apps/web/src/lib/replayLink.ts`, `apps/web/src/lib/exportSession.ts`, and `apps/server/src/lib/sessionPrivacy.ts`.
* Current scan-root server contract in `apps/server/src/routes/llm.ts`, `apps/server/src/lib/llmPrivacy.ts`, and `apps/server/src/lib/codebaseWalker.ts`.

### Environment Requirements

* Repository root commands can run with Node.js 20 or newer.
* Tests can run locally without hosted accounts, hosted storage, Cloudflare, Anthropic provider transfer, push backend, or browser notification delivery.
* Browser Notification and Service Worker behavior must remain feature-checked so happy-dom and unsupported browsers degrade cleanly.

***

## 4. Scope

### In Scope (MVP)

* Local user can manage settings preferences - Harden faction, theme, audio, reduced motion, severity, mock, scan root, notification, replay entry, reset, and local auth treatment with accessible labels and malformed-storage recovery.
* Local user can understand notification state - Make unsupported, default, denied, granted, throttled, blocked, and delivered outcomes visible without implying push backend delivery.
* Local user can replay and share safely - Keep replay windows, clear action, redacted URL fragment share links, malformed-link handling, hash stripping, payload caps, and feedback-loop prevention clear.
* Local user can export current session safely - Preserve CSV/JSON selection, local-server dependency, local auth header use, no-store and privacy header feedback, and bounded failure messages.
* Local user can scan an approved codebase root - Explain explicit root requirement, current working directory allowlist, `FACTIONOS_SCAN_ROOTS`, filesystem-root rejection, symlink exclusion, file caps, provider-transfer mode, success counts, issue counts, server offline, and invalid-root paths without broad absolute-path leakage.
* Maintainer can validate the boundaries - Add focused tests for settings persistence, scan UX, notification permission states, replay/share privacy, export privacy headers, and server scan/export error envelopes.
* Stable docs stay current - Update web, server, API, privacy, and development docs for shipped behavior and deferred erasure work.

### Out of Scope (Deferred)

* Unified erase/reset workflow across archives, memory, settings, PID/workspace files, and browser replay state - Reason: Phase 08 release hardening owns trusted erasure.
* Changing Anthropic provider-transfer policy or LLM prompt behavior - Reason: Phase 01 already defined the two-level opt-in policy; this session only explains it in UI/docs.
* Hosted analytics, hosted account settings, hosted replay storage, public replay galleries, or push notification backend - Reason: Later phases own hosted services and push backend design.
* Web-to-Worker War Room federation, agent orchestration, and arbitrary filesystem browsing UI - Reason: These are later-phase product surfaces.
* Public demo changes - Reason: Session 05 completed public demo parity and Session 06 owns the app/server settings and local runtime UX.

***

## 5. Technical Approach

### Architecture

Keep `apps/web` as the main implementation surface. Settings UI remains in `SettingsDrawer.tsx`, replay UI remains in `ReplayPanel.tsx`, command actions remain in the existing command palette runner, and persistent browser preferences remain in `useSettingsStore.ts`. Extract or tighten small pure helpers where they make behavior testable, especially scan UX copy, export error copy, and replay/share status copy.

Keep `apps/server` behavior stable unless tests reveal a mismatch with the documented scan/export contract. The server already owns approved-root resolution, `FACTIONOS_SCAN_ROOTS`, scan path redaction, export schema headers, and export privacy headers. Any server changes should preserve compact `invalid_request` envelopes and never echo raw absolute roots, prompt bodies, token-like values, or provider errors.

Docs should route through stable current sources: `apps/web/README_web.md`, `apps/server/README_server.md`, `docs/api/README_api.md`, `docs/privacy-and-security.md`, and `docs/development.md`. Keep deferred erasure, hosted replay, push backend, hosted analytics, and War Room federation clearly marked as later work.

### Design Patterns

* Pure helper plus component wiring: Put parsing, copy, and status helpers in small modules or exported functions before wiring component behavior.
* Boundary-specific redaction: Keep replay-share, export, scan, notification, and localStorage treatment explicit rather than assuming one generic privacy rule covers all surfaces.
* Local-first error mapping: Convert server/browser failures to compact local UI messages without echoing raw paths, request bodies, provider errors, or tokens.
* Reopenable surface revalidation: Refresh permission state and transient status when drawers or panels reopen so stale local state is not misleading.
* Duplicate-trigger prevention: Disable scan, export, replay, share, and notification test actions while an action is pending or ineligible.
* Existing test harnesses: Extend current Vitest, happy-dom, and server route tests before adding broad new harnesses.

### Technology Stack

* React 18.3.1 and Zustand for web state and component surfaces.
* TypeScript 5.9.3 for app, server, and tests.
* Express 4 and `ws` 8.21.0 for local runtime routes and WebSocket events.
* Vitest 4.1.7, Testing Library, and happy-dom for unit and component tests.
* Biome 2.4.16 for format and lint checks.
* No new runtime dependency unless implementation notes justify it.

***

## 6. Deliverables

### Files to Create

| File                                                                                                     | Purpose                                                                           | Est. Lines |
| -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ---------- |
| `.spec_system/specs/phase02-session06-settings-replay-notifications-and-scan-ux/implementation-notes.md` | Implementation evidence, commands, decisions, privacy checks, and remaining risks | \~120      |
| `apps/web/src/lib/scanCodebase.ts`                                                                       | Testable scan request, response, and failure-copy helpers for SettingsDrawer      | \~160      |
| `apps/web/tests/scanCodebase.test.ts`                                                                    | Focused scan helper tests for allowlist, redaction, response, and failure mapping | \~140      |

### Files to Modify

| File                                           | Changes                                                                                                          | Est. Lines |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/SettingsDrawer.tsx`   | Improve settings reset, notification, scan, replay entry, copy, accessible labels, and transient status behavior | \~220      |
| `apps/web/src/components/ReplayPanel.tsx`      | Clarify redacted local-only share posture, malformed/empty states, and duplicate-action feedback                 | \~80       |
| `apps/web/src/store/useSettingsStore.ts`       | Harden persisted snapshot normalization, partial-key tolerance, reset behavior, and storage-unavailable handling | \~80       |
| `apps/web/src/lib/notifications.ts`            | Normalize notification outcomes and test-action feedback without implying push backend delivery                  | \~70       |
| `apps/web/src/lib/useNotifications.ts`         | Preserve opt-in delivery and reset stale notification baselines when permission or settings change               | \~40       |
| `apps/web/src/lib/replayLink.ts`               | Keep malformed link handling, hash stripping, payload caps, and replay-share redaction visible and testable      | \~80       |
| `apps/web/src/lib/exportSession.ts`            | Bound local export error copy, preserve local auth headers, and surface schema/privacy headers in toasts         | \~80       |
| `apps/web/src/components/CommandPalette.tsx`   | Keep CSV/JSON export commands honest about local-server dependency and in-flight state if needed                 | \~40       |
| `apps/web/tests/SettingsScan.test.tsx`         | Cover scan UI empty, invalid, denied, offline, success, issue-count, and sanitized failure states                | \~160      |
| `apps/web/tests/useSettingsStore.test.ts`      | Cover malformed, stale, partial, storage-unavailable, and reset persistence cases                                | \~120      |
| `apps/web/tests/notifications.test.ts`         | Cover notification support, permission, throttled, delivered, and constructor-failure outcomes                   | \~80       |
| `apps/web/tests/settingsNotifications.test.ts` | Cover settings integration for opt-in, reset, and malformed notification values                                  | \~80       |
| `apps/web/tests/useNotifications.test.tsx`     | Cover hook baseline reset and no retroactive notification delivery                                               | \~80       |
| `apps/web/tests/replayLink.test.ts`            | Cover malformed shared links, event caps, redaction, and consumed hash behavior                                  | \~120      |
| `apps/web/tests/replayShareButton.test.tsx`    | Cover local-only share copy, clipboard fallback, disabled states, and user feedback                              | \~100      |
| `apps/web/tests/exportSession.test.ts`         | Cover export failure copy, privacy headers, server offline, and download cleanup                                 | \~120      |
| `apps/web/tests/wsClientPrivacy.test.ts`       | Extend privacy boundary coverage for replay-share and export UI outcomes                                         | \~80       |
| `apps/server/tests/llm.test.ts`                | Verify scan-root failure envelopes stay compact and do not leak raw roots                                        | \~80       |
| `apps/server/tests/exportRoute.test.ts`        | Verify export route privacy headers and invalid-format envelopes remain compact                                  | \~50       |
| `apps/web/README_web.md`                       | Document current settings, replay, notification, export, and scan UX contract                                    | \~50       |
| `apps/server/README_server.md`                 | Document scan-root and export boundaries used by web UX                                                          | \~40       |
| `docs/api/README_api.md`                       | Refresh scan/export API behavior, privacy headers, and compact error guidance                                    | \~40       |
| `docs/privacy-and-security.md`                 | Refresh browser settings, replay, export, notifications, and scan privacy posture                                | \~50       |
| `docs/development.md`                          | Refresh localStorage, `FACTIONOS_SCAN_ROOTS`, notification, and export development notes                         | \~40       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Settings recover from empty, malformed, stale, partial, and storage-unavailable localStorage snapshots without crashing or persisting impossible values.
* [ ] Settings controls expose accessible names, selected state, and reset feedback for faction, theme, audio, reduced motion, severity, mock, notifications, scan root, and replay entry.
* [ ] Notification UI distinguishes unsupported, default, denied, granted, throttled, blocked, delivered, and constructor-failure paths with visible local feedback.
* [ ] Replay panel communicates that share links encode redacted local URL fragments, caps payloads, avoids feedback loops, and handles malformed shared links without crashing.
* [ ] Export actions preserve CSV/JSON choice, local auth headers, local-server dependency, privacy/schema header feedback, download cleanup, and compact failure messages.
* [ ] Scan UX explains empty root, invalid root, denied root, filesystem-root rejection, no symlink traversal, file caps, issue counts, server offline, and `FACTIONOS_SCAN_ROOTS` allowlist behavior without broad absolute-path leakage.
* [ ] Server scan/export route tests continue to prove compact error envelopes and privacy headers.
* [ ] Stable docs identify shipped local behavior and keep unified erasure, hosted replay, push backend, analytics, and War Room federation deferred.

### Testing Requirements

* [ ] Focused web unit/component tests cover settings persistence, scan UX, notification permission states, replay/share, export, and privacy boundaries.
* [ ] Focused server route tests cover scan-root and export envelopes.
* [ ] Focused Biome checks pass for touched app, server, test, and docs files.
* [ ] `git diff --check`, ASCII validation for spec outputs, and LF validation pass.

### Non-Functional Requirements

* [ ] No raw prompts, command bodies, token-like values, provider errors, absolute roots, or request bodies are echoed in broad user-facing errors.
* [ ] Core local workflows continue to work without hosted accounts, hosted storage, push backend, analytics, Anthropic provider transfer, Cloudflare, or public replay hosting.
* [ ] No new runtime dependency is introduced unless implementation notes justify it.
* [ ] UI copy remains dense and operational, not marketing or hosted-product language.

### Quality Gates

* [ ] All new spec-system files are ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions and existing package patterns.
* [ ] Implementation notes capture commands, manual checks, risks, and deferred release-hardening erasure work.

***

## 8. Implementation Notes

### Key Considerations

* The project-level `.spec_system/CONVENTIONS.md` currently points back to itself as a stable docs entry, so this spec follows the concrete workspace rules from `docs/development.md`, package READMEs, existing Phase 02 specs, and current package patterns.
* `SettingsDrawer.tsx` already owns scan, notification, reset, and replay entry controls. Keep changes focused; do not redesign the drawer as a new settings app.
* `useSettingsStore.ts` uses a hand-rolled localStorage parser and persists a bounded snapshot. Extend its normalization rather than adding a persistence dependency.
* `ReplayPanel.tsx` and `replayLink.ts` already cap share payloads, redact sensitive fields, strip consumed hashes, and avoid feedback loops. This session should make those outcomes visible and tested.
* `exportSession.ts` already reads export privacy and schema headers. Make user feedback and failure text compact, and keep download Blob cleanup verified.
* The server already rejects scan roots outside `process.cwd()` or `FACTIONOS_SCAN_ROOTS`, redacts `rootResolved`, and emits compact invalid requests. Web UX should explain this instead of widening server root scope.
* Unified erasure is an active release risk but is out of scope here. Record any user-facing reset gaps for Phase 08 rather than implementing broad deletion.

### Potential Challenges

* Inline drawer complexity: Mitigate by extracting small scan/export/notification helpers and keeping component wiring thin.
* Browser Notification differences: Mitigate with feature checks and deterministic tests for unsupported, denied, default, granted, hidden-tab, visible-tab, and constructor-failure paths.
* Sensitive path leakage: Mitigate by using server redacted fields and compact UI copy; never display server-provided absolute roots in toasts or shared surfaces.
* Replay feedback loops: Mitigate by preserving `replayingSinceMs` guards and adding tests before changing replay dispatch.
* Export failures from local server offline state: Mitigate by mapping network errors to local dependency copy rather than raw exception dumps.
* Documentation drift: Mitigate by updating package READMEs and stable docs in the same session as implementation.

### Relevant Considerations

* \[P01-apps/web] **Scan-root UX needs follow-through**: This is the primary owner session for explaining approved-root and `FACTIONOS_SCAN_ROOTS` failures in the settings scan flow.
* \[P01] **Redaction is boundary-specific**: Replay, export, notification, settings, and scan UX must preserve the Phase 01 redaction posture at each boundary.
* \[P01-packages/protocol] **Protocol leads cross-package work**: No protocol change is expected; if a new shared event or REST shape becomes necessary, add it in `packages/protocol` before server or web wiring.
* \[P01] **Stable docs are the current contract**: Stable docs must be updated when shipped settings, replay, notification, export, or scan behavior changes.
* \[P01] **Unified erasure still missing**: Keep reset work scoped to current settings/replay controls and record broader erasure as Phase 08 release hardening.
* \[P01] **Do not treat local redaction as share safety**: Redacted replay links and exports are safer local artifacts, not hosted-safe or public-safe guarantees.
* \[P01-apps/server] **Do not let scan convenience widen roots**: Do not add arbitrary filesystem browsing or widen approved roots for UX convenience.

### Behavioral Quality Focus

Checklist active: Yes

Top behavioral risks for this session:

* Reopenable settings and replay surfaces can show stale permission, scan, replay, or share status after close/reopen.
* State-mutating actions can double-trigger scan, export, replay, share, reset, or notification tests while in flight.
* Permission-gated notification flows can mislead users when permission is denied, revoked, unsupported, or throttled.
* Scan and export failure paths can accidentally echo sensitive roots, provider errors, request bodies, or exception text.
* Malformed localStorage or replay URL fragments can break boot if parsing is not defensive.

***

## 9. Testing Strategy

### Unit Tests

* Extend settings store tests for malformed JSON, stale keys, partial severity maps, invalid enum values, storage-unavailable throws, and reset persistence.
* Add scan helper tests for empty root, invalid root, denied root, filesystem root, offline/network errors, empty scans, issue counts, hints, and redacted failure copy.
* Extend notification tests for unsupported, default, denied, granted, throttled, delivered, constructor-failure, visible-tab, and hidden-tab paths.
* Extend replay link tests for malformed tokens, capped entries, redacted sensitive fields, invalid offsets, invalid event types, consumed hash behavior, and null-return paths.
* Extend export helper tests for network failures, invalid JSON/plain text errors, privacy/schema headers, Blob URL revocation, anchor cleanup, and bounded failure copy.

### Integration Tests

* Extend `SettingsScan.test.tsx` for actual drawer behavior: disabled empty root, duplicate-trigger prevention while scanning, success counts, issue-count warning, invalid/denied root copy, server offline copy, and no raw absolute-root echo from server responses.
* Extend `settingsNotifications.test.ts`, `useNotifications.test.tsx`, and `replayShareButton.test.tsx` for component-level feedback and state reset on re-entry.
* Extend `apps/server/tests/llm.test.ts` and `apps/server/tests/exportRoute.test.ts` to keep scan/export route privacy envelopes aligned with web expectations.

### Manual Testing

* Open settings from the title bar and keyboard shortcut; verify drawer close, Escape behavior, focus visibility, settings reset, replay entry, notification status, and scan controls.
* Exercise scan with empty root, an approved repo root, an unapproved temp root, and local server offline.
* Open replay panel, switch windows/speeds, share a link, clear the buffer, and load a malformed replay hash.
* Trigger CSV and JSON export with local server running and offline; verify visible toasts and downloaded file behavior.

### Edge Cases

* localStorage unavailable or throwing during get/set.
* Corrupted `factionos-settings-v1`, stale `factionos-theme`, invalid severity keys, invalid roster sort, and invalid notification persisted values.
* Browser Notification API missing, permission denied, permission revoked between drawer opens, Service Worker registration missing, and notification constructor throwing.
* Replay share token with invalid base64, wrong version, oversized event, all malformed entries, stale hash on refresh, and payload that redacts paths, prompts, commands, URLs, and tokens.
* Scan root outside `FACTIONOS_SCAN_ROOTS`, filesystem root, symlink target, no matching files, server offline, and response body that is not JSON.
* Export route returning `invalid_request`, network failure, missing headers, failed Blob read, failed anchor click, and large plain-text error body.

***

## 10. Dependencies

### External Libraries

* React 18.3.1: Existing web component framework.
* Zustand: Existing state store for settings and game state.
* Vitest 4.1.7, Testing Library, and happy-dom: Existing focused test harness.
* Express 4 and ws 8.21.0: Existing local server and WebSocket runtime.
* Biome 2.4.16: Existing formatting and linting tool.

### Internal Dependencies

* `apps/web/src/components/SettingsDrawer.tsx`
* `apps/web/src/components/ReplayPanel.tsx`
* `apps/web/src/store/useSettingsStore.ts`
* `apps/web/src/store/useGameStore.ts`
* `apps/web/src/lib/notifications.ts`
* `apps/web/src/lib/useNotifications.ts`
* `apps/web/src/lib/replayLink.ts`
* `apps/web/src/lib/exportSession.ts`
* `apps/server/src/routes/llm.ts`
* `apps/server/src/lib/llmPrivacy.ts`
* `apps/server/src/lib/codebaseWalker.ts`
* `apps/server/src/routes/export.ts`
* `apps/server/src/lib/exportSession.ts`
* `docs/api/README_api.md`
* `docs/privacy-and-security.md`

### Other Sessions

* **Depends on**: `phase02-session01-product-surface-requirements-reconciliation`, `phase02-session02-cockpit-shell-and-navigation-cohesion`, `phase02-session03-hero-and-mission-workflow-completion`, `phase02-session04-battlefield-state-and-interaction-polish`, `phase02-session05-battlefield-asset-and-public-demo-parity`
* **Depended by**: `phase02-session07-product-surface-validation-and-documentation-closeout`

***

## 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/phase02-session06-settings-replay-notifications-and-scan-ux/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.
