> 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_23/session_03_projection_folding.md).

# Session 03: Projection Folding

**Session ID**: `phase23-session03-projection-folding` **Package**: apps/web **Status**: Not Started **Estimated Tasks**: \~20 **Estimated Duration**: 2-4 hours

***

## Objective

Replace the `suggestion_update` camp no-op with honest camp reconciliation inside the existing `GameProjection` reducer path.

***

## Scope

### In Scope (MVP)

* Update `apps/web/src/lib/gameProjection.ts`.
* Wire `suggestion_update` snapshots into `reconcileLegionCamps`.
* Keep scanner camp state snapshot-owned and aggregate-only.
* Recompute `alertFocus` and `lastEventAt` only when reconciliation changes projection state.
* Extend `apps/web/tests/gameProjection.test.ts` for reducer, replay, alert focus, and field-isolation behavior.

### Out of Scope

* Store persistence assertions.
* Quest Board dismissal and inspection UI.
* Camp links, pending links, mission links, camp damage, XP, loot, banners, achievements, or new protocol fields.

***

## Detailed Requirements

* Scanner findings become camps:
  * Every active `CodebaseIssue` is grouped into one sector Blight camp.
  * A camp represents one or more real issue ids.
  * A camp disappears only when its underlying issues disappear from the scanner snapshot or are dismissed through the Quest Board path.
  * Daily, manual, or triggered scanner snapshots may all feed the same reconciliation path.
  * The camp census is always snapshot-owned.
* Replace the current `suggestion_update` camp no-op with scanner camp reconciliation.
* Keep `suggestion_update` as reconciliation, not accumulation:
  * no XP
  * no loot
  * no banners
  * no achievements
  * no camp damage
  * no mission links
* If `ctx.isReplaying` is true, do not reconcile camps from replayed `suggestion_update` events.
* Normal server hydration snapshots after boot may still reconcile through the non-replay path.
* If `ctx.mockEnabled` is true, allow in-memory camp folding for spectacle, but rely on the existing persistence guard so mock camps are not persisted.
* Recompute `alertFocus` after camp changes.
* Set `lastEventAt` only when reconciliation changes projection state.
* Preserve existing camp-link behavior. This phase does not bind missions to camps.
* Do not write `pendingLinks` or `campLinks` from camp clicks, Banish, or scanner snapshots.
* Treat a new or expanded camp as `alertFocus.kind = "newCamp"` only when no higher-priority attention item is active.
* Alert focus priority stays:
  1. flare
  2. gate
  3. siege
  4. ram
  5. skirmisher
  6. new camp
* All other projection fields remain unchanged during camp reconciliation.
* Do not store raw issue messages, suggested prompts, mission prompts, transcripts, replay entries, event bodies, terminal output, provider payloads, file contents, absolute paths, environment values, or secrets in projection state.

***

## Required Tests

* `apps/web/tests/gameProjection.test.ts`
  * a `suggestion_update` with three issues in two sectors creates two camps
  * HP uses `error = 3`, `warning = 2`, `info = 1`
  * tiers change at the defined thresholds
  * sector ids, labels, and cells are stable across identical snapshots
  * large issue sets coalesce into bounded sectors rather than one camp per issue
  * repeated identical snapshots increment `entrenchedScans`
  * changed issue membership resets `entrenchedScans`
  * removed issues remove camps
  * replay snapshots do not mutate camps
  * mock-enabled snapshots mutate in memory but do not persist through the store
  * no XP/loot/banner/achievement mutation
  * no pending link or camp link mutation
  * new camps do not steal alert focus from flares, gates, siege, rams, or skirmishers
  * no unrelated projection fields change during camp reconciliation

***

## Prerequisites

* [ ] Session 01 reconciliation behavior is implemented and tested.

***

## Deliverables

1. Reducer integration in `gameProjection.ts`.
2. Expanded `apps/web/tests/gameProjection.test.ts` coverage for scanner camp reconciliation.

***

## Dependencies / Notes

* Depends on Session 01 reconciliation behavior.
* Store persistence assertions belong to Session 04.
* Quest Board dismissal and inspection behavior belongs to Session 05.

***

## Success Criteria

* [ ] Real scanner snapshots with codebase issues create projection camps in the normal event flow.
* [ ] Replay snapshots do not mutate camps.
* [ ] Mock-enabled snapshots can fold in memory without implying persisted progress.
* [ ] New camps do not steal alert focus from higher-priority flares, gates, siege, rams, or skirmishers.
* [ ] No reward, mission-link, pending-link, camp-link, or unrelated projection fields change during camp reconciliation.
* [ ] `alertFocus.kind = "newCamp"` appears only when no higher-priority focus is active.


---

# 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_23/session_03_projection_folding.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.
