3.4 Case Folding
Key names and value names are case-insensitive but case-preserving.
loregd implements this by storing both forms: the name as written, and a
folded form alongside it in a _folded column.
The folded form is computed once, when the name is written, and it is the
folded column that appears in every WHERE clause and every primary key.
Lookups are therefore plain binary comparisons
:
SELECT * FROM path_entries
WHERE parent_guid = ? AND child_name_folded = ?
This is why no custom SQLite collation is registered anywhere in loregd — the case-insensitivity has already happened by the time SQLite sees the query.
The canonical name is what comes back in responses, so callers see the case they originally supplied while storage compares the folded form.
Hive names are folded too, though not stored : routing a request to a hive and rejecting duplicate hive declarations (§2.1) both compare folded names.
Layer names are not folded. They are compared as binary, so layer names are case-sensitive.
3.4.1 How the folded form is computed #
The folded form is Unicode Simple Case Folding: each codepoint is
replaced by its status C or S mapping from CaseFolding.txt, Unicode
16.0.0, or left alone when it has none.
This is the
same rule the kernel applies when it compares layer names and every other
name in LCS, and loregd must produce byte-identical results, because a
name the two fold differently is a key that exists for one side and not
the other.
Identity is guaranteed by construction rather than by care. loregd does
not derive the fold from the Go standard library, whose case tables
implement lowercasing (a different operation) at a different Unicode
version.
Its table is generated by the kernel's own generator,
pkm/tools/lcs/generate_casefold_table.py, from the same CaseFolding.txt
that produces the kernel's table; the generated Go file records the source
version and checksum, and the lookup mirrors the kernel's binary search
over the same ranges and pairs.
A Unicode
version bump regenerates both outputs together.