About Sentinel
A quant intelligence platform for public‑company monitoring.
Sentinel detects material changes across 25 US large-cap companies using 21 public data sources and 13 quantitative analysis modules. A live report updates as new data lands; a 06:00 UTC snapshot freezes each weekday for durable permalinks. Every number carries signal provenance and a confidence interval.
Recently shipped
What's new under the hood.
The last few weeks brought three substantial upgrades: the Policy Trade Tracker's noise floor dropped ~70% via formal statistical gating, the report view became a live canonical URL with date navigation, and the dashboard became a command surface rather than an email archive.
Methodology
The math, in plain English.
Every score in the report is computed by one of thirteen quantitative modules. Each has a canonical academic basis, a pre-specified threshold, and a citation we can point to when asked "why does this number say that?" This section explains each module three ways: what it is in plain English, what the formal definition looks like, and where it appears in the product.
abnormal_return = rᵢ,t − r̂ᵢ,t
z_beta = abnormal_return / stdev(baseline_residuals)
Event window [T−1, T+3]: CAR = Σₜ (rᵢ,t − (α + β · r_m,t))
t-stat = CAR / √(L · σ²_ε) where L is event-window length
p-value = 2 · (1 − Φ(|t|)) two-sided normal approx (valid for n_est ≥ 60)
sentinel/forensic/event_study.py.deviation = treated_CAR − synth_CAR
z_synth = deviation / stdev(peer_CARs)
p_synth = 2 · (1 − Φ(|z_synth|))
sentinel/forensic/synthetic_control.py.Find largest k such that p_(k) ≤ (k / n) · q
Reject H₀ for tests 1..k (pass FDR)
where LR(signalᵢ) = P(signalᵢ | H₁) / P(signalᵢ | H₀)
bayesian_scores. The UI shows posterior probability + a contribution table so you can see which signals drove the number up or down. See sentinel/bayesian_score.py.Observation: zₜ = H · xₜ + vₜ (what we actually measure)
Estimate updated via Kalman gain: x̂ₜ = x̂ₜ₋₁ + K · (zₜ − H · x̂ₜ₋₁)
Confidence interval: 95% = x̂ₜ ± 1.96 · √Pₜ
health_score (0-100) + confidence_lower / confidence_upper. A widening CI signals degraded input coverage — you can see when the score is getting less trustworthy. See sentinel/kalman_filter.py.ECOD: outlier score from marginal ECDFs, threshold ~0.98
CUSUM: Sₜ = max(0, Sₜ₋₁ + xₜ − μ − k); alarm at Sₜ > h
COPOD: tail probability from empirical copula, threshold ~0.98
consensus_flag = (count of layers triggered ≥ 2)
consensus_flag, not individual layers. Per CLAUDE.md this reduces false positives "dramatically" vs single-detector approaches. See sentinel/anomaly_detection.py.where τ is the set of breakpoints, cost is per-segment RSS, β is the penalty
change_points. Used to flag "this isn't just a bad day — it's a different regime." See sentinel/change_point.py using the ruptures library.Observation: rₜ | Sₜ ~ Normal(μ_{Sₜ}, σ²_{Sₜ})
Transition: P(Sₜ | Sₜ₋₁) fit via Baum-Welch (EM)
Most-likely state via Viterbi
regime_states.regime + regime_probability per company per day. The IC-weighted score uses it to switch signal weights conditional on the regime. See sentinel/regime_detection.py.weightᵢ,t = max(0, ICᵢ,t) / Σⱼ max(0, ICⱼ,t)
composite_t = Σᵢ weightᵢ,t · normalize(signalᵢ,t)
sentinel/ic_weighted_score.py + sentinel/composite_score.py.Restricted model: yₜ = α + Σ βᵢ · yₜ₋ᵢ + εₜ
F-test: reject H₀ if Σ γⱼ = 0 is implausible
signal_ic_weights. Also powers the Policy Tracker's "leakage" tile — Polymarket price in the 6–48h pre-statement window as a Granger predictor of post-statement CAR.coincidence_md, cost_c = GPT-4o-mini(system=coincidence, data)
{verdict, reasoning}, cost_a = Haiku(system=arbiter, signal_md, coincidence_md, data)
publish_signal ⇔ verdict == "signal" ∧ fdr_rows ≥ 3
statement_narratives for audit. Monthly spend cap $80, scoped to tracker-only models so unrelated Sentinel LLM spend can't starve the tracker. See sentinel/jobs/trump_trade_correlation.py::_adversarial_synthesis.Honest framing. None of these methods "know" whether something suspicious happened — they measure how unlikely a pattern is under a specified null hypothesis. A fishy-score of 80 doesn't mean "insider trading"; it means "if the null were true, we'd see a pattern this extreme only rarely." All verdict language uses hedge vocabulary ("consistent with", "suggestive of") never "proves" or "confirms". A pre-registered prediction ledger resolves each call against market outcomes so the tracker's own accuracy is auditable — after 90 days of resolutions we will publish a Brier score and calibration plot.
Data sources
Twenty public feeds, all free or already-paid.
Every signal you see is built from public or open-licensed feeds — government filings, exchange data, news APIs, social firehoses. No scraping of private accounts, no PII beyond what's already in SEC / FEC filings, no commercially-restricted vendor data is republished. A short list of paid feeds we use internally for sanity-checking (prime-broker borrow data, on-chain wallet entity labels) does not appear in the published report — those vendors don't permit redistribution and we honour that.
Every row in the database carries the source it came from plus an ingested_at timestamp. The dashboard's system-status strip surfaces per-source freshness dots so you can see at a glance which feeds are late. Forward-only sources (Polymarket snapshots, Bluesky, Kalshi, Wikipedia revisions, analyst estimates) only accumulate from the day the collector was deployed — historical depth grows with time. Paid vendor feeds with commercial-use restrictions (Ortex prime-broker borrow data, Nansen / Arkham wallet labels) are used internally for cross-checks but never republished in the report.
How to read it
Interpreting each panel.
Every score on the report is built from one of the thirteen modules above. Here's how to read each one as you scroll through a company card.
Universal interpretation rule. No single panel is a buy or sell trigger. The report is built so that two or more independent panels firing in agreement is what you treat as signal — that's the entire point of the consensus gate, the FDR correction, and the multi-signal Bayesian aggregation. If only one panel says something unusual, treat it as a question, not an answer.
Stack
Boring, well-instrumented, Railway-hosted.
Honest limitations
What Sentinel is not.
Not investment advice. Not a recommendation engine. Not a short-selling tool. Not deanonymization. The tracker's "fishy score" is a statistical measure of pattern unusualness — not a claim of wrongdoing. We publish the methodology so readers can weigh the signal themselves. Data coverage is thin for forward-only sources (Polymarket / Bluesky / Kalshi only accumulate from the day the collector was deployed), and the adversarial-consensus narrative publishes only when arbiter+FDR gates agree — so many statements will show "null signal" rather than prose. A 90-day prediction-ledger calibration window is required before we promote any policy-tracker output to the daily email.
Get started
The live report is one click away.
Subscribers land on /report — the canonical live URL, always current. The dashboard at /dashboard is the command surface: system-status strip, 30-day anomaly chart, watchlist, priority-sorted signal feed. Pricing at /pricing; the 14-day trial covers up to 10 companies with full model access.