spec: implement Direction 1 + 2 implicit binder auto-introduction (#20) - #43
Open
kumavis wants to merge 1 commit into
Open
spec: implement Direction 1 + 2 implicit binder auto-introduction (#20)#43kumavis wants to merge 1 commit into
kumavis wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Implements the remaining work from docs/tracking/2026-02-22_IMPROVED_IMPLICIT_INFERENCE.org (Issue #20) by making spec signatures auto-introduce implicit binders for free capitalized identifiers (Direction 1) and refine higher-kinded binder kinds based on :where / inline trait constraints (Direction 2), plus updates stdlib specs and documentation to use the canonical “bare” form.
Changes:
- Update
process-specto preserve list-valued WS metadata entries (e.g.(:where (Foo A))) and to canonicalize auto-detected implicit binder ordering by kind after kind propagation. - Refactor many stdlib/book
.prologosspecs to drop redundant explicit{A : Type}/{C : Type -> Type}binders. - Add regression + idempotence tests and update tracking/docs to reflect the completed design.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| racket/prologos/macros.rkt | Fix WS metadata merge shape for list-valued keys; add kind-ranking + post-propagation canonical ordering of auto-detected binders. |
| racket/prologos/tests/test-extended-spec.rkt | Adds new tests covering D1+D2 combined behavior, bare-vs-explicit idempotence, and single-inline-:where regression. |
| racket/prologos/lib/prologos/data/transducer.prologos | Removes redundant explicit Type binders from transducer specs to rely on auto-introduction. |
| racket/prologos/lib/prologos/data/map-entry.prologos | Removes redundant {K V : Type} spec binders. |
| racket/prologos/lib/prologos/core/string-ops.prologos | Removes redundant {A : Type} from string fold specs. |
| racket/prologos/lib/prologos/core/set.prologos | Removes redundant {A ... : Type} from set helper specs. |
| racket/prologos/lib/prologos/core/pvec.prologos | Removes redundant {A ... : Type} from persistent vector helper specs. |
| racket/prologos/lib/prologos/core/map.prologos | Removes redundant {K V : Type} from map helper specs. |
| racket/prologos/lib/prologos/core/lattice.prologos | Keeps explicit {K V : Type} for order-sensitive call sites; adds explanatory comments. |
| racket/prologos/lib/prologos/core/generic-ops.prologos | Removes redundant {A B : Type} {C : Type -> Type} from generic ops specs. |
| racket/prologos/lib/prologos/core/fio.prologos | Removes redundant {A : Type} from fio-with-file spec. |
| racket/prologos/lib/prologos/core/collections.prologos | Refactors collection API specs to canonical bare implicit style. |
| racket/prologos/lib/prologos/book/sets.prologos | Mirrors core set spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/persistent-vectors.prologos | Mirrors core pvec spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/maps.prologos | Mirrors core map/map-entry spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/lattices.prologos | Mirrors lattice set-subset? spec change in book chapter. |
| racket/prologos/lib/prologos/book/generic-operations.prologos | Mirrors core generic ops spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/datum-and-homoiconicity.prologos | Mirrors transducer spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/collection-functions.prologos | Mirrors core collections spec refactor in book chapter. |
| racket/prologos/lib/prologos/book/characters-and-strings.prologos | Mirrors core string-ops spec refactor in book chapter. |
| racket/prologos/data/cache/pnet/prologos/data/nat.pnet | Updates a generated .pnet cache snapshot (likely unintended to commit). |
| racket/prologos/data/benchmarks/failures/test-reducible.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-pipe-compose-e2e-02.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-errors-02-ws.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-errors-01-sexp.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-04-repl.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-03-macros.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-02-ws.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-lang-01-sexp.rkt.log | Removes benchmark failure log content. |
| racket/prologos/data/benchmarks/failures/test-functor-ws.rkt.log | Removes benchmark failure log content. |
| docs/tracking/MASTER_ROADMAP.org | Adds roadmap entry for Improved Implicit Inference (#20) completion. |
| docs/tracking/2026-02-22_IMPROVED_IMPLICIT_INFERENCE.org | Marks design as DONE and documents implementation details + follow-ups. |
| docs/spec/grammar.org | Updates spec grammar documentation to present the bare implicit form as canonical. |
| .claude/rules/prologos-syntax.md | Updates contributor guidance to prefer bare implicit variables in spec. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Closes the planned-but-unimplemented work from
`docs/tracking/2026-02-22_IMPROVED_IMPLICIT_INFERENCE.org`.
**Direction 1.** Bare capitalized identifiers in a `spec` are auto-
introduced as kind-`Type` implicit binders. `{A : Type}` is no longer
needed.
**Direction 2.** Higher-kinded variables get their kind inferred from
`:where` and inline trait constraints. `{C : Type -> Type}` is no longer
needed when a `Seqable C` / `Buildable C` constraint pins the kind.
Three changes in `macros.rkt`:
1. The keyword-headed-children merge in `process-spec` flattens single-
element `:where (Foo A)` into the bare constraint `(Foo A)` and crashes
`expand-bundle-constraints` at `(car 'Foo)`. Fixed by keeping known
list-valued keys (`:where`, `:properties`, `:laws`, `:includes`,
`:examples`, `:see-also`, `:implicits`) as lists.
2. After `propagate-kinds-from-constraints`, the auto-detected portion of
the binder list is now sorted by kind (kind-`Type` first, then higher-
kinded). This matches the convention `{A B : Type} {C : Type -> Type}`
that explicit-binder users have written for years and keeps the
inserted-implicit-arg order stable when callers omit explicit binders.
Explicit and `:over` binders keep their declared order.
3. New `kind-rank` / `implicit-binder-kind-ranks-before?` helpers; new
`auto-detected-names` accumulator threaded through the refinement
pipeline.
Stdlib refactor: redundant `{A : Type}`, `{A B : Type}`, `{K V : Type}`,
and `{C : Type -> Type}` binders dropped from spec lines across 17 files
in `core/` + `book/` + `data/`. The two specs `map-merge-with` and
`map-lattice-leq` retain explicit `{K V : Type}` because the Map-K-V
Lattice impl bodies pass `K V` as explicit type args; source-walk-order
auto-detection (which sees V first in `[V V -> V]`) would silently flip
the call-site argument order. Inline comments document the caveat.
Tests: 3 new cases in `test-extended-spec.rkt` covering the issue's
target form (`spec gmap [A -> B] -> [C A] -> [C B] :where (Seqable C)
(Buildable C)`), bare-vs-explicit idempotence, and the single-constraint
inline `:where` regression. All 15 affected test files (296 tests) and
all 19 spec/elaborator/HKT/trait test files (389 tests) pass.
Docs: `docs/spec/grammar.org` and `.claude/rules/prologos-syntax.md`
updated to document the canonical bare form; design doc flipped
PLANNED → DONE; Master Roadmap entry added.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW
data: refresh test timings + propagator-cache + failure logs
Build artifacts from the issue #20 verification runs. The failure logs
are all pre-existing infrastructure issues (`prologos/propagator` and
`rackcheck` collection imports unresolvable in this sandbox without the
`prologos` package installed and rackcheck wired in) — none are caused
by the spec / auto-introduction changes.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW
data: drop stale + environment-only failure logs
The previous commit (a254cda) committed 17 failure logs that were a mix
of stale and resolvable:
- 9 logs referenced `/Users/avanti/dev/projects/prologos/...` paths
(the user's local Mac tree), for tests that don't even exist in this
repo — purely stale.
- 6 logs (test-attribute-record, test-facet-tag-dispatch,
test-meta-feedback, test-ppn-track4, test-propagator-patterns,
test-sre-coverage) failed with "collection not found: prologos/
propagator" because the `prologos` collection wasn't linked in this
sandbox. Fixed by `raco link --user --name prologos racket/prologos`;
all 6 now pass (91 tests total).
- 2 logs (test-generators, test-properties) genuinely require the
external `rackcheck` package, which can't be installed here because
the package catalog (download.racket-lang.org/releases/9.0/catalog)
returns 403 and github.com clones are blocked from this sandbox.
These are not real failures of the codebase — only of the sandbox's
network reachability — and they're orthogonal to issue #20.
Net change: drop all 17 stale logs. The 2 rackcheck-blocked tests will
fail again on any machine without rackcheck installed; they're a known
external-dep gap, not introduced or affected by this branch.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW
data: revert all benchmark/failures/ diffs to match main
Restore the 9 stale failure logs that were on main before this branch.
The previous two commits (a254cda, dbd42c9) churned this directory
unnecessarily; this commit makes the branch's net diff for
racket/prologos/data/benchmarks/failures/ empty against main.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW
spec: address PR #43 review comments
1. kind-rank: rank ANY (Type n) as 0, not just (Type 0). Forward-
defensive against universe-level inference producing (Type 1+) for
auto-introduced binders — those would previously have fallen to the
"elaborate" rank and sorted after higher-kinded arrows.
2. Drop the racket/prologos/data/cache/pnet/prologos/data/nat.pnet diff.
The file embeds an absolute build path + timestamp; the cache directory
is already in .gitignore (the file is tracked from before the ignore
rule). The diff was pure path/timestamp churn with no semantic change.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW
kumavis
force-pushed
the
claude/fix-issue-20-Acv5D
branch
from
May 1, 2026 03:50
30d484e to
4dccebe
Compare
kumavis
pushed a commit
that referenced
this pull request
May 19, 2026
Cross-impl check against @endo/ocapn revealed that Phase 52b's dedicated op:deposit-gift / op:withdraw-gift wire ops are NOT the canonical OCapN model. Endo dispatches gift handoff as method calls on the bootstrap object (export 0) with signed HandoffReceive envelopes — not as dedicated CapTPOp variants. Our wire ops are a Prologos extension. The gift TABLE (Phase 52) is unaffected; only the wire-level surface (Phase 52b) is in question. Three resolution paths logged in roadmap: (a) revert + redesign as bootstrap-method dispatch (b) keep as fast-path + add bootstrap-method dispatch alongside (c) document deviation, defer decision Pitfall #43 logged: wire-format invented before checking peer reference impl. The workflow rule "external cross-impl gates are mandatory test infrastructure for protocol ports" was violated — Phase 52b's tests were all hand-written internal round-trips, no @endo/ocapn peer was consulted. Codified the prevention: Phase 0 of any wire-extension phase is "search the reference implementation for the wire shape." https://claude.ai/code/session_01YM6gc3cMNH2Ymor4jdZY8u
kumavis
pushed a commit
that referenced
this pull request
May 19, 2026
…+ cross-impl gate The previous Phase 52b shipped dedicated op:deposit-gift / op:withdraw-gift wire ops. Those are NOT the OCapN canonical model — @endo/ocapn dispatches gift handoff as METHOD CALLS on the bootstrap object (export 0), inside the normal op:deliver flow (see @endo/ocapn/src/client/ocapn.js:528+). This commit reverts the non-canonical surface and re-implements the dispatch in the spec-compatible form. REVERTED from prior 52b (commit 6d10c58): - op-deposit-gift / op-withdraw-gift CapTPOp variants (all 4 predicates + 4 selectors + encoder + decoder + dispatch) - dedicated wire tags op:deposit-gift / op:withdraw-gift - 11 internal-only tests that exercised the non-canonical shape ADDED (canonical bootstrap-method dispatch): - maybe-bootstrap-method gateway in captp-bridge: when an op-deliver arrives with target=0 and args is a syrup-list starting with a recognised method-symbol, route to the gift handlers; otherwise fall through to the normal op-deliver dispatch path. - dispatch-deposit-gift-rest / dispatch-withdraw-gift-rest: extract gid (Nat) + refr/resolver from the args tail. - do-deposit-gift / do-withdraw-reply: the actual gift-table mutations + reply-bytes queueing. - syrup-list-or-nil + syrup-symbol-name: 1-arg shape filters that let callers avoid 11-arm SyrupValue match enumeration. Wire shape now matches @endo/ocapn: Deposit: <op:deliver <desc:export 0> (sym deposit-gift, gid+, <desc:export xid+>) false false> Withdraw: <op:deliver <desc:export 0> (sym withdraw-gift, gid+) <desc:answer ap+> false> Reply: <op:deliver <desc:answer ap+> <desc:export xid+> false false> (Reply uses the standard op:deliver-to-answer path — peer's local promise tied to ap resolves with the gift refr.) The gift TABLE infrastructure from Phase 52 (bs-add-gift, bs-lookup-gift, bs-remove-gift) is UNCHANGED — it was always correct; only the wire-surface layer needed revision. Cross-impl gate (new): peer-bootstrap-gift.mjs receives our 3-frame session+deposit+withdraw blob, decodes via @endo/ocapn's Syrup decoder, verifies the structural shape matches what @Endo would treat as canonical bootstrap-method dispatch. The wire-shape validation is what's tested; @Endo's deposit-gift / withdraw-gift HANDLERS aren't exercised (they require signed HandoffReceive envelopes + key-pair management beyond Phase 52b's scope). Pitfall discovered & worked around: @Endo's syrup decoder prefixes decoded symbols with a "syrup:" namespace (Symbol with description "syrup:deposit-gift" rather than "deposit-gift"). The peer's isSymWithSuffix accepts both forms — defensive against future namespace changes. Not codified as a goblin-pitfall since it's an @endo/JS-decoder quirk, not Prologos. Tests (149 bridge + 9 new bootstrap-dispatch tests + 1 interop): - deposit-gift via op:deliver to bootstrap records the gift - records correct gid→xid mapping - non-export refr is silent drop - withdraw-gift looks up + queues reply - unknown gid is silent drop - no answer-pos is silent drop (no reply channel) - reply wire shape: op:deliver to desc:answer with desc:export gift - non-bootstrap target falls through (regression) - unknown method symbol falls through (regression) - cross-impl: @Endo decodes our 3-frame blob and confirms shape Pitfall #43 (Wire-format invented before checking peer reference impl) reverted from goblin-pitfalls — that's an OCapN methodology lesson, not a Prologos language/tooling bug. Goblins doc focuses on Prologos-specific issues. https://claude.ai/code/session_01YM6gc3cMNH2Ymor4jdZY8u
kumavis
pushed a commit
that referenced
this pull request
Jul 27, 2026
… cells Root cause of the cache-unsoundness finding, confirmed on a minimal repro and on the real OCapN case. Two-writer inconsistency. Registry READERS are cell-primary (macros.rkt:6300 read-ctor-registry consults the cell, falling back to the parameter only when no cell exists). The normal elaboration writer dual-writes (macros.rkt:6294 register-ctor!). The .pnet cache-hit restore (driver.rkt:2637-2642, same shape through :2705) writes ONLY the parameter — no macros-cell-write! in that branch — so every restored registry entry is invisible to every reader. The .pnet file is fine; pnet-serialize.rkt serializes and deserializes the registries intact. The restore writes to the wrong place. It was demoted, not written wrong: cell-primary readers landed 7fec375 (2026-03-18), the merge landed 2ef600b (2026-03-24) — written against the parameter API six days after the readers stopped reading parameters. The sibling spec-propagation path in the same file (driver.rkt:2969-2976) got it right. Severity range from one defect: silent stuck [reduce ...] term -> silent wrong answer (a non-first match arm becomes unreachable) -> hard "Type mismatch" at module load with a partially-populated cache. Likely explains previously-unexplained flaky module-load failures. Scope is general, not OCapN-specific: 8-line repro with one data + one defn; 14 of 17 registries on that path are affected (trait and impl restoration drop identically). Subsumes the transitive-import BehaviorTag degradation as the same defect, proven with a two-module process-file repro. main is green for three independent accidents, not correctness: pnet-compile only emits prelude .pnet; batch-worker disables .pnet writes; test-support re-inits the macros cells after the prelude load, healing exactly those entries. The one cache-hit test uses only def + map literals, so it covers the unaffected surface. Also records the REFUTED hypothesis (module-network-ref's unserialized imports field is not the cause) so it is not re-chased, three candidate fixes with tradeoffs, the mandatory regression coverage, and an adjacent bug: pnet-stale? has no transitive-dependency hashing. Investigation only — no fix applied. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YM6gc3cMNH2Ymor4jdZY8u
kumavis
pushed a commit
that referenced
this pull request
Jul 27, 2026
…e CALLER's imports Reproducible, and after #43 the most severe entry in this log. Identical frames, identical call sequence, fresh connection id, differing only in the calling namespace's preamble: minimal preamble fetch=71 deliver=0 larger preamble fetch=71 deliver=41 step-connection lives in interop-driver, which BOTH preambles import identically; the extra modules are unused by the probe. Yet one emits bytes and the other silently does not. Eliminated first, each by experiment: nondeterminism (three processes agree per configuration), reduction fuel (100x no change), argument shape, connection id, in-process ordering. This breaks the guarantee that an exported function means the same thing to every caller, and it fails SILENTLY — a well-typed empty result, nothing wrong at the call site. Signature matches issue #78 ("cached module loads give you functions that don't fire"), so they may be one defect. Caveat recorded in the entry: adding the two differing modules to the OCapN server preamble did NOT fix the server, so the import set is a lever on the behaviour but not the complete rule. That change is reverted, not landed. This is the OCapN blocker's actual character: a compiler/module-resolution defect, not missing protocol code. The Phase 59b protocol work is sound — every component emits when driven directly. No tests: documentation only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YM6gc3cMNH2Ymor4jdZY8u
kumavis
pushed a commit
that referenced
this pull request
Jul 28, 2026
…net restore supersede two of my fixes Merged rather than rebased: this branch has integrated main by merge twice before (7f0b920, 1c90206), it carries 178 commits, and the divergence includes an ADD/ADD conflict on a file BOTH sides created independently. A rebase buys nothing for the goal (main's suite-perf work) at materially more risk. Three conflicts, all resolved toward main, and in two cases because main did the same work better: - loose-bvar.rkt (ADD/ADD). Both branches independently wrote a looseBVarRange short-circuit — mine at 4f6b3f0 (pitfall #31), main's at 94cfbcb (#58 P3, 308 lines). Took main's: it is more developed and, on the point my 250f331 fixed, ALREADY CORRECT — its pair case walks BOTH halves, so the association-pair under-report that made `shift` silently no-op on expr-Record never existed there. It also ships a differential-oracle walk. My 250f331 is therefore redundant against main and is dropped with it. My tests/test-loose-bvar-coverage.rkt is KEPT and passes against main's implementation. It now guards main's code: 8 assertions pinning each container shape (assoc pair, vector, hash, box) plus shift's cutoff and binder-depth behaviour on records. - substitution.rkt. My changes were only the pitfall #31 short-circuit and eq-preservation; main's #58 P1 (delta=0 early-out) + P3 supersede them. Took main's. - driver.rkt, registry-restore block. I had hand-written per-registry dual-writes to fix pitfall #43 (.pnet cache-hit restoring parameters but not cells); main's #78 P2/P3 replaced that with ONE table (`restore-registries! (pnet-restore-rows …)`) plus a cell-coverage gate, and serialized 7 registries I had not. Took main's side of the conflict only — my Racket-version compat fence for `thread #:pool 'own` (~line 562) merged cleanly and is preserved. Verified after merge: test-loose-bvar-coverage, test-record-node, test-substitution, test-substitution-scaling and test-typing-fuel-scoping all green (109 tests). My typing-fuel contradiction-scoping fix survives. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: 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 #20
Closes the planned-but-unimplemented work from
docs/tracking/2026-02-22_IMPROVED_IMPLICIT_INFERENCE.org.Direction 1. Bare capitalized identifiers in a
specare auto-introduced as kind-
Typeimplicit binders.{A : Type}is no longerneeded.
Direction 2. Higher-kinded variables get their kind inferred from
:whereand inline trait constraints.{C : Type -> Type}is no longerneeded when a
Seqable C/Buildable Cconstraint pins the kind.Three changes in
macros.rkt:The keyword-headed-children merge in
process-specflattens single-element
:where (Foo A)into the bare constraint(Foo A)and crashesexpand-bundle-constraintsat(car 'Foo). Fixed by keeping knownlist-valued keys (
:where,:properties,:laws,:includes,:examples,:see-also,:implicits) as lists.After
propagate-kinds-from-constraints, the auto-detected portion ofthe binder list is now sorted by kind (kind-
Typefirst, then higher-kinded). This matches the convention
{A B : Type} {C : Type -> Type}that explicit-binder users have written for years and keeps the
inserted-implicit-arg order stable when callers omit explicit binders.
Explicit and
:overbinders keep their declared order.New
kind-rank/implicit-binder-kind-ranks-before?helpers; newauto-detected-namesaccumulator threaded through the refinementpipeline.
Stdlib refactor: redundant
{A : Type},{A B : Type},{K V : Type},and
{C : Type -> Type}binders dropped from spec lines across 17 filesin
core/+book/+data/. The two specsmap-merge-withandmap-lattice-leqretain explicit{K V : Type}because the Map-K-VLattice impl bodies pass
K Vas explicit type args; source-walk-orderauto-detection (which sees V first in
[V V -> V]) would silently flipthe call-site argument order. Inline comments document the caveat.
Tests: 3 new cases in
test-extended-spec.rktcovering the issue'starget form (
spec gmap [A -> B] -> [C A] -> [C B] :where (Seqable C) (Buildable C)), bare-vs-explicit idempotence, and the single-constraintinline
:whereregression. All 15 affected test files (296 tests) andall 19 spec/elaborator/HKT/trait test files (389 tests) pass.
Docs:
docs/spec/grammar.organd.claude/rules/prologos-syntax.mdupdated to document the canonical bare form; design doc flipped
PLANNED → DONE; Master Roadmap entry added.
https://claude.ai/code/session_01UEKqhSHN5y9XEg88BkFnsW