Skip to content

Stop telling the model list.zip exists, then linting it for using it - #49

Merged
alpibrupa merged 2 commits into
mainfrom
fix/linter-prompt-benchmark-findings
Jul 17, 2026
Merged

Stop telling the model list.zip exists, then linting it for using it#49
alpibrupa merged 2 commits into
mainfrom
fix/linter-prompt-benchmark-findings

Conversation

@alpibrupa

Copy link
Copy Markdown
Contributor

Benchmark findings that had been sitting uncommitted in a local working copy (3 weeks stale, 8 commits behind). Rescued and rebased onto current main — the 3-way apply was clean.

Two of the four changes are corrections to things we had wrong, not new features.

1. We were the source of the list.zip hallucination

The prompt's stdlib index advertised zip as a std.list function:

| list | `std.list` | map, filter, fold, head, tail, concat, len, zip, reverse | pure |

list.zip does not exist:

$ lex check   # 0.10.6
{"kind":"unknown_field","field":"zip", ...}

We told the model it was real, then added a linter rule scolding it for reaching for it. The row also omitted six functions that do exist — including list.cons and list.range, which the prompt's own code examples use, and list.enumerate, which the new zip hint tells the model to use instead. A model told "use enumerate" had no confirmation enumerate was real.

Every one of the fourteen functions the row now claims was probed against 0.10.6 individually:

map ✓  filter ✓  fold ✓  head ✓  tail ✓  concat ✓  cons ✓
len ✓  is_empty ✓  enumerate ✓  range ✓  reverse ✓  sort_by ✓  par_map ✓

The str row was checked too — it's an incomplete subset, but claims nothing false, so it's left alone.

2. The && hint was wrong about the language

- "parse error: `&&` is not a Lex operator. Use nested `if`: `if a { b } else { false }` for AND..."
+ "parse error: `&&` is not valid Lex. Use `a and b` (Lex keyword). Example: `acc and (x == y)`."

Lex has and/or. The old hint pushed models into needless nesting to avoid an operator that has a perfectly good keyword equivalent. || gets the same fix.

3. Targeted hints for the two most-hallucinated APIs

list.ziplist.enumerate, or compare via str.join(a, ",") == str.join(b, ",").
str.to_strint.to_str from std.int.

Both verified absent on 0.10.6 before the hint was written — the linter should never assert an API doesn't exist without that being checked.

Verification

CI's own loop, run locally on 0.10.6:

for f in $(git ls-files src/ | grep '\.lex$'); do lex check "$f"; done
  exit=0   (76 files)
lex check examples/manifesto_parallel.lex
  ok

Note

The fix to the index matters more than the lint rule: the rule catches the symptom, the index was the cause. The rule stays as a safety net for models that reach for zip out of habit from other languages.

🤖 Generated with Claude Code

alpibrupa and others added 2 commits July 17, 2026 15:54
Benchmark findings from local runs, rescued from an uncommitted working copy
and rebased onto main. Two of them are corrections, not additions:

1. The prompt's stdlib index advertised `zip` as a std.list function. It does
   not exist — `list.zip(...)` is `unknown_field` on 0.10.6. We were the source
   of the hallucination the linter then flagged. The row also omitted six
   functions that DO exist, two of which the prompt's own examples use
   (`list.cons`, `list.range`), and one the new zip hint recommends
   (`list.enumerate`) — so a model told "use enumerate" had no confirmation it
   was real. Every one of the fourteen functions the row now claims was probed
   against 0.10.6 individually.

2. The `&&` linter hint said "use nested if: `if a { b } else { false }`".
   Lex has `and`. The hint now says `a and b`, and `||` gets the same treatment.
   The old advice was not just verbose, it was wrong about the language.

Plus targeted fix: hints for the two APIs models reach for most and that do not
exist — `list.zip` (→ enumerate, or compare via str.join) and `str.to_str`
(→ int.to_str). Both verified absent on 0.10.6 before writing the hint.

Verified: CI's own loop over all 76 tracked src/*.lex exits 0; the examples
check passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI's fmt --check step caught this — I had run the type-check loop locally but
missed the fmt step when reading the workflow. The prompt file has no inner
comments, so lex-lang#716 costs nothing here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alpibrupa
alpibrupa merged commit e35d993 into main Jul 17, 2026
1 check passed
@alpibrupa
alpibrupa deleted the fix/linter-prompt-benchmark-findings branch July 17, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant