> 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/phase22-session01-projection-contract/implementation-notes.md).

# Implementation Notes

**Session ID**: `phase22-session01-projection-contract` **Package**: apps/web **Started**: 2026-07-04 23:53 **Last Updated**: 2026-07-05 00:47

***

## Session Progress

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

***

### Task T019 - Run type and encoding validation

**Started**: 2026-07-05 00:43 **Completed**: 2026-07-05 00:47 **Duration**: 4 minutes

**Notes**:

* Ran the required web package typecheck and ASCII/LF checks for the new module and test file.
* Biome initially reported formatting-only changes in `gameProjection.ts`; applied `biome format --write` and reran all final checks.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Formatted with Biome after validation surfaced style-only changes.
* `apps/web/tests/gameProjection.test.ts` - Confirmed formatted with Biome.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T019 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T019 and completion checklist complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection validation still passes after formatting.
  * Evidence: 1 test file passed; 10 tests passed.
* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Web package TypeScript build passes.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `if LC_ALL=C grep -nP '[^\\x00-\\x7F]' apps/web/src/lib/gameProjection.ts apps/web/tests/gameProjection.test.ts; then exit 1; else printf 'ASCII PASS\\n'; fi`
  * Result: PASS - New code and test files are ASCII-only.
  * Evidence: Command printed `ASCII PASS`.
* Command/check: `if rg -nU $'\\r' apps/web/src/lib/gameProjection.ts apps/web/tests/gameProjection.test.ts; then exit 1; else printf 'LF PASS\\n'; fi`
  * Result: PASS - New code and test files use LF line endings.
  * Evidence: Command printed `LF PASS`.
* Command/check: `npm exec -- biome check apps/web/src/lib/gameProjection.ts apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Changed code and test files pass Biome check.
  * Evidence: Biome checked 2 files with no fixes applied.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T018 - Run focused automated validation

**Started**: 2026-07-05 00:41 **Completed**: 2026-07-05 00:42 **Duration**: 1 minute

**Notes**:

* Ran the exact focused validation command required by the session checklist.

**Files Changed**:

* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T018 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T018 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection validation passed.
  * Evidence: 1 test file passed; 10 tests passed.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T017 - Test persistence guards and reducer no-op behavior

**Started**: 2026-07-05 00:37 **Completed**: 2026-07-05 00:40 **Duration**: 3 minutes

**Notes**:

* Added `shouldPersistGameProjection` tests for real, replaying, mock-enabled, and replay-plus-mock contexts.
* Added reducer same-reference tests for `connected` and unknown event inputs.
* Completed checkpoint: focused tests and package typecheck pass; success criteria reread shows no scope drift.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added persistence guard and reducer no-op behavior tests.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T017 evidence and checkpoint.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T017 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection test file passes after adding T017 coverage.
  * Evidence: 1 test file passed; 10 tests passed.
* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Web package TypeScript build remains clean after test additions.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `sed -n '90,150p' .spec_system/specs/phase22-session01-projection-contract/spec.md`
  * Result: PASS - Success criteria reread confirms implementation remains on Session 01 scope.
  * Evidence: Criteria map to the new module and focused tests only.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Trust boundary enforcement: Tests prove replay and mock/drill contexts cannot request persistence (`apps/web/tests/gameProjection.test.ts`).
* Contract alignment: Tests prove reducer same-reference behavior for `connected` and unknown inputs (`apps/web/tests/gameProjection.test.ts`).

***

### Task T016 - Test serialization exclusions

**Started**: 2026-07-05 00:34 **Completed**: 2026-07-05 00:36 **Duration**: 2 minutes

**Notes**:

* Added serialization-boundary coverage for copied source-of-truth fields, presentation transients, replay buffers, raw prompts, broad paths, terminal output, file contents, provider payloads, tokens, and secrets.
* Test asserts both root key absence and representative sensitive snippets absent from projection JSON.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added serialization-boundary test.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T016 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T016 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection test file passes after adding T016 coverage.
  * Evidence: 1 test file passed; 8 tests passed.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Error information boundaries: Tests assert projection JSON excludes raw prompts, broad paths, terminal output, provider payloads, tokens, and secrets (`apps/web/tests/gameProjection.test.ts`).

***

### Task T015 - Test persistence helpers

**Started**: 2026-07-05 00:30 **Completed**: 2026-07-05 00:33 **Duration**: 3 minutes

**Notes**:

* Added persistence round-trip coverage for valid projection snapshots.
* Added fallback coverage for null storage, missing keys, throwing `getItem`, throwing `setItem`, and circular JSON stringify failure.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added load/persist helper tests.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T015 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T015 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection test file passes after adding T015 coverage.
  * Evidence: 1 test file passed; 7 tests passed.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Failure path completeness: Tests prove load/persist failure paths do not throw on unreliable storage or serialization (`apps/web/tests/gameProjection.test.ts`).

***

### Task T014 - Test parser fallback inputs

**Started**: 2026-07-05 00:27 **Completed**: 2026-07-05 00:29 **Duration**: 2 minutes

**Notes**:

* Added parser fallback cases for null, undefined, malformed JSON, non-object JSON, wrong version, missing root fields, extra top-level source-of-truth fields, and unsafe nested counters.
* Assertions verify each case returns the deterministic fresh projection for the supplied timestamp.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added parser fallback tests.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T014 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T014 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection test file passes after adding T014 coverage.
  * Evidence: 1 test file passed; 3 tests passed.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Trust boundary enforcement: Tests prove unsafe persisted roots and nested counters are rejected (`apps/web/tests/gameProjection.test.ts`).

***

### Task T013 - Test initial projection shape and determinism

**Started**: 2026-07-05 00:24 **Completed**: 2026-07-05 00:26 **Duration**: 2 minutes

**Notes**:

* Added Vitest coverage for the complete neutral v1 root shape.
* Covered empty records, zeroed counters, null focus fields, injected timestamps, and deterministic `season:YYYY-MM-DD` ids.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added initial-shape and deterministic timestamp tests.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T013 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T013 complete.

**Verification**:

* Command/check: `npm test -- apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Focused projection test file passes after adding T013 coverage.
  * Evidence: 1 test file passed; 2 tests passed.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T012 - Implement persistence guard helper

