every number has a name
the box keeps one file that names and binds 392 numbers to the files that own them, and the lab's record carries the same 392 back.
the takeaway in one paragraph
A codebase collects numbers. A timeout here, a matrix size there, a threshold picked once and never explained again. The box keeps one registry for these numbers instead: `magics.ts`, one row per number, each row carrying the value, its unit, which piece of code owns it, and why it is set where it is.
`MAGICS.length` at runtime is 392. The lab's canon file carries 392 entries under `formal/magic/*`, one per row. Every row in the registry has a name, a unit, an owner file, and an entry in the record.
the everyday problem
An unexplained literal in code is a known smell. A reviewer sees a bare threshold or a bare size sitting in a function and has no way to tell, without reading the whole call chain, whether it is a tuned constant, a safety margin, or an accident nobody has removed yet. The comment at the top of `magics.ts` inverts the word.
In this file a magic is a literal that has been named, typed, given its unit and window, and bound to the code that owns it. An unregistered literal is still the smell. The registry is the fix.
The comment names an actual case: the value 0.85 sits at several sites in irc-strix-halo/schwarzline, most of them unnamed constants, and one further site nearby carries the same value for an unrelated meaning. A shared literal standing in for two different things is what a registry row exists to rule out.
how a magic is bound
Each row in `magics.ts` carries a fixed shape, checked by a zod schema: an id, a kind (constant, parameter, or runtime), a value, a unit, a basis (what the number actually measures), a sign, a window (when it applies), an owner file, the symbol name in that file, and a binding — `export` if the suite imports the real symbol directly, `source` if the suite has to regex the owning file because the symbol is private. A row with no binding is rejected outright. The registry does not let a number sit in the file as a second source of truth. Every row has to point back at the one place the value actually lives.
The rows are assembled by spreading several row sets into one frozen array at the bottom of the file. The total is `MAGICS.length`, read at runtime rather than asserted by hand. That total is 392.
- the registry at `research_worker/src/kernel/magics.ts` reports 392 rows when imported and measured directly
- the lab's canon file `docs/parity/maxwell-canon.json` carries 392 artifacts whose id starts with `formal/magic/`, generated from that same registry by `research_worker/scripts/gen-canon-magics.mjs`
- the canon's own relation `relations/measured-by-magics-registry` states the rule plainly: a canon magic artifact that disagrees with the registry is a stale projection, never an independent claim
The canon file is generated from the registry by `research_worker/scripts/gen-canon-magics.mjs`. A second test, `test/kernel.canon-magics-projection.test.ts`, checks agreement in both directions: it fails if the canon lags a change to the registry, and it fails if the registry gains a row the canon has not yet picked up.
Two dated carriers still read 42: the canon entry `ideas/magic-is-a-magic-linguistic-dag`, and `docs/parity/METAPATTERNS-ONE-LANGUAGE.md`. Both are notes about a past state. The relation above names which side wins when the two disagree: the registry.
what this does not cover
- this note checks that a name exists and the count matches. it does not check that every one of the 392 bindings resolves to a live symbol in its owner file — that is a separate drift test the registry's own suite runs. that test blocks for a row owned inside this checkout, and only reports (never blocks) for a row owned in a sibling repo
- the note `ideas/meta-chip-magic-computer` frames magics as the fill step of a larger compiler-to-runtime pipeline. this note only covers the registry itself, not that pipeline
- `implementations/magics-journal` and `implementations/magics-width` are two related, already-built pieces — a per-turn record of eight readings over the whole registry and a comparator-width table that ships empty by design — that this note does not exercise, because both are recorded as built with no production consumer yet
- some rows in the registry point at another row through `same_anchor_as` — two ids recorded as the same underlying anchor, on purpose, and never merged, because merging two constants is a behaviour change. 392 rows is not 392 distinct numbers
- the record entry says a number is bound to the file that owns it. a runtime row is marked materialized instead; witnessed is never granted by the generator, because that requires an executed receipt relation in canon
the next gate
The next question the registry leaves open sits at `schwarzline.lock-coherence` in `magics.ts`: it carries the same value as the kernel LOCK constant, for a different system, and whether the two encode one law is not established — they are noted, never anchored together. The registry now records when two repos hold the same value; the next test is whether an equal value in two repos is one law or a coincidence, and `same_anchor_as` is withheld across systems until there is evidence.