Skip to content

Add SPAC consolidated report with lifecycle tracking#164

Merged
sroussey merged 14 commits into
mainfrom
claude/relaxed-gauss-7u3cmf
Jun 23, 2026
Merged

Add SPAC consolidated report with lifecycle tracking#164
sroussey merged 14 commits into
mainfrom
claude/relaxed-gauss-7u3cmf

Conversation

@sroussey

Copy link
Copy Markdown
Contributor

Summary

Introduces a comprehensive SPAC (Special Purpose Acquisition Company) consolidated reporting system that tracks the full lifecycle of SPACs from registration through IPO, deal announcement, merger completion, or liquidation. The system uses append-only event and deal tables to derive a mutable consolidated row with out-of-order filing replay protection.

Key Changes

  • SPAC Schema & Storage (SpacSchema.ts, SpacDealSchema.ts, SpacEventSchema.ts, SpacHistorySchema.ts)

    • Four-table design: mutable spac row (one per CIK), append-only spac_deal and spac_event tables, and versioned spac_history snapshots
    • Tracks three eras of data: SPAC-era (spac_*), post-merger (post_merger_*), and current (current_*) names/SIC/tickers
    • Status lifecycle: registerediposearchingdeal_announcedproxycompleted (or liquidated/withdrawn)
    • Amounts: ipo_proceeds, trust_amount, pipe_amount, total_redemption_amount
  • Row Rollup Logic (spacRollup.ts)

    • buildSpacRow() derives the consolidated row from append-only deals/events plus a filing-sourced patch
    • Out-of-order filing replay protection: patches only apply when the driving filing is not older than the row's anchor (as_of guard)
    • Stale filings may fill null slots but cannot overwrite non-null values, preserving the most-informative data
    • Status derivation: completed deals win; pending deals ranked by announced date; liquidation/failed flags override
  • Report Writer (SpacReportWriter.ts)

    • Orchestrates writes: append event, rebuild row from deals/events, snapshot history, and log changes
    • recordRegistration() and recordIpo() are the primary entry points from form processors
    • History chain coherence: bumps colliding timestamps (same-millisecond writes) to maintain strictly increasing valid_from
    • ChangeLog integration: tracks field-level changes across all TRACKED_FIELDS
  • Form Processor Integration

    • Form_S_1.storage.ts: detects SPAC registrations (SIC 6770) and calls recordRegistration()
    • Form_424.storage.ts: detects priced 424B4s with SPAC unit terms and calls recordIpo(), extracting tickers from the offering model
    • Both processors skip non-SPAC filings (null SIC headers)
  • CLI Command (commands/spac.ts)

    • spac report <cik> assembles consolidated report: row + deals + events + sponsor/underwriter counts
    • spac history <cik> shows versioned snapshots with valid_from/valid_to windows
    • Supports --format json for programmatic access
  • Dependency Injection (DefaultDI.ts, TestingDI.ts)

    • Registers four SPAC repositories with appropriate indexes (status, current_cik for the main row)
    • In-memory storage for testing via InMemoryTabularStorage
  • Tests

    • spacRollup.test.ts: unit tests for row derivation logic (status transitions, deal selection, event aggregation)
    • SpacReportWriter.test.ts: integration tests for registration→IPO flow, out-of-order replay, history coherence
    • Form_S_1.spac-report.test.ts: S-1 registration detection and row creation
    • Form_424.spac-report.test.ts: 424B4 IPO detection with ticker extraction and SPAC-specific unit terms
    • SpacRepo.test.ts: repository query ordering
    • spacStorage.smoke.test.ts: round-trip persistence
    • commands/spac.test.ts: CLI report assembly

Notable Implementation Details

  • Ticker Handling:

https://claude.ai/code/session_01PX4WhF4uDmZKdYiG2hFq6t

claude added 14 commits June 23, 2026 04:00
The ARRAY.map(Type.Literal) form left status/outcome/event_type inferring as
never; TypeStringEnum (the repo's existing enum helper) fixes inference and
lets the consumer-side casts in spacRollup and SpacRepo be removed.
…ac_tickers to full series

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PX4WhF4uDmZKdYiG2hFq6t
…ge, CLI guards

- snapshot(): guarantee strictly-increasing history valid_from so two writes in
  the same millisecond can't collide on (cik, valid_from) and overwrite a
  just-closed snapshot (data loss); detect open row with == null.
- buildSpacRow pick(): treat an explicit null patch value like an absent field
  so a newer filing that carries no value can't erase an existing non-null one.
- recordIpo(): guard empty ticker array so it stores null, not '[]'.
- sec spac report/history: reject non-numeric CIK args instead of querying NaN.
- simplify deriveStatus (dead hasRegistration branch) and nextAsOf (dead arms).
- add regression tests for the history collision and ticker non-clobber.
@sroussey sroussey self-assigned this Jun 23, 2026
@sroussey sroussey merged commit 6d74dc8 into main Jun 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants