> 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_01_pure_camp_reconciliation.md).

# Session 01: Pure Camp Reconciliation

**Session ID**: `phase23-session01-pure-camp-reconciliation` **Package**: apps/web **Status**: Not Started **Estimated Tasks**: \~18 **Estimated Duration**: 2-4 hours

***

## Objective

Create the pure Legion camp reconciliation module that turns current scanner issues into safe, stable sectors and projection camp aggregates.

***

## Scope

### In Scope (MVP)

* Create `apps/web/src/lib/legionCamps.ts` as a pure module with no React, store, persistence, or server imports.
* Implement issue severity weights, sector derivation, camp grouping, tier thresholds, stable cells, entrenchment counters, and aggregate camp output.
* Add focused tests in `apps/web/tests/legionCamps.test.ts`.
* Keep projection output aggregate-only and safe for browser-local storage.

### Out of Scope

* Projection reducer wiring.
* Store persistence.
* Quest Board UI.
* Battlefield rendering.
* Rewards, camp damage, mission links, protocol changes, hosted state, or new storage keys.

***

## Detailed Requirements

* Use the existing projection fields:

  ```ts
  interface GameProjection {
    sectors: Record<SectorId, GameProjectionSector>;
    legion: {
      camps: Record<CampId, GameProjectionCamp>;
    };
  }

  interface GameProjectionSector {
    dirKey: string;
    cell: number;
    fogPct: number;
    lastTouchedAt: string;
  }

  interface GameProjectionCamp {
    hp: number;
    maxHp: number;
    issueIds: string[];
    tier: "camp" | "fort" | "citadel";
    entrenchedScans: number;
    scarredPct: number;
  }
  ```
* Implement this recommended API unless the existing codebase requires a small naming adjustment:

  ```ts
  export interface LegionCampReconcileInput {
    issues: readonly CodebaseIssue[];
    previousCamps: Record<CampId, GameProjectionCamp>;
    previousSectors: Record<SectorId, GameProjectionSector>;
    now: string;
  }

  export interface LegionCampReconcileResult {
    camps: Record<CampId, GameProjectionCamp>;
    sectors: Record<SectorId, GameProjectionSector>;
    newCampIds: string[];
    changedCampIds: string[];
  }

  export function reconcileLegionCamps(input: LegionCampReconcileInput): LegionCampReconcileResult;
  export function issueSeverityWeight(severity: CodebaseIssue["severity"]): number;
  export function rankVisibleLegionCamps(input: RankVisibleLegionCampsInput): RankedLegionCamp[];
  ```
* Derive a stable sector key from `CodebaseIssue.filePath` or the safest available relative file label.
* Use relative path segments only. Do not store absolute paths or raw local root prefixes in projection state.
* A sector represents a safe repository-relative directory, workspace group, or fallback bucket.
* Use top-level directories or workspace groups as the first pass.
* If the repository has too few sectors to make the board readable, split one directory level deeper where safe relative paths allow it.
* If the repository has too many sectors, group the long tail into a safe `Borderlands` bucket.
* Target a practical board budget of about 24 cells. This is a legibility target, not a protocol contract.
* Apply the fixed sector budget before creating camp ids.
* Sector ids must be stable across snapshots for the same safe sector key.
* Sector labels must be compact and relative, for example `apps/web`, `packages/protocol`, or `Borderlands`.
* Sector cells must be stable and derived from the sector id or key. Never use random runtime placement.
* Preserve an existing sector cell when the sector key is unchanged.
* A camp's dominant sector is the sector for all grouped issue ids; mixed or overflow groups use the sector bucket label.
* Group all issues with the same sector key into one camp.
* `campId` is the sector id.
* `issueIds` are sorted and unique.
* `hp` is the sum of severity weights for current issues:
  * `error = 3`
  * `warning = 2`
  * `info = 1`
* `maxHp` is at least `hp`; preserve a larger previous `maxHp` if a scarred camp is still present.
* Tier thresholds are constants in the pure module:
  * `camp`: 1-5 HP
  * `fort`: 6-14 HP
  * `citadel`: 15+ HP
* `entrenchedScans` increments when the same camp appears in consecutive scan snapshots with the same `issueIds` and same `hp`.
* `entrenchedScans` resets to `0` when issue membership or HP changes.
* Entrenchment threshold must be a named constant in the pure module. It is used only for ranking or muted/edge presentation in this phase; it must not create bosses, rewards, Dawn Report mentions, or new enemy logic.
* `scarredPct` is preserved when the camp persists and defaults to `0` for new camps. This phase does not increase scar progress.
* If the scanner provides issue timestamps, selectors should expose the newest issue timestamp for ranking. If not, use the snapshot time supplied by the reducer.
* Camps absent from the newest scanner snapshot are removed.
* Empty issue snapshots return no camps and preserve no stale camp ids.
* Presentation selectors may mark a camp as muted or entrenched, but the source of truth remains `entrenchedScans`.
* The projection remains aggregates-only. It must not persist raw issue messages, prompts, event bodies, replay entries, terminal output, provider payloads, file contents, or absolute paths.

***

## Required Tests

* `apps/web/tests/legionCamps.test.ts`
  * severity weights
  * sector coalescing
  * small-repo deeper splitting
  * large-repo `Borderlands` grouping
  * relative label sanitization
  * stable ordering
  * stable cell assignment
  * tier thresholds
  * entrenchment increment/reset
  * entrenched presentation selector
  * clean snapshot result

***

## Prerequisites

* [ ] Phase 22 projection shapes are present in `gameProjection.ts`.
* [ ] Existing `CodebaseIssue` shape exposes stable issue ids, severity, and a safe path or label source.

***

## Deliverables

1. `apps/web/src/lib/legionCamps.ts`.
2. `apps/web/tests/legionCamps.test.ts`.
3. Pure reconciliation output for later projection folding.

***

## Dependencies / Notes

* None.
* The phase may update `lastEventAt` and `alertFocus` when camp reconciliation changes projection state, but that reducer decision belongs to Session 03.
* Store persistence, Quest Board UI, and battlefield rendering are out of scope.

***

## Success Criteria

* [ ] Scanner issue snapshots produce camps with expected HP, tier, sector label, stable cell, and sorted unique issue ids.
* [ ] Repeated identical snapshots increment entrenchment, changed membership or HP resets it, and removed issues remove camps.
* [ ] Tiny and large repositories coalesce into readable bounded sectors, including safe `Borderlands` grouping when needed.
* [ ] Empty snapshots return no camps and no stale camp ids.
* [ ] Projection-shaped output does not copy raw issue messages, prompts, terminal output, file contents, absolute paths, environment values, or secrets.
* [ ] A scanner issue snapshot with multiple severities produces camps with the expected HP, tier, sector label, cell, and issue id list.
* [ ] Large issue sets coalesce into bounded sectors rather than one camp per issue.


---

# 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_01_pure_camp_reconciliation.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.
