words:Status: Accepted
Date: November 2, 2026 (supervisor’s decision under the owner’s rule of
2026-10-31 and 2026-11-01, docs/supervisor.md, Language decisions: the
form the language already has for an entry’s values, and an extension nobody
pays for who does not use it)
Answers: the p557f report’s Found: (3) (#557 step 4c): ident hands
back a winnow_grammar::Symbol interned into a table the entry makes and
drops when it returns, so the caller of a Nikaia grammar cannot read the text
of a single symbol in the tree it got back; the compiler’s Rust parser keeps
its table in Parsed
Related: ADR-296 D8 (identifiers are interned symbols),
ADR-grammar-1 (an entry takes values after its input,
Yml::block(text, 2; c: Ctx::BlockOut)), ADR-366 (ident
over Bytes), ADR-001 (the string interner)
Part II 10.6 says the parser interns an identifier into “a shared table” and
yields a Symbol. It does not say whose table that is. Today each call of an
entry makes its own and drops it at the return: the symbols in the result can
be compared with each other, never read as text, and two parses (two files of
one program) cannot share their spellings. The tools in std already take the
table as a parameter (words: ref winnow_grammar::InternerContext,
bounds_basic.nika, calls.nika). Where does a Nikaia program get the table
its parse interned into?
words:An entry of a grammar that interns (it reaches ident or intern(p)) takes
the table as a value after its input, as every entry value does
(ADR-grammar-1): ParserGrammar::file(source; words: table), with table a
ref winnow_grammar::InternerContext. Every symbol the parse yields is
interned there; table.resolve(sym) reads its text after the call. One table
handed to several parses gives one spelling one symbol across all of them.
Where the entry’s result type holds a Symbol (in a field, an element, a
variant, at any depth), a call without words: is refused at the check: the
symbols would point into a table nobody can reach. An entry that interns only
on the way (a Symbol read through text(..), compared in a guard) may be
called without it and keeps a table of its own for the call, as today.
stdwinnow_grammar::InternerContext::new() makes an empty table; its ledger
entry describes it beside resolve. The lowering passes the table into the
ParseContext the generated entry builds (nikaia_std::grammar), not into
winnow-grammar.
ident or intern sees no
change, and one whose result holds no symbol may leave words: out.;; the tools already
take the table as a parameter; the Rust parser already keeps one table per
program. A symbol whose text cannot be read contradicts 10.6’s purpose.#557 step 4c waits on it. The build is #1198 (ready); the refusal of D2 is
NK1330 (reserved for that build).