07 — UI/API Topic-Axis Contract (Workstream E)
07 — UI/API Topic-Axis Contract (Workstream E)
Goal: ensure the UI does not break when topics are graph-like (many parents), and define the exact backend fields. No UI patch is authored here — §10/§12: lock the contract first.
The core problem
The live v_registries_pivot_surface is tree-shaped: node_code, parent_code, is_root assume one parent. A topic axis is a DAG — a topic can have multiple parents and lateral broader/narrower edges. Rendering a DAG through a single-parent tree silently drops parents (a correctness bug) — exactly the "do not make UI assume a tree only" forbidden item.
Decision: a graph-aware companion surface, not a mutation of the tree surface
Add v_registries_pivot_axis_surface (new, additive) alongside the existing tree surface. The legacy registry surface keeps working unchanged; the axis surface carries the DAG. This mirrors the prior pattern (v_registries_pivot_surface was added as a companion to v_registries_pivot_node_contract).
Fields the backend must expose (per node, computed in PG — never Nuxt)
| Field | Source | Why |
|---|---|---|
axis_code |
axis_registry |
which axis this node belongs to |
node_code |
taxonomy.code |
the topic node |
label / name_en |
taxonomy.name |
display |
canonical_parent_code |
taxonomy.parent_id |
the breadcrumb default |
parent_codes[] |
universal_edges + parent_id |
ALL parents (DAG) |
has_multiple_parents |
derived | UI shows context chip when true |
path / breadcrumb |
recursive over canonical parent | navigation |
relation_type |
universal_edges.kind |
broader/narrower/related |
lifecycle_status |
taxonomy.status |
candidate/active/deprecated badges |
governance_status |
governance_object_ownership join |
owned / owner_gap |
count_value |
pivot result | the measure (honest, may be 0) |
count_status |
derived | pivot_backed / PIVOT_MISSING (never silent 0) |
child_count |
derived | drives layer + grouping |
child_layer_kind |
axis rule | how children group |
grouping_status |
rp_grouping_policy |
SATISFIED / NEEDS_GROUPING / NOT_REQUIRED |
pin_state / pin_sort_rank |
registry_pin |
root priority/pinning |
substrate_ref |
fn_topic_node_substrate |
the final drill target |
warning_flags |
derived | orphan/phantom/drift/owner_gap |
The existing 34-col surface already provides ~20 of these (count_status, grouping_status, pin_, warning_flags, final_substrate_ref, child_). The net-new axis fields are: axis_code, parent_codes[], has_multiple_parents, path/breadcrumb, relation_type, lifecycle_status, governance_status.
UI behavior contract
- Root topics = Layer 1 (axis
root_rule). - Child topics = next layers (dynamic depth; no hardcoded 3 levels).
- Multiple-parent topic = render once with a breadcrumb/context chip; do not duplicate or pick a parent arbitrarily;
has_multiple_parents=truedrives the chip. - Topic substrate page = drill terminal renders
fn_topic_node_substrate(documents/IU/workflows/DOTs/events/governance/birth/lifecycle). - Badges: candidate/warning (
lifecycle_status,warning_flags), pin/root priority (pin_*), grouping when children > threshold (grouping_status). - Forbidden in UI: tree-only assumption; hardcoded 3 levels; computing counts/depth/grouping in Nuxt.
API surface
Extend the existing API family (no breaking change):
/api/registries-pivot/axes→ list registered axes fromaxis_registry./api/registries-pivot/axis/{axis_code}/rows→ nodes fromv_registries_pivot_axis_surface./api/registries-pivot/axis-node/{node_code}→fn_topic_node_substrate. Reuses the live pattern (counts in PG, Nuxt renders contract only).
Apply-packet (authored, NOT applied — keep prod minimal)
The companion view + resolver are specified as a paste-ready apply packet held for operator/owner, not executed this session (Live mutation = NO):
axis_registry+axis_assignmentDDL (additive, born, reversible) — owner-gated.v_registries_pivot_axis_surface(DROP-reversible read view overtaxonomyfacet 8 +universal_edges+governance_object_ownership+ pivot results).fn_topic_node_substrate(topic_code)(STABLE, read-only).- Pivot rows PIV-310, PIV-320..332 (additive
pivot_definitionsinserts). Why not apply now: FAC-08 is empty andaxis_registrylaw is unratified; projecting an empty axis would add prod objects with nothing to render and pre-empt owner law. The packet is the deliverable; enactment is doc 09's next macro.
UI/API impact summary (answer to macro Q8)
The current UI/API does not break if the tree surface is left intact and the axis DAG is served by a separate companion surface + axis API. The required additions are 7 net-new fields, one companion view, one resolver function, one axes endpoint — all additive. No tree-shaped assumption may leak into topic rendering.
Workstream E completion: UI/API topic-axis contract is explicit; surface extension is specified as an unapplied apply-packet.