Skip to content

scientific(membership): prevent caller-issued design coordinates at the owner boundary #643

Open

Description

@seonghobae

Finding

Fresh review of #642 found that MembershipDesignWire::from_design is public while MembershipDesign itself has public variants. That means a downstream caller can construct MembershipDesign::Nested and mint what looks like an owner-issued wire coordinate without Membership ever classifying canonical network state.

The rustdoc says the coordinate should be owner-derived, but the API does not enforce that invariant. For #638/#639 this would turn a serialization VO into a caller-authorized scientific classification boundary.

Required repair

  • make raw design→wire construction crate-private;
  • expose a narrow Membership-owned function for longitudinal support that calls classify_membership_observations(network, observations) and returns MembershipDesignWire only from that result;
  • keep public MembershipDesignWire::parse(version, name) as an interpretation/deserialization boundary only, explicitly not scientific authority;
  • do not copy network state or classification semantics into fix(release): bind fail-closed reconstructable topic-lineage results (#638) #639.

Acceptance

Activity

  1. seonghobae commented on Sep 21, 2026

    @seonghobae
    ContributorAuthor

    RED→GREEN source lineage is now ordinary-forward on #605.

    • RED 551789019aef041875bdfc4d231c5d9596f10834: integration contract requires classify_membership_observations_wire and exercises canonical nested support plus fail-closed missing membership; predecessor has no such owner-issued API.
    • causal repair 951a9e1c5d6fc3adba794f8658586f3b0d9c038d: raw MembershipDesignWire::from_design becomes pub(crate); new public classify_membership_observations_wire derives the coordinate only from canonical longitudinal Membership classification. parse(version,name) remains public deserialization and is explicitly non-authoritative.
    • export 3d10f8ee363c9a1c7a3efbb06a5e885e235978d5.
    • CHANGELOG/current exact head 8d2f8367221cb7bb653c8a0c2d71857f8572885d.

    Protected base is still main@a243f18da4a4ca8a8d068c39922537f1f8ed6ad0; compare ahead 56 / behind 0. Fresh current-head Rust 35623166272, Security 35623166406, Semgrep 35623166316, CodeQL 35623166354, Documentation 35623166381 are queued/non-terminal. No exact-head independent approval; issue remains open and PR #605 remains Draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions