ADR-0082: Sealed root dynamic-symbol and GNU version-index inventory

Status: accepted
Date: 2026-08-10
Decision owners: NAUX architecture and x86-64 root-symbol inventory boundary

Context

ADR-0080 inventories every GNU version namespace requested by the sealed root worker. ADR-0081 proves each strong request exists in the exact sealed provider named by that root. NAUX still has no authority to state how many dynamic symbols the root contains, which exact Elf64_Sym fields belong to each ordinal, or which root requirement a parallel GNU version word denotes.

The dependency-side ADR-0079 solves the analogous inventory problem for providers. Reusing its evidence as though it described the root would collapse requester and provider roles and would silently treat root bytes as dependency object bytes. Root inventory therefore needs its own policy identity, root artifact replay, namespace resolver, evidence shape, and mutation boundary.

Decision drivers

  • Read only the immutable root descriptor accepted by ADR-0070; never reopen a source path.
  • Derive a finite symbol extent without section headers or loader behavior.
  • Reconstruct System V and GNU hash topology from retained symbol names.
  • Preserve every exact Elf64_Sym field and parallel versym word in order.
  • Resolve nonlocal indices only through accepted ADR-0080 root requirements and their ADR-0081 exact-provider compatibility bindings.
  • Keep inventory separate from lookup scope, symbol selection, binding, interposition, relocation, mapping, and execution.

Considered options

Reuse the provider symbol evidence type for the root

Rejected. Its provider ordinal, defined-version namespace, and ADR-0073 object source semantics are not root semantics.

Trust .dynsym and .gnu.version section headers

Rejected. Runtime-relevant facts must be derivable from accepted program headers and dynamic entries; section headers remain outside authority.

Infer the symbol count from adjacent tables

Rejected. Padding and address ordering do not establish a semantic extent.

Decode symbols during lookup

Rejected. Lookup must consume a sealed finite universe rather than minting its own parser and extent authority.

Emit an independent root symbol/version ledger

Selected. The root gets one exact, ordered, fully replayable proof object whose only authority is inventory.

Decision

Introduce a root-symbol evidence object. Emission first fully replays ADR-0081 and the immutable root artifact, then independently decodes root bytes:

  1. require exactly one DT_SYMTAB, DT_SYMENT, DT_STRTAB, DT_STRSZ, and DT_VERSYM, with DT_SYMENT = 24;
  2. translate tables only through non-writable admitted PT_LOAD coverage;
  3. require at least one of DT_HASH or DT_GNU_HASH, derive the exact symbol extent independently, and require equal extents when both exist;
  4. reconstruct every accepted hash bucket, chain, and GNU bloom word from the decoded symbol names, including exact GNU prefix/suffix constraints;
  5. decode exactly one canonical 24-byte symbol record and one little-endian two-byte version word per ordinal; ordinal zero must be bytewise STN_UNDEF;
  6. admit only the frozen binding, type, visibility, and section-index grammar;
  7. classify indices 0 and 1 as reserved local/global identities and forbid a hidden bit on them;
  8. for every index from 2 through 0x7eff, require an undefined root symbol, exactly one ADR-0080 requirement auxiliary with that local index, and exactly one matching ADR-0081 binding carrying the same requester and exact provider/definition target identities;
  9. reject defined root symbols with a nonlocal version index because no root Verdef authority exists;
  10. seal every raw field, name/hash, version classification, ADR-0080/0081 target identity, table topology, record order, predecessor root, and one domain-separated ADR-0082 aggregate root.

Verification preflights bounded shape and predecessor identities, regenerates the complete ledger from immutable descriptor bytes, and requires exact equality. No filesystem path, section table, host ELF parser, loader API, or symbol consumer participates.

Frozen limits

  • exactly one root object;
  • at most 64 program headers, 16 load segments, and 4,096 dynamic entries;
  • at most 4,096 dynamic symbols;
  • exactly 24 bytes per Elf64_Sym and 2 bytes per version entry;
  • at most 4,096 System V buckets/chains;
  • at most 4,096 GNU buckets, 512 64-bit bloom words, and 4,096 GNU chains;
  • string-table extent at most 1 MiB and names at most 256 bytes;
  • accepted bindings: local, global, weak, and GNU unique;
  • accepted types: no-type, object, function, section, file, common, TLS, and GNU IFUNC;
  • accepted visibility: default, internal, hidden, and protected with all reserved st_other bits zero;
  • SHN_XINDEX and unsupported reserved section indices fail closed;
  • accepted ADR-0080 root-version policy root 1e728341f69e0cb1ba9d5ce8a6400cdbe72c8866a1ed8ec8e52a1a50fa9fecdf;
  • accepted ADR-0081 root-compatibility policy root db6e8c4640a19a7a7c7925d97c64923ccbd4e5baf9c3a293786f962b13a1df0e;
  • proof-only inventory; encoder policy remains 1.4.0.

