Record ratified rulings

This commit is contained in:
developtheweb 2026-07-09 23:25:01 -04:00
parent ea66a2abda
commit 2d1d17899a
2 changed files with 38 additions and 34 deletions

View file

@ -34,3 +34,5 @@ against the existing examples.
- **Byte identity: repo file == image file == served file**, enforced by checksum at image build time and a post-deploy check; rejected: minified serving (a second artifact that can drift). - **Byte identity: repo file == image file == served file**, enforced by checksum at image build time and a post-deploy check; rejected: minified serving (a second artifact that can drift).
- **Interpreter tests run on `node:test` + `node:assert` with zero npm dependencies**; rejected: third-party test frameworks (a supply chain the site's own footer brags about not having). - **Interpreter tests run on `node:test` + `node:assert` with zero npm dependencies**; rejected: third-party test frameworks (a supply chain the site's own footer brags about not having).
- **Stage-1 exception: the imported interpreter's header comment was corrected in place** (`tested: 18/18` → the provable `10 tests in js/test/`) — a falsified claim inside the canonical artifact outranks byte identity with the pre-Stage-1 deploy; end-state identity is restored when the site deploys the pinned file. - **Stage-1 exception: the imported interpreter's header comment was corrected in place** (`tested: 18/18` → the provable `10 tests in js/test/`) — a falsified claim inside the canonical artifact outranks byte identity with the pre-Stage-1 deploy; end-state identity is restored when the site deploys the pinned file.
- **Stage-3 ratification (2026-07-09): the 26 judgment calls are ruled; JUDGMENT_CALLS.md is the semantic record of MPL M0.** Per-ruling record: (1) ÷0 is `err_div0`; (2) a `∀` expression is always `⊥`; (3) an unmatched guard yields `⊥` unless caught by `|`; (4) numbers are exact rationals — BigInt num/den, lowest terms, den > 0, decimal literals exact, display `n` or `n/d` (re-evaluates to itself); IEEE doubles rejected; (5) `✎` rendering spec'd per type; (6) `⊥` is first-class, arithmetic on it `err_num`; (7) equality is structural on data, cross-type `=` false, `0.5 = 1/2` true, any function in `=`/`≠` raises `err_fn_eq`; (8) ordering is number×number and string×string (code-point) only, else `err_compare`; (9) closures capture the environment; (10) λ-application depth counter, limit 10000, `err_depth` — no keyless host error may remain reachable; (11) the 500000-step budget is an environment resource limit, not semantics — corpus entry 053 moved to js/test; (12) string escapes are exactly `\n \t \" \\`, anything else `err_escape` (grammar ESC amended to match); (13) guard conditions must be boolean, else `err_bool`; (14) `∧ ` short-circuit and demand booleans on evaluated operands (`err_bool`); (15) braces group, binders scope; (16) `≜` binds once per scope (`err_redef`; inner shadowing legal), `←` mutates an existing binding only (`err_unbound`); (17) type constraints parse, unenforced; (18) nullary `λ: e` admitted (grammar amended); (19) ```×`; (20) the empty program is valid; (21) `( seqExpr )` — the interpreter now implements it; (22) `∘` is composition, `(f ∘ g)(x…) = f(g(x…))`, non-function operand `err_notfn`; (23) set literals parse, evaluate to `err_notyet`; (24) record literals likewise; (25) `λ(a, b):` rejected everywhere; (26) `λ` is reserved — never an identifier — while other Greek letters remain identifiers.
- **Standing M1 decisions logged at ratification**: `√` vs (irrationals); an explicit local-binding construct (let/where); set semantics; record semantics; comprehension notation; `‖` parallel semantics.

View file

