KB-1E06

Topic Axis — 09 Safety / Governance / No-Hardcode Audit

4 min read Revision 1
topic-axissafetyno-hardcodeaudit2026-06-04

09 — Safety, Governance & No-Hardcode Audit (Workstream H)

No-hardcode checks (all PASS)

  • No topic_level_1/2/3 columns — PASS. Depth is emergent from taxonomy.parent_id chains ∪ universal_edges; no level columns anywhere in axis_registry or axis_assignment.
  • No tree-only assumption — PASS. parent_codes is an array; has_multiple_parents is a first-class flag; breadcrumb is per-parent. The DAG-aware surface exists precisely because the legacy surface was tree-shaped.
  • No topic-only schema — PASS. axis_registry/axis_assignment are generic; AX-TOPIC is one data row; FAC-09 (Tầng kiến trúc?) or any future axis is another row.
  • No auto-active AI topics — PASS. AX-TOPIC = CANDIDATE; all 25 assignments = candidate; 0 taxonomy nodes; 0 approved roots; 0 births. Điều 39 upheld.
  • No direct promotion without approval — PASS. Promotion lives only in the gated operator packet.
  • No ungoverned assignment treated as final — PASS. governance_status = UNGOVERNED_CANDIDATE on all 7 nodes; PIV-332 governance gap = 7.
  • axis_registry supports future axes — PASS (generic columns, node_filter jsonb).
  • axis_assignment supports multiple target types — PASS (target_type free; bridge in doc 08 uses 6+ types).

STOP conditions (encoded as warning_flags / classifications)

  • axis has no resolver → axis_registry.substrate_resolver required (AX-TOPIC = fn_topic_node_substrate).
  • relation source missing → relation_source recorded; absence would surface as 0 edges (PIV-323).
  • root rule missing → root_rule NOT NULL (enforced).
  • lifecycle missing → lifecycle_field recorded (taxonomy.status).
  • owner missing → governance_status = UNGOVERNED_CANDIDATE; PIV-332 counts it.
  • grouping needed but missing → grouping_status = GROUPING_REQUIRED.
  • orphan/phantom topic relation → warning_flags ORPHAN_TOPIC_NODE; PIV-329 orphan / PIV-330 phantom.

Mutation safety ledger (this macro)

  • Live mutations: additive only — 2 tables, 3 indexes, 2 views, 1 function, 1 axis row, 25 candidate assignment rows.
  • Triggers fired by these inserts: none (the new tables carry no triggers; DDL event-guard ignores non-trigger objects).
  • Births created: 0 (confirmed: birth_record null in resolver for candidate nodes).
  • Business tables modified: 0 (iu_metadata_tag source = 25 before and after).
  • Reversibility: full DROP script; rehearsed BEGIN/ROLLBACK net-zero before commit.

Forbidden-action register (all respected)

No topic island table; no topic levels; no candidate→active promotion; no faked GOV-COUNCIL approval; no deletion/rewrite of iu_metadata_tag evidence; no blind tag conversion (each row carries evidence_ref + candidate status); no Nuxt count math; no DAG-into-tree flattening; no RP cleanup; no dot-pivot-update touch; no birth/pre-birth/governance broad alteration; no full workflow engine; all nine workstreams completed (not a single artifact).

Generalisation verdict

The pilot is safe to generalise: a second axis (e.g. AX-LAYER over FAC-09) is purely a new axis_registry row + its own resolver, reusing axis_assignment and the surface view unchanged.

Back to Knowledge Hub knowledge/dev/reports/architecture/topic-axis-ratify-apply-pilot-populate-surface-automation-bridge-2026-06-04/09-safety-governance-no-hardcode-audit.md