parser: disambiguate bare-token compound patterns in defn (eigentrust pitfall #7)#16
Merged
Merged
Conversation
2 tasks
hierophantos
approved these changes
Apr 26, 2026
hierophantos
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Surgical scope, uses existing lookup-ctor / ctor-meta-field-types infrastructure (no new APIs), N-arg fallback preserved.
Two non-blocking observations:
- The auto-pack rule means a user who picks a parameter name matching a constructor —
defn foo | cons x y -> ...withconsas a variable — would now get the compound interpretation. ML/Haskell-aligned default is right, but worth a release note when a batch of these pitfall fixes lands. - Filed the latent
compile-match-treevariable-binding bug as #18 with your reproducer + diagnosis attributed. That tracks the recursive eigentrust case independently — your parser fix here can land without it.
Approving — ready to merge once you rebase to drop the skip commit.
dd26ad4 to
43017b6
Compare
kumavis
added a commit
that referenced
this pull request
Apr 26, 2026
The 2026-04-23 eigentrust pitfalls memo (forthcoming branch) enumerated 16 items hit during the EigenTrust implementation. Items #1-7 and #11-15 are language/elaboration defects with their own PRs. Items #8, #9, #10, and #16 are observations rather than Prologos defects; no compiler change is needed for them but the memo deserves a parallel disposition note so a future reader does not double-count them as open work. #8 (exact-Rat slow on deep iter): intrinsic to exact rational arithmetic; benchmark-scope guidance, not a fix. #9 (Posit32 literals work): positive observation; `~` literal prefix is unambiguous unlike `0/1`. No action. #10 (PVec preserves where List does not): subsumed by pitfall #3 fix. After #3 lands, both literal forms preserve element type uniformly. Close as duplicate. #16 (column-stochastic vs row-stochastic): algorithm/spec clarification, not a Prologos defect. The eigentrust implementation branch already takes column-stochastic M directly and validates via col-stochastic?. https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
Contributor
Author
expected to see an argument body following the function name. |
…defn Pre-fix: `defn f | cons r nil -> r | cons r rest -> ...` parsed each bare token after `|` as a separate arg pattern, splitting the function into clauses with mismatched arities (1 nil clause + 2 cons-3-arg clauses). This produced a per-clause helper (`f::1`, `f::3`) and the recursive call site `[f rest]` failed with `Unbound variable f::1` because the arity-1 helper only knew the nil clause and any non-empty list hit __match-fail. Fix shape (a) — implement general pattern matrices by auto-packing when the leading bare token names a known constructor whose field count matches the remaining tokens. `cons r nil` → one compound pattern `pat-compound 'cons (var-r, var-nil)` (then normalize-pattern converts var-nil to compound-nil since nil is a known nullary ctor). Fallback preserved for genuinely multi-arg defns: defn add | x y -> [+ x y] The leading `x` is a variable (lookup-ctor returns #f), so falls through to the old N-arg interpretation. Trade-off vs (b) (raise an error): (a) makes the syntax do what ML/Haskell users expect — `defn` IS the primary dispatch mechanism per .claude/rules/prologos-syntax.md, so making `cons r nil` mean "compound pattern" is the natural reading. The detection is local and does not change semantics for any pattern that didn't have a known ctor as its leading token. Scope: 23 lines in parser.rkt's parse-defn-clause + 11 new tests in test-defn-multiarg-patterns.rkt. No changes elsewhere. Test results: 11/11 new tests pass. 43/43 related tests pass (test-pattern-defn-01, test-pattern-defn-02, test-multi-body-defn). Full affected-suite: 4646 tests in 255 files, 1 unrelated pre-existing failure (stale tracking entry for non-existent test-constraint-retry-propagator.rkt). Latent issue exposed (NOT introduced by this fix): compile-match-tree binds variable patterns to outer-param names when those params get destructured by a later dispatch column. E.g., `cons r rest` after outer-cons specialization tries `let rest := __cons_1` while `__cons_1` is being destructured into `__cons_1_0` and `__cons_1_1`. This affects the recursive bodies of the eigentrust example with multi-element inputs, but is a pre-existing bug in compile-match-tree — reproducible on main with the bracketed `[cons r rest]` form, which parses to the same internal representation. The new tests cover the slices unaffected by this bug (empty + singleton inputs, wildcard patterns, all-var multi-arg) and explicitly call out the latent issue. Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
43017b6 to
458bfcf
Compare
kumavis
added a commit
that referenced
this pull request
Apr 26, 2026
The 2026-04-23 eigentrust pitfalls memo (forthcoming branch) enumerated 16 items hit during the EigenTrust implementation. Items #1-7 and #11-15 are language/elaboration defects with their own PRs. Items #8, #9, #10, and #16 are observations rather than Prologos defects; no compiler change is needed for them but the memo deserves a parallel disposition note so a future reader does not double-count them as open work. #8 (exact-Rat slow on deep iter): intrinsic to exact rational arithmetic; benchmark-scope guidance, not a fix. #9 (Posit32 literals work): positive observation; `~` literal prefix is unambiguous unlike `0/1`. No action. #10 (PVec preserves where List does not): subsumed by pitfall #3 fix. After #3 lands, both literal forms preserve element type uniformly. Close as duplicate. #16 (column-stochastic vs row-stochastic): algorithm/spec clarification, not a Prologos defect. The eigentrust implementation branch already takes column-stochastic M directly and validates via col-stochastic?. https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
13 tasks
hierophantos
added a commit
that referenced
this pull request
Apr 27, 2026
This was referenced Apr 27, 2026
kumavis
pushed a commit
that referenced
this pull request
Apr 27, 2026
Wires the OCapN port to a real Racket toolchain and fixes the issues
the test run surfaced.
Library fixes
- vat.prologos: rename `spawn` -> `vat-spawn` (collision with the
reserved surface form recognised in macros.rkt:`'spawn`),
`spawn-actor` -> `vat-spawn-actor`. Same in core.prologos and the
acceptance file.
- vat.prologos: drop the `Sigma Vat Nat` return shape for spawn /
fresh-promise / send. Replace with a named `Allocated` struct +
`alloc-vat` / `alloc-id` accessors. The Sigma form ran into
"could not infer" elaborator errors when the body destructured
via `match | pair a b -> ...` and then re-constructed a Sigma;
`[fst p]` / `[snd p]` reused on the same `p` tripped QTT
multiplicity. The named struct sidesteps both.
- vat.prologos: reorder `resolve-promise` / `break-promise` BEFORE
`apply-effect` (forward-reference rule — module elaboration is
single-pass top-to-bottom). Also reorder `step-after-act` before
`deliver-msg` and `list-length-helper` before `queue-length`.
- vat.prologos: drop the queued-pipeline-flush in resolve-promise /
break-promise. PromiseState's queue is `List SyrupValue` (wire
repr); the vat queue is `List VatMsg` (decoded); flushing across
the boundary would need re-encoding. Phase 1.
Test-fixture fix (load-bearing)
- All 8 OCapN test files were updated to capture and restore
`current-ctor-registry` and `current-type-meta` across the setup-
-> run boundary. The standard fixture pattern from
`test-hashable-01.rkt` does NOT preserve these — fine for tests
that only declare traits, but breaks once a preamble's imports
declare new `data` types (every `data` in our 8 modules). Without
it, the reducer sees a stale ctor-registry and refuses to fire
pattern arms over user constructors; results print as un-reduced
`[reduce ... | vat x y z a -> x] : Nat` strings.
Documented as goblin-pitfall #12; the canonical fixture in
test-support.rkt should grow this for every future test.
Compat fence
- driver.rkt: guard
`(current-parallel-executor (make-parallel-thread-fire-all))` with
a feature-detection try/catch on `thread #:pool 'own`. Racket 9
ships parallel threads; Racket 8 does not. Fence preserves the
Racket-9 fast path and falls back to sequential firing on 8.
Acceptance
- examples/2026-04-27-ocapn-acceptance.prologos updated to match
the new vat-spawn/Allocated API and verified to run clean via
process-file.
Pitfalls catalogue (docs/tracking/2026-04-27_GOBLIN_PITFALLS.md)
- #0 (sandbox/no-Racket): closed.
- +#11 — Racket-8 vs Racket-9 `thread #:pool` compat
- +#12 — test fixture loses ctor-registry/type-meta across calls
[highest-impact; canonical fixture pattern needs update]
- +#13 — `spawn` is a reserved surface keyword; collides silently
- +#14 — `match | pair a b ->` on Sigma + Sigma reconstruction =>
"could not infer"
- +#15 — QTT multiplicity on `[fst p]`/`[snd p]` reused thrice
- +#16 — single-pass module elaboration: forward references error
- +#17 — promise-queue (Syrup) vs vat-queue (VatMsg) type clash
on flush — design pitfall, scope cut
Test results
refr 6/6 syrup 22/22 promise 16/16 message 19/19
behavior 13/13 vat 21/21 pipeline 5/5 captp 7/7
e2e 8/8 total 117/117 PASS
kumavis
pushed a commit
that referenced
this pull request
Apr 27, 2026
Per user direction: - Replace the body of every DELETED entry with a single-sentence explanation. Numbers reserved per prior instruction. - Delete #15 (QTT multiplicity on fst/snd thrice). I re-tested with a real Racket — `pair [snd p] [fst p]` then a third use of `fst p` works fine; no multiplicity error. The failure I had conflated this with was actually #14's "match-and-reconstruct Sigma" issue. Result: pitfalls doc shrinks from 765 to 534 lines. Remaining real claims: #1, #4, #5, #11, #12, #13, #14, #16, #17, #18, #19, #20 (the user has reviewed only #0-10 so far; #11-20 still pending their review).
kumavis
pushed a commit
that referenced
this pull request
Apr 28, 2026
Builds on the lambda-FFI track (PR #35): the affine combination out[j] := bias[j] + Σ_i weight[j][i] · prev[i] is now a Prologos `defn affine-step` lambda passed across the FFI on each `net-add-prop` install. The Racket shim's broadcast item-fn invokes it once per peer per fire. What stays in Racket (the truly irreducible core): * cell-value carrier (gen-tagged immutable Posit32 vector) * the propagator's fire-fn (a Racket closure that reads input cell, invokes the Prologos kernel via the FFI bridge, and writes the output cell — pure plumbing, NO algorithmic content) * FFI marshalling glue (cons/nil chain walking, Posit32 bit-pattern extraction, per-row IR list construction) * handle/cell registries What's now in Prologos (the entire algorithm): * matrix transpose, decay scaling, bias computation * the per-row affine kernel itself * iteration driver * initial-zero vector `net-add-prop` is purpose-AGNOSTIC — it's a generic broadcast affine propagator wired to a domain-specific Prologos kernel. The same shim would serve any algorithm whose per-row update is `bias + Σ w·x`. CI integration: * New `tests/test-eigentrust.rkt` runs the .prologos file via `process-file` and asserts the converged scores match the Python reference within 1e-2 — auto-picked up by `tools/run-affected-tests --all` (the CI test command). * 5 power iterations lands within ~6e-3 of the steady-state eigenvector; runs in ~16s, under the test runner's 30s first-result guard. New pitfalls captured (docs/tracking/2026-04-28_ETPROP_PITFALLS.md): * #0 — FFI-call AST caching collapses identical side-effecting calls onto the same physical cell. Fixed via a "freshness tag" arg on `net-new-cell`. Surfaced when distinct layer cells turned out to be the same physical cell (self-loop). * #16 — FFI-callback overhead per fire is the bottleneck. Each kernel invocation runs `nf` on the lambda body. Documented as expected scaffolding cost of the off-network FFI bridge; future work is propagator-native callbacks via cell subscription. Test results: * tests/test-eigentrust.rkt: 2/2 pass (15.4s) * regression set (foreign / foreign-block / pvec / foreign-callback / eigentrust): 111/111 pass (21s) * Final converged scores match Python reference within 1e-2: [0.0712, 0.4288, 0.0712, 0.4288] (steady state ≈ [0.0652, 0.4348])
kumavis
pushed a commit
that referenced
this pull request
May 4, 2026
Wires the OCapN port to a real Racket toolchain and fixes the issues
the test run surfaced.
Library fixes
- vat.prologos: rename `spawn` -> `vat-spawn` (collision with the
reserved surface form recognised in macros.rkt:`'spawn`),
`spawn-actor` -> `vat-spawn-actor`. Same in core.prologos and the
acceptance file.
- vat.prologos: drop the `Sigma Vat Nat` return shape for spawn /
fresh-promise / send. Replace with a named `Allocated` struct +
`alloc-vat` / `alloc-id` accessors. The Sigma form ran into
"could not infer" elaborator errors when the body destructured
via `match | pair a b -> ...` and then re-constructed a Sigma;
`[fst p]` / `[snd p]` reused on the same `p` tripped QTT
multiplicity. The named struct sidesteps both.
- vat.prologos: reorder `resolve-promise` / `break-promise` BEFORE
`apply-effect` (forward-reference rule — module elaboration is
single-pass top-to-bottom). Also reorder `step-after-act` before
`deliver-msg` and `list-length-helper` before `queue-length`.
- vat.prologos: drop the queued-pipeline-flush in resolve-promise /
break-promise. PromiseState's queue is `List SyrupValue` (wire
repr); the vat queue is `List VatMsg` (decoded); flushing across
the boundary would need re-encoding. Phase 1.
Test-fixture fix (load-bearing)
- All 8 OCapN test files were updated to capture and restore
`current-ctor-registry` and `current-type-meta` across the setup-
-> run boundary. The standard fixture pattern from
`test-hashable-01.rkt` does NOT preserve these — fine for tests
that only declare traits, but breaks once a preamble's imports
declare new `data` types (every `data` in our 8 modules). Without
it, the reducer sees a stale ctor-registry and refuses to fire
pattern arms over user constructors; results print as un-reduced
`[reduce ... | vat x y z a -> x] : Nat` strings.
Documented as goblin-pitfall #12; the canonical fixture in
test-support.rkt should grow this for every future test.
Compat fence
- driver.rkt: guard
`(current-parallel-executor (make-parallel-thread-fire-all))` with
a feature-detection try/catch on `thread #:pool 'own`. Racket 9
ships parallel threads; Racket 8 does not. Fence preserves the
Racket-9 fast path and falls back to sequential firing on 8.
Acceptance
- examples/2026-04-27-ocapn-acceptance.prologos updated to match
the new vat-spawn/Allocated API and verified to run clean via
process-file.
Pitfalls catalogue (docs/tracking/2026-04-27_GOBLIN_PITFALLS.md)
- #0 (sandbox/no-Racket): closed.
- +#11 — Racket-8 vs Racket-9 `thread #:pool` compat
- +#12 — test fixture loses ctor-registry/type-meta across calls
[highest-impact; canonical fixture pattern needs update]
- +#13 — `spawn` is a reserved surface keyword; collides silently
- +#14 — `match | pair a b ->` on Sigma + Sigma reconstruction =>
"could not infer"
- +#15 — QTT multiplicity on `[fst p]`/`[snd p]` reused thrice
- +#16 — single-pass module elaboration: forward references error
- +#17 — promise-queue (Syrup) vs vat-queue (VatMsg) type clash
on flush — design pitfall, scope cut
Test results
refr 6/6 syrup 22/22 promise 16/16 message 19/19
behavior 13/13 vat 21/21 pipeline 5/5 captp 7/7
e2e 8/8 total 117/117 PASS
kumavis
pushed a commit
that referenced
this pull request
May 4, 2026
Per user direction: - Replace the body of every DELETED entry with a single-sentence explanation. Numbers reserved per prior instruction. - Delete #15 (QTT multiplicity on fst/snd thrice). I re-tested with a real Racket — `pair [snd p] [fst p]` then a third use of `fst p` works fine; no multiplicity error. The failure I had conflated this with was actually #14's "match-and-reconstruct Sigma" issue. Result: pitfalls doc shrinks from 765 to 534 lines. Remaining real claims: #1, #4, #5, #11, #12, #13, #14, #16, #17, #18, #19, #20 (the user has reviewed only #0-10 so far; #11-20 still pending their review).
kumavis
pushed a commit
that referenced
this pull request
May 6, 2026
…o-increment imports-refcount
Wires the bridge dispatcher to recognize desc:export / desc:answer
in inbound op:deliver args and increment imports-refcount per
occurrence. Combined with Phase 34c (refcount table) and Phase 34e
(release wired to bs-decr-import, next), this gives us the auto-
tracking half of distributed reference counting.
captp-bridge.prologos:
+ match-payload-as-export SyrupValue -> List Refr
+ match-payload-as-answer SyrupValue -> List Refr
Pattern-match SyrupValue payloads (typically syrup-nat).
+ extract-refrs-from-tagged String SyrupValue -> List Refr
Tag-based dispatch: "desc:export" → match-payload-as-export,
"desc:answer" → match-payload-as-answer, anything else → nil.
+ walk-toplevel-list [List SyrupValue] -> List Refr
One-level walk over a SyrupValue list, calling shallow-refr
per element.
+ shallow-refr SyrupValue -> List Refr
Per-element check: top-level desc:* tag yields a refr;
anything else (including nested syrup-list) yields nil.
+ extract-refrs-from-args SyrupValue -> List Refr
Top-level entry point: handles atomic, single tag, and
one-level-deep list.
+ bs-incr-import-by-refr Refr BridgeState -> BridgeState
+ bs-incr-imports [List Refr] BridgeState -> BridgeState
captp-incoming-with-state op-deliver / op-deliver-only /
op-deliver-to-answer arms: extract refrs from args + bulk-
increment imports-refcount before dispatching.
Limitation (documented inline): refrs nested deeper than one list
level aren't extracted. Common OCapN args shapes (top-level refr OR
list of refrs+primitives) are covered; deeper nesting (refrs inside
records inside lists) deferred to a future phase that adds
generic-walker recursion.
Lessons learned (codified):
1. Pitfall #16 (forward references / mutual recursion): true mutual
recursion (`extract-refrs-from-args` ↔ `walk-toplevel-list`)
isn't supported. Worked around by making the inner walker call
only `shallow-refr` (which doesn't recurse into syrup-list).
Trade-off: the walker is one level deep instead of full tree.
2. Multi-arity defn with constructor cons-pattern + multi-line body:
`defn name | nil -> ... | [cons hd tl] -> body` triggered
??__match-fail. Worked around by using bracketed-arg + inline
`match`: `defn name [xs] (match xs | nil -> ... | cons hd tl -> body)`.
Pattern is the same shape as data/list's `concat`. Codified.
Tests:
+ 5 new unit tests (69 total in test-ocapn-bridge.rkt):
- extract-refrs-from-args returns nil for atomic args
- extracts a top-level desc:export
- walks one-level into syrup-list (2 refrs in mixed list)
- extracts top-level desc:answer
- captp-incoming-with-state op-deliver auto-increments
imports-refcount[7] when args = <desc:export 7>
Verification:
- 73 OCapN tests pass across 5 files (40 s combined)
- bridge tests: 69/69 (5 new + 64 prior)
- All interop tests still pass — auto-increment is non-disruptive
for tests that don't pass refrs in args (count stays 0)
kumavis
pushed a commit
that referenced
this pull request
May 6, 2026
…it, `->` in identifiers silently fails Two new Prologos elaborator/reader pitfalls discovered during the refr-import track (Phase 34a + 34d). Both cost ~15 minutes each to debug because the failure modes were silent or had misleading error messages. Pitfall #34 — `data` constructor signatures have IMPLICIT return type. Writing `ctor : T1 -> T2 -> Result` is INTERPRETED as "takes 3 args (T1, T2, Result), returns Result." The user usually means "takes 2 args, returns Result." The convention in this codebase (Listener, QEntry, etc) is to drop the trailing `-> Result`: `ctor : T1 -> T2`. Discovered Phase 34a (commit 3d8c069). My initial `refr : Nat -> Nat -> Refr` caused smart constructors to fail with "Type mismatch [Pi Nat Refr -> Refr]". Fix: drop the trailing `-> Refr`. Pitfall #35 — Function names containing `->` silently fail. Identifiers with `->` (like `refr->syrup`, common in ML/Lisp converter naming) are SILENTLY DROPPED by the elaborator. The WS-mode reader parses `->` as the function-arrow type operator inside the identifier, splitting the symbol. spec/defn forms can't bind anything sensible and produce no output at all — callers get "Unbound variable" downstream. Discovered Phase 34d (commit 7c797e6). My `refr->syrup` was silently dropped; renamed to `refr-to-syrup` worked. Codebase convention: use `-to-` for converters. Also documented (no new pitfall, recurrence-only): - #18 (multi-arity defn cons-pattern) hit on add's `suc a b -> ...`; fix: bracket as `[suc a] b -> ...`. - #21 (multi-line clause body → ??__match-fail) hit on extract-refrs-from-list; fix: `defn name [arg] (match arg ...)` same shape as data/list's `concat`. - #16 (mutual recursion) hit on extract-refrs-from-args ↔ extract-refrs-from-list; fix: one-way recursion via shallow-refr. - Issue #60 (multi-constructor cross-module inference) hit on 5-arg helpers; fix: 2-3 arg shape via BridgeStep. Updated .claude/rules/prologos-syntax.md: - Added "NEVER use `->` in identifiers" to the Naming section - Added a new "Data type definitions" section with the implicit-return-type convention These two are filed in the pitfalls doc but not as GitHub issues yet — both are reasonably easy elaborator/reader fixes that upstream Prologos work could close. Triage decision deferred.
kumavis
pushed a commit
that referenced
this pull request
May 9, 2026
Three new entries in 2026-04-27_GOBLIN_PITFALLS.md: - #36: Multi-line constructor / function application — continuation args on a separate line are eaten as an inner application. Hit twice in this branch (Phase 41 `bs-add-pipeline-msg`, Phase 48 `bs-gc-listeners-by-notified`); the second occurrence triggered codification per the workflow rule "codify a 2-occurrence pattern within a track immediately." - #37: Single-arg multi-arity `defn` over `data` patterns sometimes infers a phantom 2nd parameter. Hit on `resolution-syrup-of-pst` (Phase 48); the fix was to switch to `defn name [arg] match arg` shape, which pinned the inferred type back to the spec. - #38: `let X := EXPR` value can't span multiple lines. Hit on `drive-break-with-two-ops` (Phase 49); same workaround family as #21 and #36 — collapse to one line. Recorded separately because the error message ("missing value after :=") points at a different line than the actual broken `let`. Plus a "Recurrences during Phase 47-49" section noting that pitfall #16 (forward references) was hit again on `member-nat?` — existing entry confirmed correct. Also updated `.claude/rules/prologos-syntax.md` § "Application style" with two new bullets cross-referencing #36/#37/#38, so future implementations catch these at write time rather than at load-time error. Per the workflow rule "if a workaround is needed twice in the same track, add it to the pitfalls log AND to the relevant rule file immediately." https://claude.ai/code/session_01YM6gc3cMNH2Ymor4jdZY8u
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes pitfall #7 from
docs/tracking/2026-04-23_eigentrust_pitfalls.md.Summary
failed with
Unbound variable sum-rows::1— the parser treatedcons r restas three separate arguments instead of one compound pattern.Approach (a) — auto-pack constructor patterns
In
parse-defn-clause, when the leading token after|names a known constructor whose field count matches the remaining tokens, pack them into one compound pattern. Falls back to the existing N-arg interpretation when the leading token is not a constructor (e.g.,defn add | x y -> [+ x y]still works).Local change in one branch of the cond, ~24 lines, no other files touched.
Why (a) over (b) "raise a clear error":
defnis the primary dispatch mechanism perprologos-syntax.md, and ML/Haskell users naturally readcons r nilas one compound. Detecting vialookup-ctoris local and preserves multi-arg defns unchanged.Files changed
racket/prologos/parser.rkt(+24)racket/prologos/tests/test-defn-multiarg-patterns.rkt(new, 315 lines, 11 cases)Test plan
test-pattern-defn-01/test-pattern-defn-02/test-multi-body-defnpasstest-constraint-retry-propagator.rkt)benchmarks/micro/info.rktskip; redundant once PR Migrate bench-bsp-le-track2.rkt to current ATMS API (CI unblock) #10's actual migration lands first)Latent bug surfaced (NOT introduced) — worth tracking
The fix exposed a latent
compile-match-treebug: variable patterns named in a sub-position get bound vialet v := __cons_1, referring to a param that's been destructured by a later dispatch column. This corrupts recursive bodies likecons r rest -> [+ r [recurse rest]].Reproducible on main with the bracketed
[[cons r rest]]form (same internal AST). The tests cover the slices unaffected (empty/singleton inputs, wildcards, all-var multi-arg). The commit message documents the latent issue for future tracking — it should be filed as a separate bug.Commits
1595905— primary fix inparser.rkt+ test filedd26ad4— CI fix (skip stale bench)https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x
Generated by Claude Code