KB-5E94

03 — Dynamic Child-Layer Drill-Down Algorithm + Node Data Contract

5 min read Revision 1
architecturedrilldownchild-layernode-contractpivotparent-codeno-hardcode2026-05-31

title: 03 — Dynamic Child-Layer Drill-Down Algorithm + Node Data Contract date: 2026-05-31

03 — Dynamic Child-Layer Drill-Down

Principle (preserved from the original Registries design)

If a node has count > 1, the backend MUST be able to expose a child layer.

Drill path is dynamic depth, decided by the object's species/composition and grouping needs — never a fixed depth hardcoded in Nuxt:

root → layer → species/type → group/label → collection/registry → item group → individual object → final DB/relationship substrate

Leaf = the object DB substrate (a real row, or a relationship edge).

Live anchor + the gap

  • Anchor: pivot_definitions.parent_code (text) exists for exactly this purpose; pivot_count / pivot_query / pivot_matrix already produce node values; drill groupings already exist by registry_group (cross-table → PIV-101..106; l2-drill → PIV-201..206 by composition_level atom/molecule/compound/material/product/building) and composition_level/species columns are populated.
  • Gap (verified): parent_code is NULL on all 37 pivot rows — the hierarchy field is present but unwired. Drill today is implied by registry_group naming, not by an explicit parent→child edge. EXTEND: populate parent_code so the layer graph is data-driven, not string-convention-driven.

Backend-driven algorithm (no Nuxt depth logic)

For any node N the backend returns a node contract (doc 09). The drill decision is computed server-side:

function resolve_node(pivot_code, filter_path):
    value      := pivot_count(pivot_code, filter_path)          # the node's count
    has_children := value > 1 AND next_layer_exists(pivot_code, filter_path)
    if not has_children:
        return leaf(final_substrate_ref = source_object + filter_path)   # → real rows
    next := child_grouping_dimension(pivot_code, filter_path)    # species | composition_level | group | facet | ...
    children := pivot_query(child_pivot_of(pivot_code, next), filter_path)
    group_size := children.count
    requires_auto_label := group_size > max_ungrouped_threshold(species)   # doc 04 (default 50, may be smaller)
    return layer(children, next_layer_kind = kind_of(next), next_pivot_code = child_pivot_of(...),
                 requires_auto_label, label_ref = grouping_label(next))

next_layer_exists / child_grouping_dimension — data-driven sources (REUSE)

The next dimension is chosen from PG, in priority order, never from a frontend switch:

  1. an explicit child pivot via pivot_definitions.parent_code = N.code (after EXTEND);
  2. else the node's composition_level → next finer level (atom←molecule←compound←material←product←building) via v_pivot_by_level;
  3. else species breakdown via v_pivot_species_by_level / entity_species(has parent_id+depth → species sub-tree);
  4. else a label/facet dimension via taxonomy_facets (doc 04);
  5. else collection breakdown via species_collection_map (discriminator_field);
  6. else the leaf substrate (the source_object rows themselves).

Depth is a property of data, not code

  • entity_species.depth and taxonomy.depth already exist → species/label trees are natively variable-depth (Đ24 enforces cycle-check depth<5 on taxonomy).
  • A node terminates when value ≤ 1 OR no further dimension resolves OR it reaches the substrate. Nuxt renders whatever next_layer_kind the backend declares; it contains no if level === N logic.

Node contract fields (count>1 child-layer set; full contract in doc 09)

has_children · children_count · next_layer_kind · child_grouping_dimension · next_pivot_code · drilldown_query_ref · final_substrate_ref · group_size · requires_auto_label · label_ref · pin_state.

No-hardcode tests (detail in doc 08)

  • T-DRILL-1: for every node with children_count > 1, has_children = true and a resolvable next_pivot_code OR final_substrate_ref exists. Fail ⇒ a dead-end mid-tree.
  • T-DRILL-2: no Nuxt file contains literal depth/level branching for registries-pivot (grep for level ===, fixed layer arrays). Reuses system_issues('hardcode_violation').
  • T-DRILL-3: every node value equals a pivot_count/pivot_query result (or is marked PIVOT_MISSING); no client-side arithmetic.

Verdict

Drill-down is REUSE (engine) + EXTEND (populate parent_code). No new table required; the only schema change proposed is data (parent_code values) plus optionally child-pivot rows for dimensions not yet expressed as pivots — both additive, design-only.

Back to Knowledge Hub knowledge/dev/reports/architecture/registries-pivot-os-agency-count-integrity-orphan-phantom-label-pin-rehearsal-2026-05-31/03-dynamic-child-layer-drilldown-algorithm.md