RISK-WP-0001-T07: rule on what was waiting outside the register

Four in as findings — tenant-engine unfiltered event read (high),
audit-core read path bounded by a flag not by code (medium), apps-pg with
no backup at all (high, escalated on spend), and the unverified tenant
boundary itself (high now, critical at production, escalated on
ownership, fix_owner deliberately unset). Two out as notes — noisy
neighbours and erasure-versus-audit, both real, neither changing a
decision this month, both carrying an event to be re-read at.

The round amended the scale twice: build mode lowers impact as well as
likelihood, and non-adversarial findings get their own likelihood
reading. The escalation rule gained a ratio test that distinguishes a
first sweep from steady-state intake, and a batching rule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-19 23:33:08 +02:00
parent d5a3953f2e
commit 4daff5503f
10 changed files with 612 additions and 15 deletions

View file

@ -134,15 +134,48 @@ Stated so the rule bites in both directions.
## Testing the rule against the register
The draft was tested against all three open findings before it was proposed;
the rulings are in `docs/rulings/2026-08-19-first-grading.md`.
The draft was tested against the first three findings before it was proposed
(`docs/rulings/2026-08-19-first-grading.md`) and then against the four filed
out of the backlog the same day
(`docs/rulings/2026-08-19-second-grading.md`).
Summary: `RISK-F-0001` escalates on trigger 1. `RISK-F-0002` does not escalate
on triggers 1-5 — agreeing with the reporter's own reading — but the
`RISK-F-0001`/`RISK-F-0002` ordering constraint escalates once on trigger 6,
which is the disagreement the rule was worth writing to surface. `RISK-F-0003`
does not escalate; it is known, owned, tracked, and moving.
| Finding | Escalates | Trigger |
| --- | --- | --- |
| `RISK-F-0001` flex-auth oracle | yes | 1 — governs access to tenant data |
| `RISK-F-0002` signing gate off | yes, once | 6 — ordering hazard, jointly with `RISK-F-0001` |
| `RISK-F-0003` ungraded lanes | no | known, owned, tracked, moving |
| `RISK-F-0004` tenant-engine reads | no | no real tenant data yet |
| `RISK-F-0005` audit-core reads | no | known, owned, tracked, moving |
| `RISK-F-0006` apps-pg no backup | yes | 3 — recurring spend nobody can self-authorise |
| `RISK-F-0007` unverified boundary | yes | 4 — estate-wide and unowned |
One escalation, covering two findings, out of three findings. That ratio is
the rule doing its job. If it ever reaches "most findings", the rule is wrong,
not the register.
`RISK-F-0002` is the case worth reading: `ops-warden` judged it did not need
the operator, the register agrees on triggers 1-5, and it escalates anyway on
6. That disagreement is the reason the rule was worth writing down.
## The ratio, and what it would mean
Four of seven escalate. That is more than this rule should produce in steady
state, and it is not evidence the rule is loose — it is what a **first sweep**
looks like. Three of the four are the backlog: items that sat outside the
register precisely because nobody had decided them, and undecided items are
exactly the population that needs the person who can decide.
The test therefore applies to intake, not to sweeps:
> If more than one in three **newly reported** findings escalates over any
> rolling ninety days, the rule is wrong, not the register.
If that trips, the first suspects are triggers 3 and 4 — spend thresholds set
too low, and "unowned" being read where "not yet routed" is meant.
## Escalations are batched
Four escalations are one conversation, not four interruptions. Open items go
to the operator together, in register order, each with its own decision and
its own default-if-no-answer. Escalating is not the same as escalating
separately, and a rule that produces four messages in an afternoon has made the
operator the queue by a different route.
`make check` lists everything awaiting an answer, so the batch is a report and
not somebody's recollection.

View file

@ -108,15 +108,37 @@ Every finding is graded twice:
- `severity_at_production` — the same impact, with likelihood re-read for a
system carrying real users and real tenant data.
Build mode is a legitimate likelihood input. "No consumer holds real data
here yet" genuinely lowers reach. It is *not* an impact input: what the defect
would do on the day it is exercised does not change because the calendar has
not reached production.
Build mode legitimately lowers **both** axes, for different reasons:
likelihood, where the reach itself depends on a production deployment that has
not happened; and impact, where the data that would be exposed does not exist
yet. What it must never lower is `severity_at_production` — the defect does
not improve because the calendar has not reached it.
> *Amended 2026-08-19 (`RISK-WP-0001-T07`).* This paragraph originally said
> build mode was a likelihood input and never an impact one. Grading the
> unverified tenant boundary broke that: what build mode changes there is the
> consequence of an occurrence, not the reach of it. The instrument was wrong
> on first hard use and is corrected rather than worked around.
Where the two grades differ, the production transition is a mandatory
re-score. `docs/method/review.md` binds the review date to it, so the re-score
is a scheduled event and not somebody's memory.
## Non-adversarial findings
Likelihood is written as reach because most findings are about someone getting
somewhere. Where a finding is about loss, corruption or outage — no backup, no
recovery path, an eviction-prone deployment — there is no attacker to model.
For those, likelihood reads as **the chance of the triggering event inside one
review interval**: `L1` would be surprising, `L2` is an ordinary failure the
estate has seen before, `L3` is expected in the normal course of running,
`L4` is already happening. Impact is unchanged: what is lost, and whether it
comes back.
> *Added 2026-08-19 (`RISK-WP-0001-T07`).* Forced by `RISK-F-0006`, where the
> defect is an absent backup and the reach reading produced nonsense.
## The floor
`INTENT.md`: if a finding would not change anyone's decision, it is a note,

