Adaptive check cadence: the interval is earned, not assigned
Operator ruling 2026-08-20. Severity no longer sets the review interval. A check that comes back clean climbs one rung — instant, 1h, 8h, 24h, 48h, 96h, 7d, 14d, 1mo, 1q — and anything wrong drops straight back to instant. A quarter is the ceiling. The operator may defer an instant finding to a stated date; that is the only other way off the bottom rung. The rung is the point: it says how stable the estate has been on that matter, which is information severity does not carry. Volatile things get attention automatically; quiet things stop consuming it; neither judgement has to be made by a person who might be busy. Escalation trigger 5 rebased onto the ladder — fourteen days at the bottom rung, whether that is failing checks or no checks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
8b204d0411
commit
42bbf5d2dc
17 changed files with 429 additions and 148 deletions
|
|
@ -1,7 +1,14 @@
|
|||
# Filing a finding
|
||||
|
||||
One file per finding: `findings/RISK-F-NNNN-<slug>.md`, YAML front-matter,
|
||||
then prose. Next id is one past the highest here.
|
||||
then prose.
|
||||
|
||||
**Ids are allocated by `risk-nexus`.** Take the next id past the highest you
|
||||
can see and file — that is the right thing to do — but if two reporters take
|
||||
the same one, the earlier commit keeps it and the newcomer is renumbered here,
|
||||
with the original id recorded as `filed_as`. This happened on 2026-08-20
|
||||
(`RISK-F-0009`, filed as `RISK-F-0004`), which is why it is written down. Do
|
||||
not renumber your own finding after filing; the register does it and tells you.
|
||||
|
||||
## What the reporter fills in
|
||||
|
||||
|
|
@ -24,8 +31,14 @@ related: [RISK-F-0001] # optional
|
|||
|
||||
`severity`, `severity_at_production`, `impact`, `likelihood`,
|
||||
`fidelity_modifier`, `production_rescore`, `disclosure`, `embargo_*`,
|
||||
`escalation*`, `constraint*`, `last_reviewed`, `review_by`, `graded_by`,
|
||||
`ruling`.
|
||||
`escalation*`, `constraint*`, `last_checked`, `next_check`, `cadence`,
|
||||
`clean_streak`, `graded_by`, `ruling`.
|
||||
|
||||
`cadence` is the check-frequency rung, and it is earned rather than assigned:
|
||||
a clean check climbs one rung (`instant` → `1h` → `8h` → `24h` → `48h` → `96h`
|
||||
→ `7d` → `14d` → `1mo` → `1q`), and anything moving drops it straight back to
|
||||
`instant`. So the rung on your finding is a public statement about how settled
|
||||
the matter has been — which is why it is not yours to set.
|
||||
|
||||
Setting them yourself is not an error to be corrected — it is a boundary this
|
||||
repo would rather keep. The reporter says what is true; this repo says how bad
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ escalation: withdrawn
|
|||
escalation_trigger: 1
|
||||
escalation_status: withdrawn-before-sending
|
||||
date_fixed: "2026-08-19"
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-08-26"
|
||||
last_checked: "2026-08-19T21:30:00Z"
|
||||
next_check: "2026-08-19T21:30:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19
|
||||
---
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ embargo_review: "2026-11-17"
|
|||
escalation: withdrawn
|
||||
escalation_trigger: 6
|
||||
escalation_status: withdrawn-hazard-window-closed
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-11-17"
|
||||
last_checked: "2026-08-19T21:30:00Z"
|
||||
next_check: "2026-08-19T21:30:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19
|
||||
---
|
||||
|
|
|
|||
|
|
@ -10,21 +10,24 @@ date_reported: "2026-08-19"
|
|||
system: ops-warden
|
||||
environment: production
|
||||
fix_owner: ops-warden
|
||||
fix_tracking: WARDEN-WP-0032-T05
|
||||
fix_tracking: WARDEN-WP-0032-T05 (done) / T06 (structural)
|
||||
# Graded by risk-nexus 2026-08-19 — docs/rulings/2026-08-19-first-grading.md
|
||||
severity: high
|
||||
severity_at_production: high
|
||||
severity: medium
|
||||
severity_at_production: medium
|
||||
severity_superseded: "high (2026-08-19) — the CLI-layer gap is mitigated"
|
||||
impact: I4
|
||||
likelihood: L2
|
||||
fidelity_modifier: false
|
||||
production_rescore: false
|
||||
disclosure: embargoed
|
||||
embargo_condition: "the five exec_capable lanes graded under WARDEN-WP-0032-T05"
|
||||
embargo_condition: "RISK-F-0009 resolved — the OpenBao deny set covers every high-risk lane with a KV path"
|
||||
embargo_since: "2026-08-19"
|
||||
embargo_review: "2026-09-18"
|
||||
escalation: none
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-09-18"
|
||||
last_checked: "2026-08-20T05:40:00Z"
|
||||
next_check: "2026-08-20T05:40:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19
|
||||
---
|
||||
|
|
@ -190,3 +193,35 @@ Reasoning: `docs/rulings/2026-08-19-first-grading.md`.
|
|||
Open at review: OpenBao policy coverage of the five paths; whether
|
||||
`WARDEN-WP-0032-T05` has landed; whether any compliance evidence cites
|
||||
`ADR-0004` as implemented.
|
||||
|
||||
## Check — 2026-08-20: mitigated on one layer, `high` → `medium`
|
||||
|
||||
`ops-warden` reports all 17 high-risk lanes now exiting 7 on
|
||||
`warden access --fetch` with `WARDEN_AGENT_ID` set, verified under
|
||||
`WARDEN-WP-0032-T05`/`T06`. The 14 ungraded lanes are graded; the boundary
|
||||
fires. The live gap this finding described is closed on the CLI layer.
|
||||
|
||||
**Not clean, so the cadence stays at `instant`.** Something moved, and under
|
||||
the ladder that resets the clock rather than earning a longer one. The next
|
||||
check is the one that can start climbing.
|
||||
|
||||
**`high` → `medium`.** What remains is the omission shape rather than the
|
||||
instance: whether a future lane can still be added without a grade. That is
|
||||
`WARDEN-WP-0032-T06`, and the durable form of the operator's maturity-context
|
||||
rule is `zone-engine`'s (`RISK-N-0004`). Not `low`, because "graded by hand
|
||||
once" is not the same as "cannot be ungraded again".
|
||||
|
||||
**The embargo condition changed rather than being met.** The original condition
|
||||
— the five `exec_capable` lanes graded — is satisfied. But `RISK-F-0009` shows
|
||||
the *second* layer, the OpenBao deny set that protects the direct `bao kv get`
|
||||
path, covers 6 of 17 high-risk lanes. Publishing this finding now would name
|
||||
lanes that are still reachable by the path this control exists to close. The
|
||||
condition is therefore re-pointed at `RISK-F-0009`.
|
||||
|
||||
That is the disclosure rule working across two findings rather than one: what
|
||||
matters is whether the text shortens a path, not whether this particular
|
||||
finding's own fix has landed.
|
||||
|
||||
**Verification limit, recorded rather than assumed:** the mitigation is
|
||||
`ops-warden`'s report and this register has not probed it. Their operator token
|
||||
is expired, which is also why `RISK-F-0009` rests on a file comparison.
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ embargo_condition: "the read path filters by tenant in code"
|
|||
embargo_since: "2026-08-19"
|
||||
embargo_review: "2026-09-18"
|
||||
escalation: none
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-09-18"
|
||||
last_checked: "2026-08-19T21:20:00Z"
|
||||
next_check: "2026-08-19T21:20:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19-B
|
||||
---
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ embargo_condition: "AUDIT-WP-0008-T04 lands a tenant filter in the read path"
|
|||
embargo_since: "2026-08-19"
|
||||
embargo_review: "2026-11-17"
|
||||
escalation: none
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-11-17"
|
||||
last_checked: "2026-08-19T21:20:00Z"
|
||||
next_check: "2026-08-19T21:20:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19-B
|
||||
---
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ escalation_answered: "2026-08-19"
|
|||
escalation_answered_by: the-custodian
|
||||
escalation_act: approve
|
||||
decision: "spend for apps-pg backup storage approved; no ceiling stated"
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-09-18"
|
||||
last_checked: "2026-08-19T23:05:00Z"
|
||||
next_check: "2026-08-19T23:05:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19-B
|
||||
---
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@ accepted_by: the-custodian
|
|||
accepted_on: "2026-08-19"
|
||||
accepted_until: "production transition (hard expiry, not a date)"
|
||||
decision: "pragmatic default before production — carried unverified; verification of a named consumer boundary on request"
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-09-18"
|
||||
last_checked: "2026-08-19T23:05:00Z"
|
||||
next_check: "2026-08-19T23:05:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19-B
|
||||
---
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ escalation_act: rule
|
|||
decision: "identity in audit records: opaque subject ids preferred, agent identifiers where possible, operator credentials only where necessary, policy decisions tracked to the responsible party; zone-level privacy guarantees may raise the floor"
|
||||
outstanding: "a defensible retention period per category (waits on audit-core's co-residency horizon), and the trigger list for buying an external answer"
|
||||
determination: RISK-REG-0001
|
||||
last_reviewed: "2026-08-19"
|
||||
review_by: "2026-11-17"
|
||||
last_checked: "2026-08-20T05:25:00Z"
|
||||
next_check: "2026-08-20T05:25:00Z" # due now: the ladder starts at instant
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-19-C
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
id: RISK-F-0004
|
||||
id: RISK-F-0009
|
||||
type: finding
|
||||
title: "agent-high-risk-boundary denies 6 of 17 high-risk lanes; the direct bao path is unprotected for the rest"
|
||||
status: open
|
||||
|
|
@ -11,12 +11,29 @@ system: railiance-platform
|
|||
environment: production
|
||||
fix_owner: railiance-platform
|
||||
fix_tracking: unset
|
||||
severity: unset
|
||||
disclosure: unset
|
||||
escalation: unset
|
||||
filed_as: "RISK-F-0004 by ops-warden; renumbered by risk-nexus 2026-08-20 (id collision)"
|
||||
answers: RISK-F-0003
|
||||
related: [RISK-F-0003]
|
||||
# Graded by risk-nexus 2026-08-20 — docs/rulings/2026-08-20-openbao-layer.md
|
||||
severity: high
|
||||
severity_at_production: high
|
||||
impact: I4
|
||||
likelihood: L2
|
||||
fidelity_modifier: false
|
||||
production_rescore: false
|
||||
disclosure: embargoed
|
||||
embargo_condition: "the deny set covers every high-risk lane with a KV path, verified against live OpenBao"
|
||||
embargo_since: "2026-08-20"
|
||||
escalation: none
|
||||
last_checked: "2026-08-20T05:40:00Z"
|
||||
next_check: "2026-08-20T05:40:00Z"
|
||||
cadence: instant
|
||||
clean_streak: 0
|
||||
graded_by: risk-nexus
|
||||
ruling: RISK-RULING-2026-08-20
|
||||
---
|
||||
|
||||
# RISK-F-0004 — the OpenBao half of the agent read-boundary covers a third of the lanes
|
||||
# RISK-F-0009 — the OpenBao half of the agent read-boundary covers a third of the lanes
|
||||
|
||||
## What is true
|
||||
|
||||
|
|
@ -101,3 +118,62 @@ this from an audit into an invariant.
|
|||
- ops-warden `ADR-0004`, `ADR-0007`
|
||||
- `ops-warden/wiki/playbooks/agent-read-boundary.md`
|
||||
- `railiance-platform/openbao/policies/agent-high-risk-boundary.hcl`
|
||||
|
||||
## Register ruling — 2026-08-20
|
||||
|
||||
**Renumbered from `RISK-F-0004`.** `ops-warden` filed it as `RISK-F-0004`,
|
||||
which this register had already assigned to `tenant-engine`'s unfiltered event
|
||||
read hours earlier. Earlier id keeps it; the newcomer moves. Nothing about the
|
||||
finding changes, and the filing contract now says how ids are allocated so the
|
||||
next reporter does not hit this.
|
||||
|
||||
`high` (`I4` × `L2`), embargoed, no escalation.
|
||||
|
||||
**`I4` on the worst uncovered lane.** Eight high-risk lanes have a concrete KV
|
||||
path the policy does not deny. Most are `I3`-shaped inside their own system;
|
||||
`scaleway-bootstrap` and `agent-harness-forgejo-deploy` are not — cloud account
|
||||
bootstrap credentials and a forge deploy key propagate past the system that
|
||||
holds them.
|
||||
|
||||
**`L2`.** It needs an agent token carrying a `workload-kv-read-*` policy, which
|
||||
the estate does grant. The register holds `ops-warden`'s two stated limits
|
||||
rather than resolving them in either direction: the comparison is static against
|
||||
the policy *file* because their operator token is expired (`bao token lookup` →
|
||||
403), so **the deployed policy may differ**; and whether any agent token
|
||||
currently carries `agent-high-risk-boundary` together with a
|
||||
`workload-kv-read-*` policy is not established.
|
||||
|
||||
**No fidelity modifier, same call as `RISK-F-0003`.** `ADR-0004` describes two
|
||||
independent layers and one of them covers a third of the lanes, so the
|
||||
documentation overstates the control — but the modifier is scoped to
|
||||
attestations produced at runtime, not to documentation drift. Noted twice now
|
||||
in the same system; if it recurs a third time the modifier's scope is what
|
||||
should be re-examined, not the finding.
|
||||
|
||||
**No escalation.** `railiance-platform` owns the policy, `ops-warden` owns the
|
||||
catalog, and they have not disagreed about anything — trigger 4 needs a failed
|
||||
routing exchange, not merely two repos. `ops-warden`'s suggestion that the deny
|
||||
set be generated from the catalog rather than maintained twice is routed as a
|
||||
suggestion, which is what it was offered as.
|
||||
|
||||
**The pre-existing point is the important one.** Four of the eight uncovered
|
||||
lanes were already graded `high` before the 2026-08-19 regrade. The divergence
|
||||
is not a consequence of that work; the regrade only made the two lists
|
||||
comparable enough to see it. A register that took credit for finding a fresh
|
||||
defect here would be misreading its own evidence.
|
||||
|
||||
**Disclosure: embargoed**, and it changes `RISK-F-0003`'s embargo too. This
|
||||
names eight live KV paths that nothing denies.
|
||||
|
||||
**One expired credential is blocking verification** of both this finding and
|
||||
`RISK-F-0003`'s mitigation. That is not a finding — nothing is wrong with the
|
||||
estate because a token expired — but it is why two gradings here rest on file
|
||||
comparison rather than a probe, and the register says so rather than implying
|
||||
otherwise.
|
||||
|
||||
## Reviews
|
||||
|
||||
- **2026-08-20** — renumbered, graded. Cadence starts at `instant`: nothing
|
||||
about this has been checked twice yet. Open at the next check: does the
|
||||
deployed policy match the file; do any agent tokens carry both policies; has
|
||||
`railiance-platform` taken the catalog-generated deny set.
|
||||
Loading…
Add table
Add a link
Reference in a new issue