1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! The agent-name **mint** (ARCH §2.3): a single word from the embedded
//! wordlist, drawn whenever a creation path omits `name`.
//!
//! Moved here from yog `src/names` by the yog bl-aca4 ruling: the moment
//! *every* creation path must mint on omission — the `dispatch` tool,
//! `lernie dispatch`, `lernie prompt`, none of which pass through yog —
//! the mint's one home is beside the uniqueness check it races
//! ([`super::require_available`]). Yog draws the same function through
//! the crate it already links (the [`crate::mint`] facade), so preview
//! and spawn cannot drift into two lists.
//!
//! [`mint`] is a **pure function over an injected RNG and an occupied
//! set**: one RNG draw picks a start index into the wordlist, then the
//! scan walks forward with wraparound, discarding each occupied word for
//! the next, to the first unoccupied name. Collision retry is that scan;
//! its bound is the wordlist itself — exhaustion is the scan running the
//! whole pool out ([`MintError::Exhausted`], loud, never a loop). The
//! occupied set is the caller's; at the creation pre-flights it is the
//! same living-names scan ([`super::named`]) the supplied-name check
//! reads — one derivation, never a second registry.
use ;
use HashSet;
use ;
use ;
/// The embedded pool: 541 concrete, neutral, everyday English words,
/// authored for this repository and covered by the crate's own licence
/// (bl-b59c — it replaces an EFF-derived CC BY 4.0 list, which put a
/// second licence inside an MIT package and minted names like `wrath`).
/// Provenance, the sizing argument and the invariants are in the file's
/// own header; the approval is pinned by count and digest in
/// [`tests::corpus`]. It is data, so it ships in the binary via
/// `include_str!`.
const WORDS_TXT: &str = include_str!;
/// The one way a mint fails: every word in the pool is already taken.
/// The injected randomness the mint is pure over. A trait rather than a
/// concrete generator so a test scripts the draw and the production
/// seeding stays out of the pure path. The draw takes `&self` — state
/// advances by interior mutability — so a generator rides the crate's
/// `&dyn` injection seams ([`crate::prompt::Deps`]) like every other
/// injected dependency.
/// SplitMix64 — the production [`Rng`]. Chosen because it is a few lines
/// of wrapping arithmetic: the mint needs one draw per name, and a
/// `rand` dependency for that is not worth the supply-chain surface.
/// The state is atomic (the `&self` draw above); the additive stream
/// constant makes `fetch_add` the whole state advance.
/// SplitMix64's additive stream constant.
const GAMMA: u64 = 0x9E37_79B9_7F4A_7C15;
/// The embedded wordlist as words: non-blank, non-comment lines, trimmed.
/// The mint over an explicit wordlist — the whole algorithm, kept
/// list-injectable so tests exercise collision retry and exhaustion on a
/// tiny pool instead of the embedded one. The retry is bounded by the
/// pool: each occupied word is discarded for the next with wraparound,
/// and one full lap proves exhaustion exactly — no free name is ever
/// missed, no loop runs unbounded. An out-of-range index cannot occur,
/// and a missing word reads as empty rather than panicking.
/// Mint a name from the embedded wordlist: the first single word not in
/// `occupied`, scanning from an RNG-chosen start. Pure — same RNG state
/// and same occupied set, same name.
/// The settle-the-name pre-flight both creation paths run before forking
/// (ARCH §2.3): a supplied name is validated against the living agents
/// ([`super::require_available`]); an absent one is minted against the
/// **same** living-names scan ([`super::named`]) — one occupied-set
/// derivation, so no fork ends nameless and no second registry exists to
/// drift. A refusal (taken, malformed, id-shaped, or an exhausted pool)
/// leaves no branch, no worktree and no inbox behind.
/// A seeded, process-shared [`SplitMix64`] for tests whose subject is
/// not the mint: `'static`, so it drops into a `Deps` or a call tail
/// with no local binding. A test that asserts on the minted name
/// constructs its own seeded generator instead — this one's draw order
/// depends on what ran before it.
pub