# LANE-FLOOR2 — Floor completion & aggro physiology (Phase 3, parallel)

**Executor:** Opus 4.8. **Branch:** `lane/floor2` (from main after Phase 2).
**Owns:** `src/scenes/floor/`, `src/data/strings/floor.ts`, tests. **Prereq
reading:** CLAUDE.md → `docs/GAME_DESIGN.md` §3.2 → Phase-2 REVIEW block in
`LANEHANDOVER.md`.

## Phase-2 reality (read before coding)
- `FloorDemoScene` now runs in TWO modes: standalone `'FloorDemo'` (key F,
  unchanged) and night mode `'Floor'` (launched by NightScene with a
  `NightContext`; see `bindNight()`). Night mode: shared bus/clock/state, fed by
  real door admissions (`door:verdict` → delayed `crowd.spawn`), `MeterHud` for
  HUD, exit via E at the entry anchor, sim keeps running while the player is at
  the door (`present === false` path in `update()`).
- Incidents flow through `incident:log` (single writer in core/meters).
- `NightContext.sfx` exists (SFX handle, always crisp past the location filter).
- Kayden's unstamped admits (1 in 7) are your `noStamp` supply in night mode.

## Deliverables (in priority order)

### 1. Fight brewing (design §3.2 — the last missing v0.2 infraction)
Two agents in escalating shove animation (crowd sim picks pairs with rising
aggro contribution when they collide repeatedly). A swing timer (~8s from first
shove): player must physically walk BETWEEN them before it ends. Interposed =
defused (+vibe, both marked handled); missed = fight (big −vibe, +aggro, both
auto-ejected, `incident:log` kind `fight`, and if the inspector is inside —
LANE-CONTENT's problem — it's a heat risk). Pure pair-selection + timer logic
in `floor/fights.ts`, tested. While the player is at the door, fights still
happen (that's radio-pull pressure — emit a `radio:call` urgency 3 via the
night's existing pattern: log the incident, NightScene already radios on
`maggotUnhandled`; add `fight` to that trigger via CONTRACT CHANGE REQUEST or
ask the reviewer to widen the trigger — one-line, will be approved).

### 2. Smoking area & pass-outs (closes the UV loop from the door side)
The smoking-area door becomes live: patrons drift out for a smoke (activity
'smoking' exists) and BACK IN through the entry. Re-entering smokers keep their
stamp — but a small % of NEW patrons try to slip in through the smoking door
(no stamp, never saw the front door). That's the noStamp mechanic getting a
source that isn't only Kayden. Numbers small (2–3 a night), tells readable
(they enter from the wrong door if you're watching).

### 3. Aggro physiology (FLOOR-2 CCR, deferred at Phase-1 review — now approved)
Implement slow aggro decay on a calm floor: when no unhandled infraction exists
and no fight is brewing, drift aggro down ~0.3/clock-min (numbers yours to
tune, state the final value in the handover). Implementation note: this is a
sim-level `meters:delta` emit from the floor's update, gated on `present`
being EITHER value (a calm floor calms the night whether you're watching it or
not). Add tests for the gating logic.

### 4. Night-mode polish
- Stall bangs and pat-down bin drops should hit `NightContext.sfx`
  (`doorBang`, plus pick something for the bin thunk) — overlays take an
  optional sfx handle via their constructors.
- Escorted patrons should exit via the ENTRY in night mode (they're being
  walked out the front, past the queue — future door-side schadenfreude hook).
- Perf check at 44 agents + fights + smokers in night mode; report frame times.

## Constraints
- Demo mode must stay working and identical-feeling (it's the tuning harness).
- No imports from `scenes/door/`; the night talks to you via bus + context.
- Pure logic tested; verify each mechanic by playing BOTH modes; handover per
  protocol.
