KB-6732

02 — Open Axis Model: From Current Domains to Future Axes (Branch B) (2026-06-01)

13 min read Revision 1
one-roof-governancehardening-revisionbranch-bopen-axis-modelaxis-registryfuture-axisno-hardcodeaxis-as-governed-objectcoverage2026-06-01

02 — Open Axis Model: From Current Domains to Future Axes (Branch B)

Generalizes One-Roof Governance from "today's known domains" to an open-ended axis model so future axes/modules/object-types/registries/DOTs/documents/IU-structures are pulled into coverage automatically, with no hardcoded axis array. No SQL is designed here; this is the law/design model. New definition: M-DEF-8 (Axis) and M-DEF-9 (Axis Registry) (consolidated in doc 13).

2.0 The problem this solves

The prior pack enumerated the current axes (grouping, classification, threshold, pin, phantom, pivot coverage, render). That is a hardcoded list — it cannot answer the mission's question 4 ("how is a new domain/axis/object type automatically pulled into governance coverage?") or question 6 ("how do we avoid hardcoding current domains/axes?"). The fix is to stop enumerating axes and instead define what an axis is, make an axis a governed object, and detect any un-registered axis the way the system detects orphans.

2.1 What is an axis (M-DEF-8)

An axis is any dimension along which system objects are classified, counted, grouped, pivoted, ordered, related, or displayed — i.e. any dimension that can change shared truth, classification, counting, display, or interpretation. An axis is distinct from the objects it organizes: unit_kind is an axis over information_unit rows; legal_domain tags are an axis; the parent→child→grandchild containment is an axis; a pivot's group-by column is an axis.

The membership predicate is the same shared-truth-reachability test as M-DEF-1, narrowed by a structural test: a thing is an axis if changing its definition, vocabulary, or grouping policy changes what is classified/counted/grouped/displayed as truth. No enumeration is needed — the predicate decides, so unknown future axes are in-scope automatically.

An axis is a governed object (coverage profile AXIS, doc 06 class 4). Therefore everything One-Roof says about governed objects — owner, approval, audit, rollback, issue/event path, detection — applies to axes by inheritance of the model, not by re-statement per axis.

2.2 The nine attributes of a governed axis

Every axis, present or future, is described by nine attributes. These are the registration record, not a fixed list of axes:

Attribute Meaning Example (IU legal_domain tag axis)
axis the dimension's stable code axis.iu.legal_domain
axis family the registry/domain it belongs to iu (Information Unit)
axis owner (per scope) accountable owner for policy (vocab/grouping) + supporting health/execution/render policy: GOV-COUNCIL; substrate/health: GOV-KG-SYS
axis scope who/what it spans: global / domain-local / object-local; cross-surface or single-surface global, cross-surface (KB + pivot + display)
axis source registry the registry that holds the axis's vocabulary (the allowed values) Đ24 taxonomy / dot_config (deferred — OPEN P38-X-11)
axis grouping policy the COUNCIL-owned policy governing grouping ceilings, pin, thresholds for this axis max_ungrouped ≤ 50 row (Đ24/29)
axis coverage rule the per-profile mandatory links (owner + risk-required) the axis must carry to be covered owner + vocab-source-registry + grouping-policy + issue-path
axis issue path the registered issue/event types fired when the axis is orphan/unregistered/island axis_unregistered, axis_owner_gap, axis_vocab_unowned
axis lifecycle birth → register → active → deprecate → retire (Đ0-G + Đ30) draft vocab → APR-medium enacted → retire reversible

A future axis is registered by filling these nine attributes — data, not code. No law rewrite, no array edit.

2.3 The Axis Registry (M-DEF-9) — the missing governed registry

The Axis Registry is a governed registry object (coverage profile POLICY/REGISTRY) that enumerates every active axis with its nine attributes. It is the ground-truth inventory of axes that the coverage scanner reconciles against (doc 01 T1-7; doc 10).

Live status (verified this session, doc 03/00): NO axis-registry table or governed registry exists. Axis vocabulary is scattered — unit_kind (a controlled-draft vocab), axis_b_tags (an open JSONB tag-bag with namespaces unit_kind/section_type/legal_document/topic/legal_domain), the pivot definitions, dot_config, Đ24 facets. The IU design itself flags this: "there is no single axis-registry table; axis-B vocab anchoring is an OPEN item (Đ24 vs dot_config, deferred APR)." This absence is itself a governance gap — until the registry exists, the coverage scanner cannot reconcile axes, so axes are detected case-by-case and unknown axes escape. The registry's absence is detectable as an inventory_gap (critical) the moment the model is adopted.

The Axis Registry is NOT a new island: it is owned per-scope under the existing spine (policy → GOV-COUNCIL; substrate/vocab → GOV-KG-SYS; detection → GOV-SIV; execution → GOV-DOT), reuses the registry pattern (Điều 2), and is born via the Birth Registry (Điều 0-G).

2.4 Worked map of the current axes (illustrative, not a closed list)

These are the axes that exist or are implied today, each mapped to the nine attributes. This table is an example of applying the model, not a hardcoded set — the model would generate the same record for any new axis.

Axis Family Source registry (vocab) Policy owner Substrate/health owner Open-ended? How new value added
IU original-source / order (axis A: doc_code/section_code/sort_order) iu information_unit source cols COUNCIL GOV-KG-SYS values open; schema fixed data (any doc_code)
IU specialty/domain (axis B: axis_b_tags namespaces) iu Đ24 / dot_config (deferred) COUNCIL GOV-KG-SYS fully open tag-bag data (new namespace key)
IU parent-child-grandchild (axis C: containment) iu iu_relation (contains) COUNCIL GOV-KG-SYS depth open; schema fixed data (new edge)
Composition / species composition Đ0-B levels + Đ29 species COUNCIL GOV-KG-SYS open via Đ29 vocab data (APR-medium)
Registry / pivot group-by registry pivot_definitions / meta_catalog COUNCIL GOV-SIV open data (new pivot row)
Workflow / task assembly BPMN (Đ34) COUNCIL GOV-MOW/MOT (draft) open data
DOT operation / domain dot dot_tools domain COUNCIL GOV-DOT open data (register DOT)
Label / taxonomy taxonomy Đ24 facets / label_rules COUNCIL GOV-KG-SYS open data
Event / queue event event_type_registry COUNCIL GOV-SIV open (register-before-emit) data

The point of the table is that every row was produced by the same nine-attribute template. A tenth, eleventh, hundredth axis is produced identically — the law does not grow.

