Repository navigation
scientific(membership): classify longitudinal observation support without atomistic collapse #640
Description
Scientific / DDD finding
membership_core::classify_membership_design currently classifies one shared EventTime. Topic-lineage and other longitudinal consumers instead evaluate each modeled observation at its own event time. Re-running the single-instant classifier inside those consumers would duplicate Membership-domain truth; collapsing the observation set to one synthetic instant would be scientifically wrong.
The owner contract must classify a set of (MemberId, EventTime) observation coordinates directly from MembershipNetwork, preserving the same closed design vocabulary already owned by Membership: Nested, CrossClassified, MultipleMembership, CrossClassifiedMultipleMembership, HeterogeneousClassification, and HeterogeneousClassificationMultipleMembership.
This is needed by release issue #638 / Draft #639, but the implementation belongs here in the Membership bounded context. #639 must consume a released/pinned owner contract or an ordinary protected-main landing; it must not copy this classifier.
Required RED
Add owner-side contract tests proving that observation support is classified across the actual event time of each observation:
- one member may leave/re-enter or change contextual assignments over time without the consumer selecting one global
as_ofinstant; - locally single-classified observations that span different roles across the observation support are
HeterogeneousClassification, notNested; - a local cross-classified observation plus a separate local multiple-membership observation yields
CrossClassifiedMultipleMembership; - a partial-weight/same-role multi-group observation remains
MultipleMembershipeven when other observations are nested; - any requested observation with no active membership at its own event time fails closed rather than disappearing from the support;
- an empty observation support fails closed.
The API should use opaque MemberId + EventTime coordinates only. Do not add HR/person truth, caller-asserted design labels, normalization, pseudo-row duplication, or estimator arithmetic.
Acceptance
- TDD RED first, then minimal Rust owner repair;
- public rustdoc and error semantics are explicit;
- all new branches are covered and existing single-instant classification remains unchanged;
- feat(membership): add owner-issued single-membership admission #605 remains the canonical owner vehicle unless a verified successor inherits every valid delta;
- release(contract): publish immutable temporal-analysis contract for Orgmetra consumers #638/fix(release): bind fail-closed reconstructable topic-lineage results (#638) #639 receive only an owner-path handoff until this contract lands normally;
- exact-head Rust/rustdoc/coverage/security/CodeQL/Semgrep plus qualifying independent review before protected merge;
- no source copy, force push, destructive rebase, self-approval, skip/xfail, or gate weakening.
Protected base at finding time: main@a243f18da4a4ca8a8d068c39922537f1f8ed6ad0. Canonical Membership owner PR at finding time: #605 c7defa251761f104e51a614cbba14f9f952bec58.
Activity
test(membership): RED longitudinal observation design owner contract (#…
feat(membership): add missing observation membership refusal (#640)
feat(membership): classify longitudinal observation support (#640)
feat(membership): export longitudinal observation design contract (#640)
test(membership): cover longitudinal observation accessors (#640)
docs(changelog): record longitudinal membership support contract (#640)
docs(research): trace longitudinal membership support semantics (#640)