One rule, enforced
in three places.
Audit last run
26 Sept 2026
Psychedelia will not display a quantity that cannot say where it came from. That is not an editorial aspiration — it is enforced by the type system, by the query layer, and by an audit that runs against the upstream registries and publishes its own failures. This section documents all three, and what each of them misses.
I
The constraint
Every value shown must be traceable to a record a reader can open, or to a computation this codebase performs and names. If a number cannot be sourced, it does not go on the page.
The second sentence is the one that costs something. Removing a feature is the correct outcome when its data cannot be sourced, and two upstream tables have been removed on exactly that basis — they are named, with their numbers, on the sources page.
II
How the site operates
Six upstream sources, one archive, and one direction of travel.
Nothing here is computed on demand from a live API. Data is harvested by the programs in tools/, each measurement is judged as it arrives and stored with the verdict that let it in, and the site reads only what the archive already holds. That is what makes a page reproducible: two readers a week apart see the same numbers, and the date the archive was last refreshed is printed on every plate.
The crossed arrow is the load-bearing part. The application has no write path to the archive at all — not a disabled one, not a guarded one. A correction found by a reader or by the audit becomes a proposal on the integrity report, with its evidence, and a person applies it at the source. An archive its own front end can edit is one whose history cannot be trusted.
III
Where it is enforced
Three mechanisms, none of which relies on anyone remembering the rule.
An identity audit gates the archive
tools/verify_compounds.py → data/verification.json → src/lib/verification.ts
Every compound record is re-checked against the PubChem record it cites and the ChEMBL record it cross-references before anything is displayed. The gate is applied inside the SQL, not after it, so a withheld record cannot contribute to a count, an average or a target’s compound list. Of 545 records examined, 545 are verified, 0 are shown as unconfirmed, and 0 are withheld entirely — taking 0 measurements out of view with them.
The integrity report →Provenance is typography
src/components/Provenance.tsx
Quantities render through a <Value> component that will not compile without a source, and each carries a superscript mark linking to the record it came from. An absent measurement renders as an explicit absence — never a zero, never a dash that could be read as a value, never a carried-forward figure.
The failures are a page, not a changelog
src/app/documentation/integrity
The audit publishes what each check does and what each check misses, every withheld record with the collision that caused it, and the corrections that were proposed but deliberately not applied. A reader cannot judge how far to trust a number without knowing what the archive gets wrong and how often.
What failed, and why →IV
How to read a value
Four marks, the same meaning on every page.
- P
- PubChem
- C
- ChEMBL
- R
- Computed here with RDKit
- D
- Derived here from the stored measurement
Measured and computed are never mixed. A molecular weight is computed; a binding constant is measured. Both are shown, and the mark tells you which you are looking at.
pX is derived, not stored. Every pX is the negative base-10 logarithm of the value in molar, −log₁₀(M). Values are stored in nanomolar, so it is computed as 9 − log₁₀(value in nM) from the normalized measurement, applied uniformly. It is the quantity ChEMBL publishes as pChEMBL, and a ChEMBL record whose converted pX differs from its own pChEMBL by more than 0.006 is quarantined. The database also holds a partially populated pX column; it is not read, because an axis that is sometimes one quantity and sometimes another is not an axis.
Binding constants and functional readouts are kept apart. Ki and Kd answer a different question from IC₅₀, EC₅₀, AC₅₀ and potency, so they are never pooled in a chart, a ranking or an average.
No dose, route, or safety information appears here, anywhere. The archive holds no sourced data on any of them, so there is nothing this site could say that would not be invented.
V
In this section
The simulation model
The one part of this site that computes numbers nobody measured: the model behind the Simulations sandbox, every assumption it rests on, and what it cannot represent.
- compartment
- 1
- parameters, mostly estimated
- 5
compartment
parameters, mostly estimated
Integrity report
What each check does and what it misses, every withheld record with its evidence, duplicate holdings, and the corrections proposed but not applied.
- records withheld
- 0
- measurements withheld
- 0
records withheld
measurements withheld
Sources and licenses
The three sources this build draws on, what each supplies, the terms it carries and how to cite it — and every dataset the archive holds that this build refuses to display.
- sources in use
- 3
- measurements drawn
- 19,644
sources in use
measurements drawn
VI
Reproducing the audit
The audit is not run on every start — it makes live requests to PubChem and ChEMBL. The site reads whatever the file last said and prints its date on every page, so a stale audit is visible rather than silent. To refresh it:
./run -v
Generated by tools/verify_compounds.py using RDKit 2025.09.2 on Python 3.9.6. Authorities: PubChem, MeSH Pharmacological Classification, ChEMBL.