**Started**: 2026-07-05 00:20 **Completed**: 2026-07-05 00:23 **Duration**: 3 minutes

**Notes**:

* Added `shouldPersistGameProjection(ctx)`.
* Guard returns false for replay and mock/drill contexts and true only for real non-replay projection writes.
* Completed a checkpoint after module implementation tasks; next task is T013.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added persistence guard helper.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T012 evidence and checkpoint.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T012 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Module implementation compiles after adding persistence guard.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "shouldPersistGameProjection|isReplaying|mockEnabled" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Guard denies replaying and mock-enabled contexts.
  * Evidence: Search found `return !ctx.isReplaying && !ctx.mockEnabled`.
* Command/check: `sed -n '20,140p' .spec_system/specs/phase22-session01-projection-contract/spec.md`
  * Result: PASS - Re-read objectives, scope, and success criteria; no scope drift found.
  * Evidence: Work remains limited to `gameProjection.ts` and `gameProjection.test.ts`.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Trust boundary enforcement: Persist writes are blocked during replay and mock/drill contexts (`apps/web/src/lib/gameProjection.ts`).

***

### Task T011 - Implement persist projection helper

**Started**: 2026-07-05 00:18 **Completed**: 2026-07-05 00:20 **Duration**: 2 minutes

**Notes**:

* Added `persistGameProjection(state, storage?)`.
* Uses the same guarded storage resolver as load.
* Swallows null storage, unavailable storage, quota-style `setItem` failures, and `JSON.stringify` failures.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added persist helper.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T011 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T011 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Persist helper compiles under web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "persistGameProjection|setItem\\(GAME_PROJECTION_STORAGE_KEY|JSON.stringify\\(state\\)" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Persist helper writes JSON to the versioned projection key.
  * Evidence: Search found the helper, `setItem`, and serialization path.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Failure path completeness: Storage and serialization failures are caught at the persistence boundary (`apps/web/src/lib/gameProjection.ts`).

