The eternalink promise
kaiv’s registries bind a name to bytes exactly once, forever. On what breaks when registries can change their minds, a validator standing at the door, names that outlive their publishers — and why the promise begins by refusing to be made early.
On March 22, 2016, one author unpublished eleven lines of
JavaScript called left-pad, and build pipelines across the
industry stopped dead — React’s among them. npm restored the
package within hours and tightened its unpublish policy, but
the restoration was the smaller half of the lesson. The larger
half: every build that broke had been holding a reference whose
meaning could change, and nobody had priced that in. The
package didn’t fail; the reference did. It had always been
revocable. Someone finally revoked it.
Mutable references are a quiet tax on everything downstream. A
dependency you audited last year has to be re-audited, because
its name may resolve differently now. A schema URL in a config
is a hope, not a fact. Documentation links rot, latest tags
move, registries yank, accounts get deleted and take their
artifacts with them. None of these are outages; they are the
system working as designed — the design just never promised
that a name would keep meaning what it meant.
kaiv’s registries make exactly that promise, and are built backwards from it.
A name, bound once
The kaiv ecosystem runs on four registries: type libraries
(ktaiv.com, serving .taiv), schemas (ksaiv.com), unit
definitions (kfaiv.com), and documents (kdaiv.com). For
the three name-addressed registries the rule has no fine
print: the URL is the storage key, a path is published to
exactly once, and the published artifact is frozen forever.
No edits. No deletions. No retractions. And — stricter than
any package registry — no versions: there is no “latest”, no
version selector, no range resolution, because a name is bound
to bytes once and that binding is the meaning. Evolution
happens the only honest way it can: a new version is a new
name, and the old name keeps meaning what it always meant. The
document store goes one step further and addresses .daiv
content by its BLAKE3 hash — there the name isn’t just bound
to the bytes, it is derived from them.
These URLs are called eternalinks, and the intended lifetime is in the word. They outlive their publishers by design: deleting your account stops your tokens from minting, but everything you published stays resolvable — permanence attaches to the artifact, not to you. (The one concession, on the document store only: visibility of a private document can be flipped — the GDPR posture — but the URL is then retired, never reassigned. No path is ever reclaimed, ever.)
A registry artifact, concretely, is about as unassuming as infrastructure gets — a plain text file at a URL:
$ curl -s https://t.kaiv.io/std/net.taiv | head -10
.!taiv 1 std/net
// Network identifiers. Patterns are pinned to their defining
// documents; the \x27 escape carries the apostrophe that RFC 3986
// sub-delims and the e-mail grammar admit but a pattern body
// cannot contain literally.
// URI — RFC 3986 generic syntax, exactly: scheme, optional
// authority (userinfo, reg-name / IPv4 / IP-literal host, port),
// the path forms, query, fragment, percent-encoding.
Reads are public and unauthenticated — the name registries
don’t even have a read scope. No API to version, no
negotiation: GET returns the bytes, and returns the same
bytes every time:
$ curl -s https://t.kaiv.io/std/net.taiv | sha256sum
87757da79c1e5926b86115589a24980b824409c840cd3cf897b67db4e54eaf74 -
$ curl -s https://t.kaiv.io/std/net.taiv | sha256sum
87757da79c1e5926b86115589a24980b824409c840cd3cf897b67db4e54eaf74 -
What forever buys
Schemas become contracts instead of coordinates. A kaiv
document declares the schema it validates against by name;
that name resolves to an artifact that cannot drift. Validate
the document today and in twenty years and the inputs are the
same bytes — the data, the compiled schema, both plain text,
both frozen. There is no “the schema changed under me,”
because changing a published schema is not an operation the
system has. For the safety-critical deployments of the
previous article,
this is load-bearing: the .csaiv your audit certified
against is immutable not by your process discipline but by the
registry’s construction.
Caches never expire. An immutable artifact is served with
Cache-Control: immutable and cached without revalidation —
there is nothing to revalidate; a 304 conversation with a
frozen object is wasted motion. The reference toolchain caches
fetched artifacts on first use and never asks again; offline
operation is not a degraded mode but the same mode with the
network calls already answered. Taken to its limit, the cache
moves into the binary itself — the standard libraries ship
embedded in the toolchain, so this works with the network
switched off entirely:
$ printf '.!kaiv\n.!types std/enc\n\n&bin\nid=deadbeef\n' | KAIV_OFFLINE=1 kaiv build
.!daiv
!std/enc/bin'::id=deadbeef
Look at the canonical line: the type is !std/enc/bin, a
logical path. Where the bytes came from — network, cache,
embedded copy — leaves no trace, because with immutable
artifacts every source is equivalent. Identity is the name;
resolution is a deployment detail. (The certified runtime, per
the previous article, resolves nothing at all: it reads
.daiv and .csaiv, both already local, both already frozen.)
Enforced in depth
A forever promise is only as good as its enforcement, so the
write path is built like a lock with two independent bolts.
Publishing walks five steps: authenticate; verify you own the
namespace and that the path has never been published;
upload into a pending/ staging prefix via a pre-signed URL;
pass the validation gate; promote to the canonical path. The
“never been published” check is the first bolt — the broker
refuses to issue an upload for a path that exists. The second
bolt is in the storage layer itself: promotion uses a
conditional write (If-None-Match: *) that the object store
rejects if anything already sits at the canonical path. Either
bolt alone would keep the promise; together they close every
race window between check and write. There is no code path —
not an admin tool, not a support script — that overwrites a
published artifact, because the storage substrate is
write-once and the eternalink guarantee is enforced below
the application.
And one more gate, before promotion: nothing invalid ever gets an eternalink. Every deposited artifact is validated before its URL goes live — by the reference validator itself, the same open-source crate the toolchain runs, compiled to WebAssembly inside the registry’s edge worker. The validator at the door is byte-for-byte the validator on your laptop, so “every artifact resolvable from a registry is schema-valid by construction” is not a service-level aspiration but a property of the write path. An eternalink is a permanent claim, and the registry refuses to make a permanent claim about malformed bytes.
Names without squatting
Bind names forever and you inherit a classic problem: what
stops someone from claiming every good name on day one and
sitting on them? The answer is that permanence attaches to
artifacts, not claims. A name is permanently burned only by
its first publish; a claimed namespace with zero publishes
lapses after a twelve-month grace period and is released —
which breaks no eternalink, because an eternalink never
existed for it. Namespaces are eight characters or longer —
shorter names are reserved by the system, which is why the
standard libraries live under compact names like std and
hub while everyone else’s are unmistakably theirs. And a
domain you demonstrably control — proven by a challenge code
in a DNS TXT record — can be claimed as a namespace
verbatim, dot and all: acme.com/…, syntactically
unmistakable from ordinary names, with proof of control
beating first-come-first-served for the names that mean
something. The policy is written in from day one, on the
theory that
retrofitting expiry after names are parked is a fight nobody
wins.
The promise not yet made
Here is the strictest clause, and the easiest to miss: the
promise is not yet in force. Through the current alpha
series, artifacts are served from the kaiv.io staging
subdomains — t.kaiv.io for types, s.kaiv.io for schemas,
f.kaiv.io for units — and no permanence is promised there:
alpha artifacts may still change, and the alpha registries may
be reset. Even std/net, whose URI pattern you saw above,
might still be revised before it freezes. The k*aiv.com
production domains stay dormant until beta, and the
write-once, read-forever contract begins exactly there. The
staging hosts already serve the same Cache-Control: immutable headers and run the same write-once gate — the
machinery of the promise is fully built and rehearsing;
what alpha withholds is only the commitment itself.
This is not hedging; it is the promise taken seriously. A forever guarantee cannot be issued incrementally, walked back, or patched — the first artifact published under it is as permanent as the millionth. The only way to keep a promise like that is to not make it one day earlier than you can keep it. Eternity starts at beta; until then, kaiv says so in plain text.
kaiv is an immutable structural type system for data at rest. The User Manual covers registries and resolution from the user’s side; the specification defines the resolution layers and the alpha-hosting policy; the playground runs the toolchain — with the standard libraries embedded, eternalink-style — in your browser.