04 — new_candidates Fix
04 — PROC:new_candidates Fix (6 candidate buckets vs 50 members)
Decision
count_value=6 is correct and already live (wf_process_candidate classification=PROCESS_CANDIDATE = 6, matches v_process_trigger_actionability_ledger_live). The node count is a group-bucket count (6 candidates the president would birth), not a member count. The 50 members are a deeper drill (candidate → its members). No split needed; no data change.
Change (reconciliation-basis declaration)
Declared count_grain='group_bucket' and reconciles_against='group_count' for this node in v_process_trigger_actionability_ledger_live_v2. The grain-aware grouping surface v_rp_pxt_grouping_surface_v2 computes reconcile_target = group_count = 6. v_pxt_grouped_children_v2 keeps the members rollup (child_total=50) as informational ("6 candidate groups · 50 members") — the invariant reconciles on group_count, not child_total.
Members by candidate are reachable via wf_process_candidate_member (substrate_ref) when drilling an individual candidate — the architecturally-correct second level.
Result (dual-path verified)
v_rp_full_population_drill_invariant_v2 row for PROC:new_candidates: count=6, grain=group_bucket, group_count=6, child_total=50, reconciles_against=group_count, reconcile_target=6, grouped_reconciles=true, invariant_status=PASS, reason="GROUPED reconciled on group_count: count=6 across 6 groups".
Why this generalizes
The invariant v2 now picks the reconciliation basis per node from a declared grain:
group_bucket→ reconcilecount == group_count(new_candidates).leaf/leaf_scoped→ reconcilecount == child_total(TRIG nodes, owner_gated, residual scoped). This single rule classifies every GROUPED node correctly without per-node special cases.