Gap Register
This is the complete register of what is missing. A five-lens sweep of the five repositories — security; legal and privacy; operations; commercial; engineering and AI governance — looked for absences rather than bugs, and found 86 of them.
Nothing here is on fire, because nothing is deployed and nobody is paying. Every entry is a statement about the cost of fixing something later versus now. The sequenced answer to “so what do I do” lives on What To Do Next; this page is the reference it points at.
How to read this
Section titled “How to read this”The sweep deliberately excluded anything already documented elsewhere on this site. The thirteen code contradictions and the decision register on Open Questions, the two-contract conflict on The Two Contracts, the launch blockers on Deployment Readiness, and the phase plan on the Roadmap are all still live and are not repeated here. This register is additive — if a thing appears on both, the entry here is a different problem with a similar name, and says so.
Four columns carry through every table.
| Column | Meaning |
|---|---|
| Gap | The absence. Named as what is missing, not as what to build. |
| Why it matters | One sentence. The detail is in the finding this row compresses. |
| Effort | Rough order of magnitude for one engineer: hours, days, weeks, months. |
| When | The latest point at which closing it is still cheap. |
The When vocabulary is exactly four values, in this order of urgency:
- Now — the cost of the fix rises from today, either because a schema is about to be designed around its absence or because an asset is not being accumulated.
- First customer — before anyone pays. Most of the register sits here.
- Licence — before a licence application is made or a regulator asks.
- Scale — before there are many users, many machines, or real volume.
Within each severity group, rows are sorted by When first and then by effort ascending, so the cheap urgent things are at the top of every table.
The shape of it
Section titled “The shape of it”Counts are read directly out of the findings file, not estimated.
| Severity | Count | Now | First customer | Licence | Scale |
|---|---|---|---|---|---|
| Existential | 5 | 2 | 2 | 1 | 0 |
| High | 42 | 13 | 28 | 1 | 0 |
| Medium | 35 | 2 | 25 | 4 | 4 |
| Low | 4 | 0 | 2 | 0 | 2 |
| Total | 86 | 17 | 57 | 6 | 6 |
By lens, and by effort:
| Lens | Existential | High | Medium | Low | Total |
|---|---|---|---|---|---|
| Security | 0 | 8 | 8 | 2 | 18 |
| Operations and reliability | 1 | 9 | 8 | 0 | 18 |
| Legal, privacy and data rights | 0 | 8 | 8 | 1 | 17 |
| Commercial and financial viability | 2 | 12 | 3 | 0 | 17 |
| Engineering, data science, AI governance | 2 | 5 | 8 | 1 | 16 |
| Effort | Count |
|---|---|
| Hours | 27 |
| Days | 37 |
| Weeks | 21 |
| Months | 1 |
Two things fall out of that distribution. Twenty-seven of the 86 are hours of work — mostly configuration, a file, or a guard clause — which means roughly a third of the register could be cleared in a fortnight of deliberate, boring work. And 17 are marked Now, of which the majority are not engineering at all: they are documents, decisions and a small amount of paperwork.
The five existential findings
Section titled “The five existential findings”These five are separated out because each one, left alone, invalidates work done on top of it. They are not the five most urgent — three of them are cheap and none of them is a crisis today. They are the five where a wrong answer discovered late means throwing away months.
1. No detection that a produced number is wrong
Section titled “1. No detection that a produced number is wrong”Operations and reliability · weeks · before licence
Missing. There is no reconciliation against a second source, no outlier or bounds
check, no revision-versus-previous-value comparison, and no concept of a data-quality
alarm anywhere in the platform. App\Models\DatabaseItem and App\Models\Report contain
$fillable and casts and nothing else — no validation, no observer, no mutator. There is
no ingest endpoint to validate at, because routes/api.php has no write path into either
table. No test asserts anything about the plausibility of a value.
Why it matters here. The founder decision of 2026-08-01 puts the firm on both sides of
these numbers: it sells them by subscription, advises on them, manages client capital
against them and trades its own book on them. Meanwhile database_items.value is a
string column holding a display string — '48,210 MW', '0.734' — so a wrong value is
not even type-detectable. A decimal-place error, a unit swap or a hallucinated
classification lands in the table looking exactly like a correct value, sorts to the top
of the Database page by measured_at, and is served to subscribers and to the trading desk
identically.
The failure. A worker misparses a feed and writes '4,821,000 MW' where it meant
'48,210 MW'. The page renders it, the API serves it, a position is taken on it, and the
first person who notices is a counterparty or a client. Because rows are overwritten in
place with no history — updateOrCreate in the seeders is the only writer pattern that
exists anywhere — you cannot afterwards show anyone what the number was at the moment the
decision was made, or that it was ever different. A loss plus an unreconstructable file is
the combination that costs a firm its permission to operate.
The fix is not one thing; it is the smallest useful subset of a validation layer, chosen before the ingest endpoint is designed. See Model Risk and Ground Truth.
2. No cost-of-goods model, and the founding source list has two readings ~100x apart
Section titled “2. No cost-of-goods model, and the founding source list has two readings ~100x apart”Commercial and financial viability · days · now
Missing. No document, spreadsheet, config file, code comment or README in any of the
five repositories attaches a cost to anything. No COGS model, no infrastructure sizing, no
per-source price, no inference budget, no cloud estimate, no split between fixed and
variable cost. A grep across all five repositories for currency amounts returns zero
monetary figures — every $ is a PHP variable or Rust syntax. Business Model
discusses four revenue lines and never mentions cost once.
Why it matters here. The nine declared sources on Data Pipeline can be read two ways, and the two readings are different companies.
Scenario A — the cheap path. Free and open sources at modest scale: one always-on ingest VM, managed Postgres or Timescale, object storage for a raw archive, free Sentinel-2 and Landsat imagery with some processing, and LLM classification of roughly 20k documents a day on a small model. Order of magnitude: $500–$5,000 a month, and the largest single swing factor is model choice.
Scenario B — the founding document taken literally. Google Maps plus Yandex plus Baidu plus social media plus commercial satellite plus continuous LLM at worldwide scale. Sampling a thousand traffic corridors every fifteen minutes is millions of routing calls a month; a social firehose is a five-figure monthly line on its own; commercial satellite tasking is five to six figures a year minimum; LLM over half a million documents a day is another five-figure line at frontier pricing. Order of magnitude: $50,000–$250,000 a month, which is $600k–$3M a year before a single salary.
The gap between those two readings is the entire strategic question and nobody has noticed it exists. Scenario A is fundable by one person. Scenario B needs institutional venture capital before it produces a single row of data.
The failure. The founder builds toward the founding document’s source list, signs up for a mapping platform, connects a news firehose, and discovers the cost structure by receiving a bill in month one — at which point the pipeline is architected around sources that have to be ripped out. The quieter failure is worse: an investor or a customer asks “what does it cost you to produce a report” in a first meeting, and there is no answer, which reads as the founder not understanding his own product.
3. No funding plan, no runway, no use of funds — and licensing costs money, not only time
Section titled “3. No funding plan, no runway, no use of funds — and licensing costs money, not only time”Commercial and financial viability · weeks · now
Missing. No financial model, no cap table, no funding ask, no use-of-funds breakdown, no monthly burn, no runway calculation, no milestone-to-raise mapping. The pitch deck has ten slides — Title, Problem, Solution, Product, Technology, Market Opportunity, Business Model, Interactive Community, Vision, Why Demostatics — and contains no ask, no traction, no team slide, no financials, and no numbers of any kind. There is nothing to raise against.
Why it matters here. Every document on this site treats licensing as a clock: “months to years, and no amount of engineering shortens it”. That is true and it is half the picture. Authorisation regimes generally also carry minimum capital requirements — the firm has to hold and maintain regulatory equity, and the amount typically differs between advisory and discretionary management. What those amounts are, and whether they apply, is a question for counsel in a jurisdiction that has not been chosen. The structural point does not need counsel: line 3 cannot be started with zero capital regardless of how long you wait, and no document anywhere acknowledges that licensing has a price as well as a duration.
Stacked on that: a compliance officer is a salary, not a checkbox; discretionary management implies a custodian, an administrator, an auditor and professional indemnity cover; and proprietary trading is not a revenue line at all — it consumes capital, and no document says where the firm’s own trading book comes from. Meanwhile the platform itself needs money for whichever COGS scenario is chosen, plus 9–18 months of a founder’s time.
The failure. The founder reaches the end of the engineering plan having burned personal runway, then discovers that starting the licensing path requires capital he does not have and cannot raise on a deck with no numbers in it — while the four-line decision has already committed him to a structure that needs all of it. See Cost and Funding and Regulatory Posture.
4. No model risk framework of any kind
Section titled “4. No model risk framework of any kind”Engineering, data science and AI governance · weeks · before first customer
Missing. There is no concept anywhere in the platform of validating a model, measuring
its accuracy, detecting drift, backtesting a signal, attaching a confidence interval, or
requiring a human to approve a machine-produced figure before it is published. No policy
document, no code, no schema column, no test. A case-insensitive grep across every .md,
.php, .rs, .ts and .tsx file in all five repositories for the vocabulary of model
governance returns eleven hits, every one of which is either “drift” meaning API-contract
drift or unrelated tooling boilerplate. A search for ML artifacts — *.py, *.ipynb,
requirements*.txt, *.onnx, *.gguf, *.safetensors — returns nothing at all across
all five repositories.
Why it matters here. The entire premise is that ML models and LLMs turn messy world inputs into numbers; Worker Tier says the models “are themselves specialized workers”. The 2026-08-01 decision means the firm will advise clients, manage their capital and trade its own book on those numbers. That makes model output the firm’s core risk exposure, and it is currently unmanaged in the strict sense — not badly managed, not managed at all. From inside the system, a model that is wrong is indistinguishable from a model that is right.
The failure. A processing worker reads a figure reported in thousands as units and
publishes a country’s industrial output an order of magnitude low. It lands in
database_items, renders on the Database page, is sold to subscribers, feeds an advisory
call and sizes a position on the firm’s own book. Nothing anywhere compares it to anything.
It is discovered when a client challenges it — at which point the firm cannot say how the
number was produced, cannot reproduce it, and cannot show that any other number it has ever
published was checked either.
This is the cheapest existential item to start on, because at zero rows the framework can be written as a page of rules that the schema is then designed to satisfy. See Model Risk and Ground Truth.
5. No ground truth: nothing can say whether a Demostatics number is correct
Section titled “5. No ground truth: nothing can say whether a Demostatics number is correct”Engineering, data science and AI governance · weeks · before first customer
Missing. There is no reconciliation against any authoritative external source, no
reference dataset, no accuracy metric, and no mechanism by which the firm could ever answer
“is our figure for X right?” — for any X. No repository contains code that reads an external
reference and compares it to a stored value. There is no fixtures directory, no golden
dataset, and no expected column, table or file anywhere in demostatics-web/database/.
Why it matters here. This is a different thing from finding 4. Model validation is a process; ground truth is the measuring instrument that process needs, and you cannot build the process without it. Several of the declared sources — ISO datasets, FX rates, national statistics — publish figures that are themselves the authoritative answer for quantities Demostatics intends to derive. Nothing plans to compare the two. Without that comparison there is no accuracy number to put in a subscription pitch, no way to detect a source that has silently changed format, and no basis on which to price the product against a competitor’s.
The failure. A prospective institutional subscriber asks the only question that matters — “how accurate is your data, and how do you know?” — and there is no answer, no historical error series, and no way to produce one retroactively, because no observation was ever recorded alongside a reference value. The sales conversation ends there.
The only values that exist in the product today are seven hand-written strings in
DatabaseItemSeeder.php and twelve hand-written reports in ReportSeeder.php. That is
also the opportunity: choosing the reference series now costs a page of writing, and choosing
it after a million rows exist costs a backfill that cannot be done.
High severity
Section titled “High severity”Forty-two findings, grouped by lens. Thirteen of these are marked Now; they are at the top of their tables.
Security
Section titled “Security”Detail and the recommended order of work are on Security and Privacy.
| Gap | Why it matters | Effort | When |
|---|---|---|---|
| Live known-vulnerable dependencies, and nothing scans PHP or JavaScript | composer audit reports 28 advisories across 11 packages, and two of the highs sit in the mail and routing path the next deployment step switches on | hours | Now |
| No threat model in any repository | Every other security decision — information barriers, publication ordering, what gets logged — depends on naming the adversary, and this firm’s adversary set is unusual | days | Now |
| Changing a password does not revoke anything | updatePassword never deletes tokens, so the compromised session a user is trying to kill survives for up to 30 days; the reset path a few methods away gets this right and has a test for it | hours | First customer |
The demo seeder creates a live admin with the password password | No seeder carries an environment guard, and the credentials are published in the README, in docs/api-v1.md and on this site | hours | First customer |
| No security event logging | The whole Laravel app makes one Log:: call; a valid credential reading everything produces zero errors and zero alerts, and afterwards nothing can say which account, from where, or when | days | First customer |
| The paid data surfaces have no rate limit and no usage accounting | bootstrap/app.php never calls throttleApi(), so /reports and /database-items are unthrottled and unmetered, and no future usage tier has anything to price against | days | First customer |
| No second factor on any account, including the administrator | Admin authority is protected by a password alone, and the first enterprise security questionnaire asks this question directly | weeks | First customer |
| Insider risk is operationally unaddressed | One person can edit database_items.value — which has no provenance, no revision history and no source column — and also builds the side of the business that trades on it | weeks | First customer |
Legal, privacy and data rights
Section titled “Legal, privacy and data rights”Investment licensing itself is on Regulatory Posture and is not repeated here.
| Gap | Why it matters | Effort | When |
|---|---|---|---|
| Third-party code entered the tree with no assignment | The mobile app’s entire first commit came from an outside contributor via an AI app builder, with no CLA and no assignment on file; this is fixable today and stops being fixable when people are unreachable | days | Now |
| Ingested-source rights have nowhere to live in the schema | Provenance answers “where did this come from”; it does not answer “may we sell it”, and the four business lines may hold different rights on the same row | weeks | Now |
| Account deletion leaves rows behind, and the two paths differ | The web path never deletes tokens, personal_access_tokens and model_has_roles carry no foreign key, and the test suite certifies only the half that works | days | First customer |
| Poll votes are identified opinion records on political topics | The unique index on (user_id, poll_id) makes the ballot identified by construction, stored forever, with no consent record and no retention limit | days | First customer |
| No subscriber contract, liability limit or accuracy statement | Nothing states what the firm commits to or caps, exports carry no notice and no customer fingerprint, and the Windows installer already asserts subscription terms that have never been written | weeks | First customer |
| No privacy notice, lawful-basis position or data inventory | The system holds more personal data than an inventory-free team would guess, and the inventory gets harder to assemble every month | weeks | First customer |
| Erasure and the moderation record destroy each other | Deletion cascades posts, votes and the ban record together, so the only erasure available simultaneously over-deletes and under-deletes, and nobody has chosen which obligation wins | weeks | First customer |
| No founder-side paper: shareholding, vesting, IP assignment | An entity does not own the code until it is assigned, and assignments signed after a dispute or a second founder are much harder than assignments signed now | days | Licence |
Operations and reliability
Section titled “Operations and reliability”| Gap | Why it matters | Effort | When |
|---|---|---|---|
app:delete-unverified-users is an unguarded mass delete | Under the documented default MAIL_MAILER=log no user can ever verify, so its selection criterion matches the entire user table; no dry run, no confirmation, no log, no backup behind it | hours | Now |
| Bus factor of one, with no credential inventory | 158 of 163 commits are by one person, every .env is correctly gitignored, and nothing records where the domain, the store accounts or the future APP_KEY live | hours | Now |
| No backup of anything, anywhere | The live database is one untracked SQLite file; user accounts, forum history, votes and the curated paid rows are derivable from nothing | hours | First customer |
Nothing polls /api/v1/health, and there is no alert destination | The health endpoint’s only consumer is a customer-facing footer in the mobile app; the diagnosis exists and the detection does not | hours | First customer |
| No error tracking in any of the three shipped codebases | Server exceptions land in a file on the box; a mobile render throw is a white screen with no report and no error boundary | hours | First customer |
| The external world dataset has no recorded version | Every stored country_id is a bare integer pointing into a community dataset whose ids have been renumbered across releases, with no foreign key and no version pin | hours | First customer |
| No trusted-proxy configuration | The moment TLS is terminated in front of the app, every auth throttle keys on the proxy address, so one bucket of five attempts per minute is shared by the whole internet | hours | First customer |
| A silently stopped feed is indistinguishable from a quiet world | Nothing computes freshness; measured_at is read only to sort and to display, so a dead source renders as an unchanged indicator | days | First customer |
| No restore has ever been attempted and no recovery procedure exists | The restore has non-obvious steps — the external geo store, APP_KEY, the scheduler cron, the queue worker — that will be discovered under pressure | days | First customer |
Commercial and financial viability
Section titled “Commercial and financial viability”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| No price, no break-even seat count, no cash cost on the 9–18 month plan | The break-even arithmetic is trivial once COGS exists and it changes what gets built; the roadmap sequences engineering as if time were the only scarce resource | days | Now |
| No minimum viable data set | Nothing names which sources are required to ship something sellable versus which are aspirational, which is why “what is the smallest thing you could sell in six months” has no answer | days | Now |
| The history clock has not started | Point-in-time history is the one asset that can only be accumulated in real time; a dumb archiver could run this week and would be worth more in two years than any downstream engineering done meanwhile | days | Now |
| No competitor is named anywhere | The incumbents’ prices anchor the positioning, and a one-person firm cannot win on breadth — the entry has to be narrow, and that is a decision nobody has made | days | Now |
| Three of the four business lines cannot produce revenue for years | Advisory and discretionary management wait on a licence, proprietary trading consumes capital rather than producing recurring revenue, so line 1 funds everything alone | days | Now |
| Almost all cost is fixed, and the only allowance table meters the cheap things | A high-fixed, near-zero-marginal structure reduces the business to “how many seats amortize the pipeline”; the mock server’s dev limits meter egress and the customer’s own CPU, and give Enterprise unlimited AI | days | First customer |
| The satellite claim is unsourced and uncosted | Flight, maritime and road data do not come from imagery, and the one genuine use case is served by free public programmes — so the expensive part of “satellite” is not required by anything the product describes | days | First customer |
| Mapping provider terms likely prohibit what the model does with the data | Storing refined data and reselling it collides with the redistribution and derived-dataset restrictions common to those platforms; this needs checking before a line of ingestion code is written | days | First customer |
| The single asset is bulk-extractable by any verified account | No throttle, no quota, no usage record, no watermark and no redistribution term; the control has to exist before the data does, because retrofitting it onto existing customers is a renegotiation | days | First customer |
| Nothing can collect money, and the named payment rail may be unavailable | No billing code, no plans or invoices tables, no tax handling, no currency decision — and the roadmap’s Phase 3 assumption needs checking against the entity’s country before the entitlement system is designed around it | weeks | First customer |
| There is no top of funnel, and no way to measure one | The homepage redirects to an editorial list, the contact page refuses personal email addresses, and no analytics of any kind exist anywhere | weeks | First customer |
| The four named buyer segments cannot procedurally buy | Every one of them requires terms, a DPA, security documentation and often a formal audit posture before a purchase order can be raised; first revenue realistically comes from somewhere else | months | First customer |
Engineering, data science and AI governance
Section titled “Engineering, data science and AI governance”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| No output contract can express uncertainty | Every delivered number is a bare scalar, so a figure corroborated by three sources is indistinguishable from one an LLM inferred from a single article — and adding the field later leaves every historical row permanently null | days | Now |
| No worker design spec | The decisions that must precede writing the worker — orchestration, idempotency, delivery semantics, retry, backpressure, binding output to a model version — exist nowhere, while an orphaned tasks table sits in the wrong repository encoding a guess at them | weeks | Now |
| The composite risk score has no documented methodology | It is a mean coefficient of variation weighted by how many series each category happens to contain, saturating at a constant with no stated justification, presented as a risk model | weeks | First customer |
| The risk score depends on the viewer’s tier and requested update rate | A Pro subscriber computes a structurally different number from an Individual subscriber for the same world, and nothing in the UI or the contract says so | weeks | First customer |
| Observations have no time axis | Every displayed statistic is computed over arrival index, and the correlation table aligns two front-dropping windows by prefix, so two clients can see materially different r for the same pair | weeks | First customer |
Medium severity
Section titled “Medium severity”Thirty-five findings. None of them will stop a launch on its own; most are cheap, and several are hours of work sitting in front of a much larger cost.
Security
Section titled “Security”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| No vulnerability disclosure path | No SECURITY.md, no security contact, no security.txt — and public installers are the artefact an unsolicited researcher pokes at first | hours | First customer |
| Report export writes untrusted strings into spreadsheets | csv() and xlsx() neutralise nothing while doc() in the same class escapes everything; the tables will be worker-populated from scraped text | hours | First customer |
| The desktop client takes the password as a command-line flag | Visible in ps, captured in shell history and collected by exactly the endpoint tooling the intended customer runs; there is no stdin, env or prompt alternative | hours | First customer |
| The release pipeline publishes a dev build authenticated by a hardcoded password | The release job never enables the remote feature, so everything good in the client’s security design is compiled out and the shipped credential is demo | hours | First customer |
| Release supply chain: mutable action refs with write access, no provenance | Five third-party actions pinned to tags, workflow-level write permission on every build job, and a checksum file generated by the pipeline it is meant to attest | hours | First customer |
| CORS is open to every origin and no security response headers are set | Any hostile page can drive the unthrottled public API from a visitor’s browser, and there is no CSP behind the forum’s user-submitted bodies | hours | First customer |
| No incident containment capability | No way to freeze one account, stop new signups, or expire tokens issued before a date; the only blunt instrument takes the whole business offline | days | First customer |
| The desktop assistant is an unpoliced exfiltration channel | Live indicator values and base64 screenshots of the workspace POST to whatever URL a command-line flag names, with no allowlist, scheme check or audit record | days | Scale |
Legal, privacy and data rights
Section titled “Legal, privacy and data rights”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| No licence file anywhere, and the server’s manifest declares itself MIT | composer.json still carries the Laravel skeleton’s name and MIT licence on the only implemented server, which says the opposite of the desktop repository’s proprietary declaration | hours | Now |
| The one third-party dataset already shipping has no recorded licence or attribution | The geo cascade is redistributed through a public unauthenticated API with no terms recorded anywhere and no notice carried to the point of delivery | hours | Now |
| Ban status and presence are published to unauthenticated callers | UserResource emits is_banned, roles and is_online on every public forum listing, so an adverse statement about identified people is world-readable | hours | First customer |
| Mail written to an unrotated log makes reset tokens permanent | While MAIL_MAILER=log is set, the log is a mail archive containing account-granting tokens, with no rotation, no retention and no erasure path | hours | First customer |
| No breach-notification path, and the contact page repels reporters | The notification clock starts on awareness, and awareness usually arrives from a private individual writing from a personal address — which the page states will not be accepted | days | First customer |
| Forum rule 17 points at an empty report endpoint | The route exists and its controller body is a TODO comment; there is no reports table, no moderator queue, and no channel at all for a non-user | days | First customer |
| No insurance of any kind is named anywhere | Selling a number people act on, and later advising on money, are the exposures these policies exist for; cover is also a common condition of authorisation and of institutional contracts | weeks | First customer |
| Running the firm’s compute on customers’ machines has no disclosure text | Once the coordinator lands, the firm is sending work to hardware it does not own, and nothing states what runs, whose work it is, or how to withdraw | days | Scale |
Operations and reliability
Section titled “Operations and reliability”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| The production log sink is an unrotated file at debug level | LOG_STACK=single with LOG_LEVEL=debug on a small VPS where the database, sessions, cache and queue share one disk; a daily channel exists and is simply not selected | hours | First customer |
| Desktop crash reports are written and never sent | The panic hook writes a file to the user’s machine that nobody will ever open, so the crash rate of every shipped version is permanently unknown | days | First customer |
| No staging environment | Changes go from one laptop to production, and the cross-driver behaviours the code carefully handles are never executed against Postgres or MySQL by anything, ever | days | First customer |
| A 5000-row export runs synchronously in the request with no rate limit | The paid feature builds an entire spreadsheet in memory inside the worker that is also serving everyone else, and nothing throttles it | days | First customer |
| Mobile has no kill switch, no OTA channel, and a build-time-baked API origin | Once a build is in a store, the only lever is a new submission; the server also does not know what version any client is | days | First customer |
| No on-call, no incident procedure, no availability commitment | An always-connected streaming subscription is a product whose customers notice downtime in minutes, and nobody has decided what happens at 3am | days | First customer |
| No cost ceiling or circuit breaker on any paid external dependency | An LLM proxy has unbounded cost per request by design — images, long context, tool loops — exposed to a client the firm does not control, with no cap and no alarm | days | First customer |
| Every authenticated request rewrites one shared cache key, and nothing has been load tested | A read-modify-write of a single global entry on every request, on a single-writer SQLite file; it is both a serialization point and a lost-update race | hours | Scale |
Commercial and financial viability
Section titled “Commercial and financial viability”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| Single-provider dependency with no substitution layer | Every layer rests on one named provider, two of them with a documented history of unilateral repricing, and there is no seam behind which a second source could be dropped in | days | First customer |
| The pricing model bills customers for compute their own hardware performs | Charging for statistical work executed on the customer’s laptop is hard to hold in a renewal, and the meter that would count it is client-side and does not exist as a crate | days | First customer |
| Turkish non-dilutive funding and technology-zone status are mentioned nowhere | Grant programmes and R&D tax regimes exist for close to this exact profile, and eligibility depends on an entity structure being decided right now for regulatory reasons | weeks | Licence |
Engineering, data science and AI governance
Section titled “Engineering, data science and AI governance”| Gap | Why it matters | Effort | When |
|---|---|---|---|
| Statistics are fitted to visually-downsampled data | Above 64 samples the fit runs over LTTB output — a perceptual algorithm that over-selects extrema — and the resulting R² is handed to the AI assistant as the authoritative summary | hours | First customer |
| Automatic model selection by in-sample R², then extrapolated | R² never decreases with complexity, so the cubic usually wins on noisy data, and the chosen curve is extrapolated with confident prose about growth to infinity | days | First customer |
| Polynomial fitting has no conditioning guard | Raw index powers to Σx⁶ against an absolute pivot threshold produce coefficients that have silently lost most of their significant digits rather than returning None | days | First customer |
| No test exercises a real customer path across two components | Every test is intra-repository and each side is tested against its author’s belief about the other, which is exactly the class of failure the two-contract problem will produce | weeks | First customer |
| No output artifact can be reconstructed after the fact | Exports carry no as-of time, no build version, no filters and no sample counts, and the in-memory history behind them is discarded on exit | days | Licence |
| No change control over methodology | The constants that move every displayed number are ordinary constants in ordinary files, with no method version, no changelog and no gate — while the site commits to adapting the platform by community vote | days | Licence |
| AI assistant output is unrecorded and unattributed | Nothing persists an exchange, the model identity, the grounding context or the tools called, and the local path already emits trading suggestions | weeks | Licence |
| Contributed compute has no result-verification design | Once the coordinator exists, output the firm sells and trades on will have been computed on machines it does not control, by users with a financial interest in its positions | weeks | Scale |
Low severity
Section titled “Low severity”| Gap | Lens | Why it matters | Effort | When |
|---|---|---|---|---|
| No secret scanning anywhere | Security | Nothing would have caught the live Gemini key that sat in demostatics-web history for 20 revisions, and the next roadmap steps create SMTP, payment and eventually broker credentials. .gitignore also covers .env.backup but not .env.bak | hours | Now |
| Bundled fonts carry notice obligations and no third-party licence file ships | Legal | cargo-deny verifies a licence is allowed; it does not generate the notice file, and nothing else does either | hours | First customer |
| The desktop caches proprietary data to disk in plaintext and never clears it | Security | The token is deliberately protected and the thing the token protects is not; nothing wipes the snapshot on logout, expiry or downgrade | hours | Scale |
| Documentation is the system of record and nothing verifies it | Engineering | This site makes several hundred checkable claims and has no build check, no link checker and no CI; the first broken claim discounts everything else on it | hours | Scale |
What is already right
Section titled “What is already right”The sweep also looked for things done well, and found roughly fifty. This section exists for two reasons: it tells you what not to touch while working through the register, and it is the evidence that the register is a survey rather than a pile of complaints. The items below were re-verified against the repositories while writing this page.
Security and hygiene
Section titled “Security and hygiene”-
Every
.envis gitignored, in the web, desktop and docs repositories, and.env.exampleships empty placeholders rather than real values. -
Every lockfile is committed:
composer.lockandpackage-lock.jsonin the web repo,Cargo.lockin the desktop workspace,package-lock.jsonin mobile,pnpm-lock.yamlhere. -
Sanctum token expiry is set explicitly.
config/sanctum.phpline 58 readsenv('SANCTUM_EXPIRATION', 60 * 24 * 30)— a 30-day default in place of Laravel’s shippednull, which means tokens that never expire. That is a deliberate hardening of a framework default and it is the kind of thing that is normally missed. -
Scoped token abilities exist.
App\Support\TokenAbilitydeclares a real vocabulary —data:read,forum:write,account:write,moderate,ingest:write— withingest:writedeliberately withheld from every interactive token, and a docblock explaining why the vocabulary had to be declared before a second kind of token exists. (Two known gaps in how it is applied are already logged as contradictions 4 and 5 on Open Questions.) -
Forgot-password does not enumerate accounts. The API returns the same body whether or not the address exists, with a comment in
AuthControllerexplaining that otherwise “anyone could walk a list of addresses through”. -
There is no file-upload surface at all. A grep across
app/,resources/views/androutes/forhasFile,UploadedFile,Storage::putFileandenctypereturns nothing. An entire vulnerability class is absent by construction. -
No unescaped Blade output.
{!! !!}appears nowhere inresources/views/, across a forum that renders user-submitted bodies up to 40,000 characters. -
Raw SQL is disciplined. Seven
whereRaw/orderByRawcall sites, every user-supplied value bound as a parameter, every column name supplied by controller code and never from the request. TheLOWER(col) LIKE ?pattern carries a comment explaining it exists because a bareLIKEis case-sensitive on PostgreSQL. -
WebPKI validation plus optional SHA-256 certificate pinning on the desktop QUIC transport (
crates/ds-transport/src/quic.rs), with the insecure bypass an explicit, documented opt-in rather than a default. -
cargo-denyruns in CI on the Rust workspace with an allow-listed licence set and a single ignored advisory that carries a written justification and a revisit condition.
Statistics and correctness
Section titled “Statistics and correctness”- Welford’s online algorithm for running mean and variance rather than the naive
sum-of-squares (
crates/ds-analytics/src/streaming.rs), with a test asserting it matches the batch result. - Bessel-corrected sample variance — divides by
n-1— in both the batch and streaming paths, documented as such in each. - Two-pass Pearson correlation (
crates/ds-analytics/src/correlation.rs) rather than the numerically unstable single-pass form. - Degenerate inputs return
Option::None, notNaN. A caller cannot accidentally render a garbage number, because there is no garbage number to render.
Those four are the reason the analytics findings in this register are about methodology rather than arithmetic. The arithmetic is careful.
Engineering discipline
Section titled “Engineering discipline”- Every one of the 22 migrations has a real
down(). Not one is a stub. - 211 Laravel tests, 922 assertions, green in 2.2 seconds — re-run while writing this page. A suite that fast gets run, which is most of the value of having one.
- The hand-written
Featureserde implementation incrates/ds-core/src/identity.rsexists because of a real bug, and its test asserts that an unknown feature name still parses rather than failing the whole payload — forward compatibility deliberately chosen. - Every repo-relative path cited on this docs site exists. All 57 distinct paths quoted
in backticks across
src/content/docs/were checked against disk. The claims are accurate today; the LOW finding above is about keeping them that way, not about fixing them.