> 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/phase23-session06-battlefield-camp-layer/spec.md).

# Session Specification

**Session ID**: `phase23-session06-battlefield-camp-layer` **Phase**: 23 - Legion I - Scanner Camps **Status**: Not Started **Created**: 2026-07-05 **Base Commit**: 9bd52bab83a07b4ca415b0d864f8df491d9b1194 **Package**: apps/web **Package Stack**: TypeScript

***

## 1. Session Overview

This session renders the existing Phase 23 scanner camp aggregate on the `apps/web` battlefield. Camps come from the current `GameProjection` and the ranking selectors, then appear as accessible CSS-only markers below hero tokens and above the terrain clear surface.

It is next because Phase 23 Sessions 01-05 are complete: camp reconciliation, ranking, projection folding, persistence boundaries, and Quest Board camp focus callbacks are now available. Session 06 is the first phase step that turns that source-backed data into the primary battlefield experience.

The implementation stays presentation-focused. It must not add a protocol event, storage key, new server route, new art asset, combat playback, rewards, camp damage, achievements, hosted state, or trusted-erasure claim.

***

## 2. Objectives

1. Create a presentation-only `CampLayer` that renders ranked camps as native, keyboard-accessible controls with tier, HP, issue count, sector label, and stable sector-cell placement.
2. Integrate the camp layer into `Battlefield.tsx` without moving camp reconciliation, ranking, or Quest Board business logic into the board markup.
3. Wire camp inspection and dry Banish entry points to the existing Quest Board camp focus and Banish store actions from Session 05.
4. Prove camp readability, Champion Mode limits, z-order, empty-terrain clearing, reduced-motion parity, and entrenched-camp presentation in `Battlefield.test.tsx`.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase23-session02-ranking-and-presentation-selectors` - provides `rankVisibleLegionCamps`, roster limits, stable ordering, and entrenched presentation metadata.
* [x] `phase23-session03-projection-folding` - folds current scanner snapshots into `GameProjection.legion.camps` and `GameProjection.sectors`.
* [x] `phase23-session05-quest-board-camp-focus` - provides `focusQuestBoardCamp`, `clearQuestBoardCampFocus`, and `banishQuestBoardCamp` callbacks.
* [x] `phase22-session05-store-folding-and-selectors` - provides the web store projection selector pattern used by battlefield presentation.

### Required Tools Or Knowledge

* React 19, TypeScript, Tailwind utility conventions, and CSS in `apps/web/src/index.css`.
* Existing battlefield layering in `apps/web/src/components/battlefield/Battlefield.tsx`.
* Existing projection and camp types in `apps/web/src/lib/gameProjection.ts` and `apps/web/src/lib/legionCamps.ts`.
* Existing Quest Board camp focus store actions in `apps/web/src/store/useGameStore.ts`.
* Vitest and React Testing Library patterns in `apps/web/tests/Battlefield.test.tsx`.

### Environment Requirements

* Node 26.2.0 or newer and npm 11.16.0.
* Root workspace dependencies installed.
* Commands run from the repository root.

***

## 4. Scope

### In Scope (MVP)

* The battlefield reads ranked camps from the existing game projection and selector path in `apps/web`.
* `CampLayer` renders each camp as a native button with an accessible name that includes tier, HP, current issue count, and safe sector label.
* Camp markers use stable sector-cell placement and a consistent z-index band below hero tokens.
* Camp markers show compact HP and issue-count chips in normal and reduced-motion modes.
* Camp tier is legible by text and size treatment, not motion or color alone.
* Entrenched camps are muted or edge-placed while remaining focusable, inspectable, and honest about their current issues.
* One-hero and two-hero boards respect Champion Mode visible camp limits and avoid filling the board with the full camp census.
* Camp activation opens the existing focused Quest Board for that camp's real issue ids.
* Camp Banish uses the existing dry Banish path, with duplicate-trigger and rollback behavior owned by the Session 05 store action.
* The empty-terrain clear-selection affordance remains below camp controls and continues to work.
* Tests cover camp rendering, callbacks, ordering, Champion Mode, z-order, reduced-motion static equivalents, entrenched camp presentation, and non-occlusion-oriented layout attributes.

### Out Of Scope (Deferred)

* Dispatch Scouts ceremony, scan-not-run, failed-scan, mock-drill, and Golden Age battlefield states - Reason: Session 07 owns scan lifecycle and clean scanner state presentation.
* Live combat playback, camp damage, camp clearing animation, target flags, progress rewards, XP, loot, banners, achievements, kill credit, seasons, or dynamic audio - Reason: Phase 23 explicitly forbids these expansions.
* New art assets or required audio assets - Reason: Session 06 visual v1 is CSS-only.
* New protocol events, server routes, storage keys, hosted state, or trusted-erasure claims - Reason: existing `suggestion_update`, game projection, Quest Board actions, and browser-local persistence boundaries are sufficient.
* Rich issue titles, messages, prompts, file contents, raw scan payloads, or absolute paths in projection or camp marker state - Reason: Quest Board owns rich issue cards; camps store only aggregate ids and safe sector labels.

***

## 5. Technical Approach

### Architecture

Create `apps/web/src/components/battlefield/CampLayer.tsx` as a presentation component with explicit props:

```ts
interface CampLayerProps {
  camps: readonly RankedLegionCamp[];
  reduceMotion: boolean;
  onInspectCamp: (campId: string, issueIds: readonly string[]) => void;
  onBanishCamp: (campId: string, issueIds: readonly string[]) => void;
}
```

Keep the layer responsible for marker copy, placement, CSS custom properties, test ids, and input handling. It should not reconcile camps, mutate projection state, know about WebSocket events, or call network APIs directly.

In `Battlefield.tsx`, read `gameProjection`, `questSuggestions`, visible hero count, and Session 05 store actions. Use `rankVisibleLegionCamps` with `gameProjection.legion.camps`, `gameProjection.sectors`, the visible hero count, and current Quest Board issue data when available. Pass the resulting ranked camps into `CampLayer`.

Camp inspection should call `focusQuestBoardCamp` with `campId`, `issueIds`, safe sector label, and tier label. Camp Banish should first focus the camp so the user lands in the real Quest Board issue set, then call `banishQuestBoardCamp`; the store continues to own duplicate-trigger prevention, optimistic removal, rollback, and feedback.

Placement should be deterministic from `sector.cell`, using the existing 24-cell selector output. Entrenched camps should use `placement: "edge"` or muted metadata from `RankedLegionCamp` to choose quieter position and styling. The rendered layer should sit above the empty terrain button and below the hero token layer so heroes remain foreground actors.

### Design Patterns

* Presentation-only component: keep `CampLayer` reusable and testable through props.
* Selector-led rendering: use `rankVisibleLegionCamps` instead of inventing battlefield-local ordering.
* Same-instance Quest Board focus: open the existing focused Quest Board surface rather than duplicating issue cards.
* CSS-only markers: use existing palette tokens, labels, chips, and shapes instead of new art assets.
* Reduced-motion parity: provide static chips, labels, and tier treatment when motion is reduced.

***

## 6. Deliverables

### Files To Create

| File                                                | Purpose                                                                                             | Est. Lines |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/battlefield/CampLayer.tsx` | Presentation layer for ranked battlefield camp markers, placement, labels, callbacks, and test ids. | \~220      |

