> 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-session02-hero-attention-reducer/spec.md).

# Session Specification

**Session ID**: `phase22-session02-hero-attention-reducer` **Phase**: 22 - Projection Foundation **Status**: Not Started **Created**: 2026-07-05 **Base Commit**: 2d9af05a53126c91bf0a54d2ae3d1d0ef6c8b1f1 **Package**: apps/web **Package Stack**: TypeScript

***

## 1. Session Overview

This session expands the new `apps/web/src/lib/gameProjection.ts` contract from a neutral shape and no-op reducer into the first real pure reducer slice. It covers hero lifecycle reconciliation, player-attention flares, gate attention from permission families, and the single deterministic `alertFocus` priority authority.

It is next because `phase22-session01-projection-contract` is complete and validated, and the Phase 22 session stubs make hero attention the first reducer slice before Legion enemies, camp links, store folding, persistence lifecycle, honesty regression tests, and erasure closeout. The work remains pure `apps/web` library and Vitest coverage only; it does not add rendering, audio, store wiring, localStorage scheduling, protocol events, or a second game state authority.

The output gives later store and UI sessions one projection-owned focus computation they can read without recomputing pulse priority from separate cockpit stores. Attention state stays aggregate-only and privacy-safe: it records ids, timestamps, and source families needed for deterministic focus promotion, not prompts, rationales, command text, raw details, terminal output, file contents, tokens, or broad paths.

***

## 2. Objectives

1. Implement a no-mutation `reduceGameProjection(state, event, ctx)` slice for hero lifecycle, flares, and gate attention.
2. Add narrow serializable attention refs so `recomputeAlertFocus(state)` can promote focus in the priority order `flare > gate > siege > ram > skirmisher > newCamp > null`.
3. Preserve earned hero aggregates across roster snapshots and dismissals without copying roster source-of-truth data into the projection.
4. Add reducer and parser tests proving purity, alert priority promotion, replay-safe swift-command behavior, gate clearing, and privacy-safe serialization.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase22-session01-projection-contract` - Provides `gameProjection.ts`, the v1 aggregate contract, persistence constants, storage guards, `recomputeAlertFocus`, and a no-op reducer shell.

### Required Tools Or Knowledge

* Node 26.2.0+ and npm 11.16.0 workspace toolchain.
* TypeScript and Vitest patterns from `apps/web/tests/gameProjection.test.ts`.
* Existing web store handling for `roster_update`, `internal_hero_spawn`, `hero_dismissed`, `permission_request`, `permission_response`, `guarded_action_update`, and `command_center_permission_update` in `apps/web/src/store/useGameStore.ts`.
* Protocol event contracts from `packages/protocol/src/events.ts`, `packages/protocol/src/guardedActions.ts`, and `packages/protocol/src/orchestrationCommandCenter.ts`.

### Environment Requirements

* Local workspace dependencies installed.
* No local server, provider credentials, Cloudflare credentials, hosted services, or browser runtime are required for this pure reducer session.

***

## 4. Scope

### In Scope (MVP)

* Web projection reducers need immutable event folding - implement typed switch handling in `apps/web/src/lib/gameProjection.ts` for the Session 02 event families with same-reference returns when state is unchanged.
* Future focus consumers need one projection-owned attention authority - add serializable flare and gate refs, update validation guards, and compute `alertFocus` from projection state rather than ad hoc UI stores.
* Hero attention needs aggregate-only lifecycle state - create or preserve projection hero records on `internal_hero_spawn`, reconcile `roster_update` hero presence without deleting earned aggregates, and keep dismissed heroes' earned projection fields intact.
* Player interruptions need deterministic flare semantics - fold `awaiting_input` and `input_received` into active flare refs, `flareCeremony`, and `swiftCommand` counters while blocking replay-mode accumulation.
* Permission and guarded-action gates need one priority tier - fold `permission_request`, `permission_response`, pending `guarded_action_update` proposals, and requested/in-flight `command_center_permission_update` entries into gate refs without storing raw rationale, detail, or expected-result text.
* Reducer tests need focused proof - extend `apps/web/tests/gameProjection.test.ts` for purity, hero preservation, alert priority promotion, flare clearing, gate clearing, replay-safe counters, parser compatibility, and serialization exclusions.

### Out Of Scope (Deferred)

* Store folding, selectors, `useGameStore.ts` integration, and persistence scheduling - Reason: Sessions 05 and 06 own store lifecycle, selectors, debounce, flush, and localStorage write timing.
* Legion enemy reducers for camps, skirmishers, ram, gremlins, wraiths, and siege - Reason: Session 03 owns enemy slices, though `recomputeAlertFocus` must already read existing neutral or test-seeded Legion fields.
* Camp links, pending camp accept hooks, HP, and mission binding - Reason: Session 04 owns camp-link boundaries.
* XP, levels, title grants, relics, essence income, building XP, War Tide gains/losses, council objectives, nemesis promotion, fog, territory changes, and Dawn Report diffs - Reason: later Phase 22 work or future game presentation phases own those mechanics.
* Rendering, battlefield UI, Quest Board UI, audio, toasts, hosted persistence, protocol changes, server routes, and any second game state authority - Reason: Phase 22 foundation explicitly excludes presentation and parallel authority.

***

## 5. Technical Approach

### Architecture

Keep all implementation in `apps/web/src/lib/gameProjection.ts` as pure TypeScript. Add a compact `attention` aggregate to `GameProjection` for active flare and gate refs, default it from `createInitialGameProjection`, validate it in `isGameProjection`, and preserve compatibility for Session 01 persisted shapes by adding a safe normalization path in `parsePersistedGameProjection`.

Implement reducer helpers around copy-on-write updates: normalize existing or new hero projection records, reconcile snapshots without deleting aggregate progress, update active flare/gate maps, run `recomputeAlertFocus` after recognized events, and return the original state reference when the recognized event produces no aggregate change. `ctx.now` remains the only clock input. `ctx.isReplaying` may reconcile active attention but must not increase ceremony or swift-command counters.

### Design Patterns

* Pure reducer module: Continue the Session 01 `apps/web/src/lib/gameProjection.ts` pattern and avoid React, Zustand, timers, DOM, audio, and network dependencies.
* Protocol-aligned event narrowing: Use declared `ServerEvent` variants from protocol packages and fail closed on unsupported or terminal states.
* Copy-on-write immutability: Return old references for ignored or unchanged inputs so store folding can later avoid unnecessary writes.
* Privacy-safe aggregate refs: Store request/proposal ids, source family, hero id when needed, and timestamps only; do not persist prompt text, rationale, command details, expected results, file contents, paths, or terminal output.

***

## 6. Deliverables

### Files To Create

| File | Purpose                                                           | Est. Lines |
| ---- | ----------------------------------------------------------------- | ---------- |
| None | This session expands existing projection contract and tests only. | 0          |

### Files To Modify

| File                                    | Changes                                                                                                                                                                                                                       | Est. Lines |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/gameProjection.ts`    | Add attention aggregate types/defaults/guards, immutable reducer helpers, hero lifecycle folding, flare and gate reducers, alert focus priority computation, replay-safe counter behavior, and persisted-shape normalization. | \~260      |
| `apps/web/tests/gameProjection.test.ts` | Add focused reducer, alert priority, flare, gate, replay, parser compatibility, and privacy serialization tests.                                                                                                              | \~280      |

***

## 7. Success Criteria

### Functional Requirements

* [ ] `reduceGameProjection` returns the original state reference for ignored events and for recognized events that do not change projection state.
* [ ] `internal_hero_spawn` creates a neutral projection hero with deterministic `quirkSeed`; `roster_update` reconciles hero presence without deleting earned aggregates; `hero_dismissed` does not remove earned aggregates.
* [ ] `awaiting_input` records one active flare per hero without storing prompt text and recomputes `alertFocus` to the highest-priority flare.
* [ ] `input_received` clears the matching flare, promotes the next eligible focus, and updates `swiftCommand.count` and `meanMs` only outside replay mode.
* [ ] `permission_request` and `permission_response` create and clear legacy gate refs without storing `rationale` or `detail`.
* [ ] `guarded_action_update` and `command_center_permission_update` reconcile pending/requested gate refs, clear terminal states, and ignore duplicate or stale terminal snapshots.
* [ ] `recomputeAlertFocus` produces exactly `flare > gate > siege > ram > skirmisher > newCamp > null` and is deterministic when multiple refs share a tier.
* [ ] Snapshot and replay handling cannot mint XP, essence, banners, kills, titles, War Tide progress, or other progress numbers.

### Testing Requirements

* [ ] `apps/web/tests/gameProjection.test.ts` covers reducer purity, same-reference unchanged returns, hero lifecycle preservation, flare creation and clearing, replay-safe swift-command behavior, gate source creation and clearing, alert priority promotion, parser compatibility, and privacy serialization exclusions.
* [ ] `npm test -- apps/web/tests/gameProjection.test.ts` passes.
* [ ] `npm --workspace @factionos/web run typecheck` passes.

### Non-Functional Requirements

* [ ] Projection JSON remains bounded and excludes raw prompts, permission rationale, command detail, expected result text, terminal output, file contents, provider payloads, tokens, secrets, broad absolute paths, replay entries, toasts, animation state, audio state, and copied roster source-of-truth data.
* [ ] The reducer is deterministic under fixed state, event, and `ctx.now`.
* [ ] The module remains side-effect free except for the existing storage helper functions from Session 01.

### Quality Gates

* [ ] All files ASCII-encoded.
* [ ] Unix LF line endings.
* [ ] Code follows project conventions.
* [ ] Primary user-facing surfaces are unchanged; this session adds no UI surface.

***

## 8. Implementation Notes

### Working Assumptions

