audit: cycle-close tidy for #44$-lexer-reservation (refs #44)

Cycle-close audit for the #44 Form-A `$`-reservation cycle
(b151990..HEAD). One drift item fixed inline. Both regression scripts
exited 1; investigated and attributed to machine load this session, NOT
a code regression — baseline deliberately NOT updated.

Architect drift review:
- [fixed] design/models/0001-authoring-surface.md — the line "The only
  reserved tokens are `(`, `)`, and whitespace" was made stale by this
  cycle (the lexer now rejects any identifier token containing `$`).
  Corrected to distinguish token *delimiters* (`(`/`)`/whitespace) from
  the `$` *character reservation within a token*, scoped to the Form-A
  authoring surface, naming the enforcement site
  (`LexError::ReservedDollar`) and the intentional `.ail.json` non-guard.
- [carry-on] honesty sweep otherwise clean: the only other `$`-mentions
  in the ledger (0008-memory-model.md, 0003-pipeline.md) describe
  synthetic mint names (buf$1, <hint>$lr_N) and remain correct. No
  over-broad "no Module can contain `$`" prose exists. The corrected
  fresh_binder doc-comment (feat commit) is Form-A-scoped and honest.
- Decision: no new ledger *contract* added. 0015-language-constraints
  holds the four RC-soundness preconditions (strict eval, no recursive
  value bindings, no shared mutable refs, acyclic ADTs); a lexical
  character reservation is a different category and is documented in the
  authoring-surface model doc with its enforcement site, which is its
  natural home. Architect confirmed absence of `$`-contract prose is not
  itself drift.

Lockstep pairs: none apply (architect walked each against the diff):
- Pattern::Lit typecheck <-> pre_desugar_validation.rs — neither changed.
- lower_app <-> is_static_callee — codegen unchanged.
- INTERCEPTS <-> (intrinsic) markers — intercepts.rs + kernel sources
  unchanged.

Regression scripts:
- bench/cross_lang.py: EXIT 0. 25 metrics; 0 regressed, all stable.
- bench/compile_check.py: EXIT 1; "12 regressed" — ALL are check_ms.*
  (type-check wall-clock), baseline ~1.8-3.3ms vs actual ~2.5-4.4ms,
  ~+0.8ms absolute and roughly UNIFORM across every fixture regardless
  of size (hello +39%, bench_list_sum +51%). All 12 build_O0_ms.* (the
  ~93ms LLVM portion of the same `ail build`) are within tolerance but
  also uniformly shifted +12-15%. Attribution: NOT this cycle's code.
  The guard adds one `raw.contains('$')` byte-scan per token; a tiny
  module is ~50 tokens, so the added cost is nanoseconds — physically
  cannot account for +0.8ms on a 2ms check. The uniform ~12-15% shift
  across the WHOLE `ail` invocation (check AND build) is a global
  machine-slowdown fingerprint (heavy concurrent subagent/cargo load
  this session); it crosses the 25% tolerance only on the tiny-baseline
  check_ms metrics. Localised by reasoning, not by the bencher (the
  effect is environmental, nothing to localise in code).
- bench/check.py: EXIT 1; throughput metrics flipping run-to-run with
  identical code (rc_over_bump moved in/out of REGRESSION across four
  runs; bump_s swung -9.5/-11/-14/-15%). Same machine-load variance;
  rc_over_bump is a ratio of two independently-noisy wall-clock
  measurements, the noisiest metric in the set.

Baseline NOT updated on either script: ratifying a machine-load delta
would bake an under-load baseline in and mask a future real regression.
OPEN VERIFICATION: re-run bench/compile_check.py and bench/check.py on a
quiet machine to confirm green; tracked as the cycle's one open item.
Cycle #44 closes (code + docs clean; regression gate pending a
clean-machine confirmation, baseline untouched).
This commit is contained in:
2026-05-30 15:18:49 +02:00
parent 11e4c4624d
commit 7321826c66
+12 -1
View File
@@ -58,7 +58,18 @@ Every other maximal token is classified post-hoc:
Consequence: arithmetic operators like `+` / `-` / `*` / `/` / `%`, Consequence: arithmetic operators like `+` / `-` / `*` / `/` / `%`,
qualified names like `io/print_str`, and cross-module references qualified names like `io/print_str`, and cross-module references
like `std_list.map` are all single ident tokens with no special like `std_list.map` are all single ident tokens with no special
lex rule. The only reserved tokens are `(`, `)`, and whitespace. lex rule. The only token *delimiters* are `(`, `)`, and whitespace.
One character is *reserved within* a token: `$`. Any identifier
token containing `$` is rejected by the lexer
(`LexError::ReservedDollar` in `crates/ailang-surface/src/lex.rs`),
because `$` is reserved for the compiler's synthetic namespace
(match-scrutinee, lifted-let-rec, and shadow-rename binders).
Making `$` unauthorable keeps that synthetic namespace
collision-free by construction. The reservation is on the
Form-(A) authoring surface only — `$` inside a string literal or
a comment is unaffected, and the canonical `.ail.json`
deserialization path is intentionally not guarded.
Bool literals (`true`, `false`) and unit (`(lit-unit)`) are Bool literals (`true`, `false`) and unit (`(lit-unit)`) are
disambiguated by parser context, not by lex. Comparison and disambiguated by parser context, not by lex. Comparison and
equality are class methods (`eq` / `compare`) and named fns equality are class methods (`eq` / `compare`) and named fns