KB-27BF

07 — Label / Grouping Policy (50 = MAX ungrouped ceiling, per-species)

5 min read Revision 1
designregistries-pivotauto-labelgroupingdieu24dieu29thresholdmax-ungroupedno-hardcode2026-05-31

title: 07 — Label / Grouping Policy date: 2026-05-31

07 — Label / Grouping Policy

Incorporates the GPT threshold clarification: 50 is a MAXIMUM ungrouped display ceiling, NOT a target. Not "wait until 50, then classify."

Binding interpretation

  1. If a list already has classification/labels/groups → reuse it immediately (do not add another layer).
  2. If a list has no classification and is becoming too long to inspect safely → classification must start immediately, before it becomes unmanageable.
  3. Default max ungrouped threshold = 50 rows, but the backend may use a smaller threshold per species/list type (max_ungrouped_threshold is per-species, in PG).
  4. Goal: every displayed layer short, inspectable, scalable.
  5. Pagination is not a substitute. Pagination helps the UI; semantic grouping/labeling is required when a list is too long.
  6. Labels MUST be PG-backed, governed, pivot-countable, registeredno frontend label arrays (Đ28 NT-D3).

Live anchors (REUSE/EXTEND — Đ24 Label Law + Đ29 Classification)

  • label_rules(38): condition jsonb → result_label, priority, status, skip_wide_warning — a wide-list concept already exists in the rule engine. REUSE as the classification rule store.
  • taxonomy(58)/taxonomy_facets(10)/taxonomy_matrix(36): governed label tree (Đ24, cycle-check depth<5). taxonomy_facets.max_labels_per_entity+cardinality model grouping cardinality. taxonomy_matrix(facet_id, composition_level, requirement) → the source for child_grouping_dimension.
  • entity_labels(718,744): applied entity↔label assignments — labels are live, not theoretical.
  • species_collection_map(164): discriminator_field/value/operator → grouping a collection by an intrinsic dimension.
  • collection_groups(9) + entity_species(42, parent_id+depth) + Đ29 species-grouping. → No new label store needed. Work = carry threshold/decision on the contract, resolve each label to a registered row, make group counts pivot-backed.

Decision algorithm (server-side; Nuxt holds no thresholds)

classify_list(node):
    if has_existing_grouping(node):                 # taxonomy/label_rules/species_collection_map present
        classification_status := 'classified'; return reuse_grouping(node)   # immediately
    threshold := max_ungrouped_threshold(node.species)        # PG; default 50, may be smaller
    if node.children_count <= threshold:
        classification_status := 'inspectable'; grouping_required := false
        return show_children_directly(node)
    classification_status := 'classification_required'        # acted on as soon as unsafe, NOT at exactly 50
    grouping_required := true
    grouping_reason := 'exceeds max_ungrouped_threshold(' || threshold || ')'
    dim := suggest_dimension(node)                            # from taxonomy_matrix/facets/species attrs
    if dim is null:
        classification_status := 'LABEL_MISSING'             # propose governed label generation
        emit system_issues(issue_type='label_missing', ...)  # propose type (doc 09)
    suggested_next_grouping := dim
    classification_workflow_trigger := 'label.classify'      # design (doc 09)

Contract fields (threshold addendum)

classification_status (classified|inspectable|classification_required|LABEL_MISSING) · classification_dimension · label_ref (→taxonomy.code/label_rules.id) · grouping_required · grouping_reason · max_ungrouped_threshold (per-species, default 50 = MAX) · suggested_next_grouping · classification_workflow_trigger.

Governance & no-hardcode

  • Labels live in taxonomy/label_rules (PG), counted by pivots (PIVOT_MISSING: PIV-31x label-by-facet), governed by Đ24 (provenance, status lifecycle, replaced_by).
  • T-LABEL-1: every label_ref resolves to a live taxonomy/label_rules row; literal label array in web/hardcode_violation.
  • T-LABEL-2: max_ungrouped_threshold read from PG per species; a hardcoded 50 in frontend is itself a violation (the ceiling is data).
  • T-LABEL-3: group counts are pivot_count/pivot_query or PIVOT_MISSING.

Acceptance impact

PASS only if 50 is treated as a per-species MAX ceiling (can be smaller), existing grouping is reused immediately, classification starts before lists become unmanageable, labels are PG-backed/governed/pivot-countable, and there is no frontend label array or hardcoded threshold.