What leaves this machine, what is kept, and what is never collected
Every figure on this platform is traceable to a named public filing or publisher, and the only outbound traffic carrying a figure is the request that fetches it. There is no advertising network, no data broker and no third-party analytics. Three screens load an asset from a third party — CARTO tiles on GEO and TMAP, the Python runtime on the Quant Sandbox — and those are listed below with everything else. Everything here names the module or the route behind it.
What leaves this machine
traceable to a fileOutbound HTTPS requests to the 36 publishers listed on the sources page, and nothing else. 36 of them are queried with no credential at all. The requests are made by the server process on this machine — your browser never contacts a data publisher directly, so no publisher sees your IP address or your browser.
- No analytics vendor and no crash reporting. The fonts and icons are self-hosted precisely so the interface renders with no network access at all.
- Three screens fetch an asset from a third party, and only those three. GEO and TMAP load basemap tiles from CARTO; the Quant Sandbox fetches its Python runtime from jsDelivr the first time you press Run. Those requests come from your browser, so CARTO and jsDelivr see your IP address — and on the maps, which part of the world you are looking at. This page used to say "no CDN" without that exception, which was not true.
- One first-party record exists and it is off by default: a log of which screens you opened and for how long, kept so the terminal can suggest what to look at next. Nothing is written until you switch it on, it is never sent anywhere but this install, and switching it off erases it. This page used to say "no telemetry" without that exception, which was not true.
- No account with anyone. Every source above is read anonymously except where you have chosen to set an optional credential.
- No language model is called, with or without a key. The plain-English reading under a screen's figures is computed in your browser from the data already on it — no model, no key, nothing sent (frontend/kit/readout.js).
Source list: frontend/data_sources.js. The reading rules are in frontend/kit/readout.js and run entirely in the browser.
What is stored for your account
Sessions open on your account
What has happened to your account
Your name, and your data
Delete this account
This removes the account record, every session it owns, and every document stored under it. It cannot be undone and there is no grace period.
One thing survives, and it is named rather than hidden: a single audit line recording that an account was deleted and when. A record of a deletion that can itself be deleted is not a record. Nothing else about you remains.
Download your data first — the button is in the panel above.
What is stored on this machine
traceable to a file| Location | What it holds |
|---|---|
| work/users/<user_id>/<namespace>.json | Your watchlists, notes, portfolio, alert ownership, preferences, workspaces and saved views. One file per account per namespace. The path is derived from an internal user id, never from a username, so a username containing ../ cannot reach another account's data. |
| work/source_cache.sqlite3 · work/free_source_cache.sqlite3 | Cached upstream responses, so a refused or slow publisher does not blank a screen. Public market data, no personal content. |
| work/route_cache/ | Last-good API payloads, replayed when a route 5xxs. Authenticated routes under the prefixes listed in PRIVATE_API_PREFIXES in app/main.py are excluded from this cache by key. |
| work/activity.sqlite3 | Which metric sets and screen codes you used, and when. It deliberately does NOT record which issuer was on screen. |
| browser localStorage: singularity_prefs | Ticker, density, motion, accent and the landing-page live toggle. Read by frontend/page_kit.js. Cleared by clearing site data. |
Namespaces, caps and the empty-document shapes are defined in app/services/userstore.py. A new account's namespace is genuinely empty — nothing is seeded.
What is never collected
traceable to a file- The ticker you were looking at. app/services/activity.py records metric ids and screen codes through two allowlist filters, and a ticker cannot pass either. That is structural, not a policy promise: the only values that reach SQLite are ones that survive sanitize_metrics and sanitize_screen.
- Any analytics, telemetry or crash-reporting beacon. Searched across app/, frontend/ and static/ for google-analytics, googletagmanager, gtag, mixpanel, segment, sentry, posthog, plausible, amplitude, hotjar, fullstory and datadog: zero occurrences.
- The value of any credential. /api/pages/environment returns a boolean per variable name and nothing derived from the value. There is no route that returns one, and no way to set one from the browser.
- Your password in any reversible form, anywhere, including logs. It exists only as an scrypt derivation.
What an API key can reach
measured liveA key set here widens one source and reaches nothing else. It is read by the module named in the last column, sent to that one publisher, and never returned to the browser — this table asks the server whether each name is non-blank and gets back a boolean.
| Variable | Set here | What it unlocks | Read by |
|---|---|---|---|
| FMP_API_KEY | no | Financial Modeling Prep consensus estimates on the economic calendar. The calendar falls back to model-implied estimates and labels them as such. | app/services/phase6.py |
| SINGULARITY_FRED_API_KEY | no | The official FRED JSON API instead of the public CSV endpoints. Macro series still load over CSV; some series are unavailable. | app/services/macro_rates.py |
| FINNHUB_API_KEY | no | Finnhub as an additional company-news source. The news hub runs on its remaining sources. | app/services/news.py |
| REDDIT_CLIENT_ID | no | Reddit OAuth. Reddit's anonymous JSON endpoints now answer 403. Reddit-derived chatter screens report the missing credential. | app/services/news.py |
| X_BEARER_TOKEN | no | X/Twitter posts in the social feed. The X source reports 'disabled — requires a paid Basic tier or above'. | app/services/news.py |
| GOVINFO_API_KEY | no | GovInfo as a source in business-intelligence research. That source is skipped and the reason is shown. | app/services/phase8.py |
| REGULATIONS_GOV_API_KEY | no | Regulations.gov dockets in business-intelligence research. That source is skipped and the reason is shown. | app/services/phase8.py |
| PATENTSVIEW_API_KEY | no | The PatentsView search API behind the patent complexity scorer. The screen states which credential it requires. | backend/patent_scorer.py |
| AIS_API_KEY | no | Worldwide AIS vessel positions on the global map. The vessel layer is not drawn and reports 'missing credential'. | app/services/geo.py |
| SINGULARITY_SMTP_HOST | no | Email delivery for alerts. Pairs with SINGULARITY_SMTP_FROM. Alerts still fire in-page, as desktop notifications and as sound. | app/services/notifications.py |
| SINGULARITY_SMTP_FROM | no | The sender address on alert email. Email delivery stays off; the alerts panel says so. | app/services/notifications.py |
Set column is live from /api/pages/environment. Variable names and effects: frontend/data_sources.js.
Accounts and sessions
traceable to a file| Control | How it is implemented |
|---|---|
| Password hashing | hashlib.scrypt, n=2^14 (16384), r=8, p=1, 64-byte derived key, per-user salt. Never SHA-256, never MD5, never plain. |
| Session token | secrets.token_urlsafe(32) — 256 bits. Never a counter, never the user id, never in a URL or query string. |
| Cookie | HttpOnly, SameSite=Lax, and Secure whenever the request arrived over HTTPS. |
| Session lifetime | 12 hours idle, 7 days absolute maximum. |
| Comparison | hmac.compare_digest for every secret. The username-not-found branch performs a real scrypt derivation against a dummy hash so timing cannot distinguish it. |
| Login failures | Say 'incorrect username or password' — never which one was wrong. |
| Rate limiting | 5 failures per account and 20 per IP, then a 15-minute lockout. |
All of it in app/services/auth.py, standard library only — hashlib, secrets, hmac. No custom cryptography was written.
The honest scope boundary
Password authentication over localhost is appropriate for what this is: a single-machine research terminal, reached from the machine it runs on. The controls listed above are real and were written to be correct, not decorative.
If you expose this server to a network, that is your decision and it changes the threat model entirely. This design has not been audited, has not been penetration tested, and was not hardened for the open internet. Nothing on this page should be read as a claim that it was. Put it behind something you trust, or keep it on localhost.
None has been performed. There is no third-party audit, no bug bounty and no CVE process behind this build. The controls above can be verified by reading app/services/auth.py and the tests beside it, which is the only assurance on offer.