***

### Task T010 - Implement load persisted projection helper

**Started**: 2026-07-05 00:16 **Completed**: 2026-07-05 00:18 **Duration**: 2 minutes

**Notes**:

* Added storage resolution that uses an explicit dependency when supplied and safely falls back to `window.localStorage` only when available.
* Added `loadPersistedGameProjection(storage?, now?)` with null-storage and throwing-storage fallback to a fresh projection.
* Kept storage reads synchronous and side-effect-free beyond the provided storage object.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added storage resolver and load helper.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T010 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T010 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Load helper compiles under web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "resolveProjectionStorage|loadPersistedGameProjection|getItem\\(GAME_PROJECTION_STORAGE_KEY\\)|window.localStorage" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Load helper uses guarded storage resolution, the projection key, and parser fallback.
  * Evidence: Search found storage resolver and guarded `getItem` path.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Failure path completeness: Unavailable or throwing storage returns a fresh projection instead of throwing (`apps/web/src/lib/gameProjection.ts`).

***

### Task T009 - Implement persisted projection parser

**Started**: 2026-07-05 00:14 **Completed**: 2026-07-05 00:16 **Duration**: 2 minutes

**Notes**:

* Added `parsePersistedGameProjection(input, now?)`.
* Parser accepts direct validated objects or JSON strings and returns a fresh neutral projection for null, undefined, malformed JSON, wrong version, or unsafe shape.
* Fixed a TypeScript inference issue by keeping the parser candidate explicitly `unknown`.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added defensive persisted parser.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T009 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T009 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Parser compiles under web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "parsePersistedGameProjection|JSON.parse|isGameProjection|createInitialGameProjection\\(now\\)" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Parser has explicit JSON parsing, guard acceptance, and fresh fallback branches.
  * Evidence: Search found parser, `JSON.parse`, `isGameProjection`, and fallback calls.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Failure path completeness: Malformed JSON and unsafe persisted input return a controlled fresh projection instead of throwing (`apps/web/src/lib/gameProjection.ts`).

***

### Task T008 - Add projection test builders

**Started**: 2026-07-05 00:12 **Completed**: 2026-07-05 00:13 **Duration**: 1 minute

**Notes**:

* Created the focused projection test file.
* Added fixed timestamp constants, in-memory storage, throwing storage, and representative connected/unknown `ServerEvent` builders.
* Deferred assertions to the dedicated testing tasks.

**Files Changed**:

* `apps/web/tests/gameProjection.test.ts` - Added reusable builders for later projection tests.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T008 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T008 complete.

**Verification**:

