Skip to content

feat(spac): AI SPAC classifier, sponsor promote, de-SPAC linkage (#149, #150, #151)#196

Merged
sroussey merged 2 commits into
harnessfrom
claude/hopeful-albattani-veyi2k
Jul 15, 2026
Merged

feat(spac): AI SPAC classifier, sponsor promote, de-SPAC linkage (#149, #150, #151)#196
sroussey merged 2 commits into
harnessfrom
claude/hopeful-albattani-veyi2k

Conversation

@sroussey

Copy link
Copy Markdown
Contributor

Implements three SPAC roadmap items, based on harness.

#149 — AI content classifier for miscoded SPACs

extractSpacClassification runs behind the existing S1Classification.classifier_source = "ai" seam to catch SPACs filed under a miscoded/absent SIC. It runs in processFormS1 only when the deterministic SIC path did not flag the filing and a cheap keyword heuristic (looksLikeBlankCheck, ≥2 blank-check signals) trips, so the AI call stays rare. A confident spac verdict (it distinguishes a true SPAC from shell/operating) flips is_spac, overwrites the classification row as "ai", and mints the known-SPAC row so lifecycle extractors attach. "Not a SPAC" auto-resolves its MODEL_EMPTY dead-letter (like the LOI detector); a model-unavailable blank-check filing dead-letters spac-classification for retry.

  • Config: SEC_S1_CLASSIFIER_MODEL / SEC_S1_CLASSIFIER_CONFIDENCE_FLOOR; registered in secModelIds(); added to EVAL_EXTRACTORS.

#150 — Sponsor promote economics

extractSponsorPromote + a new spac_promote_terms table capture founder (Class B) shares & percentage, private-placement warrant count/price/public coverage, and trust per-share/total. Keyed (extractor_id, accession_number) like spac_unit_terms, so S-1-registered and 424-final promote compare across extractor ids. Wired into the shared runOfferingSections (SPAC-only) so both S-1 and priced-424 pipelines populate it; added to the eval harness and DI.

#151 — De-SPAC linkage

On a completed combination, buildSpacRow derives surviving_name/current_name from the deal target, and SpacReportWriter.recordDeSpacLinkage (invoked on the item-2.01 8-K) fills surviving_name/post_merger_sic/post_merger_tickers from the SPAC CIK's post-close entity/entity_tickers metadata — each only when it diverges from the SPAC-era value, so replays stay order-safe. current_cik stays null in the common CIK-survives case. New sec spac backfill-despac refreshes completed SPACs after submissions catch up.

Testing

  • npx tsc --noEmit clean.
  • New/updated tests: classifier heuristic + extractor + processFormS1 integration, sponsor-promote extractor + storage + offering-wiring, de-SPAC rollup + writer + 8-K integration.
  • Affected suites green: src/storage, src/config, src/task/forms, src/sec/forms/registration-statements, src/sec/forms/miscellaneous-filings, src/eval.

No new extractor id was added — the classifier reuses S-1, promote reuses S-1/424, de-SPAC linkage rides the 8-K path. Genuinely separate newco/S-4 CIK linkage remains deferred.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KqMBp35YzRXtkJMu4Xa4zm


Generated by Claude Code

#150, #151)

Implements three SPAC roadmap items:

#149 AI content classifier for miscoded SPACs: an AI classifier behind the
existing S1Classification `classifier_source = "ai"` seam catches SPACs filed
under a miscoded/absent SIC. Gated on a cheap blank-check keyword heuristic so
the AI call stays rare; a confident SPAC verdict flips is_spac, overwrites the
classification row, and mints the known-SPAC row. Env: SEC_S1_CLASSIFIER_MODEL /
SEC_S1_CLASSIFIER_CONFIDENCE_FLOOR. Added to the eval harness.

#150 Sponsor promote economics: extracts founder (Class B) shares + percentage,
private-placement warrant count/price/public coverage, and trust per-share/total
from the prospectus into a new spac_promote_terms table, via the shared
offering-sections runner (S-1 and priced-424). Added to the eval harness.

#151 De-SPAC linkage: on a completed combination the rollup derives
surviving_name/current_name from the deal target, and recordDeSpacLinkage
populates surviving_name/post_merger_sic/post_merger_tickers from the SPAC CIK's
post-close entity metadata on the item-2.01 8-K. New `sec spac backfill-despac`
refreshes completed SPACs after submissions catch up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqMBp35YzRXtkJMu4Xa4zm

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements three SPAC roadmap items across the S-1 and 8-K pipelines: (1) an AI content classifier to catch SIC-miscoded SPACs, (2) extraction + storage of sponsor-promote economics from SPAC prospectuses, and (3) de-SPAC linkage enrichment from post-close entity metadata (plus a CLI backfill).

Changes:

  • Add an AI-gated SPAC classifier (keyword heuristic → model classification → upgrade is_spac / mint SPAC row) and evaluation fixtures.
  • Add sponsor promote extraction + persistence (spac_promote_terms) and wire it into SPAC offering section processing.
  • Add de-SPAC linkage derivation/enrichment and wiring on 8-K Item 2.01 close, plus a CLI refresh command.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/storage/spac/spacRollup.ts Derives surviving/current identity fields from completed deals and post-merger patches.
src/storage/spac/spacRollup.test.ts Tests surviving/current name behavior for completed vs pending deals and explicit overrides.
src/storage/spac/SpacReportWriter.ts Adds recordDeSpacLinkage to enrich post-merger identity from entity metadata.
src/storage/spac/SpacReportWriter.deSpac.test.ts Tests de-SPAC linkage enrichment and no-op conditions.
src/storage/offering/SpacPromoteTermsSchema.ts New storage schema/token for sponsor promote terms table.
src/storage/offering/SpacPromoteTermsRepo.ts Repo wrapper for saving/querying sponsor promote terms.
src/storage/offering/SpacPromoteTermsRepo.test.ts Repo round-trip and query ordering tests.
src/sec/forms/registration-statements/s1/sponsorPromoteSchema.ts DataPort schema for sponsor promote model output.
src/sec/forms/registration-statements/s1/spacContentHeuristic.ts Cheap keyword heuristic to gate classifier calls.
src/sec/forms/registration-statements/s1/spacClassifierSchema.ts DataPort schema/types for SPAC content classification.
src/sec/forms/registration-statements/s1/spacClassifierModel.ts Model resolution + confidence floor config for classifier.
src/sec/forms/registration-statements/s1/spacClassifier.test.ts Tests heuristic + classifier extractor behavior.
src/sec/forms/registration-statements/s1/sectionExtractors.ts Adds extractSponsorPromote and extractSpacClassification.
src/sec/forms/registration-statements/s1/offeringSections.ts Wires sponsor-promote extraction + persistence into offering runner (SPAC-only).
src/sec/forms/registration-statements/s1/extractSponsorPromote.test.ts Tests sponsor promote extractor parsing/null behavior.
src/sec/forms/registration-statements/Form_S_1.storage.ts Integrates AI classifier upgrade path into processFormS1.
src/sec/forms/registration-statements/Form_S_1.storage.offering.test.ts Integration tests for sponsor-promote persistence and SPAC/non-SPAC gating.
src/sec/forms/registration-statements/Form_S_1.storage.classifier.test.ts Integration tests for classifier upgrade/non-upgrade/no-call scenarios.
src/sec/forms/miscellaneous-filings/spac8kMilestones.test.ts Tests de-SPAC linkage wiring on 8-K close (Item 2.01).
src/sec/forms/miscellaneous-filings/Form_8_K.storage.ts Calls recordDeSpacLinkage after completion milestone write.
src/eval/fixtures.ts Adds eval harness extractors + fixtures for sponsor-promote and spac-classification.
src/config/TestingDI.ts Registers in-memory storage for spac_promote_terms in tests.
src/config/setupAllDatabases.ts Ensures spac_promote_terms storage is set up.
src/config/resetAllDatabases.ts Ensures spac_promote_terms storage is reset.
src/config/registerModels.ts Includes SEC_S1_CLASSIFIER_MODEL in registered model IDs.
src/config/DefaultDI.ts Registers persistent storage for spac_promote_terms.
src/commands/spac.ts Adds sec spac backfill-despac CLI to refresh post-merger identity on completed SPACs.
CLAUDE.md Documents classifier gating/config, sponsor promote table, and de-SPAC linkage/backfill command.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/storage/spac/SpacReportWriter.ts Outdated
Comment on lines +349 to +353
// Renamed surviving entity: the current entity name once it diverges from
// the blank-check shell name. Overrides the deal-target-derived fallback.
if (entity?.name != null && entity.name !== existing.spac_name) {
patch.surviving_name = entity.name;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — all three comments (this, the post_merger_sic, and the post_merger_tickers ones) were the same real gap: the code overwrote on every run whenever entity data diverged, contradicting the "cannot regress a populated linkage" contract. Fixed in 3c6b481 to make these genuine write-once close-time snapshots:

  • surviving_name: upgrades the deal-target fallback (or fills an empty slot) exactly once; never overwrites an already entity-sourced value on a later replay/rebrand.
  • post_merger_sic: only set when the slot is still null.
  • post_merger_tickers: only set when still null, deduped + sorted for determinism, and only when the symbol set diverges from spac_tickers (no more SPAC-era-symbol leak).

Added tests for the later-rebrand no-mutation case and the SPAC-era-ticker non-leak case.


Generated by Claude Code

Comment thread src/storage/spac/SpacReportWriter.ts Outdated
Comment on lines +354 to +357
// Operating-company SIC once it diverges from the SPAC-era ~6770.
if (entity?.sic != null && entity.sic !== existing.spac_sic) {
patch.post_merger_sic = entity.sic;
}
Comment thread src/storage/spac/SpacReportWriter.ts Outdated
Comment on lines +358 to +360
// New listing symbol(s) — JSON string[] mirroring the spac_tickers shape.
const symbols = tickers.map((t) => t.ticker).filter((s): s is string => !!s);
if (symbols.length > 0) patch.post_merger_tickers = JSON.stringify(symbols);
Address review: recordDeSpacLinkage overwrote surviving_name / post_merger_sic /
post_merger_tickers on every run whenever entity data diverged from the SPAC-era
value, contradicting the "cannot regress a populated linkage" contract, and
wrote post_merger_tickers without checking divergence from spac_tickers or
sorting (non-deterministic order).

- surviving_name: upgrade the deal-target fallback (or fill an empty slot) once;
  never overwrite an already entity-sourced snapshot on a later replay/rebrand.
- post_merger_sic: write-once (only when the slot is still null).
- post_merger_tickers: write-once, deduped + sorted for determinism, and only
  when the symbol set diverges from the SPAC-era tickers.

Adds tests for the later-rebrand no-mutation case and the SPAC-era-ticker
non-leak case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KqMBp35YzRXtkJMu4Xa4zm
@sroussey
sroussey merged commit 45b2025 into harness Jul 15, 2026
1 check passed
@sroussey
sroussey deleted the claude/hopeful-albattani-veyi2k branch July 15, 2026 22:25
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.

[SPAC] De-SPAC linkage via 8-K / merger extraction [SPAC] Sponsor promote economics extraction [SPAC] AI content classifier for miscoded SPACs

3 participants