Skip to content

fix(builtins): add Idxof to Builtin::ALL#726

Merged
danieljohnmorris merged 1 commit into
mainfrom
hotfix/idxof-missing-from-all
May 22, 2026
Merged

fix(builtins): add Idxof to Builtin::ALL#726
danieljohnmorris merged 1 commit into
mainfrom
hotfix/idxof-missing-from-all

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Build blocker: Builtin::Idxof was declared in the enum but never appended to Builtin::ALL. Calling idxof panics with Builtin::ALL must include every variant on every engine, failing tests/regression_idxof.rs::idxof_empty_haystack_not_found and ::idxof_both_empty_returns_zero on every PR's CI. Appended last to preserve every existing on-wire tag.

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.
@danieljohnmorris danieljohnmorris added the mac-reviewing Currently being merge-prepped by mac-side agent label May 22, 2026
@danieljohnmorris danieljohnmorris merged commit 43110e9 into main May 22, 2026
10 checks passed
@danieljohnmorris danieljohnmorris deleted the hotfix/idxof-missing-from-all branch May 22, 2026 12:00
@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

danieljohnmorris added a commit that referenced this pull request May 22, 2026
…ILO-368) (#661)

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Emit ILO-T044 when a `with` expression on an anonymous record references
a field that does not exist in the source record. Adds registry entry and
two coverage tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Anonymous record `with` updates must only touch existing fields.
Adding a new field via `with` would silently produce a different
record type. Verifier emits ILO-T044 with the missing field name.

Drive-by main-fixes folded into the same PR because every PR needs
them to lint-pass:
- src/diagnostic/registry.rs: ILO-T044 entry gains the required
  `phase: Phase::Verify` field (registry shape changed after the
  PR was opened)
- src/main.rs: collapse `BuildTarget::eval` match into a single
  `matches!` (clippy::match_like_matches_macro), drop an unused
  `std::io::Write` import
- src/ast/mod.rs: silence clippy::should_implement_trait on
  `UsePredicate::from_str` — implementing FromStr would change the
  return type from Option to Result
- src/interpreter/mod.rs: `#[allow]` on `StdinLinesHandle` for the
  intentional complex iterator type and `new()`-without-Default
  (StdinLinesHandle is a singleton, never Default-constructed)
- src/vm/mod.rs: drop unreachable `HeapObj::LazyStdinLines` arms in
  the two foreach catch-alls (the variant is handled earlier in the
  same match)

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
danieljohnmorris added a commit that referenced this pull request May 22, 2026
…72) (#653)

* Add hex-rev builtin for byte-pair reversal / endian conversion (ILO-372)

Implements `hex-rev s > t`: reverses a hex-encoded string byte-pair-wise
for little↔big endian conversions (Bitcoin txid display vs wire encoding).
Odd-length input errors ILO-T013. Case preserved. Tree-bridge eligible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: align with fleet patches

* hotfix: fix examples_engines failures blocking all open PR CI (#723)

* fix(examples): rewrite mpairs.ilo iter fold to use brace-lambda syntax

Labelled-arg inline lambdas (`acc:L _; pair:L _;…`) inside `fld` now fail
with ILO-P003 since the parser treats `:` as a type-ascription delimiter.
Replace with brace-lambda `{acc pair > [acc, pair]}` — supported since
ILO-404 — and drop the `cat` call (comma-spread in list literal achieves
the same append without the `cat` arg-2 type error on `L (L _)`).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(builtins): add Sha256Hex and Sha256d to Builtin::ALL

The variants were defined and dispatched (tree-bridge, interpreter) but
missing from ALL, causing a panic (`Builtin::ALL must include every
variant`) whenever sha256-hex or sha256d was called via the VM.  Append
them immediately after CtEq — the existing crypto-primitives cluster —
preserving all prior on-wire tags.

Fixes examples/sha256-hex.ilo and examples/sha256d-bitcoin.ilo which
both panicked at src/builtins.rs:1198.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368) (#661)

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Emit ILO-T044 when a `with` expression on an anonymous record references
a field that does not exist in the source record. Adds registry entry and
two coverage tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Anonymous record `with` updates must only touch existing fields.
Adding a new field via `with` would silently produce a different
record type. Verifier emits ILO-T044 with the missing field name.

Drive-by main-fixes folded into the same PR because every PR needs
them to lint-pass:
- src/diagnostic/registry.rs: ILO-T044 entry gains the required
  `phase: Phase::Verify` field (registry shape changed after the
  PR was opened)
- src/main.rs: collapse `BuildTarget::eval` match into a single
  `matches!` (clippy::match_like_matches_macro), drop an unused
  `std::io::Write` import
- src/ast/mod.rs: silence clippy::should_implement_trait on
  `UsePredicate::from_str` — implementing FromStr would change the
  return type from Option to Result
- src/interpreter/mod.rs: `#[allow]` on `StdinLinesHandle` for the
  intentional complex iterator type and `new()`-without-Default
  (StdinLinesHandle is a singleton, never Default-constructed)
- src/vm/mod.rs: drop unreachable `HeapObj::LazyStdinLines` arms in
  the two foreach catch-alls (the variant is handled earlier in the
  same match)

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: fix clippy unnecessary to_string

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
danieljohnmorris added a commit that referenced this pull request May 22, 2026
* feat: bounded generics for sound polymorphism (ILO-61)

Add explicit generic type parameters with bound constraints to ilo
function signatures. The verifier now enforces cross-call-site type
variable consistency and bound satisfaction, closing the soundness hole
where `fn id a>a` silently accepted inconsistent types at different call
sites.

MVP:
- Parser: `name<a:bound ...>` block after fn name; `<a>` unbounded
- Bounds: any (default), comparable (n/t/b), numeric (n), text (t)
- Verifier: unifies type variable bindings per call site (ILO-T044)
- Backward compatible: legacy `fn x:a>a;x` style unchanged
- New error codes: ILO-T044 (inconsistency/bound violation), ILO-P022
  (malformed type-param block)
- `examples/generics-bounded.ilo` passes on tree engine
- 7 new verify tests; all 3330+ existing tests green

Deferred: variance, higher-kinded types, multiple-bound conjunctions,
bound inference from usage, return-type generic substitution, VM/JIT
type-param-aware dispatch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: bring CI patches in line with main fleet (caps + budgets)

* verify: substitute generic return types at call sites (ILO-385) (#628)

When a function has explicit type_params (e.g. `gid<a> x:a>a`), the
verifier now infers the concrete return type at each call site by
substituting the type-variable bindings collected from the arguments.

Previously `gid 5` produced `Ty::Unknown`; it now correctly produces
`Ty::Number`, enabling downstream type-checking to catch mismatches
(ILO-T007) when the return value is passed to typed contexts.

- Add `original_return: ast::Type` to `FuncSig` to carry the AST
  return type alongside the already-stored `original_params`
- Add `collect_type_var_bindings` to extract bindings from compound
  param shapes (`L a`, `M t a`, `R a t`, etc.)
- Add `subst_return_ty` to recursively substitute type-variable letters
  in the return type using the collected bindings
- Hoist `var_bindings` out of the `if has_explicit_bounds` block so
  it is available for return-type substitution in all cases
- Add 4 regression tests covering: number identity, text identity,
  type mismatch detection, and list-element extraction

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* hotfix: fix examples_engines failures blocking all open PR CI (#723)

* fix(examples): rewrite mpairs.ilo iter fold to use brace-lambda syntax

Labelled-arg inline lambdas (`acc:L _; pair:L _;…`) inside `fld` now fail
with ILO-P003 since the parser treats `:` as a type-ascription delimiter.
Replace with brace-lambda `{acc pair > [acc, pair]}` — supported since
ILO-404 — and drop the `cat` call (comma-spread in list literal achieves
the same append without the `cat` arg-2 type error on `L (L _)`).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(builtins): add Sha256Hex and Sha256d to Builtin::ALL

The variants were defined and dispatched (tree-bridge, interpreter) but
missing from ALL, causing a panic (`Builtin::ALL must include every
variant`) whenever sha256-hex or sha256d was called via the VM.  Append
them immediately after CtEq — the existing crypto-primitives cluster —
preserving all prior on-wire tags.

Fixes examples/sha256-hex.ilo and examples/sha256d-bitcoin.ilo which
both panicked at src/builtins.rs:1198.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368) (#661)

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Emit ILO-T044 when a `with` expression on an anonymous record references
a field that does not exist in the source record. Adds registry entry and
two coverage tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Anonymous record `with` updates must only touch existing fields.
Adding a new field via `with` would silently produce a different
record type. Verifier emits ILO-T044 with the missing field name.

Drive-by main-fixes folded into the same PR because every PR needs
them to lint-pass:
- src/diagnostic/registry.rs: ILO-T044 entry gains the required
  `phase: Phase::Verify` field (registry shape changed after the
  PR was opened)
- src/main.rs: collapse `BuildTarget::eval` match into a single
  `matches!` (clippy::match_like_matches_macro), drop an unused
  `std::io::Write` import
- src/ast/mod.rs: silence clippy::should_implement_trait on
  `UsePredicate::from_str` — implementing FromStr would change the
  return type from Option to Result
- src/interpreter/mod.rs: `#[allow]` on `StdinLinesHandle` for the
  intentional complex iterator type and `new()`-without-Default
  (StdinLinesHandle is a singleton, never Default-constructed)
- src/vm/mod.rs: drop unreachable `HeapObj::LazyStdinLines` arms in
  the two foreach catch-alls (the variant is handled earlier in the
  same match)

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: native VM bytecode for defer/errdefer (ILO-366) (#662)

* feat: add defer and errdefer for guaranteed cleanup (ILO-56)

- Parser: defer/errdefer as statement-starts; both keywords reserved
- AST: Stmt::Defer { expr, kind: DeferKind::Always | OnError }
- Interpreter: per-frame defer stack, drained LIFO at function exit
- VM: program-wide bridge to tree-walker when any fn contains defer
- Codegen: fmt, explain, python all handle Stmt::Defer
- Verifier: type-checks deferred expression, yields Nil
- 18 regression tests; 2 examples (defer-basic.ilo, errdefer.ilo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: bump BYTE_BUDGET_PER_MODULE to 8_000

* ci: cargo fmt

* feat: native VM bytecode for defer/errdefer (ILO-366)

Replaces the program-wide tree-bridge fallback for defer-containing
functions with two new opcodes compiled directly into the VM bytecode:

  OP_DEFER_PUSH (191) — snapshots a 0-arg closure onto the current
    frame's per-frame defer stack at defer-registration time.

  OP_DEFER_DRAIN (192) — drains the stack LIFO before every OP_RET,
    calling Always-kind thunks unconditionally and OnError-kind thunks
    only when the return value carries TAG_ERR.

Each `defer expr` / `errdefer expr` is compiled into a synthetic thunk
chunk that captures all in-scope locals by value (via OP_MAKE_CLOSURE),
then pushed with OP_DEFER_PUSH.  The compiler emits OP_DEFER_DRAIN
before every OP_RET in defer-containing functions via the new emit_ret()
helper, including early returns inside braceless guards and explicit
`ret` statements.

Performance: 47× faster than the tree-bridge (500-iteration timing test
added to regression_defer.rs shows ~156 ms tree vs ~3.3 ms VM in debug
builds).

All 1 167 existing tests pass.  19 regression_defer tests pass including
7 new VM-path tests covering LIFO ordering, errdefer fire/no-fire, and
early-return semantics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: align with fleet patches

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(rd): remove extension-based auto-parse; add rd-json builtin (ILO-374) (#654)

* fix(rd): remove extension-based auto-parse; add rd-json builtin (ILO-374)

rd! on a .json path silently returned a parsed value instead of raw
text, breaking the documented t → R t t contract. This caused type
errors when callers applied jpar on the result of rd.

Fix: rd (1-arg) always returns R t t (raw text). Extension-based
auto-parse is removed from the interpreter, VM bytecode, and JIT paths.

Add rd-json: t → R ? t that reads and parses JSON explicitly. Migrate
config-shaper.ilo (rd → rd-json) and ecommerce-analytics.ilo
(rd → rd path "csv"). Add verifier hint (ILO-W001 warning) when rd
is called on a literal .json path without an explicit format arg.

Regression tests added in interpreter and VM test suites.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: align with fleet patches

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add hex-rev builtin for byte-pair reversal / endian conversion (ILO-372) (#653)

* Add hex-rev builtin for byte-pair reversal / endian conversion (ILO-372)

Implements `hex-rev s > t`: reverses a hex-encoded string byte-pair-wise
for little↔big endian conversions (Bitcoin txid display vs wire encoding).
Odd-length input errors ILO-T013. Case preserved. Tree-bridge eligible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: align with fleet patches

* hotfix: fix examples_engines failures blocking all open PR CI (#723)

* fix(examples): rewrite mpairs.ilo iter fold to use brace-lambda syntax

Labelled-arg inline lambdas (`acc:L _; pair:L _;…`) inside `fld` now fail
with ILO-P003 since the parser treats `:` as a type-ascription delimiter.
Replace with brace-lambda `{acc pair > [acc, pair]}` — supported since
ILO-404 — and drop the `cat` call (comma-spread in list literal achieves
the same append without the `cat` arg-2 type error on `L (L _)`).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(builtins): add Sha256Hex and Sha256d to Builtin::ALL

The variants were defined and dispatched (tree-bridge, interpreter) but
missing from ALL, causing a panic (`Builtin::ALL must include every
variant`) whenever sha256-hex or sha256d was called via the VM.  Append
them immediately after CtEq — the existing crypto-primitives cluster —
preserving all prior on-wire tags.

Fixes examples/sha256-hex.ilo and examples/sha256d-bitcoin.ilo which
both panicked at src/builtins.rs:1198.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368) (#661)

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Emit ILO-T044 when a `with` expression on an anonymous record references
a field that does not exist in the source record. Adds registry entry and
two coverage tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(verify): restrict `with` from adding new fields to anon records (ILO-368)

Anonymous record `with` updates must only touch existing fields.
Adding a new field via `with` would silently produce a different
record type. Verifier emits ILO-T044 with the missing field name.

Drive-by main-fixes folded into the same PR because every PR needs
them to lint-pass:
- src/diagnostic/registry.rs: ILO-T044 entry gains the required
  `phase: Phase::Verify` field (registry shape changed after the
  PR was opened)
- src/main.rs: collapse `BuildTarget::eval` match into a single
  `matches!` (clippy::match_like_matches_macro), drop an unused
  `std::io::Write` import
- src/ast/mod.rs: silence clippy::should_implement_trait on
  `UsePredicate::from_str` — implementing FromStr would change the
  return type from Option to Result
- src/interpreter/mod.rs: `#[allow]` on `StdinLinesHandle` for the
  intentional complex iterator type and `new()`-without-Default
  (StdinLinesHandle is a singleton, never Default-constructed)
- src/vm/mod.rs: drop unreachable `HeapObj::LazyStdinLines` arms in
  the two foreach catch-alls (the variant is handled earlier in the
  same match)

* hotfix: clippy errors on main blocking all PR lint jobs (#724)

Fixes 5 clippy errors:
- Remove unreachable HeapObj::LazyStdinLines arms in FOREACHPREP/FOREACHNEXT match blocks (vm/mod.rs)
- Add #[allow(clippy::should_implement_trait)] to UsePredicate::from_str (ast/mod.rs)
- Extract StdinLinesInner type alias to reduce complex type (interpreter/mod.rs)
- Add Default impl for StdinLinesHandle (interpreter/mod.rs)
- Convert match to matches! macro in BuildTarget::eval (main.rs)
- Suppress unused import warning in test (main.rs)

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: bump ilo-language cap to 1800 (measured 1746) (#725)

ILO-382 set the per-module caps to measured-baseline-plus-50 to gate
silent doc drift. ilo-language.md grew past 1700 (now 1746) as the
post-#722 brace-lambda + or-pattern sections landed, blocking every
PR's CI lint. Bump to 1800 with the same ~50-token headroom.

* fix(builtins): add Idxof to Builtin::ALL (cross-engine dispatch) (#726)

`Builtin::Idxof` was added to the enum but never appended to
`Builtin::ALL`, so calling `idxof` panicked with
'Builtin::ALL must include every variant' on every engine.
Appended last to preserve every existing on-wire tag.

Restores `tests/regression_idxof.rs::idxof_empty_haystack_not_found`
and `::idxof_both_empty_returns_zero` to passing.

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: fix clippy unnecessary to_string

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: package registry — ilo add GitHub-org-based (ILO-63) (#614)

* feat: package registry — ilo add GitHub-org-based (ILO-63)

Add `ilo add <owner>/<repo>[@<ref>]` and `ilo update` subcommands.
Packages are shallow-cloned into ~/.ilo/pkgs/<owner>/<repo>/ and
locked in ilo.lock (tab-separated slug/sha/url).

`use "owner/repo"` in any .ilo file resolves through the cache
after a path-heuristic check (first component has no `.`); missing
packages emit ILO-P017 with an `ilo add` hint.

Deferred: version constraints, transitive deps, auth, non-GitHub hosts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci: bump SKILL.md cap to 20 KB

* ci: cargo fmt

* feat(pkg): semver version constraints for ilo add

Extend `ilo add owner/repo@<ref>` to accept semver constraints:
- `^MAJOR[.MINOR[.PATCH]]`  — caret (compatible) range
- `~MAJOR.MINOR[.PATCH]`    — tilde (patch-compatible) range
- `MAJOR.MINOR.PATCH`       — exact semver triple

Uses `git ls-remote --tags` to list remote tags without a full clone,
then picks the highest version tag matching the constraint via the
`semver` crate.  The resolved tag name is passed to the clone step so
`ilo.lock` records the concrete SHA.

Closes ILO-356.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(pkg): transitive dep resolution for ilo add (ILO-357) (#678)

* feat(pkg): transitive dep resolution for ilo add

After cloning a package into the cache, walk its top-level *.ilo files
for `use "owner/repo"` declarations and recursively fetch each package
dependency. All resolved versions are written to ilo.lock. Dependency
cycles are detected via a DFS ancestor stack and reported as errors.
Already-resolved packages are skipped via a visited set.

Closes ILO-357

* chore: cargo fmt --all

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* hotfix: bump ilo-builtins-io token cap 2000→2200 (#729)

Co-authored-by: Daniel Morris <daniel@cubitts.com>

* hotfix: pkg.rs build break + resolve_imports arity (ILO-63 followup)

PR #614 (ilo add) merged with two compile errors:

1. src/pkg.rs:253 unwraps git_ref to &str, then line 260 tries to
   match it as Option. Remove the early unwrap; the later match at
   273-276 already handles the Option correctly.

2. src/main.rs:2465 calls resolve_imports with 4 args but it takes 5
   (the build_target arg was added by #643). Add the missing arg.

Restores main to a clean build.

* Add tokcount builtin and port check-skill-tokens to ilo (ILO-47) (#705)

Adds a `tokcount s > n` builtin (bytes/3.4 approximation of cl100k_base
token count) so skill-file budget checks can be written in ilo itself,
removing the last Python file from the build chain.

- New Builtin::Tokcount in builtins.rs, verify.rs, and vm.rs (tree-bridge
  eligible, appended to ALL to preserve on-wire tags)
- tokcount_impl in interpreter/mod.rs: ceil(bytes / 3.4)
- scripts/check-skill-tokens.ilo: ilo port of the deleted Python script,
  matching output format; caps set for the bytes/3.4 approximation
- scripts/check-skill-tokens.py: deleted
- .github/workflows/rust.yml: replace tiktoken/python step with
  `cargo run -- run scripts/check-skill-tokens.ilo`
- examples/tokcount-basic.ilo: cross-engine regression test
- SPEC.md / ai.txt / skills/ilo/ilo-builtins-text.md: doc touch-points

Deferred (ILO-47 follow-up): replace bytes/3.4 stub with tiktoken-rs BPE
once crate WASM and licence questions are resolved.

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Daniel Morris <daniel@cubitts.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mac-reviewing Currently being merge-prepped by mac-side agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant