2026 · SECURITY SALES INTEL

SecuritySalesHub

Pre-sales signal intelligence across regulated U.S. industries — GridSignals restacked from Python/SQLite to Next.js 14 + Supabase and generalized from one energy-sector use case to three industries and 61 products across 47 vendors. A two-hop event→capability→product reasoning chain keeps recommendations config-driven: no product name is hardcoded in the classifier or scoring logic. 565 commits · 113 PRs across 11 active days; remote deploy not yet wired.

IN PROGRESS
565COMMITS
113PULL REQUESTS
11BUILD DAYS
SOURCE: GITHUB COMMIT HISTORY · 2026-08-25
Build cadence — commits per active day
Aug 13 Heaviest day: 110 commits · Aug 16 Aug 25

Overview

A multi-industry, multi-vendor pre-sales signal intelligence platform — a restack of the Python/SQLite GridSignals prototype into Next.js 14 + Supabase. Monitors 29 free public sources (SEC EDGAR, CISA KEV, HHS OCR breach portal, FDIC enforcement, NERC/FERC pages, and 24 more) to detect buying signals for 61 security products across 47 vendors, covering energy, financial services, healthcare, and cross-industry regulated entities. The core architectural additions over GridSignals: industry-keyed scoring weights, a two-hop event→capability→product reasoning chain in config-as-data CSVs, watchlist entity resolution by regulatory identifier (CIK/ticker/LEI/Wikidata QID), and seven trust invariants enforced as schema CHECK constraints and tested against the live database. Built as a single-operator portfolio/demo product — 21 database migrations, 68 test files across two runtimes (Vitest + Deno). 565 commits · 113 PRs · 11 active days; remote Supabase and Netlify deploy not yet wired as of 2026-08-25.

Project Design

Built as an explicit generalization of GridSignals — a Python/SQLite/Streamlit prototype that covered only energy and a single vendor set. Every architectural decision was a deliberate generalization: industry-keyed scoring weights instead of a flat model, a CSV-seeded capability category layer between events and products instead of hardcoded mappings, and a seller-preference filter that enforces the vendor line card without touching classifier or scoring logic. The plan orchestrator — a custom SQLite-backed conductor at tools/orchestrator/ — managed 113 PRs through chunk lifecycle, gate verdicts, and seam locks. Cross-runtime discipline between Next.js (Node) and Supabase Edge Functions (Deno) was enforced by a generated-types hash sentinel that fails CI on any type drift, including Windows CRLF variants.

Five-layer pipeline — config seeds → ingestion → classification/resolution → scoring/recommendation → read surface
Config/domain
20 CSV seeds: 61 products, 14 capability categories, 199 watchlist entities29 source policies, 47 vendor preferences, industry-keyed scoring weightsAdmin-editable without code deploy
Ingestion
15+ Deno Edge Functions on pg_cron, one per public sourceShared runner: idempotent dedupe, TTL skip, cursor-resumable pagination, per-source error containmentRaw events stored verbatim in raw_events before any interpretation
Classification + resolution
5 typed classifiers (incident, company statement, leadership, ransomware, regulatory)Entity resolver: CIK/ticker/LEI/QID paths + difflib fuzzy fallback; ambiguous CIK → operator review queue
Scoring + recommendation
SQL decay formula in single authoritative migration (DN1, no TypeScript reimplementation)Two-hop recommend Edge Function: event_type → capability_category → productsAppend-only recommendation_snapshots (UPDATE/DELETE/TRUNCATE blocked by DB trigger)
Read surface
Next.js 14 App Router: /feed, /account/[id], /triage, /reviewAll reads from typed Supabase client; no LLM calls on any read pathLeaflet map over PostGIS with CARTO dark tiles, no API key

Key modules

Pipeline

Ingestion layer

15+ Deno Edge Functions (one per public source) on pg_cron, inheriting a shared runner with idempotent dedupe via ON CONFLICT DO NOTHING, TTL skip, cursor-resumable pagination, and per-source error containment.

Data

Entity resolver

Deterministic resolution by CIK, ticker, LEI, and Wikidata QID; difflib fuzzy fallback for names. An ambiguous CIK (two watchlist rows sharing one CIK) routes to the operator review queue, never auto-fires a signal.

Config

Multi-vendor catalog + seller filter

61 products across 47 vendors in CSV seeds; a per-vendor carried/not-carried preference layer enforces the seller's line card without touching recommendation logic. 35 vendors marked carried; 12 excluded for direct-only motion or partner-agreement conflicts.

Pipeline

Two-hop recommendation engine

Event-type-to-capability-category mapping in a CSV; capability-to-product mapping via the seeded products table filtered by seller preferences. No product name hardcoded in any classifier or scoring function.

Data

SQL scoring function

Decay formula (base_strength × 0.5^(age_days/half_life) × account_fit × scope_fit) lives in a single authoritative migration (0008); no TypeScript reimplementation. Industry and subsector weights are keyed rows in scoring_weights.csv.

Pipeline

Stack inference (infer-stack)

Reads each watchlist entity's EDGAR 10-K Item 1C cybersecurity filing to infer incumbent vendor stack using word-boundary regex — incumbent context for the recommendation engine, zero paid data sources.

Config

Config seeds

20 CSV files seeded via scripts/seed-loader.mjs. Products, capability categories, scoring weights, watchlist entities, and vendor preferences are admin-editable without a code deploy.

Key features

Per-industry scoring weights

The core v2 addition over GridSignals. Migration 0008 documents it explicitly: "ADDED for v2: the per-industry dimension (scoring_weights is keyed by industry since 0002), which the original had no concept of." Each row in scoring_weights.csv keys on industry + weight_kind + subsector — iou_electric (NERC CIP registered entities) scores at 1.10 for energy; midstream at 0.95 (TSA pipeline directives); equivalent rows exist for financial_services and healthcare subsectors. An event touching an unknown subsector falls back to a neutral 1.0 weight, never errors. The same scoring function handles all three industries.

Two-hop config-as-data recommendation

The multi-vendor reasoning path: event_type → capability_category → products. First hop lives in event_type_to_category.csv — an editable mapping, not code. Second hop is the seeded products table filtered by the seller's vendor preferences CSV. A healthcare entity triggering an HHS OCR breach enforcement event routes to identity_access and grc_compliance capability categories; the recommendation engine then surfaces the relevant vendor subset from the seller's carried line card, with a trigger class (reactive/compliance/opportunity) explaining the sales motion. Adding a vendor, swapping a product, or adjusting a capability mapping requires no code deploy and no classifier change — only a seed update.

Security & ops decisions

Seven-trust-invariant signal path
Raw public events · 29 sources
Entity resolution: deterministic identifier paths (CIK/ticker/LEI/QID); ambiguous CIK routes to review queue, never auto-fires a signal
Classification: 5 typed classifiers; unconfirmed_early_warning cards never customer_facing_allowed — schema CHECK constraint, migration 0009
Scoring: SQL-only decay formula, no TypeScript reimplementation; recommendation_snapshots append-only (DB trigger blocks UPDATE/DELETE/TRUNCATE)
Read surface: zero LLM calls, zero paid data; market position displayed only with named analyst source + verified date (21 products downgraded to unranked/none after post-seed review, commit f22c5047)

Builder notes

Lessons learned

What carried forward

The two-hop config-as-data reasoning chain — event→capability→product with no hardcoded product names — and the principle that trust invariants belong in the schema (CHECK constraints + append-only triggers) rather than in application code.

Posts from this project

Case study in progress.

"A written rule is a suggestion. A gate is a control."
The operating principle behind every project here. The same bug shipped three times past written rules — and zero times past a CI gate. Deterministic enforcement beats advisory documentation, in agent harnesses and security programs alike.