A static page generated from a single register. Every record in that register is currently null: nothing has been supplied, and nothing is guessed.
npm run check # build, then run every gate
npm run serve # serve public/ on http://localhost:4173src/config/facts.js holds every external fact as a record:
{
id: 'contract',
label: 'Token contract address',
group: 'contract',
value: null, // the fact itself
source: SOURCE.NONE, // who vouched for it
absent: '…', // the sentence shown while value is null
present: (v) => v, // the sentence shown once a value exists
}A record reads as stated only when it carries both a value and a source.
Carrying exactly one of the two is a half-stated fact, and both build.js and
scripts/verify.js refuse it.
To publish a fact, set value and source together. That is the only edit
required: the panel, the chip, the count, the page description and any control
all derive from the record, so a sentence written today cannot survive as a
falsehood once the value arrives.
value: null is the honest unknown. It is never a placeholder, an empty
string, a zero, or an example.
The contract record is first in the register and first in the document. It is measured above the fold at every tested viewport.
While the contract value is null there is no copy control and no client script on the page. When a value is supplied, the control and its script are emitted together, and the control reads the same element the page displays, so the string a reader sees and the string placed on the clipboard are one expression.
Register integrity asks whether both halves of a fact are present. It does not
ask whether what they contain is worth printing, and that gap shipped once: a
dry run left 0x000…dead in the contract record with a source beside it, and
every gate passed while the page rendered a burn address as a stated fact with
a working copy control.
A record may now declare kind: KIND.ADDRESS, and a stated address is rejected
by both build.js and scripts/verify.js when it is a burn or vanity address
(contains dead or beef), the all-zero address, built from fewer than four
distinct hex digits, or contains a paste-in sentinel (example, placeholder,
changeme, tbd, todo). It must also be a 0x-prefixed 40 digit hex string.
The limit, stated plainly. This catches values that say nothing. It does not
catch values that are wrong. A real, well-formed, deployed contract address that
belongs to the wrong contract, the wrong chain, or to somebody else passes every
check and always will. Nothing here contacts a network or confirms that code
exists at the address. A green build is not confirmation that the address is
correct; that stays a human step. The same limit is written beside the rule in
src/config/facts.js.
The gate also runs its own matcher against a fixed set of samples on every build, so a regression that quietly stopped rejecting things would be caught while the register is still empty.
The X and repository slots sit in the masthead in both states, so wiring a channel moves nothing on the page.
A channel record carries kind: KIND.URL, and its value is both the text
the register prints and the destination the slot navigates to. There is no
second table of hrefs to fall out of step with the register, so wiring a
channel is a single field edit:
value: 'https://…', source: SOURCE.CLIENT,One function renders both states. While the record is null the slot is a
<span> with role="link", aria-disabled="true" and tabindex="0" — no
href, keyboard reachable, inert. Once the record is stated the same call site
emits an <a>. A disabled slot and a live link cannot drift, because the gate
fails on either mismatch.
The visible reason on hover and focus is the record's own absent sentence,
not new wording. The same sentence is always present in the slot's visually
hidden label and again in the register row below, so the explanation is never
only in a tooltip.
public/artwork.jpg is a client file, placed at the client's written
instruction. It is re-encoded from pixel data only, so the EXIF and XMP the
supplied JPEG carried do not ship.
It sits after the register under its own heading, as a single framed figure. It is deliberately not a row, not a strip, and not next to anything that could read as a list of relationships: it is artwork, not a statement. No record was added for it, nothing in the register refers to it, and no sentence on this page is true or false because of it.
It is never the page's identity. The favicon and the og image are both built from the mark, and a gate fails the build if either points at the artwork, so it cannot become the preview that represents the site.
Its alt is empty and the caption carries the context. Describing the picture
would mean writing out what it depicts, and this page does not put that into
words.
src/styles/tokens.css is the only file that names a colour. Every value in it
was sampled from a client file and carries its provenance in a comment beside
it.
Method: k-means (Lloyd, k-means++ seeding, fixed seed) over the opaque pixels of the RGBA logo for the mark, and over the background region of the flattened logo for the ground. The per-cluster median is taken as the representative value rather than the centroid, so every token is a colour that actually occurs in the file.
Only two hue families appear on this page, because only two appear in the artwork: lime H 62–69 from the mark, blue H 207–217 from the ground. Where a sampled value missed its contrast target, lightness alone was moved and hue and saturation were held; both values are recorded in the comment.
The banner in reference/ was sampled and deliberately not used. Its
non-sky clusters are third-party mark colours.
public/mark.png and public/og.png are generated from the RGBA logo only.
The transparent pixels in that file are pure black, so both are produced with a
premultiplied resize — premultiply, resample, unpremultiply — otherwise black
is dragged into every antialiased edge and the mark gains a dark halo.
Glyphs are authored in a 48 unit user space and rendered at 48 CSS px. The
first child of each is a transparent rect spanning the whole user space, so the
hit area is geometry rather than padding. scripts/verify.js re-derives the hit
area in CSS pixels from the emitted viewBox and width attributes, so changing
the grid changes the measurement rather than silently invalidating it.
The supplied artwork is a mark, not an icon set, so the glyphs remain neutral geometric forms. No third-party mark is drawn.
scripts/verify.js runs eleven gates and exits non-zero on any failure:
| gate | fails when |
|---|---|
| register integrity | a value has no source, a source has no value, or a stated channel's value is not an absolute https url |
| stated values say something | a stated address is a burn or vanity address, all-zero, built from too few distinct nibbles, or a pasted sentinel |
| channel slots | a slot links while its record is null, renders disabled while its record is stated, is not keyboard reachable, or its href differs from the value it displays |
| supplied artwork | the artwork is missing, is used as the favicon or og image, or sits inside the register |
| reference terms | a term from the studied reference appears in a shipped file |
| authorship attribution | assistant authorship is credited anywhere, dotfiles included |
| emitted html comments | the shipped document contains any comment |
| image metadata | a shipped image carries a text or EXIF segment |
| tap targets | a glyph's hit area is under 44 CSS px once viewBox scaling is applied |
| token contrast | any token misses its target on either painted ground |
| orphan copy control | a copy control or a script appears while the address is null |
Deny lists are stored as SHA-256 digests of the normalised term, never as text. Matching runs the other way round: text under test is normalised, cut into n-grams, hashed, and looked up. A published gate file therefore cannot be read back into the words it rejects.
Each gate has been broken deliberately and observed to fail before being accepted as passing.
Measured in a real engine against the effective viewport, with browser chrome subtracted from the nominal device size. With the page served, run:
(() => {
const H = innerHeight, W = innerWidth;
const q = (s) => document.querySelector(s)?.getBoundingClientRect();
return {
viewport: W + 'x' + H,
contractBottom: q('#contract')?.bottom,
aboveFold: q('#contract')?.bottom <= H,
horizontalScroll: document.documentElement.scrollWidth > W,
};
})()