ADR-168: The Re-entrancy Check Is Built as a Build Option, and Part I 1.2’s Status Note Was Wrong About Two of Its Three Clauses

Status: Superseded by ADR-281 — its D1-D3 are D36-D38 there Date: September 20, 2026 Target Version: Nikaia 0.0.86 Related: ADR-039 D8 (the decision this builds), D2 (the rule it is self-control of), D6, ADR-033 D8 (the precedent: a default that cannot be switched off is imposed), ADR-037 D4 (a switch is a cache-key dimension) and D7, ADR-021 D7 (dimensions coexist; they do not share), ADR-057 D2 and D3 (what the mark costs), ADR-167 D1 (which made NK2203 reach real programs), Part I 1.2, Part II 12.3

1. Context

ADR-039 D8 decided that the runtime re-entrancy check becomes a build option, on by default, in the manifest. #175 carried it as one of the lock section’s refusals nothing raises.

Measuring it first found the note that describes it to be wrong:

Implementation status: Not implemented. Nothing refuses the nesting of Part II 12.3, no re-entrancy check is emitted, and nikaia.toml has no key for this option.

Two of those three clauses were false. NK2203 refuses the nesting and has for some time; the runtime check is in std’s crossing shape, as a mark read before every acquisition. Only the third — no key — was true. A stale status note is a defect in its own right (README.md §1), because a reader cannot tell a plan from a promise, and this one told a reader that a guarantee they have is one they do not.

2. Decisions

D1 — reentrancy-check is a [build] key, yes or no, and yes is the default.

A third spelling is refused rather than guessed at — on reads like this option and is not it — because a build that took the default for a word it did not know would ship the guarantee the manifest declined. The key is checked against [build]’s own list, so reentrancy_check with an underscore is the mistake that list exists to catch.

No command-line override, which D8 asks for in one direction and this makes explicit in the other: it lives in the manifest, because a shipped build that could be changed from the command line is not reproducible. Part I 1.2 names the two options a single build may override, and this is not one of them. The environment carries the resolved word to the wrapper, which is a channel and not a second front door — Cargo owns the wrapper’s arguments.

D2 — It is a dimension of the build cache and of the compiled std’s own tree.

The first is ADR-037 D4’s rule for any switch. The second is new here and is what the other two switches did not need: the check lives in the nikaia-std crate, so the word decides what that crate contains. Without it the second project on a machine links the first one’s answer, and a guarantee declined in one manifest ships from another’s cache (ADR-021 D7: dimensions coexist; they do not share).

The mechanism is a Cargo feature on nikaia-std, on by default, and the generated manifest writes default-features = false for a package that declined it — a switch the compiler acts on has to reach the crate the code is in.

D3 — Declining it reaches the crossing shape alone, and the reason is that the other check is not ours.

std has two lock shapes (ADR-059). The crossing one carries a mark this compiler wrote — an atomic load before the acquisition and a store after it, which ADR-057 D2 makes free at one thread and D3 charges only on values that actually cross — and that is what the switch declines. The single-threaded one is a RefCell, whose borrow flag notices a re-entrant borrow whatever anyone asks: it is the language below’s, and no option of ours switches it off.

That is more noticing than the switch promises, which costs a program obeying the rule nothing and is stated rather than left to be discovered.

3. Consequences

4. What this does not decide

5. What is built

All three decisions. crates/nikaia/tests/reentrancy_switch.rs holds the key, the default, the refused third spelling, the mistyped key, and both cache dimensions; crates/nikaia-std’s own tests hold the check firing where the build carries it — reached by writing the nesting in Rust, because under D2 no Nikaia program can get there — and the RefCell’s flag noticing either way.

This site is open source. Improve this page.