09 — Governance Auto-Coverage Detectors (hardened, build-ready inputs)
09 — Governance Auto-Coverage Detectors (hardened, build-ready inputs)
Package:
one-roof-axis-auth-proposal-operational-hardening-build-ready-design-2026-06-02Mode: DESIGN ONLY · READ-ONLY · NO COMMIT · NO MUTATION Hardens: prior…-2026-06-01/09-governance-coverage-and-anarchy-detection.md. Closes GPT review gap #5: "Governance auto-coverage needs precise detector inputs, severity/noise controls, and issue types before operational scanner design."
9.0 When does a thing become a governance object?
Coverage is discovered, not declared. A thing crosses into governed truth when it is born + active/UI-visible; candidates are governed as input-quality only (never governance orphans).
| Thing | Becomes governed when | Until then |
|---|---|---|
| Axis | axis_registry row lifecycle_status='active' |
input-quality |
| Topic node | taxonomy.status='active' and born |
candidate/provisional |
| Relation / edge | status='active' and provenance present |
candidate |
| Assignment | axis_assignment.zone='approved' |
candidate/quarantine |
| UI projection | a view/screen exposes the axis officially | n/a |
| Candidate (any) | never a governance orphan — governed as input quality | — |
9.1 Issue-type catalog (data rows, register-before-emit)
All ride existing system_issues buckets and emit on the governance event domain (SB-11; register the type before any emit — Điều 45). Severity is computed, not stored.
| issue_type | Detector input | Default severity | Coalesce grain |
|---|---|---|---|
axis_unregistered |
an axis-bearing surface not in axis_registry |
critical | (axis surface) |
inventory_gap |
axis_registry empty / facets unprojected (the current state) |
critical | (global) |
axis_owner_gap |
active axis with no owner_scope_ref resolvable in SB-2 |
high | (axis) |
axis_vocab_unowned |
axis vocabulary source with no owner | high | (axis) |
axis_grouping_island |
axis storing its own relations/issues/owners privately | high | (axis) |
topic_unowned |
active FAC-08 node with no owner | high | (node) |
wrong_topic / topic_low_confidence |
approved assignment with confidence < threshold or contradicted |
computed | (entity,axis) |
topic_overlap/topic_duplicate/topic_alias |
pg_trgm + KG similarity over taxonomy FAC-08 |
medium | (node-pair) |
topic_stale |
approved assignment older than coverage_rule.stale_after under a new ruleset_version |
computed | (entity,axis) |
ui_visible_unapproved |
a projection exposes a node/assignment not active/approved |
critical | (surface,object) |
reconstruction_integrity_fail/containment_cycle |
doc 08 detectors | critical | (doc / node) |
iu_object_orphan |
born object/axis with no owner / not covered | medium-high | (object) |
unratified_exception |
an exception in use without a governed exception row | high | (object) |
governance_island |
born+UI thing bypassing central APR | high | (object) |
hardcode_violation |
a literal where a registry/row is required (Điều 37) | high | (site) |
label_orphan/projection_lag |
entity_labels⇄axis_assignment reconcile drift (doc 05 §5.5) |
low-medium | (entity,axis) |
raw_status_authz |
a consumer reading governance_build_authorization.status for a COMMIT decision (doc 03 INV-10) |
high | (code site) |
9.2 Scanner discovery inputs (precise — GPT gap #5)
No new scanner is invented; reuse the GCOS six-layer scanner + T6 coverage DOTs. The hardened inputs:
| Input source | What it yields | Live anchor |
|---|---|---|
meta_catalog (orphan_count, actual_count vs baseline_count/record_count) |
objects drifting out of coverage | 169 rows |
collection_registry (coverage_status, coverage_scope_status, governance_role) |
per-collection coverage verdict ledger | 168 rows |
GCOS candidate-scan over birth_registry cursor-tail (key collection:entity_code) |
newly-born governed candidates | 1,069,055 rows; cursor SB-13 |
axis-surface sweep DOT enumerating axis-bearing surfaces (taxonomy_facets, label tables, KG edge types, pivot defs) vs axis_registry |
unregistered axes | — |
axis_assignment (zone, confidence, provenance, valid_time) |
wrong/low-confidence/stale/quarantine assignments | new |
SB-2 v_object_owner_gap |
owner gaps for axes/topics/objects | new |
| projection views vs lifecycle/zone | UI-visible-but-unapproved | new |
9.3 The five named detectors (build-ready sketches)
-- D1 unregistered axis: surfaces that classify but aren't registered
-- (taxonomy_facets / KG edge_types / pivot defs) EXCEPT axis_registry
SELECT s.surface FROM v_axis_surfaces s
LEFT JOIN axis_registry a ON a.vocabulary_source = s.surface
WHERE a.axis_code IS NULL; -- → axis_unregistered (critical)
-- D2 topic without owner
SELECT t.code FROM taxonomy t
JOIN taxonomy_facets f ON f.id=t.facet_id AND f.code='FAC-08'
WHERE t.status='active'
AND NOT EXISTS (SELECT 1 FROM v_object_effective_owner o -- SB-2
WHERE o.object_code=t.code AND o.owner_kind='accountable'); -- → topic_unowned
-- D3 local island: an axis whose relations/issues/owners aren't on the central spine
-- (private command catalog / private event family / private audit) → axis_grouping_island / governance_island
-- D4 UI-visible but unapproved
SELECT v.surface, v.object FROM v_ui_exposed_objects v
LEFT JOIN axis_assignment x ON x.id=v.assignment_id AND x.zone='approved'
WHERE v.is_official AND x.id IS NULL; -- → ui_visible_unapproved (critical)
-- D5 wrong / low-confidence / stale assignment
SELECT x.id FROM axis_assignment x
JOIN axis_registry a ON a.axis_code=x.axis_code
JOIN coverage_rule cr ON cr.code=a.coverage_rule_ref
WHERE x.zone='approved'
AND ( x.confidence < cr.min_confidence -- wrong/low-confidence
OR x.valid_time << tstzrange(now()-cr.stale_after,NULL) -- stale under new ruleset
); -- → wrong_topic / topic_stale (computed sev)
(v_axis_surfaces, v_ui_exposed_objects, v_object_effective_owner, coverage_rule are the named inputs; the first two are new helper views, the latter two are SB-2/registry rows.)
9.4 Severity / noise / coalescing rules
- Computed severity = f(issue_type base, blast radius, reversibility, is-UI-visible, is-non-exemptable-integrity). Stored severity is forbidden (it goes stale).
- Coalesce at governance grain via
issue_signature/ a per-type coalesce key (table above). Re-detecting the same condition updates one issue, does not spawn duplicates. - Materiality threshold per type (a row) — below it, the finding is informational, not alerting.
- Decaying verdict (§9.6) — "checked" is never a forever-boolean; an old PASS decays and is re-scanned.
- count > 1 = candidacy, not mandate — multiple weak signals raise candidacy for review, they do not auto-act.
- register-before-emit + heartbeat — no governance event emits until its type is registered (SB-11);
queue_heartbeatproves the scanner is alive (silent-gap detection, Điều 45).
9.5 Avoiding both failure modes
| Failure mode | Cause | Control |
|---|---|---|
| Under-coverage | declared coverage assumed complete; new born objects unseen | discovery (not declaration); birth_registry cursor-tail; meta_catalog.orphan_count delta; decaying verdict forces re-scan; inventory_gap fires when axis_registry is empty/incomplete |
| Noise explosion | every drift = a new alert | coalesce at grain; computed+materiality severity; candidacy-not-mandate; per-type thresholds; heartbeat not per-row chatter |
The decaying verdict is the bridge: it prevents under-coverage (stale PASS expires) and noise (a fresh PASS suppresses re-alerting within the freshness window).
9.6 Decaying verdict (SB-10)
Coverage verdicts live in governance_candidate_state, keyed (candidate_key, snapshot, ruleset_version, scan_time) where candidate_key = collection:entity_code (doc 05 §5.3). A verdict is valid only within coverage_rule.stale_after of scan_time and under the current ruleset_version (SB-12). For high-risk objects, staleness fails closed (G-PROD): an un-rescanned high-risk object is treated as non-compliant, not assumed-good.
9.7 Reuse & ownership
- No new scanner: reuse GCOS six-layer scanner; T6 = 7 coverage DOTs (read/propose only, gated, doc 12); T7 = issue/event/notification router riding
system_issues/event_outbox. The only new inputs are the axis issue types +axis_registry+ SB-2 owner views. - Owner map (proposals, to ratify under SB-2/OP-B): axis substrate → GOV-KG-SYS; axis policy → GOV-COUNCIL; integrity (recon/containment) → GOV-SIV; coverage detection → GOV-SIV; DOT execution → GOV-DOT; render/UI → GOV-MOUT.
9.8 Open decisions & forbidden-compliance
- O-COV-1: per-type materiality thresholds +
stale_aftervalues (rows). - O-COV-2: which issue types fail-closed vs advisory.
- O-COV-3: T6 read/propose-only even after build until C-7 rulings (no auto-apply).
- Forbidden-compliance: design-only; no issue created; no event registered/emitted; no DOT registered; no scan run; read-only.