* Package context is `apps/web`: The analyzer selected `apps/web` for the Session 02 stub, Phase 22 names `apps/web/src/lib/gameProjection.ts`, and `apps/web/README_web.md` defines `src/lib/` plus `tests/` as the right pure-helper and Vitest locations. Planning can proceed with a concrete package path.
* Session 02 is the next executable session: The analyzer reports `current_session: null`, `phase22-session01-projection-contract` appears in completed sessions, and Session 02 depends only on Session 01. Later Phase 22 stubs depend on reducer foundation and should not be selected first.
* Attention refs are projection aggregate state, not presentation state: The Session 02 stub explicitly allows persisted pending refs needed to promote lower-priority alerts, and the current v1 shape has no other place to retain active flare/gate ids. It is safe to proceed because store persistence is not wired yet and tests can enforce privacy-safe serialization.

### Conflict Resolutions

* Session 01 described a complete neutral v1 shape, while Session 02 requires persisted refs for alert promotion. The chosen interpretation is to keep `version: 1` but add a narrow `attention` aggregate with safe parse normalization for Session 01-shaped snapshots. This satisfies the Session 02 focus contract without introducing a protocol change or a second state authority.
* Permission event sources expose different state vocabularies across legacy permissions, guarded actions, and command-center permissions. The chosen interpretation is one gate tier with active states `permission_request`, guarded-action `pending`, and command-center `requested` or `in_flight`; approved, rejected, expired, stale, duplicate, cancelled, executed, failed, and unavailable states clear or no-op.

### Key Considerations

* `alertFocus` is derived from aggregate state and should not become an independent hand-maintained flag that can drift.
* Hero projection records should keep earned fields even when roster snapshots omit a hero or a hero is dismissed.
* Gate refs should be sufficient to focus attention and clear correctly, but not sufficient to reconstruct sensitive local permission content.
* `ctx.isReplaying` can clear stale attention during replay but must not increase counters or progress-like values.

### Potential Challenges

* Backward-compatible parsing: The exact-key guard from Session 01 must either accept and normalize the old shape or safely fall back without poisoning state.
* Deterministic ordering: Multiple active flares or gates need stable tie-break rules, such as oldest timestamp then id, so tests are not order-dependent.
* No-mutation proof: Nested record updates should be copy-on-write and tests should freeze or compare pre-event structures to catch mutation.

### Relevant Considerations

* \[P03] **Stable docs are the current contract**: Use `.spec_system/PRD/phase_22/PRD_phase_22.md`, package READMEs, and protocol types as current truth rather than archived source material.
* \[P18-apps/web] **Pure normalization before store mutation**: Normalize event and snapshot payloads before projection mutation so malformed or terminal entries cannot blank the aggregate.
* \[P20] **Broad privacy gates are release-critical**: Keep raw prompts, terminal output, file contents, provider payloads, broad paths, tokens, and secrets out of projection snapshots and tests.
* \[P08] **Full trusted erasure remains no-claim**: New browser-local projection refs do not imply erasure across archives, logs, backups, hosted surfaces, or workspace files.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Event snapshots could accidentally store sensitive permission or prompt detail in the projection.
* Replay could inflate ceremony or swift-command counters if accumulation and reconciliation are not separated.
* Alert focus could drift if `alertFocus` is manually patched instead of recomputed from active refs and Legion state.

***

## 9. Testing Strategy

### Unit Tests

* Test hero lifecycle creation, roster reconciliation, dismissal preservation, deterministic quirk seeds, and same-reference unchanged behavior.
* Test flare creation, duplicate flare no-op behavior, input clearing, promotion to the next focus, swift-command mean calculations, and replay-safe non-accumulation.
* Test legacy permission, guarded-action, and command-center permission gate creation and clearing across active and terminal states.
* Test `recomputeAlertFocus` priority using seeded flare, gate, siege, ram, skirmisher, and new-camp states.
* Test parser compatibility for Session 01-shaped projection JSON and serialization exclusions for prompt/rationale/detail strings.

### Integration Tests

* None for this session. Store folding, selectors, reset behavior, persistence lifecycle, and local erasure are later Phase 22 sessions.

### Runtime Verification

* Run `npm test -- apps/web/tests/gameProjection.test.ts`.
* Run `npm --workspace @factionos/web run typecheck`.
* Run ASCII and LF checks against `apps/web/src/lib/gameProjection.ts`, `apps/web/tests/gameProjection.test.ts`, and the session artifacts.

### Edge Cases

* Duplicate `awaiting_input` for the same hero, `input_received` without active flare, permission response without request, guarded-action snapshots with only terminal proposals, command-center snapshots with duplicate or stale states, replay mode clearing attention without accumulation, old persisted Session 01 shape, malformed persisted shape, and multiple same-priority refs with stable deterministic selection.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase22-session01-projection-contract`.
* Depended by: `phase22-session03-legion-enemy-reducer`, `phase22-session05-store-folding-and-selectors`, `phase22-session06-persistence-lifecycle`, `phase22-session07-honesty-regression-tests`, and `phase22-session08-erasure-docs-and-validation`.

***

## 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/phase22-session02-hero-attention-reducer/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.