### Files To Modify

| File                                                  | Changes                                                                                                                                   | Est. Lines |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/battlefield/Battlefield.tsx` | Derive visible ranked camps from the existing projection and wire inspect/Banish callbacks into `CampLayer`.                              | \~60       |
| `apps/web/src/index.css`                              | Add camp marker, tier, entrenched, and reduced-motion styles.                                                                             | \~90       |
| `apps/web/tests/Battlefield.test.tsx`                 | Add focused battlefield camp rendering, callback, ordering, z-order, Champion Mode, reduced-motion, and entrenched presentation coverage. | \~180      |

***

## 7. Success Criteria

### Functional Requirements

* [ ] Ranked camps render on the battlefield only from current projection camp data.
* [ ] Each camp is a native, keyboard-accessible control with tier, HP, issue count, and safe sector label in its accessible name.
* [ ] Activating a camp opens the existing Quest Board camp focus for the real current issue ids.
* [ ] Dry Banish entry uses the existing Quest Board Banish action and does not create progress, rewards, camp damage, or projection side effects.
* [ ] Camps sit below hero tokens and do not disable empty-terrain clearing.
* [ ] Champion Mode limits the visible camps for one-hero and two-hero boards.
* [ ] Entrenched camps are quieter while remaining keyboard accessible and inspectable.
* [ ] Reduced-motion mode preserves complete static HP, issue, tier, and sector information.

### Testing Requirements

* [ ] `apps/web/tests/Battlefield.test.tsx` covers camp rendering, accessibility, callbacks, ordering, Champion Mode limits, z-order, empty-terrain clearing, reduced-motion static equivalents, and entrenched presentation.
* [ ] `npm test -- apps/web/tests/Battlefield.test.tsx` passes.
* [ ] `npm --workspace @factionos/web run typecheck` passes.
* [ ] `npm run format:check` passes or any unrelated pre-existing formatting issue is documented by implementation.

### Non-Functional Requirements

* [ ] No new protocol event, server route, storage key, hosted dependency, art asset, required audio asset, or trusted-erasure claim is introduced.
* [ ] Camp marker UI does not render raw issue messages, prompts, transcripts, terminal output, file contents, provider payloads, environment values, secrets, broad absolute paths, or diagnostics.
* [ ] Battlefield remains readable at common desktop and mobile board sizes.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] Primary user-facing surfaces contain product-facing copy only.

***

## 8. Implementation Notes

### Working Assumptions

* The missing `docs/ongoing-projects/war-effort-phase-2-legion-i-scanner-camps-session-plan.md` file is not required for this session because `.spec_system/PRD/phase_23/PRD_phase_23.md`, the Session 06 stub, and live source files provide complete planning inputs.
* The session package is `apps/web` because the analyzer selected the Session 06 stub package, the Phase 23 PRD scopes the feature to the web cockpit game layer, and every deliverable path is under `apps/web`.
* Golden Age-specific test ids are deferred to Session 07 because the Session 06 stub explicitly allows those hooks to be completed when that state owns the DOM.

### Conflict Resolutions

* The master PRD phase table still labels Phase 23 as `Not Started`, while the analyzer, phase-local PRD, and completed session records show Phase 23 is in progress with Sessions 01-05 complete. The analyzer and phase-local PRD win for workflow planning because they are current state and phase execution records.
* Session 06 requires battlefield Banish callbacks, but Session 05 owns the actual Banish mutation semantics. The chosen interpretation is that Session 06 provides the battlefield entry point and delegates duplicate prevention, rollback, and feedback to the existing store action.

### Key Considerations

* Keep `GameProjection` as the single derived game-state authority.
* Keep Quest Board as the rich issue inspection surface.
* Keep camp projection aggregate data narrow and browser-local.
* Keep replay, mock mode, and Banish progress-inert.
* Keep optional hosted, trusted-erasure, and production-hosted claims as no-claim boundaries.

### Potential Challenges

* Camp and hero occlusion: use stable sector-cell positions, muted/edge placement for entrenched camps, compact chips, and tests for layout attributes.
* Layering conflicts: assign camps one z-index band between empty terrain and hero tokens, leaving room for later effects layers.
* Overcrowding in large repositories: use Session 02 visible limits and Champion Mode roster metadata rather than rendering the full camp census.
* Store action coupling: keep callbacks narrow and delegate Quest Board focus and Banish behavior to existing store actions.

### Relevant Considerations

* \[P22-apps/web] **Game projection is the single derived authority**: the battlefield must read projection selectors instead of creating a parallel camp state source.
* \[P22-apps/web] **Derived projection storage is narrow**: camp rendering must not add storage keys or broaden persisted projection contents.
* \[P22-apps/web] **Do not add parallel game authorities**: `CampLayer` stays a presentation component, not a second source of camp truth.
* \[P22-apps/web] **Do not persist replay or drill progress**: camp interactions must not create durable rewards, kills, progress, or synthetic camp state.
* \[P18-apps/server] **Quest Board state is durable local evidence**: camp inspection and Banish must use existing issue ids and issue dismissal semantics without broadening erasure claims.
* \[P07] **Redaction is boundary-specific**: new UI and tests must avoid raw commands, terminal output, file contents, provider payloads, secrets, and broad paths.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Interactive camp controls must have accessible names, focus treatment, and keyboard activation that match pointer behavior.
* State-mutating Banish entry must rely on Session 05 duplicate-trigger prevention and rollback while it is in flight.
* Battlefield rendering must keep explicit empty, reduced-motion, and offline static equivalents without blank or motion-only meaning.

***

## 9. Testing Strategy

### Unit Tests

* Add `Battlefield.test.tsx` cases for ranked camp rendering, accessible names, HP and issue chips, tier labels, stable ordering, Champion Mode limits, entrenched camp attributes, and reduced-motion data attributes.

### Integration Tests

* Render `Battlefield` with seeded `gameProjection`, `questSuggestions`, and hero counts, then assert camp inspect activation calls the existing Quest Board focus action and dry Banish uses the existing Banish action path.

### Runtime Verification

* Run `npm test -- apps/web/tests/Battlefield.test.tsx`.
* Run `npm --workspace @factionos/web run typecheck`.
* Run `npm run format:check`.

### Edge Cases

* No camps render no camp controls and leave empty terrain behavior unchanged.
* One-hero and two-hero rosters show only the highest-priority visible camps.
* Entrenched camps remain focusable and inspectable even when muted.
* Reduced-motion mode removes motion-only treatment while preserving tier, HP, issue count, and sector copy.
* Camp ids or issue ids with stale Quest Board cards still inspect into the bounded issue id set without copying rich issue details into projection.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase23-session02-ranking-and-presentation-selectors`, `phase23-session03-projection-folding`, `phase23-session05-quest-board-camp-focus`
* Depended by: `phase23-session07-scanner-and-golden-age-states`, `phase23-session08-validation-and-documentation`

***

## Next Steps

Run the `implement` workflow step to begin 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/phase23-session06-battlefield-camp-layer/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.