View file

@ -0,0 +1,100 @@
---
id: RISK-RULING-2026-08-19-B
type: ruling
title: "What was waiting outside the register: four findings, two notes"
status: recorded
owner: risk-nexus
date: "2026-08-19"
workplan: RISK-WP-0001-T07
---
# What was waiting outside the register — 2026-08-19
`INTENT.md` named six things as visible but unfiled, held back "pending this
repo setting the precedent for what warrants a record of its own". The
precedent now exists (`docs/method/severity.md`), so each is ruled here. "Still
waiting on the precedent" is no longer an available answer.
| Item | Ruling | Why |
| --- | --- | --- |
| `tenant-engine` unfiltered event read | `RISK-F-0004`, high | Live cross-tenant read, owner can act, ordering changes |
| `audit-core` unfiltered read path | `RISK-F-0005`, medium | Bounded by a deployment flag, not by code |
| `apps-pg` no backup | `RISK-F-0006`, high, escalated | Unrecoverable loss; needs spend nobody can self-authorise |
| Unverified tenant boundary | `RISK-F-0007`, high, escalated | Estate-wide, unowned, two confirmed instances |
| Noisy neighbours uncharacterised | `RISK-N-0001`, note | Measurement work, no decision changes today |
| Erasure versus audit | `RISK-N-0002`, note | No obligation exists yet; regulatory-intake work |
Four in, two out. If everything had cleared the floor, the floor would not be
one.
## The three from RISK-F-0001's unfiled list
They were recorded inside another finding "so they are visible, not filed as
findings, because filing them was not asked for". Filing is now asked for.
Each is filed on the owning repo's own self-report, unverified by this repo,
and says so in its own text. `risk-nexus` reads from everywhere and is
downstream by construction; the system remains authoritative about itself.
Each owner has been asked to confirm or correct, and two of the three
(`RISK-F-0004`, `RISK-F-0006`) have `fix_tracking: unset`, which is a question
put to the owner rather than a criticism.
`RISK-F-0006` is the surprise of the round. It is the least dramatic item on
the list — a missing configuration block — and it grades highest of the three,
because it is the only one where nothing comes back afterwards. It also
escalates, on spend, which is the trigger that most needed a real case to
prove it is not decorative.
## The unverified tenant boundary
`RISK-F-0007`, and the one this register was arguably built to hold.
`INTENT.md` calls it the estate's largest known gap and complains that it lives
as open question 3 of an unratified draft, with no owner, no severity and no
date. It now has three of the four; `fix_owner` stays `unset` deliberately,
because the escalation is precisely about who owns it.
Two design points, both deliberate:
- **It is not a duplicate of `RISK-F-0004` and `RISK-F-0005`.** Those are two
instances; this is the absence of anything that would have found them. The
instances get fixed by their owners and this one does not go away when they
do.
- **It grades `high` today and `critical` at production**, which is the first
real use of `production_rescore`. Today's consequence is bounded because the
estate holds no real tenant data. That bound is a fact about the calendar, so
it belongs in the build-mode column and not in a comfortable headline.
## What the notes are for
`RISK-N-0001` and `RISK-N-0002` are the floor doing its job: both are real,
both are known, neither changes a decision this month. The note keeps "we saw
it" without inflating a register that has to stay small enough to read.
Both carry a `revisit` condition that is an event rather than a date, and both
events are ones the estate cannot miss — two tenants sharing a saturating
workload, and the first real person's data. Neither note is a promise to
remember; both are promises to be re-read when the condition arrives.
## What this round did to the instruments
Two amendments, both dated in `docs/method/severity.md`:
1. **Build mode lowers impact as well as likelihood.** The original text said
it was a likelihood input and never an impact one. `RISK-F-0007` broke that
in one sentence: what build mode changes for an unverified boundary is the
consequence of an occurrence, not the reach of it. Corrected rather than
worked around.
2. **Non-adversarial findings get their own likelihood reading.** `RISK-F-0006`
has no attacker in it, and reading likelihood as "reach" produced nonsense.
Likelihood there is the chance of the triggering event inside one review
interval.
An instrument that survives its first hard use unchanged has probably not been
used hard.
## Register size
Seven findings, six open, two notes. `INTENT.md` requires the register stay
small enough to read, and `REGISTER.md` is still one screen. The next thing
that would break it is a batch — a review round producing ten entries at once.
When that happens the answer is a harder floor, not a wider table.