Shell Heuristics · application docs

publisher · enricher-v2 · corpus

Heuristics — the fingerprint signals

Two categories:

  1. EDGAR fingerprint signals — rule-based, deterministic. Output: NDJSON files on node-eighteen. Produced by the sibling edgar-fraud-scan project, consumed by postcrime-heuristics + ciks-banana.
  2. In-corpus enrichment signals — produced by this repo's workflows in processor/src/extract/. Output: columns on documents + rows in case_facts / triples / entities.

The line between (1) and (2) is structural: (1) scans every issuer ever filed with the SEC, (2) decorates only documents we already crawled into corpus.db.


Part 1 — EDGAR fingerprint signals

Live at: node-eighteen:/mnt/oink/docker/edgar-fraud-scan/data/flagged/*.ndjson.

Refresh status: last touched 2026-05-12 (mtime 14:34). All four files. GAP: stale by ~1 week as of 2026-05-19; refresh cadence is owned by edgar-fraud-scan, not this repo. Trigger a refresh via the EDGAR side or coordinate with whoever owns edgar-cik-cli pulls.

Common envelope

Every NDJSON row has the same envelope:

{
  "cik": "0001372183",
  "rule": "<rule-name>",
  "accession": "<base-filing-accession>",
  "form": "8-K",
  "score": 0.3,
  "evidence": [
    { "accession": "...", "field": "...", "value": "...", "snippet": "..." }
  ],
  "ts": "2026-05-01T15:12:30.355Z"
}

score is rule-specific (some return 0–1, some {0, 0.3, 1}); evidence is an array of prior or sibling filings the rule found supporting the flag.

1. edgarizer_fingerprint (99 MB)

What it detects: filings produced via the same filing agent + template combo as other suspect filings. The "edgarizer" pattern is the same shop pumping out S-1s for a chain of shells.

How it's computed: edgar-fraud-scan keeps a set of known shell-friendly filing-agent CIK prefixes (e.g. 0001140361, used by Edgarizer LLC). Any filing whose filing-agent CIK matches gets a hit, with the prior filings of that agent listed as evidence.

Example hit:

{"cik":"0000320193","rule":"edgarizer_fingerprint","accession":"...","form":"8-K","score":1,
 "evidence":[{"accession":"0001140361-26-017175","field":"filing_agent_cik_prefix",
              "snippet":"filing agent CIK prefix: 0001140361"}]}

(Apple is in there with score=1 — the signal flags the agent, not Apple's substance. Treat raw hits as candidates, not verdicts.)

TODO: reconcile against the ciks-banana/heuristics/edgar-heuristics.json curated list (next to litigation-curated.json) so we know which agent CIK prefixes are "known Cane scheme" vs "Edgar-style filing shop but unrelated".

2. reg_s_issuance (102 MB)

What it detects: filings citing Regulation S (offshore offerings) — a recurring shell-network method to issue stock to nominal foreign holders who then dump on US markets.

How it's computed: regex match for "Regulation S" or "Reg. S" with section-citing context near issuance language.

Example:

{"rule":"reg_s_issuance","score":0.3,"evidence":[{"field":"reg_s_reference",
 "snippet":"...there are no transactions between Mr. Ternus and Apple..."}]}

Score 0.3 is the "incidental mention" tier; score 1 is for filings that actually use Reg S for the issuance. The Apple example above is a 0.3 — the phrase "Regulation S-K" tripped the matcher.

3. promissory_note_clauses (58 MB)

What it detects: filings that disclose convertible promissory notes — especially "death-spiral" notes (variable-conversion debt that dilutes common stock as price drops). This is the Cane Clark fingerprint.

How it's computed: regex over filing text for note-existence + maturity + conversion language. Score reflects how many of those sub-patterns hit.

Example:

{"rule":"promissory_note_clauses","score":0.3,"evidence":[{"field":"note_existence",
 "snippet":"...aggregate principal amount of $91.3 billion (collectively the &#8220;Notes&#8221;)..."}]}

(Again Apple is in there at 0.3 with their bond issuance — substance does not equal fraud. Cane-flavoured hits are the small issuers with sub-$1m notes that convert to common.)

4. opinion_letter_presence (1.5 MB)

What it detects: Rule 144 opinion letters from law firms that have signed off on shell-network issuances. This is the smallest file and the highest-quality lead — these letters are the legal-side fingerprint.

How it's computed: extracts firm names from opinion-letter signature blocks.

Example:

{"rule":"opinion_letter_presence","score":1,"evidence":[
 {"field":"opinion_firm","value":"The Loev Law Firm","snippet":"...The Loev Law Firm, PC..."}]}

This is the file to grep for Cane, Clark, Loev, etc.

Spot-check schemas

ssh rooot@node-eighteen \
  'for f in /mnt/oink/docker/edgar-fraud-scan/data/flagged/*.ndjson; do \
     echo "=== $f ==="; head -1 "$f"; ls -la "$f"; done'

Part 2 — In-corpus enrichment signals

These run on every crawled document via the federation queue. Each is a WorkflowDef with selectSql() (what to scan), process(doc) (what to compute), and an applyEndpoint.

Signal File Type Output
case-facts processor/src/extract/case-facts.ts regex/heuristic, no LLM case_facts.{defendants_json, first_act_date, plea_date, sentence_date, monetary_amount}
entities processor/src/extract/entities.ts regex + canonicalise entities + mentions rows
triples processor/src/extract/triples.ts LLM via pool-fraud-triples (qwen3:8b) triples table
scheme-classify processor/src/extract/scheme-classify.ts LLM, JSON-schema-constrained documents.{scheme, scheme_confidence, scheme_classified_at, scheme_slug}
format-title processor/src/extract/title-format-workflow.ts regex+composite documents.{title_formatted, title_format_source}
title-llm processor/src/extract/title-llm.ts LLM Bluebook fallback same columns, title_format_source='llm'
link-references processor/src/extract/link-references.ts regex + JSON documents.reference_filing_json
summarize processor/src/extract/summarize.ts LLM (1/3/5/7 sentence/paragraph) documents.summary_* columns
refetch-pdf processor/src/extract/refetch-pdf.ts HTTP repairs missing pdf_path
ocr-recover processor/src/extract/ocr-recover.ts tesseract sidecar repopulates body for [OCR_UNRECOVERABLE docs

case-facts — currently the cutover pilot

  • Deterministic regex over body.
  • Extracts: defendant list, first-act date, plea date, sentence date, max dollar amount.
  • LLM-free → fast → ideal canary for fraud-enricher-v2.
  • Output column: writes to case_facts table via /apply/case-facts.

scheme-classify

  • LLM call via gpumon-ingress pool pool-fraud-triples (qwen3:8b, enable_thinking=false).
  • Constrained to the fraud taxonomy at docs/stats/01-fraud-taxonomy.md:
    • Layer 0 buckets: corporate-fraud, financial-fraud, health-care-fraud, cyber-fraud, public-corruption, obstruction, racketeering, non-corporate.
    • Layer 1 (securities-fraud sub-types): pump-and-dump, unregistered-securities, insider-trading, market-manipulation, accounting-fraud, pre-ipo-fraud, ponzi, advance-fee, affinity-fraud, boiler-room, fcpa, crypto-securities, broker-dealer-fraud, investment-adviser-fraud.
  • Drives the /scheme/[slug] pages.

format-title + title-llm

  • format-title does regex (clean H1) + composite (caption + case-num + date) — covers ~55% of corpus cleanly. Source codes: regex, composite, fallback.
  • title-llm is the LLM fallback for the ~45% the deterministic pass marked fallback. Synthesises Bluebook-style titles, e.g. "SEC v. Harsh V. Patel, No. 1:26-cv-03203 (S.D.N.Y. Apr. 20, 2026), alleged ..." — see _overnight-questions.md Q12.

link-references

  • Pulls (case_number, accession_no, citation) references out of body text → JSON array → documents.reference_filing_json.
  • Search-ui renders these as "Related" anchors on the document page (commit 815b460).

What's NOT yet a heuristic in this repo

Surfaced under "Goals" in frontend.md and roadmap.md:

  • GAP: agent-bypass — currently runs as edgar-agent-bypass swarm service (sibling EDGAR pipeline), no postcrime-heuristics workflow that joins its output to documents.
  • GAP: rm-expander — same, edgar-rm-expander running, output not joined here.
  • GAP: officer-transition-patterns — no extractor exists; would be a workflow that scans 8-Ks for the "officer resigns + new officer with same address" pattern.
  • GAP: sic-anomaliesciks-banana/cane-network/ is referenced in the brief but does not exist on disk (ls returns "No such file"). The closest live data is ciks-banana/.vercel/output/static/ciks/heuristics/.
  • TODO: cross-corpus join — docs/refactor/edgar-indexer-schema.md is the scaffolded plan; Phase F in CHANGELOG marked "scaffolded" with TODO(schema) markers. No live data yet.