> 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/specs/phase24-session05-scrying-and-alert-focus/spec.md).

# Session Specification

**Session ID**: `phase24-session05-scrying-and-alert-focus` **Phase**: 24 - Legion II - Live Tier And Combat Playback **Status**: Not Started **Created**: 2026-07-08 **Base Commit**: `caf2ab1abefa4f6cb997a9ac4970600de9582957` **Package**: `apps/web` **Package Stack**: TypeScript

***

## 1. Session Overview

This session makes quiet live work legible on the `apps/web` battlefield. A hero with an active mission and no recent tool or mission event shifts into a scrying posture so silence reads as channeling instead of disconnect, stall, or empty state.

It also moves urgency into one visible alert-focus treatment. The board already computes `gameProjection.alertFocus` with the required priority ladder, and this session renders a single focus ring for that target instead of letting multiple urgent surfaces compete for attention.

This is next because Phase 24 sessions 03 and 04 have already shipped the live enemy and combat playback layers. Scrying and alert focus now sit above those surfaces without creating new projection state, protocol events, storage keys, audio behavior, or reward logic.

***

## 2. Objectives

1. Derive silent-but-active hero posture from current heroes, missions, event log activity, and the existing projection clock without adding persisted state.
2. Render scrying posture with a motion rune circle and a reduced-motion static channeling badge integrated into the battlefield hero state vocabulary.
3. Render exactly one urgency focus ring from `gameProjection.alertFocus` across flare, gate, siege, ram, skirmisher, and new-camp targets.
4. Prove threshold, clearing, focus priority, reduced-motion parity, and ten-event-free-minute calm behavior with focused tests.

***

## 3. Prerequisites

### Required Sessions

* [x] `phase24-session03-live-enemy-presentation` - provides live enemy markers, keep/siege anchors, reduced-motion live-tier conventions, and board layer ordering.

### Required Tools Or Knowledge

* React 19 component patterns in `apps/web/src/components/battlefield/Battlefield.tsx`.
* Zustand store selectors in `apps/web/src/store/useGameStore.ts`.
* Projection contracts in `apps/web/src/lib/gameProjection.ts`, especially `alertFocus` and `lastEventAt`.
* Existing board coordinate helpers in `apps/web/src/lib/battlefield2d.ts`, `apps/web/src/lib/liveLegion.ts`, and `apps/web/src/components/battlefield/CampLayer.tsx`.
* Vitest and React Testing Library patterns in `apps/web/tests/`.

### Environment Requirements

* Node 26.2.0+ and npm 11.16.0, matching `.spec_system/CONVENTIONS.md`.
* No hosted service, Cloudflare, provider, audio asset, or server credential is required.

***

## 4. Scope

### In Scope (MVP)

* Local cockpit viewer can tell that an active quiet hero is channeling - implemented as scrying posture derived from active mission presence and recent event activity.
* Local cockpit viewer sees one board urgency pulse at a time - implemented as a single `alertFocus` layer using the projection's existing priority ladder.
* Keyboard and screen-reader users receive product-facing scrying and alert summaries - implemented with bounded labels, static badges, and accessible layer text.
* Reduced-motion users receive equivalent state - implemented with static channeling and focus indicators instead of looping animation.
* Test authors can prove silence stays calm - implemented with deterministic helper tests and component tests simulating ten event-free minutes.

### Out Of Scope (Deferred)

* World cue audio and bark reuse - Reason: Session 06 owns audio routing, SFX manifests, and opt-in audio posture.
* Replay/mock/persistence boundary expansion - Reason: Session 07 owns broad honesty and persistence regression coverage.
* Generated Phase 3 asset catalog handoff - Reason: Session 08 owns direct generated-asset references.
* Alert-focus priority changes - Reason: `gameProjection.ts` already computes the priority ladder and this session renders it.
* New protocol events, server routes, storage keys, hosted state, rewards, XP, loot, banners, or trusted-erasure claims - Reason: Phase 24 guardrails explicitly exclude them.

***

## 5. Technical Approach

### Architecture

Add a pure helper module, `apps/web/src/lib/scryingAndAlertFocus.ts`, that derives two presentation models: scrying hero views and one alert focus target. The helper consumes existing browser state: heroes, missions, event log entries, `gameProjection.lastEventAt`, `gameProjection.alertFocus`, live Legion presentation, ranked camps, and board coordinates. It holds no timers, writes no projection state, and persists nothing.

Add a thin board layer, `apps/web/src/components/battlefield/ScryingAndAlertFocusLayer.tsx`, rendered from `Battlefield.tsx` with one shared clock value owned by `Battlefield`. The interval is cleaned up on unmount and no child layer creates per-target timers. The layer renders a rune-circle posture for silent active heroes and one focus ring for the resolved alert target. `Battlefield.tsx` also passes scrying state into `HeroToken` so the static channeling badge joins the existing state-badge treatment.

### Design Patterns

* Pure derivation first: keeps threshold, target lookup, safe labels, and clock edge cases testable without DOM state.
* Thin board layer: matches `CampLayer.tsx`, `LiveLegionLayer.tsx`, and `CombatPlaybackLayer.tsx` by rendering selector-fed presentation data only.
* Single projection authority: uses `gameProjection.alertFocus` and existing event data instead of adding a new game-state source.
* Reduced-motion twin in the same pass: every motion cue has a static equivalent in `apps/web/src/index.css` and component tests.

***

## 6. Deliverables

### Files To Create

