KB-1ED9

12 — Red-Team Scenarios (Branch L, 24 scenarios) (2026-06-01)

12 min read Revision 1
one-roof-governanceclause-hardeningbranch-lred-teamadversarial-scenariosdetectionblocking-ruleescape-analysis2026-06-01

12 — Red-Team Scenarios (Branch L)

24 adversarial scenarios. For each: expected detection · severity · accountable owner (Branch C) · issue/event · blocking rule · and whether the CURRENT pack catches it or a hardening fix is required. A scenario marked ESCAPES (pre-fix) is one the un-hardened pack would miss — those are the teeth of this review.

Legend: ✅ caught by pack as-is · ⚠️ caught only after the named hardening fix · ❌ ESCAPES even after fixes (residual risk for council).


Block 1 — Ownership / island

1. New API route added without owner.

  • Detect: route inventory (G2) reconciles nginx+Nuxt → route not mapped to an owner. Sev: high (route_orphan). Owner: GOV-MOUT (surface). Issue/event: owner_gap/route_orphangovernance.orphan_detected. Block: G-ROUTE fails (route unverifiable/unowned).
  • Status: ⚠️ requires G2 (no route registry today → ESCAPES as-is; this is the biggest live blind spot).

2. New pivot added without approval.

  • Detect: pivot inherits source-collection owner (J8); if source covered, owner ok but counting-contract change needs APRapproval_path_gap. Sev: high. Owner: GOV-SIV (health) + COUNCIL (approve). Event: governance.approval_path_gap. Block: G-IMPL fails (no APR).
  • Status: ⚠️ requires I1 (assign/contract action-type) — else PROPOSE can't even file the APR.

3. Personal pin becomes global. (mission #6)

  • Detect: a user-scoped pin (Class 0, non-governed) is re-scoped to global → crosses into PROFILE-POLICY (B2) → pin_policy_unowned. Sev: high. Owner: COUNCIL. Event: governance.policy_unowned. Block: G-IMPL/G-PROD.
  • Status: ⚠️ requires A2/B1 — without the non-governed class + the shared-truth test, the scanner either floods on every personal pin (noise) or misses the global escalation. The fix is what makes #3 detectable without drowning in #personal-pins.

4. Local policy table created under a module. (mission #7)

  • Detect: PG scan finds a table with policy shape and no owner_gov_code/relation → F-ISLAND-3. Sev: high. Owner: COUNCIL. Event: governance.policy_unowned/island_detected. Block: G-IMPL + CI (P8).
  • Status: ✅ (PG-detectable island) — but island roll-up needs D3.

5. Direct-PG adapter added as "temporary" but never expires. (mission #5)

  • Detect: exception with no replacement_plan (E1) → auto-critical; EXCEPTION-REVIEW flips on TTL/review-cadence miss. Sev: critical. Owner: COUNCIL (policy) / SIV (risk) / MOUT (surface) — C4. Event: governance.unratified_exception. Block: G-ROUTE + president.
  • Status: ⚠️ requires E1 (replacement_plan mandatory) — without it, the exception renews forever (the exact red-team failure). With E1 + max-renewals it's caught.

6. A grouping policy invents its own classification outside Đ24 facets.

  • Detect: classification_policy_unowned (doc 07 #15) + Đ24 §5.4-note (grouping derived-from classification). Sev: high. Owner: COUNCIL (policy) + KG/taxonomy (substrate, J7). Block: G-IMPL.
  • Status: ⚠️ requires J7 (don't dump on COUNCIL; substrate owner is KG).

7. Two agencies both claim a policy (double owner).

  • Detect: coverage view finds 2 accountable owners in the same responsibility scope (C1/C2) → conflict/island. Sev: high. Owner: COUNCIL (tie-break §4.12d / owner-of-last-resort A5). Event: island_detected. Block: G-IMPL.
  • Status: ⚠️ requires C1/C2 — without responsibility-scope, the pack can't tell a legitimate multi-scope split from an illegitimate same-scope double-owner.

8. An object falls in a seam nobody owns.

  • Detect: owner-of-last-resort (A5) → defaults to COUNCIL → never a "no owner because ambiguous" gap. Sev: warning (defaulted). Owner: COUNCIL. Block: none (covered-by-default, tracked).
  • Status: ⚠️ requires A5.

Block 2 — Execution / DOT

9. DOT apply writes labels without approval. (mission #3)

  • Detect: mutating DOT not approval-gated → approval_path_gap + Đ32 §6 lifecycle gate blocks apply without quorum (doc 06). Sev: critical (anarchic — mutates classification). Owner: GOV-DOT + COUNCIL. Event: governance.dot_authority_gap. Block: Đ32 quorum (PG-enforced) + G-IMPL.
  • Status: ✅ partly (Đ35 §3 paired + Đ32 lifecycle) — ⚠️ but the SoD rule (I4) must be stated so a future refactor can't merge propose+apply.

10. A mutating DOT outside dot_tools (no paired_dot).

  • Detect: dot_authority_gap; Đ35 §3 trigger already rejects tier-B without paired_dot. Sev: critical. Owner: GOV-DOT. Block: PG trigger (live) + CI F-ISLAND-4.
  • Status: ✅ (already PG-enforced).

11. The coverage scanner itself is unowned (bootstrap orphan).

  • Detect: anti-bootstrap (§6.5) — scanner is a governed object; COVERAGE-AUDIT watches SCAN; seed attestation (I3). Sev: critical. Owner: SIV/DOT. Event: watchdog_fault. Block: seed APR + attestation before first scan.
  • Status: ⚠️ requires I3 (bootstrap sequence) — else the chicken-egg is hand-waved.

12. The applier DOT also approves its own change (self-grant).

  • Detect: SoD rule (I4/C6) — approval is always Đ32 quorum, never the DOT. Sev: critical (island under the roof). Block: CI F-ISLAND + Đ32 lifecycle.
  • Status: ⚠️ requires I4 — pack implies SoD via pairing but never forbids self-approval explicitly.

13. PROPOSE files a malformed approval (no valid action_code).

  • Detect: I1 — no assign_governance_owner/grant_exception action-type exists → PROPOSE returns proposal_blocked. Sev: high (system can't remediate). Block: G-IMPL prerequisite.
  • Status: ❌ ESCAPES as-is — the pack assumes the action-type exists; without I1 the whole remediation path silently can't run. Caught only after I1 (register action-types).

14. APPLY tries to assign an owner to a law-orphan route (object edge).

  • Detect: I2 — chk_relations_target_type blocks object edges; APPLY returns apply_blocked: object_edge_unexpressible. Sev: high (OWNER_GAP persists). Block: needs §5.4-EXT.
  • Status: ❌ ESCAPES / inoperable as-is — APPLY cannot do object-grain assignment until §5.4-EXT. This is the deepest structural limit (I2/B7).

Block 3 — Display / truth

15. UI hardcodes classification. (mission #4)

  • Detect: CI source scan (G8/K6) of web/** incl. server/api/** → F-ISLAND-6. Sev: high. Owner: GOV-MOUT. Event: hardcode_violation/island. Block: G-ROUTE + CI; Test-4 (100% Nuxt=PG) fails.
  • Status: ⚠️ requires P8 CI (UNVERIFIABLE-pre-CI). The live health.get.ts totalGap=reduce() is the canonical instance.

16. UI computes a count not backed by a pivot (PIVOT_MISSING).

  • Detect: pivot_coverage_unowned (#14) — grand-total must be a constant-bucket VIEW (Đ26 §MTx). Sev: high. Owner: GOV-SIV. Event: governance.pivot_coverage_gap. Block: G-ROUTE.
  • Status: ✅ (concept) — ⚠️ requires the pivot to be a governed object (J8).

17. Render shell decides governance state (covered/orphan) in Nuxt.

  • Detect: NT-D1-ext — Nuxt must not compute governance state; CI catches. Sev: high. Owner: MOUT. Block: G-ROUTE + Test-4.
  • Status: ⚠️ requires P8 CI + the render owner resolved (J6).

Block 4 — Issue / event / scale

18. Event type emitted before registration. (mission #8)

  • Detect: Đ45 §3.2 register-before-emit; event_outbox registry CHECK fail-closed (verify, I5). Sev: high (queue anti-pattern). Owner: GOV-SIV. Block: producer fails (PG CHECK).
  • Status: ✅ for events (CHECK) — ⚠️ but issue_type has NO such gate (H2/H4): a DOT writing an unregistered issue_type is NOT caught. Caught only after the H2 vocabulary + register-before-write.

19. Scanner reports 1 million duplicate issues. (mission #9)

  • Detect: coalesce_key dedup + aggregate-to-summary + hard per-scan emit ceiling (G7). Sev: warning (summary). Owner: SIV. Event: one governance_coverage_degraded + scan_anomaly. Block: emit ceiling caps it.
  • Status: ⚠️ G7 backstop needed for the unknown high-cardinality case; pack handles known classes.

20. Parent registry coverage hides a child policy gap. (mission #10)

  • Detect: B4 anti-hiding — inheritance covers owner-link ONLY; child's own approval/audit/rollback never inherited. Sev: high (child APPROVAL_PATH_GAP). Owner: child's profile owner. Block: G-IMPL.
  • Status: ⚠️ requires B4 — without it, the child is masked as covered (the exact red-team escape). This is the highest-value scale fix.

21. A source is missing from the L1 inventory (detector blind).

  • Detect: G1 inventory-completeness vs information_schema/directus_collections/meta_cataloginventory_gap (critical). Sev: critical. Owner: COUNCIL. Block: G-IMPL (detector provably blind).
  • Status: ⚠️ requires G1 — without the ground-truth reconciliation, "remembering to add the L1 row" is the new memory-dependence.

22. An owner agency flips draft and dependents silently rot.

  • Detect: G3 governance-context trigger re-scans MOUT-owned objects on status flip. Sev: warning→high. Owner: COUNCIL. Event: owner_gap. Block: G-PROD (touched objects no longer covered).
  • Status: ⚠️ requires G3changed_since(object) alone misses this (object didn't change, context did).

23. An exempted read-only adapter quietly gains a write endpoint (scope creep).

  • Detect: E5 state-fingerprint — exception auto-invalidates on signature change → re-enters orphan + exception_scope_drift (critical). Sev: critical. Owner: SIV (risk). Block: G-ROUTE + president.
  • Status: ⚠️ requires E5 — without fingerprinting, the old waiver silently covers the new write path.

24. An object is parked in ignored to make the gate go green.

  • Detect: F2 — ignored is a gated permanent exception (COUNCIL + law-ref + replacement_plan); ungated ignored = UNRATIFIED_EXCEPTION (critical). Sev: critical. Owner: COUNCIL. Block: G-PROD.
  • Status: ⚠️ requires F2 — without gating ignored, the identity closes while the gap hides (accounting fraud analog).

Red-team verdict

Outcome Count Scenarios
✅ caught by pack as-is 3 4, 10, 16(concept)
⚠️ caught only after a hardening fix 19 1,2,3,5,6,7,8,9,11,12,15,17,18,19,20,21,22,23,24
❌ ESCAPES / inoperable even with wording fixes (need substrate change) 2 13 (no APR action-type), 14 (no object edge)

Conclusion: the un-hardened pack catches only the cases the existing Đ35/Đ45 machinery already enforces (DOT pairing, event registration, PG-visible no-owner tables). The majority of governance-specific escapes require the hardening fixes — most importantly A2/B1 (non-governed class, or #3 floods/misses), B4 (inheritance anti-hiding, or #20 escapes), G1/G2/G3 (detection completeness/freshness, or #1/#21/#22 escape), E1/E5/F2 (exception integrity, or #5/#23/#24 escape). The two hard ❌ (#13, #14) are not wording problems — they need new APR action-types (I1/E2) and the §5.4-EXT object edge (I2/B7) in the substrate. This is the empirical case for NO-GO-until-hardened: the pack as written does not yet stop the attacks it was built to stop.

Back to Knowledge Hub knowledge/dev/reports/architecture/one-roof-governance-clause-review-hardening-2026-06-01/12-red-team-scenarios.md