Consequences

  • Positive: later lookup receives an exact finite root requester universe.
  • Positive: every imported symbol’s version index is tied to both its root requirement and the exact provider definition already proven compatible.
  • Positive: descriptor replay remains independent of source replacement or deletion.
  • Negative: complete hash reconstruction adds linear verification work and a larger proof ledger.
  • Negative: unusual loader-tolerated noncanonical hash layouts remain refused.
  • Open: lookup scope, binding/type/visibility rules, weak and GNU-unique semantics, IFUNC/TLS, relocation, mapping, initialization, and execution require later ADRs.

Acceptance gates

  1. Lock the exact root symbol count, hash shape, version count, and every ordered record for default and all-feature worker artifacts.
  2. Bind every nonlocal version index uniquely to matching ADR-0080 and ADR-0081 evidence; lock defined/undefined, hidden, and reserved-index behavior.
  3. Missing, duplicate, mismatched, truncated, excessive, early-terminal, cross-bucket, bloom, name/hash, STN_UNDEF, info/other/shndx, count, version-index, stale-root, reorder, and shallow mutations fail closed.
  4. A coherent alternate valid requirement/compatibility target with all local and aggregate seals recomputed still fails independent regeneration.
  5. Production source has no filesystem, path, section-header, host parser or loader, lookup, selection, relocation, mapping, native, timing, or claim authority; exact replay succeeds after root source replacement and dependency source deletion.
  6. Focused default/all-feature, workspace, strict lint, governance, refinement, format, shell, link, parity, static-authority, and descriptor- replay gates pass before acceptance.
  • ADR-0079 supplies the analogous provider-side inventory policy but no root authority.
  • ADR-0080 supplies root requester namespaces and local indices.
  • ADR-0081 supplies exact provider-definition targets for every strong root request.

Acceptance record

Accepted on 2026-08-10 under policy root 6d68c8c455536c683484f012a3d0c3e91f8a879ac981f96362c7c45b37ea6ea4. The immutable root descriptor contains exactly 108 ordered dynamic-symbol records and 108 parallel version words. It has no System V hash table. Its GNU hash topology is exactly symbol offset 108, bloom shift 26, one zero-export bloom word, one zero-export bucket, and zero chains. Thus every root dynamic symbol is outside the GNU exported suffix; the decoder and mutation boundary explicitly preserve this valid all-import/no-export edge case.

Each nonlocal version word names an undefined symbol and resolves uniquely to one ADR-0080 requirement auxiliary plus its matching ADR-0081 exact-provider binding. Reserved local/global indices carry no invented namespace evidence. The ledger seals every raw symbol field, name and both name hashes, version word, requester and compatibility identities, complete hash topology, record order, predecessor roots, object root, and aggregate root. Verification preflights bounded structure and regenerates the entire ledger from the immutable ADR-0070 descriptor.

Raw mutations cover ELF identity, dynamic tags, symbol-entry width, GNU header, empty-export bloom and bucket topology, symbol name offset, binding/type/visibility/section grammar, and reserved or unsupported version indices. Shallow evidence mutation, record reorder, stale predecessor roots, and a coherently resealed alternate valid requirement/compatibility target all fail closed. The exact evidence replays after root path replacement and after all dependency source files are deleted.

Focused default and all-feature carriers pass in 715.65 and 751.11 seconds with the same exact 108-record topology. The final all-feature workspace exits successfully: the library suite reports 417 passed, zero failed, and six intentionally ignored tests in 438.61 seconds; process isolation reports three passed and zero failed in 303.77 seconds; the ADR-0073 through ADR-0082 carrier reports two passed and zero failed in 763.19 seconds. Strict Clippy across the workspace, targets, and features with warnings denied, cargo check, 22/22 governance, 8/8 strict refinement, all nine shell syntax checks, frozen policy-root tests, static-authority inspection, format/diff, local Markdown link audit, and full descriptor regeneration pass.

Acceptance grants no lookup scope, symbol selection, interposition, binding, weak fallback, visibility/type compatibility, relocation, mapping, initialization, IFUNC/TLS execution, sandbox, standalone, timing, performance claim, or global encoder-policy authority.