06 — Governance Coverage Invariant Hardening (Branch F) (2026-06-01)
06 — Governance Coverage Invariant Hardening (Branch F)
Reviews decision-pack doc 04 (
…/04-governance-coverage-invariant.md). Adversarial. The invariant is the keystone that makes One-Roof self-enforcing — so its closure rules must be exact.
F0. What the pack says (summary)
Doc 04 states the identity total_governed(S) = covered + governance_orphans + approved_exceptions + retired_or_ignored, which must "close exactly for every scope" (the governance twin of the RP count-integrity invariant). Derived gates: production-eligibility (orphans({o})==0), authority, DOT, issue. Inheritance (§4.4) lets coverage flow parent→child where law permits (DOT never inherits). §4.5: "computed, never remembered." §4.6: GOVERNANCE_COVERAGE_PASS(feature) = every touched object covered==true OR approved-exception. §4.7: honest baseline = FALSE today (draft owners, agency-orphaned laws, unratified exception).
Overall: the accounting-identity approach is excellent and the right model. But there are three contradictions/loopholes that, unfixed, let the identity close while real gaps hide, or make the gate trivially unsatisfiable.
F1 — Contradiction: per-object identity (doc 04) vs container-grain (doc 11)
- Original: doc 04 §4.2 says the identity holds "for any scope" over "governed objects," counting "at the object grain." Doc 11 §11.1 says "10⁸ records collapse to a few thousand registry-coverage checks … governance coverage is resolved at the owning-container grain, not the leaf-record grain."
- Contradiction: these describe different populations. If
total_governedis per-object (doc 04), 10⁸ records are in it (the explosion doc 11 forbids). If it's container-grain (doc 11), thentotal_governedis NOT "all governed objects" and the identity is over a reduced set — but doc 04 never says which objects are excluded. An implementer can't build a closing identity from two incompatible population definitions. - Hardened wording — define the governance grain precisely (the leaf-vs-meta discipline applied to governance):
"The coverage identity is computed at the governance grain, defined as the set of objects that require their own coverage: (a) roots (objects with no covered parent), (b) non-inheriting classes (policy, DOT, route/surface, law, pivot, exception — anything in a non-EPHEMERAL profile that does not inherit), and (c) containers (registries/collections that other objects inherit from). Inheriting leaf records are NOT counted individually — they are represented by their container's coverage (one container check stands for all its inheriting children).
total_governed(S)= count of governance-grain objects in S, never the leaf-record count." - This is the exact analog of the RP
v_registry_leaf_setleaf rule that kept count-integrity correct (a meta/rollup row is not summed with its children). State it with equal precision: a governance-grain object is one whose coverage is NOT fully determined by a covered parent. - Acceptance test: the identity closes over the governance-grain population; adding 10⁶ inheriting child records to a covered container changes
total_governedby 0 (they inherit), proving container-grain; adding one new root changes it by 1 and surfaces asOWNER_GAPif unowned. - Open question: none — this is the single most important precision fix in the invariant.
F2 — Loophole: retired_or_ignored lets any object be parked to make the identity close
- Original: §4.2 term 4 = "retired_or_ignored — lifecycle=retired, or explicitly out-of-governance by law."
- Loophole: "ignored" is an un-gated escape hatch. To make
orphans(S)=0(pass the gate), one can move an inconvenient object intoignored. Who authorizes "ignored"? The pack doesn't gate it. This is the accounting equivalent of writing off a liability with no approval. - Hardened wording — split the term and gate "ignored":
"
retired(lifecycle=retired per Điều 36; Luật Bảo toàn — retire ≠ delete) is free (a retired object legitimately leaves the coverage population).ignoredis NOT free: marking an object out-of-governance is itself a permanent exception requiring the same COUNCIL approval + law-ref as any exception (Branch E), and it carries areplacement_plan(why it can stay out forever). An object inignoredwith no approval is itself anUNRATIFIED_EXCEPTION(critical)." - Rename the term
retired_or_approved_ignoreto signal the gate. - Acceptance test: moving an object to
ignoredwithout a COUNCIL-approved out-of-governance record raisescritical, not silently shrinks the orphan count. - Open question: none.
F3 — Contradiction: is a warning-severity orphan blocking? §4.6 says yes, §4.7 says no
- Original: §4.6:
GOVERNANCE_COVERAGE_PASS(feature)= every touched objectcovered == trueOR approved-exception. §4.7: a draft-owner object is awarning-severity orphan (covered == false) but is treated as a tolerable baseline, not a production blocker. - Contradiction: a draft-owner orphan has
covered == false, so §4.6 ("covered==true required") blocks it. But §4.7 treatswarningas non-blocking. The gate is not severity-aware, so it either blocks on warnings (too strict — every feature touching anything MOUT-rendered fails because MOUT is draft, J6) or it silently treats warnings as pass (undocumented). - Hardened wording — make the gate severity-aware:
"
GOVERNANCE_COVERAGE_PASS(feature)⟺ for every touched governance-grain object: zerocriticaland zerohighorphans (or covered by an unexpired approved exception).warningorphans are reported and tracked with a remediation deadline but do not block the production gate;infois ignored. The gate blocks on anarchic / authority-critical gaps, not on descriptive ones." - This aligns with D2 (anarchic = authority-critical missing link) and §4.7's honest baseline: draft-owner = warning = tracked-not-blocked, with a deadline to activate.
- Acceptance test: a feature touching only
warning-orphan objects passes the gate (with deadlines logged); a feature introducing ahigh/criticalorphan fails. The two clauses (§4.6/§4.7) no longer contradict. - Open question: OQ-F3 — what remediation deadline converts a tolerated
warninginto a blockinghigh? (Age-based escalation; council sets the window — links to H3.)
F4 — Exception term must align with B5 (exception is NOT covered)
- Original: §4.2 has
approved_exceptionsas a separate term (correct), but §4.3 lists "approved exception" as a valid owner path (so it would land incovered) — the B5 contradiction surfaces here too. - Hardened wording: as B5 — remove "approved exception" from §4.3's valid-owner-path list; an exception object counts only in
approved_exceptions, nevercovered. This keeps the four identity terms mutually exclusive (no object in two terms), which is required for "closes exactly." - Acceptance test: every governance-grain object is in exactly one of the four terms; the four counts partition
total_governedwith no overlap. - Open question: none.
F5 — "covered requires an active agency" makes the baseline mostly-FALSE and the gate near-unusable today
- Original: §4.3.1: owner paths 2/3 require an active agency; GOV-MOUT/MOW/MOT/MOIT are draft, so objects owned only by them are "not yet covered" (warning). Laws 24/26/28/45 have no owner edge →
OWNER_GAPregardless. - Risk (not a defect — but needs the F3 fix to be usable): with the strict §4.6, this makes
GOVERNANCE_COVERAGE_PASSFALSEsystem-wide today, which the pack honestly admits (§4.7). But a gate that is always red is ignored. The F3 severity-aware fix is what makes this baseline actionable (draft-owner = warning = non-blocking-with-deadline), so F5 is resolved by F3 — but only if F3 lands. Flagging the dependency. - Hardened wording: none new — explicitly note "§4.3.1 is only usable in combination with the F3 severity-aware gate; otherwise the gate is permanently red and will be bypassed."
- Acceptance test: with F3 applied, today's baseline yields a PASS for features that touch only draft-owner (warning) objects, while still surfacing the backlog.
- Open question: see J6 (interim render-owner so MOUT-draft doesn't make every UI feature a high orphan).
F6 — Inheritance closure can hide a broken parent (cycle/depth corner)
- Original: §4.4 inheritance is bounded-depth, cycle-free (RP walk depth-3). A child is covered if
covered(parent). - Corner case: if the parent's coverage is itself stale (not re-scanned since its owner went draft, G3), the child inherits a stale TRUE. Inheritance propagates stale coverage downward.
- Hardened wording: inheritance carries the parent's
last_scanned_atand the parent's worst severity down to the child; a child's effective coverage freshness =min(own, parent-chain); a stale parent makes the whole subtreeSTALE(doc 11 §11.9), not silently covered. - Acceptance test: marking a parent stale marks its inheriting subtree stale; the subtree cannot satisfy the production gate while stale.
- Open question: none.
F7 — Numerical anchor (§4.7) is illustrative but states the gate predicate before F3 — must be re-stated
- Original: §4.7 computes "current
GOVERNANCE_COVERAGE_PASS(system, truth-class) = FALSE" using the pre-F3 predicate. - Note: after F3, restate it as "
PASS = FALSEbecause there existhigh/criticalorphans (agency-orphaned laws 24/26/28/45 =OWNER_GAPhigh; Direct-PGUNRATIFIED_EXCEPTIONcritical/QUARANTINED), while the 4 draft owners arewarning(tracked, non-blocking)." This is more precise and still honest. - Acceptance test: the baseline narrative distinguishes the blocking (high/critical) gaps from the tracked (warning) ones.
- Open question: none.
F-summary — Branch F verdict
| ID | Severity | Type | Disposition |
|---|---|---|---|
| F1 | high | contradiction | define governance grain (container + non-inheriting); leaves not counted |
| F2 | high | loophole | gate "ignored" as a permanent approved exception |
| F3 | high | contradiction | severity-aware gate: block on high/critical, track warning |
| F4 | high | contradiction (=B5) | exception is a separate term, not covered |
| F5 | medium | usability | resolved by F3; note the dependency |
| F6 | medium | corner | propagate staleness through inheritance |
| F7 | low | restate | re-state baseline using severity-aware predicate |
The invariant is the best idea in the pack and the most dangerous if imprecise: F1 (grain) + F3 (severity-aware gate) + F2 (ignore gating) are all mandatory before the views are rehearsed (P4), or the identity will close while real gaps hide.