risk-nexus/docs/method/review.md
tegwick 7d6ded5743 The inbox round: two grades corrected, one note promoted
Read the repo inbox after grading, which is the wrong order and is now
recorded as such. flex-auth had answered the NetworkPolicy question on
2026-08-18 (narrow ingress, not default-deny — L3 becomes L2, critical
becomes high) and reported RISK-F-0001 fixed at 12:35 today with live 401
probes. F-0001 closes fixed and public; its escalation is withdrawn
before it was ever sent. RISK-F-0002's ordering constraint lifts with it
and its trigger-6 escalation is withdrawn.

audit-core had routed the erasure-versus-audit legal question here on
2026-08-18 asking for an owner. RISK-N-0002 was wrong to call it a note:
the remedy is not retrofittable, so the decision can only be taken early.
Promoted to RISK-F-0008, owned by this repo as regulatory intake,
escalated on trigger 2.

Accepted rapp-postgres's record format and ops-warden's typed-act
escalation vocabulary. Reading the inbox is now question zero of every
review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:38:07 +02:00

115 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: RISK-METHOD-REVIEW
type: method
title: "Review and expiry: what happens when nobody looks"
status: adopted
owner: risk-nexus
adopted: "2026-08-19"
workplan: RISK-WP-0001-T04
review_interval: 180d
---
# Review and expiry
`INTENT.md`: a finding that has sat untouched past its review date is itself a
finding. Silence is not resolution. This document makes that operable.
## Intervals
Set from the headline severity at grading time, and reset at each review.
| Severity | Interval | Stale (2×, escalation trigger 5) |
| --- | --- | --- |
| `critical` | 7 days | 14 days |
| `high` | 30 days | 60 days |
| `medium` | 90 days | 180 days |
| `low` | 180 days | — (ages out through review) |
A finding graded `critical` is being looked at weekly or it is not being
managed. If weekly is unbearable, the honest response is to re-grade it, not
to let the date slide.
## What a review is
Five questions, answered in writing on the finding. It takes minutes; it is not
an investigation.
0. **Has the inbox said anything?** Read the messages addressed to this repo
before anything else. This is question zero because on 2026-08-19 the
register graded `RISK-F-0001` `critical` while two messages sat unread in
its own inbox — one narrowing the exposure, one reporting the fix. Both
changed the grade. A register that does not read its own inbox is guessing
with a straight face.
1. **Is the grade still right?** Re-read impact and likelihood against what has
changed. New facts move the grade in both directions.
2. **Is the blocker still true?** This is the one `RISK-F-0002` bought with
evidence: *a blocker is a claim about the world at a date*. Its own stated
blocker — "`flex-auth` is not deployed yet" — was invalidated within a day
by `RISK-F-0001`, and nothing would have re-checked it. Every review
re-checks every stated blocker.
3. **Has the fix moved?** Read the owner's tracking record, not our memory of
it. Confirm the record still exists and still refers to this defect.
4. **Is the disclosure state still right?** An embargo whose condition has
been met is published; an embargo whose condition has not moved in two
reviews is a stall.
The finding gets a dated line under `## Reviews`, `last_reviewed` is updated,
and `review_by` is pushed by one interval. A review that changes nothing still
writes the line — "checked, nothing moved" is the evidence that the silence was
observed rather than accidental.
## When a review is missed
Overdue is not a status change on the finding. It is a fact about *this repo*,
and it surfaces in three places:
- `make check` reports it (`tools/register_check.py`), always, unconditionally.
- `REGISTER.md` shows the finding as overdue with the day count.
- At **twice** the interval, escalation trigger 5 fires for `critical`,
`high` and `medium`. That is the point at which the register's own silence
reaches the operator.
The register does not auto-escalate severity for lateness, and it does not
auto-close anything. Both would be the register lying about its own state to
make a number look better.
## The production re-score
Every finding carries `severity_at_production` alongside `severity`
(`docs/method/severity.md`). Where the two differ, the finding is flagged
`production_rescore: true`.
On the day any part of the estate declares production readiness, every flagged
finding is re-scored before that declaration completes. This is not a review
date — it is an event, and it fires regardless of where the review dates
happen to sit.
Until then, `make check` lists the flagged findings so the size of that
obligation is visible rather than discovered on the day.
## Front-matter this adds
```yaml
last_reviewed: "2026-08-19"
review_by: "2026-08-26"
production_rescore: true
```
`review_by` is what the nag reads. It is a date, never a duration, so that
nothing has to recompute an interval to know whether a finding is late.
## Closing a finding
A finding leaves `open` for exactly one of:
- `fixed` — the owner's record shows the defect gone, and this repo has read
something concrete rather than been told. Publication follows if the
disclosure state was `embargoed`.
- `accepted` — the estate is deliberately carrying it. Requires who accepted
it, why, and a re-review date. `accepted` is not `closed`; it keeps a review
interval forever.
- `withdrawn` — the finding was wrong, or the defect never existed. Say which.
There is no `stale`, no `wontfix` and no silent expiry. A finding that nobody
will fix and nobody will accept stays `open` and keeps arriving in the nag,
because that is the true state.