## ADDED Requirements

### Requirement: SessionStart Hook Wiring

The plugin SHALL declare a `SessionStart` hook in `hooks/hooks.json` at the plugin
root (not under `.claude-plugin/`) with `matcher` `startup|resume`. The hook SHALL
invoke only the deterministic reminder script, SHALL specify a low `timeout`
(≤5 seconds), and SHALL never block the session.

#### Scenario: Hook is declared with the correct matcher

- **WHEN** the plugin is enabled and a session starts
- **THEN** a `SessionStart` hook with `matcher` `startup|resume` invokes the deterministic reminder script with a `timeout` of at most 5 seconds

#### Scenario: Build-spike banner renders visibly

- **WHEN** a trivial `SessionStart` hook emitting a fixed `systemMessage` banner is wired and a real session is started
- **THEN** the banner renders visibly to the user, confirming the `systemMessage` mechanism works in a real session

### Requirement: Reminder Emits a Visible Zero-Token Banner

The reminder SHALL emit its staleness notice via the hook's JSON `systemMessage`
field (a user-facing banner), NOT via `additionalContext` (which is silent to the
user). The banner SHALL name the slash command the user runs to act on it. The
reminder SHALL spend ZERO AI tokens and SHALL run no scan and no classification.

#### Scenario: Banner uses systemMessage and names the command

- **WHEN** the reminder decides to notify the user
- **THEN** it emits a `systemMessage` banner stating how stale the docs are and naming the slash command to run, and spends no AI tokens

#### Scenario: Reminder performs no analysis

- **WHEN** the reminder runs at session start
- **THEN** it reads only state, invokes no scanner and no model, and reads no document content

### Requirement: Reminder Mutates Only last_reminded

The reminder SHALL mutate nothing except writing `last_reminded` to state, and
only when it emits a banner. When it stays silent it SHALL write nothing. It SHALL
always exit 0 so the session is never blocked.

#### Scenario: Banner emission records last_reminded

- **WHEN** the reminder emits a banner
- **THEN** it writes `last_reminded` set to the current time and changes no other file

#### Scenario: Silent run mutates nothing

- **WHEN** the reminder decides not to notify
- **THEN** it writes no file and exits 0

#### Scenario: Unreadable state never blocks the session

- **WHEN** state is missing or unreadable at session start
- **THEN** the reminder treats the project as never-checked (stale) and still exits 0 without blocking the session

### Requirement: Reminder Fires Only When Docs Are Stale

The reminder SHALL emit a banner only when the docs are stale — when `last_check`
is unset or older than the configured staleness threshold. When docs are fresh
(within the threshold) it SHALL stay silent.

#### Scenario: Fresh docs produce no banner

- **WHEN** `last_check` is within the staleness threshold of the current time
- **THEN** the reminder stays silent and emits no banner

#### Scenario: Never-checked project is stale

- **WHEN** `last_check` is unset
- **THEN** the reminder treats the project as stale and emits a banner (subject to the snooze)

### Requirement: Reminder Snoozes At Most Once Per Calendar Day While Stale

While docs are stale, the reminder SHALL emit a banner at most once per calendar
day, gated by `last_reminded`. A second stale session on the same calendar day
SHALL be silent; the next calendar day while still stale SHALL banner again. The
snooze SHALL be decidable deterministically with an injected clock.

#### Scenario: Second stale session same day is snoozed

- **WHEN** the docs are stale and `last_reminded` is the current calendar day
- **THEN** the reminder stays silent (no second banner that day)

#### Scenario: Next day while still stale re-banners

- **WHEN** the docs are stale and `last_reminded` is a prior calendar day
- **THEN** the reminder emits a banner and updates `last_reminded`

#### Scenario: Snooze survives repeated startup/resume within a working day

- **WHEN** the `SessionStart` hook fires again via `startup` or `resume` (the matched events) on the same calendar day after a banner already showed
- **THEN** the reminder stays silent rather than re-firing the banner
