KB-3320

10 — UI Contract — OS Agency Standard (Đ28 render-shell)

4 min read Revision 1
designregistries-pivotui-contractos-agencydieu28render-shelldesign-templatestraffic-lighttokens2026-05-31

title: 10 — UI Contract — OS Agency Standard date: 2026-05-31

10 — UI Contract — OS Agency Standard

The surface is a render-shell over PG (Đ28). Nuxt reads a registered template + config + the doc-03 contract and renders. Nuxt does no business logic, no DB query, no counting, no hardcode, no components outside the template (Đ28 NT-D1). Config lives in PG JSONB, not text/arrays (NT-D3).

Template registration (Đ28)

Every display surface = an instance of a template registered in design_templates (status active via template_statuses + fn_template_lifecycle_guard(); 8-key birth checklist). Reuse existing templates:

  • TabPivot — the L1 9-row summary + matrix tabs (Đ26 Tab Pivot).
  • DirectusTable / DynamicEntityList — L2/L3 group & entity lists.
  • DirectusMatrix (TPL-002) — L5 matrices (≤7 dims).
  • (L4 detail) — entity "DB about itself" template (6 headings). Any route not backed by an active registered template renders "Not found" (Đ28 §VIII whitelist) — so the surface cannot show a fabricated/phantom screen.

OS-Agency node columns (rendered from the doc-03 contract)

Reflection row (per node/list): total · plus · minus · orphan · phantom · drift · verification · warning · next_action, plus drill affordance when has_children, plus pin_state, plus the child-summary chips (child_count, child_orphan/phantom/drift, missing_birth/pivot/iu/dot, top_child_groups). Numbers render exactly as served (pivot value or the literal PIVOT_MISSING).

Traffic-light + status semantics (reuse OS-Agency tokens)

  • 🟢 green = verified, count_integrity ok, no warnings.
  • 🟡 amber = drift OR unmonitored OR classification_required OR PIVOT_MISSING.
  • 🔴 red = count_integrity failed OR orphan/phantom present OR unregistered.
  • Tokens: primary #639922, accent #ef9f27, alert #e24b4a (established OS-Agency palette).
  • Warning flags shown as chips; next_action as an explicit affordance (not a hidden state).

Drill interaction

Click any node with has_children → backend resolve_node returns the child layer (doc 04). Breadcrumb shows the dynamic path root→…→substrate. At a leaf, render L4 detail (the object's own DB view + relations/IU). The client never decides depth or layer kind — it renders next_layer_kind.

Pin / label affordances

  • Pin: a pin toggle posts an event (design) → registry_pin; pin_state re-rendered from PG (doc 08). No local pin state.
  • Grouping: when requires_auto_label, the layer renders grouped by label_ref/suggested_next_grouping; LABEL_MISSING renders an explicit "needs classification" affordance (doc 07), not a flat 1000-row dump.

Accessibility / scale

  • Long lists are grouped (doc 07), not just paginated — keeps each rendered layer ≤ the per-species ceiling.
  • WCAG 2.1 AA contrast on the palette; traffic-light has text/icon, not color-only.

Boundaries (forbidden in the shell)

  • No reduce/Math.abs(gap)/Σ on counts (the health.get.ts anti-pattern — doc 11).
  • No literal category/species/label/threshold arrays.
  • No direct PG from Nuxt; all data via Directus/API serving the doc-03 contract.
  • No route or component outside the Đ28 registry (DOT-template-coverage scanner target: 0 outside registry).

Coverage / parity

  • Đ28 Test-4 Truth Check: 100% of rendered cells == PG, 0 wrong.
  • DOT-template-coverage: every registries-pivot route maps to a registered template; 0 outside registry.
  • UI preview specs (when needed) live under knowledge/dev/ui/registries-pivot/; runtime static preview under /ui-preview/registries-pivot/<version>/ (per doc-governance, only when a preview is needed).