The mechanism behind RISK-F-0003 was sharper than the finding described.
is_high_risk was risk == "high", but risk was never absent at the model layer:
RouteEntry.risk carried a dataclass default of "standard". An omitted grade was
not unhandled, it was actively resolved to the permissive value — fail-open by
construction, which is why nothing ever warned.
The default is now "ungraded" and is_high_risk returns true for anything outside
an explicit low-risk vocabulary (standard / low / accepted). An omitted grade and
an unrecognised grade from a newer catalog both resolve to high, so the boundary
fails safe in both directions rather than reading an unknown value as permission.
test_every_repo_catalog_lane_is_explicitly_graded is the CI gate that stops an
ungraded lane being committed, per ADR-0007: absence is not a grade.
"accepted" is in the low-risk vocabulary deliberately, ready for the
maturity-derived default — an experimental-context lane may be explicitly
accepted, which is a graded decision rather than an omission.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes the RISK-F-0003 exposure. All 14 ungraded lanes now carry an explicit
risk grade with its justification in the entry: 17 high, 10 standard, 0
ungraded. The agent read-boundary now fires (exit 7) on lanes that were silently
outside it.
Graded on merit rather than defensively. A first pass marked two ordinary
internal workload secrets high; test_high_risk_lanes_classified asserted the
opposite and was right, so both were regraded down. high means disclosure into a
logged context is damaging beyond what rotation recovers. inter-hub-bootstrap-ssh
is high conservatively, with the reason in the entry so it is regraded with
evidence rather than assumed down.
ADR-0007 records the rule the grading rests on: build-stage permissiveness
applies to controls that gate work, not to controls that prevent credential
disclosure. The test is friction, not severity — the read-boundary blocks nobody,
since --out/--exec/--wrap remain available, so relaxing it buys nothing. A
blocked operation is recovered by retrying; a credential in a logged transcript
is not recovered by rotation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Splits RISK-F-0003's response in two. T05 grades the five exec_capable ungraded
lanes explicitly — a live gap in a shipped ADR should not wait months for the
zone model. T06 makes absence impossible once the model says what absence means,
per the operator's maturity-derived default.
Grading is flagged as judgement requiring operator sanction, not backfill.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Amended by net-kingdom as canon owner of tenancy-posture_v0.1, answering
ZONE-WP-0001-T01.
T01: organization_posture does not fold into zones and does not belong in a
per-repo declaration — it is a fleet-wide time-varying scalar. Hand it over as an
input.
T03: zone membership is declared in tenancy.yaml under a reserved zones: key
(canon Decision 5.6). ops-warden has no tenancy.yaml, so this now implies
declaring the six-axis posture vector too. Also records why this declaration may
not set stance: a declarer that sets its own stance makes exempt conformant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flex-auth reviewed ZONE-WP-0001 as the consuming PDP and two findings
land on the ops-warden consumer side:
T02 - fail_closed is not expressible by a PDP. Fail-open describes what
warden sign does when flex-auth is unreachable, so no decision exists to
carry it. The replacement for policy.enabled is two things: stance,
which arrives in the decision, and failure mode, which stays local and
is declared per zone.
T02 - build_flex_auth_registry.py:77 already emits a hardcoded
trust_zone: platform that no policy reads. Resolve that before
compiling zone membership rather than adding security_zone beside it.
T03 - the declaration must say whether a zone rides the actor (subject)
or the lane (resource); in the compiled registry an actor is both.
No flex-auth registry schema change is needed - metadata, labels and
attributes already flatten into the rego input.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
zone-engine is seeded and owns the security zone model as ZONE-WP-0001. Under
ADR-0005 ops-warden implements one lane narrowly and routes the rest, and an
estate-wide enforcement model is not a lane to absorb — it was ops-warden's
deferred flip that exposed the gap, not ops-warden's model to define.
WARDEN-WP-0032 is rewritten as the consumer side: hand the estate inputs to
ZONE-WP-0001-T02 (27 catalog lanes, the actor inventory, the three posture axes,
the three controls the model must express, and the compiled-registry path),
then replace policy.enabled with a zone-aware control and amend ADR-0006 to say
ops-warden follows the model rather than owning it.
ADR-0006 and SCOPE updated to point at zone-engine, which joins the related
repositories table.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Expands the placeholder into a real plan, grounded in what the estate already
has rather than first principles:
- tenancy-posture_v0.1 is the structural model to follow (canon standard +
per-repo declaration + "accuracy, not altitude"), and its §14 adoption stance
is "structure, not tooling" — a precedent about sequencing.
- Reefs are substrate placement zones with real risk statements. A security
zone is not a reef; repo-manager's own "topology is not readiness" applies
here as "placement is not posture".
- flex-auth is latency-critical and already consumes a compiled registry
snapshot, so zone membership should reach the PDP by compilation rather than
a synchronous lookup in the decision path.
- warden plan already returns verdicts with reasons; zone-aware enforcement
extends that machinery instead of growing a parallel one.
T01 settles ownership before any modelling, because it decides which repo the
rest lives in: canon standard, a zone-engine runtime authority, or flex-auth
policy data. The recommendation is canon-first with zone-engine named as an
explicit promotion — but the time-boxed refactor exception is the case that
could justify an engine immediately, since an expiring grant is state and state
wants an owner.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flex-auth enforced its ops-warden pin (FLEX-WP-0016 T03) and the gate verified
clean against it: readiness exits 0, decision:f3f7c88f9585582a, anonymous
/v1/check now 401. Everything needed to set policy.enabled: true was in place.
It stays false, by decision. policy.enabled is a single repo-wide boolean, and
with fail_closed: true it makes flex-auth a hard dependency of every warden
sign — including the certs the ops-bridge tunnels depend on, one of which
carries the policy call itself. Uniform enforcement across an estate being
actively rebuilt hardens the access needed to perform the rebuild.
The repo already refuses one-dimensional posture: WP-0015 shipped environment
and maturity axes, WP-0029 added organization_posture. A global flag ignores all
three. ADR-0006 records that enforcement belongs to a zone, and binds future
work — a zone-blind enforcement flag is out of order, not merely unwise.
WARDEN-WP-0032 drafts the zone model, leading with the ownership question:
whether this is ops-warden's to own or NetKingdom canon to consume (ADR-0005).
WP-0031 is finished with T05 cancelled and resuming as WP-0032-T05.
Also replaces the hand-run kubectl port-forward with a managed ops-bridge
tunnel, flex-auth-ops-warden-railiance01 (-L 19090:10.43.1.165:8080).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>