From 42a61670783b59b5ac5bed0120880bf6c7a92a3d Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 20 Jul 2026 19:24:24 -0500 Subject: [PATCH 1/2] vm: prescriptive error for '+' on lists (#680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `[1,2] + [3,4]` reported `cannot apply '+' to list and list` — correct but not actionable. A Python/JS prior lands here (observed live: an AI given only a syntax primer wrote `xs + [v]` and crashed) and has to guess the idiom. The message now names the fix, mirroring the existing mixed-type f-string hint: cannot apply '+' to list and list (use 'append of [xs, v]' to add an element, or 'concat of [a, b]' to join two lists) Cold error path (rt_error), no hot-path cost. dict+num and other non-list cases keep the generic message; mixed str+X keeps the f-string hint. First of the prescriptive-error pass (#680): at points where the language diverges from mainstream priors, teach the fix — helps humans and AI alike, and a context-rich AI stumbling there is a lower bound on human friction. Regression: EE20b. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 8 ++++++++ src/vm.c | 6 ++++++ tests/test_error_extra.eigs | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 919159e6..8a41f3e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,14 @@ All notable changes to EigenScript are documented here. max-subtraction (overflow to inf), a mis-indexed target, and sign errors. ### Changed +- **`+` on two lists now names the fix (#680).** `[1,2] + [3,4]` reported + `cannot apply '+' to list and list` — correct but not actionable; a Python/JS + prior lands here and has to guess the idiom. The message now prescribes it: + `... (use 'append of [xs, v]' to add an element, or 'concat of [a, b]' to join + two lists)`, mirroring the existing f-string hint for mixed-type concatenation. + First of the prescriptive-error pass (#680) — errors at points where the + language diverges from mainstream priors should teach the fix, for humans and + AI alike. Regression: `test_error_extra.eigs` EE20b. - **The observer learning-rate gate is now two-channel (entropy *and* drift).** `observer_matrix_scale` throttled a weight matrix to 0.5x whenever its entropy was quiet — but entropy is computed over one SGD step's worth of diff --git a/src/vm.c b/src/vm.c index ac30ebe0..daba1b8f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2481,6 +2481,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume) { rt_error(EK_TYPE, current_line, "cannot apply '+' to %s and %s (use an f-string or 'str of' to concatenate)", ta, tb); + else if (a->type == VAL_LIST || b->type == VAL_LIST) + /* #680: name the fix, don't just diagnose. '+' never joins lists + * (it is numbers-or-strings only); a Python/JS prior lands here. */ + rt_error(EK_TYPE, current_line, + "cannot apply '+' to %s and %s (use 'append of [xs, v]' to add an element, or 'concat of [a, b]' to join two lists)", + ta, tb); else rt_error(EK_TYPE, current_line, "cannot apply '+' to %s and %s", ta, tb); vm_push(make_null()); diff --git a/tests/test_error_extra.eigs b/tests/test_error_extra.eigs index 79434755..3c11e81e 100644 --- a/tests/test_error_extra.eigs +++ b/tests/test_error_extra.eigs @@ -227,6 +227,18 @@ catch e: assert of [caught20 == 1, "EE20 caught '+' on dict and num"] assert of [(contains of [msg20.message, "cannot apply '+'"]) == 1, "EE20 message mentions cannot apply '+'"] +# ---- '+' on two lists NAMES THE FIX (#680: prescriptive, not just diagnostic) ---- +caught20b is 0 +msg20b is "" +try: + r is [1, 2] + [3, 4] +catch e: + caught20b is 1 + msg20b is e +assert of [caught20b == 1, "EE20b caught '+' on list and list"] +assert of [(contains of [msg20b.message, "append of"]) == 1, "EE20b list '+' message prescribes append"] +assert of [(contains of [msg20b.message, "concat of"]) == 1, "EE20b list '+' message prescribes concat"] + # ---- '/' on incompatible types ---- caught21 is 0 msg21 is "" From 6a03e96404cf70a7d160fe134e0b825b9b058068 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 20 Jul 2026 19:44:13 -0500 Subject: [PATCH 2/2] =?UTF-8?q?CLAUDE.md:=20standing=20rule=20=E2=80=94=20?= =?UTF-8?q?clear=20ready=20contributor=20PRs=20before=20merging=20our=20ow?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contributors work from forks we can't push to, so if our merge stales their PR the only fixes are asking them to rebase or the fetch-reland dance (#657). We rebase our own for free. So: land ready contributor PRs first, then rebase ours. Folded here rather than a standalone docs PR to avoid a wasted CI cycle. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 113f2a0c..13abd76a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,16 @@ session: a gap you route upstream is a contribution; a gap you paper over is lost data. Do this without being told, the way you'd run the tests without being told. +## Before merging your own PR, clear ready contributor PRs first + +External contributors work from **forks we cannot push to** — a fork branch is +theirs. If our merge makes their PR stale, the only remedies are asking them to +rebase (friction, delay) or the fetch-rebase-reland dance (see #657). Our OWN PRs +we rebase for free. So before merging one of ours: `gh pr list` and land any +**ready** contributor PR (green + reviewed, not authored by us) first, then rebase +ours onto the new main. Rebasing our own costs nothing; asking them does. (Only +*ready* PRs — never merge an unready contributor PR just to dodge a rebase.) + ## Build & test ```