Skip to content

Family-tier resolve, then re-enable drop-previous for the family kinds #246

Description

@sroussey

Follow-up to #237, which registered coverage for sponsor-family / underwriter-family but deliberately left dropPrevious unregistered, so sec version drop-previous resolver sponsor-family still errors.

Why the purge was held back

On the person/company tier a version purge is safe because identity links are derived. The observation rows outlive the purge, so sec resolve --kind person --all rebuilds every link that was removed. Purge-then-rebuild is a closed loop.

The family tier has no such backstop:

  • there is no observation → identity-link table — the per-filing link row is the attribution (spac_sponsor_link, underwriter_link), not a projection of something that survives it; and
  • batch sec resolve refuses family kinds (person|company allow-list), so nothing can rebuild what a purge deletes.

Recovery from a family purge today means re-extracting every affected S-1/424 through the AI pipeline and re-paying that cost. And the trap is quiet: drop-previous is symmetric in shape across all four resolver kinds, so at the call site it reads like the same routine cleanup whichever kind it is handed.

What this issue asks for

  1. Implement a family-tier resolve so family attribution is rebuildable from data that survives a purge, restoring the invariant person/company rely on.
  2. Then register the dropPrevious closures for both family kinds, re-enabling the ceremony.

The hard part

A family is keyed off the sponsor/underwriter common name the AI extractor emitted. Only the legal name reaches the observation row, and the canonical family retains just one variant's display name — so a naive batch pass cannot faithfully re-partition families. A normalizer change that splits a family would reassign every member from that single stored name.

So this is not just wiring: it needs a decision about where the common name lives durably. Options worth weighing:

  • persist the extractor's common name on the observation row (or a sibling table), so re-partitioning has the original input to work from;
  • store the per-filing family assignment inputs alongside the link row, making the link reconstructable without re-extraction;
  • accept re-extraction as the only rebuild path and keep drop-previous refusing family kinds permanently — in which case close this and document the asymmetry as deliberate rather than temporary.

Already in place

SpacSponsorLinkRepo.deleteForResolverVersion and UnderwriterLinkRepo.deleteForResolverVersion landed in #237 with tests, and are intentionally unreferenced by any command. They are the building block the purge needs — no command reaches them until the closures are registered.

registerResolvers.family.test.ts currently asserts the refusal and that every family row survives it on both tiers at both versions; those tests invert when the purge is re-enabled.


🤖 Generated with Claude Code

https://claude.ai/code/session_01KB8s4qR5goCoxjE94YDFUV

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