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
- If a list already has classification/labels/groups → reuse it immediately (do not add another layer).
- If a list has no classification and is becoming too long to inspect safely → classification must start immediately, before it becomes unmanageable.
- Default max ungrouped threshold = 50 rows, but the backend may use a smaller threshold per species/list type (
max_ungrouped_thresholdis per-species, in PG). - Goal: every displayed layer short, inspectable, scalable.
- Pagination is not a substitute. Pagination helps the UI; semantic grouping/labeling is required when a list is too long.
- Labels MUST be PG-backed, governed, pivot-countable, registered — no 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+cardinalitymodel grouping cardinality.taxonomy_matrix(facet_id, composition_level, requirement)→ the source forchild_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_refresolves to a livetaxonomy/label_rulesrow; literal label array inweb/⇒hardcode_violation. - T-LABEL-2:
max_ungrouped_thresholdread from PG per species; a hardcoded50in frontend is itself a violation (the ceiling is data). - T-LABEL-3: group counts are
pivot_count/pivot_queryorPIVOT_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.