* Command/check: `sed -n '1,180p' apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Test builder file contains fixed timestamps, storage doubles, and event fixtures.
  * Evidence: Inspected file content directly.
* Command/check: `rg -n "FIXED_NOW|LATER_NOW|MemoryStorage|ThrowingStorage|makeConnectedEvent|makeUnknownEvent" apps/web/tests/gameProjection.test.ts`
  * Result: PASS - Required builder symbols are present.
  * Evidence: Search found the fixed times, storage doubles, and event builders.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T007 - Define persisted v1 runtime guards

**Started**: 2026-07-05 00:05 **Completed**: 2026-07-05 00:11 **Duration**: 6 minutes

**Notes**:

* Added strict runtime guards for the persisted v1 aggregate root and every nested projection area.
* Guards reject wrong versions, malformed records, invalid enum values, unsafe counters, wrong array contents, and extra top-level source-of-truth fields.
* Fixed a TypeScript narrowing issue in the `essence.burst` guard before marking the task complete.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added root and nested persisted-shape guards.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T007 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T007 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Runtime guards compile after fixing the local `essence.burst` narrowing issue.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "function is(GameProjection|Legion|Essence|Buildings|AlertFocus|PendingLink)|GAME_PROJECTION_ROOT_KEYS" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Guard coverage exists for root state and representative nested trust-boundary shapes.
  * Evidence: Search found root-key allowlist plus root, legion, pending-link, essence, buildings, and alert-focus guards.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

**BQC Fixes**:

* Trust boundary enforcement: Added explicit schema-style guards before persisted data can be accepted (`apps/web/src/lib/gameProjection.ts`).

***

### Task T006 - Implement no-op reducer shell

**Started**: 2026-07-05 00:04 **Completed**: 2026-07-05 00:05 **Duration**: 1 minute

**Notes**:

* Added `reduceGameProjection` as a pure same-reference shell for Session 01.
* Added `recomputeAlertFocus` as the stable alert-focus API, returning the current focus until later reducer sessions own attention mutation.
* Avoided broad event folding, storage, timers, UI side effects, and mutation.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added no-op reducer and alert-focus API shell.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T006 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T006 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Reducer shell compiles under web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `sed -n '300,360p' apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Reducer ignores event/context and returns the original `state` reference.
  * Evidence: Inspected `reduceGameProjection` body.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T005 - Implement initial projection factory

**Started**: 2026-07-05 00:01 **Completed**: 2026-07-05 00:03 **Duration**: 2 minutes

**Notes**:

* Added `createInitialGameProjection(now?)`.
* Returned every required v1 root field with neutral records, arrays, counters, null focus fields, and injected-time fields.
* Kept the factory pure with no timers beyond the default timestamp fallback when no `now` is supplied.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added public initial projection factory.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T005 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T005 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Factory compiles under web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `sed -n '260,330p' apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Factory returns all required root keys with neutral nested values.
  * Evidence: Inspected `version`, `sectors`, `legion`, `pendingLinks`, `campLinks`, `heroes`, `essence`, `buildings`, `warTide`, `council`, `nemeses`, `alertFocus`, `season`, `flareCeremony`, and `lastEventAt`.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T004 - Implement deterministic factory helpers

**Started**: 2026-07-04 23:59 **Completed**: 2026-07-05 00:01 **Duration**: 2 minutes

**Notes**:

* Added timestamp normalization and deterministic `season:YYYY-MM-DD` id derivation.
* Added fresh neutral nested-state factories for legion, essence burst windows, buildings, War Tide, season, and flare ceremony.
* Ensured helper factories return new objects instead of shared nested records.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added deterministic timestamp and neutral nested-state helpers.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T004 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T004 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Helper additions compile under the web package TypeScript config.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `rg -n "resolveProjectionTimestamp|seasonIdForTimestamp|createNeutral(Legion|Essence|Buildings|WarTide|Season|FlareCeremony)" apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Required helper set exists in the module.
  * Evidence: Search found timestamp, season, legion, essence, buildings, War Tide, season, and flare ceremony helpers.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T003 - Define serializable projection contract

**Started**: 2026-07-04 23:57 **Completed**: 2026-07-04 23:59 **Duration**: 2 minutes

**Notes**:

* Added public aliases for sector, camp, hero, mission, building, essence, camp tier, council objective, alert focus, and nemesis identities.
* Added nested serializable interfaces for sectors, legion, links, heroes, essence, buildings, War Tide, council, nemeses, alert focus, season, flare ceremony, and the v1 root state.
* Updated the reducer type alias to accept and return `GameProjection`.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Added the serializable v1 projection type contract.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T003 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T003 complete.

**Verification**:

* Command/check: `npm --workspace @factionos/web run typecheck`
  * Result: PASS - Web package TypeScript build accepts the new type contract.
  * Evidence: `tsc -b --noEmit` exited 0.
