Skip to content

fix(persistence): validate pre-existing membership share budgets on 0010 upgrade #619

Open

Description

@seonghobae

Finding

Migration 0010_membership_same_role_share_budget must prove that rows persisted before 0010 are reconstructable by the Membership owner. Two predecessor states are otherwise schema-admissible but owner-invalid:

  1. a positive NUMERIC weight admitted by 0006/0009 that underflows to binary64 zero (for example 1e-10000), although Membership scientific(membership): reject zero-share active affiliations #613 requires a strictly positive represented binary64 share; and
  2. overlapping same-member/same-role rows whose exact represented binary64 shares exceed one at a common event-time state, including the scientific(membership): make same-role share-budget admission exact at the binary64 boundary #612 boundary case.

The earlier live contracts reset to an empty database and tested only post-0010 writes, so they could not detect invalid pre-existing state.

Required acceptance

Upgrade from the canonical embedded predecessor through 0009, seed pre-existing data while it is still predecessor-admissible, then require 0010 to fail closed for:

Positive controls must preserve exact unity, disjoint event-time spells, role separation, pointwise-valid spanning membership, and bounded/unbounded/open/closed temporal ranges.

Do not rewrite 0006/0009, normalize/clamp legacy rows, or fabricate membership mass. Remediation of invalid historical data requires explicit product/data-owner action.

Cutover rule after #622

#622 supersedes the earlier idea of validating historical rows before installing the trigger. Because the repository applies migration statements sequentially, that ordering has a validation-to-trigger write race. The successor must install retry-safe fail-closed admission first, then perform the expensive historical scan. Therefore an invalid predecessor dataset fails the migration while leaving future writes protected; explicit remediation can then be followed by an idempotent retry without dropping the gate.

Current ordinary-forward candidate lineage on #615:

  • upgrade RED/acceptance 44e310839bcc24bcefc503db4777b899614120de;
  • pointwise historical validator aa43c6520f71744504c703bd853a97a53571341f;
  • duplicate-edge refinement 98abb27c7c5a29f4ec4ea7502375987cdea84035;
  • retry-safe trigger-before-validation repair 84e5859a34a7864f06d74794bac2f6180ac05e97;
  • protected failed-upgrade + remediation/retry live contract f471211abbce2503d51c503533d5d197f6c0b09e;
  • no-gap retry trigger contract 54bf6128333b6698c2926ed20b9945aa917ecf43 → CREATE OR REPLACE TRIGGER repair 10b07fcdf47f867e3c7b78ba1b8e8a2a668cc4b3.

Refs #604, #605, #610, #612, #613, #614, #615, #616, #617, #618, #620, #621, #622.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions