You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
scientific(membership): reject zero-share active affiliations #613
MembershipWeight on #605 currently accepts finite [0,1], including +0.0 and -0.0. That is inconsistent with the canonical active-membership meaning and with TEPP's existing persistence boundary: MembershipAssignmentRecord::validate already rejects membership_weight <= 0.0, and migration 0006_typed_membership_assignment has CHECK (membership_weight > 0).
A zero-share edge therefore has no affiliation mass but can still enter MembershipNetwork, contribute an active group/role edge, alter classify_membership_design, and affect nested-ICC applicability. This is structural contamination, not an estimator tolerance question.
MembershipWeight::new(+0.0) and MembershipWeight::new(-0.0) must return InvalidMembershipWeight;
transparent serde must reject zero as well;
the minimum positive binary64 subnormal (f64::from_bits(1)) remains valid so the repair does not invent an epsilon threshold;
1.0 remains valid and existing finite >1, negative, NaN, and infinity refusals remain intact.
Repair boundary
Change the owner VO domain from [0,1] to (0,1]. Do not clamp, renormalize, use a tolerance, or reinterpret zero as missing data. #612 exact dyadic share-budget arithmetic remains separate and may still represent arithmetic zero internally; persisted/public MembershipWeight must remain strictly positive.
Persistence follow-up
Zero is already refused by both the Rust persistence record validator and PostgreSQL 0006. A separate persistence-owner gap remains for the upper bound: MembershipAssignmentRecord::validate and the database currently accept weights above one even though membership_core rejects them. Repair that through the active persistence lineage without rewriting historical migration 0006 or colliding with #287's reserved 0008_analysis_run_persistence migration.
Acceptance
public RED before production repair;
minimal (0,1] owner fix with unit/serde edge coverage;
Source lineage is now concrete on #605. Public RED 3ee43cca54594eaba1c49324dd6fb55a3c00f49c rejects +0.0/-0.0 through both constructor and transparent serde while preserving f64::from_bits(1) as the smallest valid positive share. Causal repair 064d5e3e285c604a431f8b87ee504a1d1ad887f0 changes MembershipWeight to finite (0,1] and documents why zero-share active edges are structurally invalid. #605 is still Draft; exact-head Rust Foundation/Security/CodeQL are queued and Semgrep is pending, with no qualifying current-head approval. Keep #613 open through protected-main landing and downstream acceptance.
Activity
seonghobae commentedon Sep 19, 2026
Source lineage is now concrete on #605. Public RED
3ee43cca54594eaba1c49324dd6fb55a3c00f49crejects+0.0/-0.0through both constructor and transparent serde while preservingf64::from_bits(1)as the smallest valid positive share. Causal repair064d5e3e285c604a431f8b87ee504a1d1ad887f0changesMembershipWeightto finite(0,1]and documents why zero-share active edges are structurally invalid. #605 is still Draft; exact-head Rust Foundation/Security/CodeQL are queued and Semgrep is pending, with no qualifying current-head approval. Keep #613 open through protected-main landing and downstream acceptance.