* Command/check: `sed -n '1,220p' apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Root and nested interfaces match the Session 01 PRD shape.
  * Evidence: Inspected exported types for all required aggregate areas.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T002 - Create projection module scaffold

**Started**: 2026-07-04 23:55 **Completed**: 2026-07-04 23:56 **Duration**: 1 minute

**Notes**:

* Added the new pure projection module under `apps/web/src/lib`.
* Exported v1 version, storage key, persistence cadence constants, reducer context, persistence context, and an initial reducer type.
* Kept imports limited to type-only `ServerEvent` from `@factionos/protocol`.

**Files Changed**:

* `apps/web/src/lib/gameProjection.ts` - Created scaffold with constants, contexts, and type-only protocol import.
* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added T002 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T002 complete.

**Verification**:

* Command/check: `sed -n '1,120p' apps/web/src/lib/gameProjection.ts`
  * Result: PASS - Scaffold contains only the intended constants, contexts, and type-only protocol import.
  * Evidence: Inspected file content directly.
* Command/check: `rg -n "from \"(react|zustand|\\.\\./store|@/store|.*components|.*audio|.*backgroundMusic)\"" apps/web/src/lib/gameProjection.ts || true`
  * Result: PASS - No UI, store, React, Zustand, or audio imports found.
  * Evidence: Search returned no matches.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

### Task T001 - Verify Session 01 scope

**Started**: 2026-07-04 23:53 **Completed**: 2026-07-04 23:54 **Duration**: 1 minute

**Notes**:

* Confirmed Session 01 is limited to `apps/web/src/lib/gameProjection.ts` and `apps/web/tests/gameProjection.test.ts`.
* Confirmed store wiring, erasure inventory updates, UI rendering, audio, hosted persistence, broad reducer slices, and protocol changes are out of scope for this session.
* Confirmed Phase 22 and the stub both require a pure versioned projection contract with defensive storage helpers and tests.

**Files Changed**:

* `.spec_system/specs/phase22-session01-projection-contract/implementation-notes.md` - Added session progress and T001 evidence.
* `.spec_system/specs/phase22-session01-projection-contract/tasks.md` - Marked T001 complete.

**Verification**:

* Command/check: `sed -n '1,260p' .spec_system/PRD/phase_22/PRD_phase_22.md && sed -n '261,620p' .spec_system/PRD/phase_22/PRD_phase_22.md`
  * Result: PASS - Phase PRD confirms projection foundation scope, no rendering, and no second game authority.
  * Evidence: Inspected Phase Scope, `GameProjection` shape, Public API, Persistence And Honesty, and Session 01 implementation surface.
* Command/check: `sed -n '1,260p' .spec_system/PRD/phase_22/session_01_projection_contract.md`
  * Result: PASS - Session stub confirms no dependencies and same deliverables.
  * Evidence: Stub in-scope list matches the active session spec.
* UI product-surface check: N/A - Task changed no user-facing surface.
* UI craft check: N/A - Task changed no UI.

***

## Task Log

### 2026-07-04 - Session Start

**Environment verified**:

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

**Notes**:

* Resolved package context from `spec.md` as `apps/web`.
* Re-ran tool checks under pinned Node 26.2.0 with workspace-local binaries on PATH.

**Verification**:

* Command/check: `bash .spec_system/scripts/analyze-project.sh --json`
  * Result: PASS - Current session is `phase22-session01-projection-contract`; session directory exists.
  * Evidence: Script reported monorepo `true`, package candidates, and `current_session_files` containing `spec.md` and `tasks.md`.
* Command/check: `bash .spec_system/scripts/check-prereqs.sh --json --env --package apps/web`
  * Result: PASS - Spec system, jq, git, workspace manifest, and package directory are available.
  * Evidence: Overall status `pass` with no issues.
* Command/check: `. "$NVM_DIR/nvm.sh" && nvm use 26.2.0 >/dev/null && PATH="$PWD/node_modules/.bin:$PATH" && bash .spec_system/scripts/check-prereqs.sh --json --tools "node,npm,tsc,vitest"`
  * Result: PASS - Required toolchain is available.
  * Evidence: Node v26.2.0, npm 11.16.0, TypeScript 6.0.3, and Vitest 4.1.8.

***


---

# 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/phase22-session01-projection-contract/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.
