Skip to content

The corpus was recording equality where the language does predicate application - #75

Merged
rmichaelthomas merged 1 commit into
mainfrom
feat/corpus-define-cases
Sep 12, 2026
Merged

rmichaelthomas merged 1 commit into
mainfrom
feat/corpus-define-cases

Conversation

@rmichaelthomas

Copy link
Copy Markdown
Owner

Two defects in the generator, both surfaced by adding define cases ahead of porting it.

It never built a predicate table

validate_line called parse(tokens) with neither composition_names nor predicate_names — the two sets the CLI supplies from the session. So define large: is above 50 registered nothing, is large fell through to string equality, and the corpus recorded that as the language's behaviour.

Worse, require total is not large — locked at v31 §83 and implemented — came out as a parse error. I briefly believed §83 was unimplemented on the strength of the corpus, before probing the interpreter directly and finding PredicateApplicationNode(negated=True) right there in the parser.

Rendering cannot tell the two apart

require total is large      → require total is large      (predicate application)
require total is overdue    → require total is overdue    (string equality)

Identical. The corpus compared status, canonical rendering and error kind — so a port that implemented define as a no-op would have passed every case I had just added.

So each success now records nodes: every AST node kind in the tree, sorted.

require total is large    → ['NameRef', 'PredicateApplicationNode', 'RequireNode']
require total is overdue  → ['BareWord', 'ConditionNode', 'NameRef', 'RequireNode']

Kind names already agree across implementations — RequireNode is RequireNode on both sides — so this needs no translation layer.

Six define cases

Application, negation, field elision in the body (§90), a predicate referencing a predicate (§84), a bareword that is not a predicate staying equality, and a predicate used before it is defined. The last two are what make define non-breaking per §82, and the corpus now says so rather than implying it.

One case was renamed: "an undefined predicate is refused" was wrong — it is not refused, it is equality, which is the point.

48 cases. 1748 passed, 2 skipped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E6qcDj1e1dEYvc8jLnpGZy

does predicate application

Two defects in the generator, both found by adding `define` cases.

**It never built a predicate table.** `validate_line` called `parse(tokens)`
with neither `composition_names` nor `predicate_names`, which the CLI
supplies from the session. So `define large: is above 50` registered
nothing, `is large` fell through to string equality, and the corpus
recorded that as the language's behaviour. `is not large` — which is
locked at v31 §83 and implemented — was recorded as a parse error. The
port would have been taught both.

**Rendering cannot tell the two apart.** `require total is large` and
`require total is overdue` render identically; the first is a predicate
application and the second is equality against a bareword. The corpus
compared status, canonical and error kind, so a port that implemented
`define` as a no-op would have passed every new case.

So each success now records `nodes`: every AST node kind in the tree,
sorted. Predicate application carries `PredicateApplicationNode`;
equality carries `BareWord` and `ConditionNode`. Kind names already agree
across the two implementations — `RequireNode` is `RequireNode` on both
sides — so the comparison needs no translation layer.

Six `define` cases added: application, negation, field elision in the
body, a predicate referencing a predicate, a bareword that is not a
predicate staying equality, and a predicate used before it is defined.
That last pair is what makes `define` non-breaking, and the corpus now
says so rather than implying it.

48 cases.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E6qcDj1e1dEYvc8jLnpGZy
@rmichaelthomas
rmichaelthomas merged commit 1d84c60 into main Sep 12, 2026
3 checks passed
@rmichaelthomas
rmichaelthomas deleted the feat/corpus-define-cases branch September 12, 2026 06:59
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