@ -1,13 +1,15 @@
# JUDGMENT_CALLS — semantic decisions awaiting ratification # JUDGMENT_CALLS — semantic decisions awaiting ratification
Every section below is a semantic question the interpreter currently RATIFIED 2026-07-09 — this file is the semantic record of MPL M0.
answers by accident of implementation. Nothing here is ratified. Each
section states the question, what `js/mpl.js` observably does today, and Every section below is a semantic question Stage 2 surfaced, stated with
which corpus entries pin that behavior. The `RULING:` line is blank on the behavior `js/mpl.js` exhibited at observation time (Stage 2 head,
purpose — rulings are Reverend's, in Stage 3, in batches. A ruling either `ea66a2a`) and the corpus entries that pinned it. Each `RULING:` line
blesses the observed behavior (the pinning entries flip to `ratified`) or records Reverend's ratified decision of 2026-07-09. BLESS rulings kept the
overrules it (the interpreter changes, the entries are re-recorded, then observed behavior; OVERRIDE/SPLIT/IMPLEMENT/AMEND rulings changed the
ratified). grammar or the interpreter in Stage 3, and the corpus was re-recorded to
match. The "Observed:" text is the historical record, not the current
behavior — the rulings govern.
## 1. Division by zero ## 1. Division by zero
@ -15,7 +17,7 @@ Question: what does `x ÷ 0` do — error, infinity, or ⊥?
Observed: raises `err_div0` (both `÷` and `/`, integer or float operands). Observed: raises `err_div0` (both `÷` and `/`, integer or float operands).
Pins: `043_div_zero`. Pins: `043_div_zero`.
RULING: RULING: BLESS. `x ÷ 0` (and `/`) raises `err_div0`. Division by zero is undefined.
## 2. The value of a ∀ expression ## 2. The value of a ∀ expression
@ -23,7 +25,7 @@ Question: what does `∀ x ∈ list : body` evaluate to?
Observed: the value of the last body evaluation; `⊥` for an empty list. Observed: the value of the last body evaluation; `⊥` for an empty list.
Pins: `018_forall_value`, `019_forall_scope`. Pins: `018_forall_value`, `019_forall_scope`.
RULING: RULING: OVERRIDE. `∀` is an iterator; the expression's value is `⊥` always (including empty collections). Using a statement as a value is undefined — same principle as ruling 3.
## 3. Result when no guard matches ## 3. Result when no guard matches
@ -32,7 +34,7 @@ Observed: an internal no-match that surfaces as `⊥` everywhere except
directly to the left of `|`. directly to the left of `|`.
Pins: `021_no_guard_match`, `023_alt_chain`. Pins: `021_no_guard_match`, `023_alt_chain`.
RULING: RULING: BLESS (semantics, not mechanism). An unmatched guard yields `⊥` unless caught by `|`. Implementations choose their own internal sentinel.
## 4. Integer vs float display ## 4. Integer vs float display
@ -43,7 +45,7 @@ decimal point (`2`), non-integral as JS renders them (`0.5`, and
`0.50``0.5`). `0.50``0.5`).
Pins: `006_number_display`, `007_float_arithmetic`. Pins: `006_number_display`, `007_float_arithmetic`.
RULING: RULING: OVERRIDE. Numbers are exact rationals (arbitrary-precision integer numerator/denominator). Decimal literals convert exactly (`0.1` = 1/10). Display: integers bare; otherwise lowest-terms fraction `num/den`, sign on the numerator, denominator > 0; zero as `0`. Output is valid MPL that re-evaluates to the same value. IEEE doubles are rejected: the language must not lie about `0.1`. `√ vs ` is logged as a standing M1 decision.
## 5. ✎ formatting per type ## 5. ✎ formatting per type
@ -53,7 +55,7 @@ quoted inside lists; booleans `true`/`false`; lists `[a, b]` with
one-space separation; closures as `λ`; `⊥` as `⊥`. one-space separation; closures as `λ`; `⊥` as `⊥`.
Pins: `009_string_concat`, `011_list_display`, `031_show_all_types`. Pins: `009_string_concat`, `011_list_display`, `031_show_all_types`.
RULING: RULING: BLESS, spec'd. `✎` renders: numbers per ruling 4; strings bare at top level, double-quoted inside lists; booleans `true`/`false`; lists `[a, b]` (comma-space); closures as `λ`; `⊥` as `⊥`.
## 6. ⊥ display and propagation ## 6. ⊥ display and propagation
@ -63,7 +65,7 @@ strings (`"x" + ⊥` → `x⊥`), sits in lists, but arithmetic on it is
`err_num`. `err_num`.
Pins: `030_bot`, `052_bot_arith`. Pins: `030_bot`, `052_bot_arith`.
RULING: RULING: BLESS. `⊥` is first-class: displays as `⊥`, sits in lists, string concatenation renders it (`"x" + ⊥``x⊥`); arithmetic on it is `err_num`.
## 7. Equality across types ## 7. Equality across types
@ -74,7 +76,7 @@ and `⊥ = ⊥` → `true`. Comparing a self-referential closure crashes with a
keyless host error (unpinnable by the corpus). keyless host error (unpinnable by the corpus).
Pins: `034_cross_type_equality`, `033_string_compare`. Pins: `034_cross_type_equality`, `033_string_compare`.
RULING: RULING: SPLIT. Data equality is structural: element-wise lists, cross-type `=` is `false`, `⊥ = ⊥` is `true`, `0.5 = 1/2` is `true` (same rational). Any equality comparison involving a function raises `err_fn_eq` — function equality is undecidable; a keyed error replaces the current keyless crash.
## 8. Ordering across types ## 8. Ordering across types
@ -83,7 +85,7 @@ Observed: raw host comparison with JS coercion — `1 < "2"` → `true`,
`"10" < 9``false`, `true < 2``true`; strings order lexicographically. `"10" < 9``false`, `true < 2``true`; strings order lexicographically.
Pins: `035_mixed_compare`, `033_string_compare`. Pins: `035_mixed_compare`, `033_string_compare`.
RULING: RULING: OVERRIDE. `< > ≤ ≥` are defined on number×number and string×string (Unicode code-point order) only; anything else raises `err_compare`. Host coercion (`1 < "2"`) is JavaScript soul leakage, not mathematics.
## 9. Closure capture ## 9. Closure capture
@ -93,7 +95,7 @@ Observed: the environment — later mutation of a captured variable is
visible on the next call (`013` prints 11 then 21). visible on the next call (`013` prints 11 then 21).
Pins: `013_closure_capture`, `026_def_vs_assign_scope`. Pins: `013_closure_capture`, `026_def_vs_assign_scope`.
RULING: RULING: BLESS. Closures capture the environment. (The corpus itself forces this: `factorial` only works because the λ sees its own later binding.)
## 10. Recursion depth ## 10. Recursion depth
@ -104,7 +106,7 @@ before the 500 000-step budget can trigger, so the corpus cannot pin it
`err_steps`. Depth ~500 is comfortably safe. `err_steps`. Depth ~500 is comfortably safe.
Pins: `016_recursion_sum` (works at 500), `053_step_budget` (`err_steps`). Pins: `016_recursion_sum` (works at 500), `053_step_budget` (`err_steps`).
RULING: RULING: OVERRIDE. Recursion is bounded by an explicit λ-application depth counter, limit 10 000, raising `err_depth`. A keyless host RangeError is a hole in the error surface; the limit is conformance surface in every implementation.
## 11. The step budget itself ## 11. The step budget itself
@ -114,7 +116,7 @@ Observed: hard-coded 500 000; nested `∀` loops over a 10-element list six
deep exceed it. deep exceed it.
Pins: `053_step_budget`. Pins: `053_step_budget`.
RULING: RULING: RECLASSIFY. The step budget is an environment resource limit, not language semantics — like out-of-memory. `err_steps` (500 000) remains in the browser implementation; entry 053 leaves the portable corpus and becomes a js/test implementation test.
## 12. String escape round-tripping ## 12. String escape round-tripping
@ -125,7 +127,7 @@ grammar instead REJECTS unknown escapes — a recorded divergence.
Pins: `008_string_escapes`; divergence in DIVERGENCES.md ("drop\qme" and Pins: `008_string_escapes`; divergence in DIVERGENCES.md ("drop\qme" and
the `"a\zb"` fuzz entry). the `"a\zb"` fuzz entry).
RULING: RULING: OVERRIDE. Escapes are exactly `\n \t \" \\`; any other `\x` raises `err_escape`, matching the grammar. Silent data-mangling is forbidden.
## 13. Guard condition truthiness ## 13. Guard condition truthiness
@ -135,7 +137,7 @@ strings, lists and `⊥` do not (they yield the no-match path) — so numbers
are truthy for `⟹` but nothing else is. are truthy for `⟹` but nothing else is.
Pins: `022_guard_truthiness`. Pins: `022_guard_truthiness`.
RULING: RULING: OVERRIDE. A guard condition must be boolean; any non-boolean condition (numbers included) raises `err_bool`. A condition is a proposition.
## 14. ∧ operand truth ## 14. ∧ operand truth
@ -146,7 +148,7 @@ Observed: no — operands are tested with strict boolean equality, so
accident in the surface. accident in the surface.
Pins: `036_logic_ops`, `037_logic_short_circuit`. Pins: `036_logic_ops`, `037_logic_short_circuit`.
RULING: RULING: SPLIT. `∧ ` short-circuit (blessed, observable by side effect) and demand boolean operands — a non-boolean evaluated operand raises `err_bool` instead of silently comparing false. One notion of truth, everywhere; an unevaluated right operand raises nothing.
## 15. Block scoping ## 15. Block scoping
@ -155,7 +157,7 @@ Observed: no — bindings made inside a brace block leak out (`028` prints
9). Only λ bodies and each `∀` iteration scope. 9). Only λ bodies and each `∀` iteration scope.
Pins: `028_block_no_scope`, `027_block_sequencing`. Pins: `028_block_no_scope`, `027_block_sequencing`.
RULING: RULING: BLESS. Braces group; they do not scope. Scope is created by binders only (λ parameters, ∀ iteration variables) — the Curry-Howard reading: a discharged hypothesis IS a λ. An explicit local-binding construct (let/where) is logged as a standing M1 decision.
## 16. ≜ vs ← scoping and creation ## 16. ≜ vs ← scoping and creation
@ -168,7 +170,7 @@ legal re-definition).
Pins: `024_def_assign_rebind`, `025_def_assign_value`, Pins: `024_def_assign_rebind`, `025_def_assign_value`,
`026_def_vs_assign_scope`. `026_def_vs_assign_scope`.
RULING: RULING: OVERRIDE (both halves). `≜` introduces a name exactly once per scope — same-scope redefinition raises `err_redef`; shadowing in inner scopes is legal. `←` mutates the nearest enclosing binding and raises `err_unbound` when none exists — silent creation is the typo trap. Both remain expressions returning the value.
## 17. Type constraints ## 17. Type constraints
@ -178,7 +180,7 @@ is discarded unevaluated — `g ≜ λs∈𝔹: s + "!"` happily takes a string.
Matches the site's "parsed today, not yet enforced" claim. Matches the site's "parsed today, not yet enforced" claim.
Pins: `039_type_constraint_unenforced`. Pins: `039_type_constraint_unenforced`.
RULING: RULING: BLESS. Type constraints parse and are discarded, unenforced — this is the published claim and Stage 5's mandate.
## 18. Nullary calls and zero-parameter λ ## 18. Nullary calls and zero-parameter λ
@ -188,7 +190,7 @@ so every `f()` is a runtime `err_arity`. The call syntax exists; nothing
can satisfy it. can satisfy it.
Pins: `046_arity_nullary`, `047_arity_extra`. Pins: `046_arity_nullary`, `047_arity_extra`.
RULING: RULING: AMEND GRAMMAR. Nullary functions exist: `λ: e` is admitted (bare colon; the parenthesized spelling stays rejected per ruling 25). Effects made M0 procedural the day `✎` entered it; arity 0 is not an exception to . `f()` calls it; arity mismatches remain `err_arity`.
## 19. as multiplication ## 19. as multiplication
@ -196,7 +198,7 @@ Question: is `` (U+2217) an operator, and what does it mean?
Observed: exactly `×` — same token, same precedence. Observed: exactly `×` — same token, same precedence.
Pins: `041_asterisk_multiplication`. Pins: `041_asterisk_multiplication`.
RULING: RULING: BLESS. `` (U+2217) is exactly `×`.
## 20. Divergence: empty program ## 20. Divergence: empty program
@ -206,7 +208,7 @@ Observed: the grammar accepts it; the JS interpreter rejects it
Pins: none possible until ruled (decision 3 — divergent programs cannot Pins: none possible until ruled (decision 3 — divergent programs cannot
enter the corpus). Repro in DIVERGENCES.md (fuzz index 49). enter the corpus). Repro in DIVERGENCES.md (fuzz index 49).
RULING: RULING: OVERRIDE. The empty program is valid and produces no output. The grammar is right; the interpreter accepts it.
## 21. Divergence: sequences inside parentheses ## 21. Divergence: sequences inside parentheses
@ -217,7 +219,7 @@ rejects both (`err_expect`).
Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 86, 119, Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 86, 119,
247, 233, 279, 406, 468, 101…). 247, 233, 279, 406, 468, 101…).
RULING: RULING: OVERRIDE. Parentheses contain one seqExpr per the standing DECISIONS ruling: `(e1; e2)` is legal, value = last expression. The interpreter implements its own language.
## 22. Divergence: `∘` composition ## 22. Divergence: `∘` composition
@ -227,7 +229,7 @@ even has the `\circ` escape) but has no parse rule for it — every use is
`err_expect`. `err_expect`.
Pins: none until ruled. Repro in DIVERGENCES.md (fuzz index 9). Pins: none until ruled. Repro in DIVERGENCES.md (fuzz index 9).
RULING: RULING: IMPLEMENT. `∘` is function composition: `(f ∘ g)(args…) = f(g(args…))`. Operands must be functions — a non-function operand raises the expected-a-function key (reuse the existing key if the audit finds one, else introduce `err_fn`). Precedence and associativity follow the grammar.
## 23. Divergence: set literals ## 23. Divergence: set literals
@ -237,7 +239,7 @@ Observed: the grammar accepts `({5, "a b"})` and friends; the JS
interpreter has no set support and rejects them (`err_expect`). interpreter has no set support and rejects them (`err_expect`).
Pins: none until ruled. Repros in DIVERGENCES.md (multiple fuzz indexes). Pins: none until ruled. Repros in DIVERGENCES.md (multiple fuzz indexes).
RULING: RULING: PARSE-ONLY. Set literals parse (the interpreter gains the grammar's brace disambiguation) and evaluation raises `err_notyet`. Set semantics are an M1 design, logged.
## 24. Divergence: record literals ## 24. Divergence: record literals
@ -248,7 +250,7 @@ Observed: the grammar accepts `({y: 0})`; the JS interpreter rejects
Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 25, 212, Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 25, 212,
425, 427, 447). 425, 427, 447).
RULING: RULING: PARSE-ONLY. Record literals: same as 23.
## 25. Divergence: parenthesized λ parameters ## 25. Divergence: parenthesized λ parameters
@ -260,7 +262,7 @@ The interpreter carries a syntax form the language explicitly rejected.
Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 13, 29, Pins: none until ruled. Repros in DIVERGENCES.md (fuzz indexes 13, 29,
76, …). 76, …).
RULING: RULING: OVERRIDE. `λ(a, b): e` is rejected by the interpreter too — the grammar already enforces the ratified DECISIONS ruling.
## 26. Divergence: bare λ and Greek letters as identifiers ## 26. Divergence: bare λ and Greek letters as identifiers
@ -271,4 +273,4 @@ Observed: grammar accepts `({λ})`; JS rejects (`err_expect` — λ demands a
parameter list). parameter list).
Pins: none until ruled. Repro in DIVERGENCES.md (fuzz index 52). Pins: none until ruled. Repro in DIVERGENCES.md (fuzz index 52).
RULING: RULING: AMEND GRAMMAR. `λ` is a reserved token, never an identifier. Only λ; other Greek letters (π et al.) remain identifiers — Fatima wants π.