D089 - Naming a hash backwards is a search over somebody else's vocabulary, so the vocabulary is an argument

Status: decided. 2026-09-09.

Naming a hash backwards is a search over somebody else's vocabulary, so the vocabulary is an argument rather than a dependency.

Orbistoun asked this repository to name three identifiers that a running guest imports and that its own 30,184-name database cannot explain (REQ-20260909T1250Z-1f74). The forward direction has lived here since D004: hash a name, get an identifier. The reverse has no closed form - the hash is one-way - so the only method is to hash a vocabulary and look for the value, and whichever vocabulary you hash is the answer's strength.

That is exactly the shape the admission test forbids owning. A million-odd mined identifiers are obSCEne's measurement product and stay there; a search tool that shipped its own word list would be a second copy of that corpus wearing a different name, and would drift from it.

So crates/selfish-nid/examples/name_nid.rs takes the vocabulary by path and hashes every whitespace-separated word on every line, which means a table with the name in any column works without being reshaped first. What the repository keeps is the format knowledge: the hash, the encoding, and the two things a caller gets wrong.

The two things a caller gets wrong, and why the tool prints both

Byte order. An identifier read one way and the same identifier read the other are both plausible sixteen-hex-digit numbers, and this collection contains three conventions that disagree: selfish and obSCEne's mined table write the little-endian u64 that Nid::value returns, and orbistoun prints it byte-reversed. Nothing about either form says which it is. So a raw value is searched both ways and the output names the reading that hit.

The encoded form. A corpus that stores eleven characters cannot be grepped for a hex value at all. The tool prints the encoding of every reading whether or not a vocabulary was supplied, because that string is what makes the question askable of a corpus in the other notation.

--suffix is there for the same reason Nid::with_suffix is: an identifier that no name explains is one of the few honest reasons to ask whether the salt is what differs, and asking costs one run.

What the search found, which is the part worth keeping

Three answers of three different kinds, and the difference between them is the useful part:

That third one is the reason to write this down. A hash nothing can name is evidence about a toolchain, not only about a vocabulary, and the first question to ask of an unnameable identifier is whether something hashed a string that was already an identifier. The forward direction settles it in one run: hash the candidate string and see whether the mystery value comes back.

The module this repository builds gets it right - selfish imports on the consumer's module leg shows fYZQG4CU71c against libSceAgc, so mkmodule honours the sigil. The plain payload leg has no vendor tables at all (0 vendor import entries, 0 DT_NEEDED), so there the symbol keeps its literal name and anything hashing that name gets the wrong number. The answer to "which library ordinal does the entry carry" is therefore neither valid nor invalid: there is no vendor import table in that file to carry one.