| File                                                                | Purpose                                                                                                               | Est. Lines |
| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/lib/scryingAndAlertFocus.ts`                          | Pure scrying posture and alert-focus target derivation with named threshold constants.                                | \~190      |
| `apps/web/src/components/battlefield/ScryingAndAlertFocusLayer.tsx` | Board-internal layer for scrying rune circles, static channeling badges, single alert ring, and accessible summaries. | \~190      |
| `apps/web/tests/scryingAndAlertFocus.test.ts`                       | Focused helper tests for threshold, clearing, target resolution, fallback labels, and ten-minute silence.             | \~220      |

### Files To Modify

| File                                                  | Changes                                                                                                                                                    | Est. Lines |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `apps/web/src/components/battlefield/Battlefield.tsx` | Wire helper inputs, one shared clock, layer ordering, and HeroToken scrying badge/aria/data state.                                                         | \~120      |
| `apps/web/src/index.css`                              | Add rune circle, static channeling badge, single alert focus ring, reduced-motion styles, and any needed neutralization of competing urgency pulse styles. | \~150      |
| `apps/web/tests/Battlefield.test.tsx`                 | Add component coverage for scrying posture, alert ring target resolution, focus promotion, and silence behavior.                                           | \~180      |
| `apps/web/tests/BattlefieldInteraction.test.tsx`      | Add reduced-motion and accessible state coverage for channeling badges and single focus treatment.                                                         | \~90       |

***

## 7. Success Criteria

### Functional Requirements

* [ ] A hero with an active mission and no recent event past the named threshold renders as channeling/scrying in both animated and reduced-motion modes.
* [ ] A recent event for that hero clears the scrying posture before the threshold.
* [ ] Only one alert-focus element renders at a time from `gameProjection.alertFocus`.
* [ ] Clearing a higher-priority focus lets the next projection focus target render without component-local priority logic.
* [ ] Ten event-free minutes produce calm scrying posture with zero urgency signals when `alertFocus` is null.

### Testing Requirements

* [ ] Pure helper tests cover threshold edges, per-hero event matching, fallback activity timestamps, all alert focus target kinds, and safe bounded labels.
* [ ] Component tests cover animated and reduced-motion scrying, one alert ring, focus promotion, and no urgent pulse during calm silence.
* [ ] Focused Vitest targets pass.
* [ ] Web typecheck passes.

### Non-Functional Requirements

* [ ] No new protocol events, server routes, storage keys, hosted dependencies, reward systems, or trusted-erasure claims.
* [ ] No raw prompts, command output, file contents, provider payloads, secrets, or broad absolute paths are rendered in scrying or alert labels.
* [ ] The shared clock interval is cleaned up on unmount and no per-target timers are introduced.
* [ ] Board text and badges remain readable without overlap on existing desktop and mobile component fixtures.

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

* Per-hero silence can be derived in the web presentation layer: `Battlefield.tsx` already has heroes, missions, event log entries, and `gameProjection.lastEventAt`, while `GameProjection` stores global `lastEventAt` but no durable per-hero last-tool-event map. This is safe because scrying is presentation-only and does not persist, fold, or export state.
* Alert focus can be rendered as a coordinate-anchored overlay rather than by measuring DOM nodes. Existing camp, live Legion, and combat layers already use board percentage coordinates and named anchors; this keeps the focus layer deterministic and testable without layout measurement.

### Conflict Resolutions

* Session 03 required motion variants for live enemies, while Session 05 requires exactly one urgent pulse. Resolution: this session centralizes urgent pulsing in the alert-focus ring while preserving non-urgent state motion only when it has a reduced-motion static twin. Any existing live-tier animation that reads as urgency should be neutralized or converted so the focus ring is the only urgency pulse.

### Key Considerations

* The helper must use bounded, product-facing labels for alert targets and avoid exposing raw event details.
* The shared clock should tick only often enough to cross the scrying threshold and must not resize or shift the board.
* The layer should not block hero, camp, or wraith native button interactions.

### Potential Challenges

* Skirmisher focus refs may use raw projection keys while visible live Legion refs are sanitized: resolve via projection data or a helper-exported ref mapping instead of string guessing in the component.
* Gate focus may not have a visible dedicated DOM marker: map gate focus to the owning hero when the gate record has `heroId`, otherwise use the keep/gate anchor with product-facing copy.
* Existing active hero ring animation can visually compete with scrying: scope CSS so the channeling treatment is distinct and reduced-motion remains static.

### Relevant Considerations

* \[P23-apps/web] **Scanner camps are projection-owned**: The alert focus layer reads projection selectors and existing camp coordinates rather than adding camp state.
* \[P23-apps/web] **Presentation-only battlefield layers**: The new layer stays thin, native-control-compatible, reduced-motion-aware, and selector-fed.
* \[P22-apps/web] **Do not add parallel game authorities**: Scrying and focus presentation derive from existing store/projection state only.
* \[P07] **Redaction is boundary-specific**: Scrying and alert labels must stay bounded and product-facing.

### Behavioral Quality Focus

Checklist active: Yes Top behavioral risks for this session:

* Shared clock lifecycle could leak intervals or update after unmount.
* Alert focus rendering could accidentally show multiple urgent indicators or stale target labels.
* Reduced-motion mode could lose state equivalence if static channeling and focus indicators are not tested.

***

## 9. Testing Strategy

### Unit Tests

* `apps/web/tests/scryingAndAlertFocus.test.ts`: derive silent active heroes at the threshold, clear on recent events, ignore idle/dismissed/no-mission heroes, resolve all alert focus target kinds, bound labels, and keep ten-minute silence calm when no alert focus exists.

### Integration Tests

* `apps/web/tests/Battlefield.test.tsx`: render the full battlefield with active mission fixtures, event logs, camps, live Legion states, and projection alert focus to prove layer ordering and target mapping.
* `apps/web/tests/BattlefieldInteraction.test.tsx`: verify reduced-motion static badges, accessible names, and stable hero state badges.

### Runtime Verification

* Render `Battlefield` with an active quiet hero, with recent hero activity, and with each alert focus kind through component fixtures.
* Run focused Vitest targets, `npm --workspace apps/web run typecheck`, and root format check.

### Edge Cases

* No heroes, no active missions, missing mission ids, invalid event timestamps, stale hero ids, unknown focus refs, reduced-motion enabled, mobile-size board fixtures, and `alertFocus` null after ten event-free minutes.

***

## 10. Dependencies

### Other Sessions

* Depends on: `phase24-session03-live-enemy-presentation`.
* Depended by: `phase24-session08-generated-asset-implementation-handoff` and `phase24-session09-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/specs/phase24-session05-scrying-and-alert-focus/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.
