Skip to content

Base52 moment stamps

 3 min Nine ASCII-ordered characters of microseconds that byte-sort by time and omit A, E, I, O, and U, reducing accidental matches when keys live inside model prose.
Published

Sep 23, 2026

Task identity in the Spice harness is a nine-character stamp minted from this alphabet:

ALPHABET = "0123456789BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"

Base52: the ten digits plus both cases of every letter except A, E, I, O, and U. The ordering and the omissions do different jobs.

The conventional vowels are dropped to make ordinary-word collisions rarer. These keys are embedded in model-generated prose and matched back out of it by the harness’s ACK grammar, so reducing the surface shared with English is useful. Fixed width and the surrounding ACK syntax identify the stamp.

The ordering is the other trick. Digits, then uppercase consonants, then lowercase is ASCII-monotonic—the alphabet’s rank order equals byte order—so a fixed-width, zero-padded encoding of epoch microseconds sorts lexicographically in time order under bytewise comparison. Python’s ordinary string order for these ASCII characters, SQLite’s BINARY collation, and LC_ALL=C sort agree on chronology without parsing anything. Locale-aware sorting need not.

Width and unit are one decision. A stamp of ww characters counting unit uu spans 52wu52^w u from the epoch. Each row below adds a character and a thousandfold finer unit, keeping about a nineteenth of the span above it:

528ms≈1694years529µs≈88.1years5210ns≈4.58years \begin{aligned} 52^{8}\,\text{ms} &\approx 1694\ \text{years} \\ 52^{9}\,\text{µs} &\approx 88.1\ \text{years} \\ 52^{10}\,\text{ns} &\approx 4.58\ \text{years} \end{aligned}

The first character turns once per fifty-second of the span: every 32.6 years, 1.69 years, and 32 days. Eight characters of milliseconds reach 3664, and their first character reads 1 from 2002 to 2035. Ten characters of nanoseconds ran out in 1974. Nanoseconds need eleven characters, and Python’s datetime stops at microseconds. Ten characters of microseconds are the same nine behind a 0 until 2058.

Nine characters of microseconds reach February 2058. Their first character reads d from November 2025 to August 2027, and each character after it turns 52 times as often: about every 12 days, 5.5 hours, 6.3 minutes, 7.3 seconds, 141 ms, 2.7 ms, 52 µs, and 1 µs. A shared prefix is a shared span: stamps that agree on two characters were minted in the same 12 days, on three in the same 5.5 hours, on four in the same 6.3 minutes.

Stamps were eight characters of milliseconds until September 2026. The ninth character went to precision rather than range, which suits what the stamp is for: a stable name spread through the time it is actually used. At microseconds, every position turns at a useful rate. Eight-character stamps keep their spelling and decode as milliseconds. Bytewise order holds within one width, so comparisons across widths use the decoded instant.

Collisions advance the clock rather than adding entropy:

def mint_incepted(existing: set[str] | None = None) -> str:
    """Fresh nine-character stamp, advanced one microsecond past collisions."""
    ...
    micros = epoch_micros()
    while True:
        stamp = encode_width(micros)
        if stamp not in existing:
            return stamp
        micros += 1

For serialized callers sharing an up-to-date existing set, two tasks minted in the same microsecond get adjacent stamps: still sorted, unique inside that set, and each stamp remains a pure function of one integer. No random suffix, no second identity component to reason about. This is local collision avoidance, not atomic allocation: two processes can read the same rows and the same microsecond, then mint the same value before either persists it. Fixed width is enforced as an error rather than a widening—an oversized value would silently break the sort property, so it refuses.

The rendered handle is KEY-INCEPTED, and only the stamp is stored. KEY derives from the current project’s rightmost segment at render time, so re-homing a task renames it for free; resolution matches on the stamp alone. The human-friendly part of the name is a projection, never data.