2.5 How a future axis is born, registered, and covered

  1. Born (Điều 0-G). A new axis is created like any object: it gets a birth-registry entry. Before birth it is a birth-orphan (handled by the birth detector, precedence per M-DEF-4).
  2. Registered (Axis Registry, M-DEF-9). Its nine attributes are filled. Registration is an APR-gated change (it can change classification/counting/display truth) — assign_axis_owner action-type (doc 01 T1-6: prerequisite). Vocabulary anchors to a named source registry (Đ24 or a declared dot_config/registry surface).
  3. Owner-assigned (per scope). policy owner (COUNCIL), substrate/vocab owner (GOV-KG-SYS or the family's substrate owner), health (GOV-SIV), execution (GOV-DOT), render (GOV-MOUT after activation; interim COUNCIL delegation).
  4. Coverage rule attached (profile AXIS, doc 06). Mandatory links: owner + source-registry + grouping-policy + issue-path; risk-required: approval-path (vocab edits are APR-gated), audit, rollback.
  5. Covered ⟺ all profile-mandatory links resolve. Until then it is axis_orphan / axis_unregistered / axis_vocab_unowned.

2.6 Minimum governance coverage for any axis

Required Why
Accountable policy owner (one) a dimension that changes truth must have one accountable definer
Named source registry for its vocabulary no axis may invent its own classification outside a registered vocab (Đ24) — else axis_vocab_unowned/classification-island
Grouping/threshold policy as COUNCIL-owned rows numeric ceilings (e.g. max_ungrouped ≤ 50) are governed rows, never literals
Issue/event path registered (register-before-emit) orphan/island detection must have a place to write
Approval path for vocab/grouping edits adding a value or changing a ceiling can change counts/display → APR-gated
Audit + rollback vocab/grouping changes are reversible and logged
Coverage inheritance: owner-link ONLY an axis-family container may pass its owner to member axes; risk links computed per axis (anti-hiding)

2.7 How an unregistered axis is detected (the orphan analog)

The mission requires "the system must detect anything outside governance like it detects orphans." For axes this is concrete:

  • axis_unregistered (critical): a thing functioning as an axis — appearing as a pivot group-by column, a classification facet, a tag-namespace driving display, a new unit_kind value, a new grouping dimension — that is not present in the Axis Registry. Detected by reconciling ground-truth axis-bearing surfaces (pivot_definitions, axis_b_tags namespaces, Đ24 facets, meta_catalog dimensions, dot_config grouping keys) against the Axis Registry. This is the axis-level inventory_gap.
  • axis_owner_gap (high): registered axis missing an accountable policy owner.
  • axis_vocab_unowned (high): axis whose vocabulary is not anchored to a registered source registry (a classification island — red-team #6/#25).
  • axis_grouping_island (high): axis whose grouping/threshold policy lives in a local table with no central owner (red-team #4/#29).

Detection is the same six-layer scanner as for objects (doc 10), reading axis-bearing surfaces as just another input. No per-axis code.

2.8 How Registries-Pivot displays an axis

Registries-Pivot is the render surface for the Axis Registry and axis coverage, under Đ28 (render owner GOV-MOUT, interim COUNCIL delegation). It must:

  • list every registered axis with its nine attributes and coverage state (covered / orphan / island / exception) — pivotable by family, owner, scope, lifecycle;
  • surface axis_unregistered / axis_owner_gap / axis_vocab_unowned as first-class rows alongside object orphans (not a separate page);
  • compute no axis truth in Nuxt — it reads L5/pivot/coverage views only (Đ28 NT-D1-ext, doc 04). A hardcoded axis list in the UI is itself a red-team target (#37) → hardcode_violation.

2.9 How DOTs scan / propose / apply / audit an axis

Axes reuse the coverage-DOT lifecycle (Đ35 §6.2-bis): DETECT (scan axis-bearing surfaces vs Axis Registry) → PROPOSE (assign_axis_owner / register_axis APR — prerequisite action-type) → APPROVE (Đ32 quorum) → APPLY (write axis ownership edge — needs §5.4-EXT object/axis edge, T1-6 prerequisite) → VERIFYCLOSE. Separation of duty: the DOT never approves its own axis registration. The same two-mode-apply limitation as objects applies: axis-grain owner edges are apply_blocked until §5.4-EXT (T1-6).

2.10 No fixed axis arrays — compliance statement

This model contains no enumerated axis array that the system depends on. The current-axis table (§2.4) is illustrative; the runtime depends only on (a) the shared-truth/axis predicate (M-DEF-1/8), (b) the Axis Registry (M-DEF-9, data), and (c) the inventory-completeness reconciliation (doc 10). A future axis is a new registry row; the laws, the scanner, and the display do not change. This satisfies mission §5 ("do not create fixed axis arrays") and questions 4/6.

Branch-B verdict

The open axis model converts "governance of the current axes" into "governance of whatever functions as an axis." The one new dependency is the Axis Registry (M-DEF-9) — a governed registry object that does not exist live; its absence is the first thing the model detects (inventory_gap). With it, future axes are covered by data, and an unregistered axis is caught exactly like a birth-orphan.

Back to Knowledge Hub knowledge/dev/reports/architecture/one-roof-governance-hardening-revision-all-domains-all-axes-2026-06-01/02-open-axis-model.md