Commit Graph

1159 Commits

Author SHA1 Message Date
92f6f187b7 merge: architecture into bugs/jit-perf — Phase 1 deadline tweaks
Conflict in lib/tcl/test.sh: architecture had bumped `timeout 2400 → 7200`,
this branch had restored it to `timeout 300` based on the Phase 1
quiet-machine measurement (376/376 in 57.8s wall, 16.3s user). Resolved by
keeping `timeout 300` — the 7200s bump was preemptive against contention,
not against an actual substrate regression. Phase 1 confirms the original
180s deadline is comfortable; 300s gives 5× headroom for moderate noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 14:07:14 +00:00
c361946974 perf: deadline tweaks (tcl 2400→300s, erlang 120→600s); plan + Phase 1 findings
Phase 1 of the jit-perf-regression plan reproduced and quantified the alleged
30× substrate slowdown across 5 guests (tcl, lua, erlang, prolog, haskell). On
a quiet machine all five suites pass cleanly:

  tcl test.sh         57.8s wall, 16.3s user, 376/376 ✓
  lua test.sh         27.3s wall,  4.2s user, 185/185 ✓
  erlang conformance  3m25s wall, 36.8s user, 530/530 ✓ (needs ≥600s budget)
  prolog conformance  3m54s wall, 1m08s user, 590/590 ✓
  haskell conformance 6m59s wall, 2m37s user, 156/156 ✓

Per-test user-time at architecture HEAD vs pre-substrate-merge baseline
(83dbb595) is essentially flat (tcl 0.83×, lua 1.4×, prolog 0.82×). The
symptoms reported in the plan (test timeouts, OOMs, 30-min hangs) were heavy
CPU contention from concurrent loops + one undersized internal `timeout 120`
in erlang's conformance script. There is no substrate regression to bisect.

Changes:

* lib/tcl/test.sh: `timeout 2400` → `timeout 300`. The original 180s deadline
  is comfortable on a quiet machine (3.1× headroom); 300s gives some safety
  margin for moderate contention without masking real regressions.
* lib/erlang/conformance.sh: `timeout 120` → `timeout 600`. The 120s budget
  was actually too tight for the full 9-suite chain even before this work.
* lib/erlang/scoreboard.{json,md}: 0/0 → 530/530 — populated by a successful
  conformance run with the new deadline. The previous 0/0 was a stale
  artefact of the run timing out before parsing any markers.
* plans/jit-perf-regression.md: full Phase 1 progress log including
  per-guest perf table, quiet-machine re-measurement, and conclusion.

Phases 2–4 (bisect, diagnose, fix) skipped — there is no substrate regression
to find. Phase 6 (perf-regression alarm) still planned to catch the next
quadratic blow-up early instead of via watchdog bumps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 14:05:29 +00:00
9f539ab392 ocaml: phase 3 polymorphic variants (+4 tests, 382 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 46s
Tokenizer recognises backtick followed by an upper ident, emitting a
ctor token identical to a nominal ctor. Parser and evaluator treat
polyvariants as ctors — same tagged-list runtime. So:

  `Red                   -> ("Red")
  `Some 42               -> ("Some" 42)
  match `Red with | `Red -> 1 | `Green -> 2 | `Blue -> 3
                          -> 1
  `Pair (1,2)            -> ("Pair" 1 2) (with tuple-arg flatten)

Proper row types in HM deferred.
2026-05-08 14:03:09 +00:00
986b15c0e5 ocaml: phase 6 Float module: sqrt/sin/cos/pow/floor/ceil/round/pi (+6 tests, 378 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Wraps host SX math primitives via _float_* builtins. Float.pi is a
Float literal in the OCaml-side module.
2026-05-08 13:58:52 +00:00
0b4f5e1df9 js-on-sx: top-level this resolves to the global object
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 15s
Per ES non-strict script semantics, top-level this is the global
object (window/global/globalThis). Was throwing "Undefined symbol:
this". Two-part fix:
1. js-global-this runtime variable set to js-global after globals
   are defined; js-this falls back to it when no this is active.
2. js-eval wraps transpiled body in (let ((this (js-this))) ...)
   so JS this resolves to bound this, or top-level to global.
Fixes String(this), this.Object === Object, etc.
built-ins/Object: 46/50 → 47/50. conformance.sh: 148/148.
2026-05-08 13:55:12 +00:00
ee002f2e02 ocaml: phase 1/5/6 float arithmetic +./-./*./. (+5 tests, 372 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
Tokenizer: +. -. *. /. (with -. avoiding clash with negative float
literals). Parser table places dotted ops at int-precedence levels.
Eval routes to host SX +/-/*//. HM types them Float->Float->Float;
literal floats now infer as Float (was Int).

OCaml-style 1.5 +. 2.5 : Float works end-to-end through tokenize +
parse + eval + infer.
2026-05-08 13:55:04 +00:00
16df48ff74 ocaml: phase 6 List.combine/split/iter2/fold_left2/map2 (+4, 367 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 30s
Mechanical pair-walk OCaml implementations. failwith on length
mismatch matches Stdlib semantics. List module now covers 30+
functions.
2026-05-08 13:48:48 +00:00
46d0eb258e ocaml: phase 5.1 baseline 8/8 — quicksort + exceptions + closures
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 38s
Added 3 baseline programs:
- closures.ml — curried make_adder; verifies closure capture
- quicksort.ml — recursive sort using List.filter + List.append, sums result
- exception_handle.ml — exception NegArg of int + raise + try/with

All 8/8 baseline programs pass through ocaml-run-program. Combined the
suite exercises: let-rec, modules, refs, for-loops, pattern matching,
exceptions, lambdas, list ops (map/filter/append/fold), arithmetic.

run.sh streamlined to one sx_server invocation per program. End-to-end
runtime ≈2 min.
2026-05-08 13:44:28 +00:00
de7be332c8 ocaml: phase 5.1 baseline OCaml programs (5/5 pass) + lookahead boundary
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
lib/ocaml/baseline/{factorial,list_ops,option_match,module_use,sum_squares}.ml
exercised through ocaml-run-program (file-read F). lib/ocaml/baseline/
run.sh runs them and compares against expected.json — all 5 pass.

To make module_use.ml (with nested let-in) parse, parser's
skip-let-rhs-boundary! now uses has-matching-in? lookahead: a let at
depth 0 in a let-decl rhs opens a nested block IFF a matching in
exists before any decl-keyword. Without that in, the let is a new
top-level decl (preserves test 274 'let x = 1 let y = 2').

This is the first piece of Phase 5.1 'vendor a slice of OCaml
testsuite' — handcrafted fixtures for now, real testsuite TBD.
2026-05-08 13:33:24 +00:00
4ab79f5758 js-on-sx: parser handles comma operator (a, b, c)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 48s
Was failing with "Expected punct ')' got punct ','" because the
paren handler only consumed a single assignment. Added
jp-parse-comma-seq helpers that build a js-comma AST node with
the expression list; transpiler emits (begin ...) so each is
evaluated in order and the last value is returned.
built-ins/Object: 44/50 → 46/50. conformance.sh: 148/148.
2026-05-08 13:20:53 +00:00
756d5fba64 ocaml: phase 5 HM with user type declarations (+6 tests, 363 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
ocaml-hm-ctors is now a mutable list cell; user type-defs register
their constructors via ocaml-hm-register-type-def!. New
ocaml-type-of-program processes top-level decls in order:
- type-def: register ctors with the scheme inferred from PARAMS+CTORS
- def/def-rec: generalize and bind in the type env
- exception-def: no-op for typing
- expr: return inferred type

Examples:
  type color = Red | Green | Blue;; Red : color
  type shape = Circle of int | Square of int;;
  let area s = match s with
    | Circle r -> r * r
    | Square s -> s * s;;
  area : shape -> Int

Caveat: ctor arg types parsed as raw source strings; registry defaults
to int for any single-arg ctor. Proper type-source parsing pending.
2026-05-08 13:12:07 +00:00
5bc7895ce0 ocaml: phase 5 HM let-rec + cons / append op types (+6 tests, 357 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
ocaml-infer-let-rec pre-binds the function name to a fresh tv before
inferring rhs (which may recursively call the name), unifies the
inferred rhs type with the tv, generalizes, then infers body.

Builtin env types :: : 'a -> 'a list -> 'a list and @ : 'a list ->
'a list -> 'a list — needed because :op compiles to (:app (:app (:var
OP) L) R) and previously these var lookups failed.

Examples now infer:
  let rec fact n = if ... in fact : Int -> Int
  let rec len lst = ... in len    : 'a list -> Int
  let rec map f xs = ... in map   : ('a -> 'b) -> 'a list -> 'b list
  1 :: [2; 3]                      : Int list
  let rec sum lst = ... in sum [1;2;3] : Int

Scoreboard refreshed: 358/358 across 14 suites.
2026-05-08 13:08:51 +00:00
81247eb6ea ocaml: phase 5 HM ctor inference for option/result (+7 tests, 351 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
ocaml-hm-ctor-env registers None/Some : 'a -> 'a option, Ok/Error :
'a -> ('a, 'b) result. :con NAME instantiates the scheme; :pcon NAME
ARG-PATS walks arg patterns through the constructor's arrow type,
unifying each.

Pretty-printer renders 'Int option' and '(Int, 'b) result'.

Examples now infer:
  fun x -> Some x : 'a -> 'a option
  match Some 5 with | None -> 0 | Some n -> n : Int
  fun o -> match o with | None -> 0 | Some n -> n : Int option -> Int
  Ok 1 : (Int, 'b) result
  Error "oops" : ('a, String) result

User type-defs would extend the registry — pending.
2026-05-08 13:05:22 +00:00
d2bf0c0d00 ocaml: phase 5 HM pattern-match inference (+5 tests, 344 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
ocaml-infer-pat covers :pwild, :pvar, :plit, :pcons, :plist, :ptuple,
:pas. Returns {:type T :env ENV2 :subst S} where ENV2 has the pattern's
bound names threaded through.

ocaml-infer-match unifies each clause's pattern type with the scrutinee,
runs the body in the env extended with pattern bindings, and unifies
all body types via a fresh result tv.

Examples:
  fun lst -> match lst with | [] -> 0 | h :: _ -> h : Int list -> Int
  match (1, 2) with | (a, b) -> a + b              : Int

Constructor patterns (:pcon) fall through to a fresh tv for now —
proper handling needs a ctor type registry from 'type' declarations.
2026-05-08 13:02:15 +00:00
202ea9cf5f ocaml: phase 6 List.sort + compare (+7 tests, 339 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
compare is a host builtin returning -1/0/1 (Stdlib.compare semantics)
deferred to host SX </>. List.sort is insertion-sort in OCaml: O(n²)
but works correctly. List.stable_sort = sort.

Tested: ascending int sort, descending via custom comparator (b - a),
empty list, string sort.
2026-05-08 12:59:50 +00:00
812aa75d43 ocaml: phase 6 Hashtbl (+6 tests, 332 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Backing store is a one-element list cell holding a SX dict; keys
coerced to strings via str so int/string keys work uniformly. API:
create, add, replace, find, find_opt, mem, length.

_hashtbl_create / _hashtbl_add / _hashtbl_replace / _hashtbl_find_opt /
_hashtbl_mem / _hashtbl_length primitives wired in eval.sx; OCaml-side
Hashtbl module wraps them in lib/ocaml/runtime.sx.
2026-05-08 12:57:22 +00:00
6d7197182e ocaml: phase 5 HM tuple + list types (+7 tests, 326 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 29s
Tuple type (hm-con "*" TYPES); list type (hm-con "list" (TYPE)).
ocaml-infer-tuple threads substitution through each item left-to-right.
ocaml-infer-list unifies all items with a fresh 'a (giving 'a list for
empty []).

Pretty-printer renders 'Int * Int' for tuples and 'Int list' for lists,
matching standard OCaml notation.

Examples:
  fun x y -> (x, y) : 'a -> 'b -> 'a * 'b
  fun x -> [x; x] : 'a -> 'a list
  []                : 'a list
2026-05-08 12:54:15 +00:00
b7627b4102 js-on-sx: ToPrimitive treats functions as non-primitive
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s
Per ES, ToPrimitive only accepts strings/numbers/booleans/null
/undefined as primitives — objects AND functions trigger the next
step. Was treating function returns from toString/valueOf as
primitives (recursing to extract a string), so toString returning
a function didn't fall through to valueOf. Widened the dict-only
check to (or (= type "dict") (js-function? result)) in both
js-to-string and js-to-number ToPrimitive paths.
built-ins/String: 85/99 → 86/99. conformance.sh: 148/148.
2026-05-08 12:50:40 +00:00
88c02c7c73 ocaml: phase 6 expanded stdlib (+15 tests, 319 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
List: concat/flatten, init, find/find_opt, partition, mapi/iteri,
assoc/assoc_opt. Option: iter/fold/to_list. Result: get_ok/get_error/
map_error/to_option.

Fixed skip-to-boundary! in parser to track let..in / begin..end /
struct..end / for/while..done nesting via a depth counter — without
this, nested-let inside a top-level decl body trips over the
decl-boundary detector. Stdlib functions like List.init / mapi / iteri
use begin..end to make their nested-let intent explicit.
2026-05-08 12:49:23 +00:00
bc557a5ad2 ocaml: phase 3 exception declarations (+4 tests, 304 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
exception NAME [of TYPE] parses to (:exception-def NAME [ARG-SRC]).
Runtime is a no-op: raise/match already work on tagged ctor values, so
'exception E of int;; try raise (E 5) with | E n -> n' end-to-end with
zero new eval logic.
2026-05-08 12:37:58 +00:00
d8f6250962 ocaml: phase 3 type declarations (+5 tests, 300 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 52s
Parser: type [PARAMS] NAME = | Ctor [of T1 [* T2]*] | ...
- PARAMS: optional 'a or ('a, 'b) tyvar list
- AST: (:type-def NAME PARAMS CTORS) with each CTOR (NAME ARG-SOURCES)
- Argument types captured as raw source strings (treated opaquely at
  runtime since ctor dispatch is dynamic)

Runtime is a no-op — constructors and pattern matching already work
dynamically. Phase 5 will use these decls to register ctor types for
HM checking.
2026-05-08 12:32:39 +00:00
851e0585cf ocaml: phase 3 'as' alias + 'when' guard in match (+6 tests, 295 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Pattern parser top wraps cons-pat with 'as ident' -> (:pas PAT NAME).
Match clause parser consumes optional 'when GUARD-EXPR' before -> and
emits (:case-when PAT GUARD BODY) instead of :case.

Eval: :pas matches inner pattern then binds the alias name; case-when
checks the guard after a successful match and falls through to the next
clause if the guard is false.

Or-patterns deferred — ambiguous with clause separator without
parens-only support.
2026-05-08 12:28:07 +00:00
d51ae65bbb js-on-sx: fn.toString honours Function.prototype.toString overrides
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
Two hardcoded paths returned the native marker regardless of user
override: js-invoke-function-method and the lambda branch of
js-to-string. Both now look up Function.prototype.toString via
js-dict-get-walk and invoke it on the function, falling back to
the native marker only if no override exists.
built-ins/String: 84/99 → 85/99. conformance.sh: 148/148.
2026-05-08 12:07:55 +00:00
e97bdc4602 js-on-sx: native prototypes carry wrapped primitive marker
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 32s
Per ES, Boolean.prototype is a Boolean wrapper around false,
Number.prototype wraps 0, String.prototype wraps "". So
Boolean.prototype == false (loose-eq unwraps), and
Object.prototype.toString.call(Number.prototype) ===
"[object Number]". Set __js_*_value__ on each in post-init.
built-ins/Boolean: 23/27 → 24/27, String: 80/99 → 84/99.
conformance.sh: 148/148.
2026-05-08 11:27:18 +00:00
f03aa3056d js-on-sx: js-to-number throws TypeError on non-primitive
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 49s
Mirrors the earlier js-to-string fix. Number(obj) must throw
if ToPrimitive cannot extract a primitive (both valueOf and
toString return objects). Was returning NaN silently. Replaced
the inner (js-nan-value) fallback with (raise (js-new-call
TypeError ...)).
built-ins/Number: 45/50 → 46/50. conformance.sh: 148/148.
2026-05-08 10:53:58 +00:00
254052a43b datalog-plan: rolling status 224/224
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
2026-05-08 10:36:40 +00:00
30880927f2 datalog-plan: rolling status update (219/219, 7 demos)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s
2026-05-08 10:24:45 +00:00
4c11c4e1b9 js-on-sx: native prototypes inherit from Object.prototype
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 39s
Per ES, every native prototype's [[Prototype]] is Object.prototype
(and Function.prototype.[[Prototype]] is too). Was missing those
links, so Object.prototype.isPrototypeOf(Boolean.prototype)
returned false (the explicit isPrototypeOf walks __proto__, not
the recent fallback). Added 5 dict-set! lines to the post-init.
built-ins/Boolean: 22/27 → 23/27, built-ins/Number: 44/50 → 45/50.
conformance.sh: 148/148.
2026-05-08 10:21:05 +00:00
4a643a5c52 datalog-plan: rolling status header (208/208, all phases addressed)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s
2026-05-08 10:11:00 +00:00
5100c5d5a6 datalog-plan: tick Phase 9 federation demo (already in demo.sx)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s
2026-05-08 10:07:35 +00:00
a53e47b415 datalog: dl-magic-query driver (204/204)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s
End-to-end magic-sets entry point. Given (db, query-goal):
  - copies the caller's EDB facts (relations not headed by any
    rule) into a fresh internal db
  - adds the magic seed fact
  - adds the rewritten rules
  - saturates and runs the query
  - returns the substitution list

Caller's db is untouched. Equivalent to dl-query for any
fully-stratifiable program; intended as a perf alternative on
goal-shaped queries against large recursive relations.

2 new tests: equivalence to dl-query on chain-3 ancestor, and
non-mutation of the caller's db (rules count unchanged).
2026-05-08 10:00:44 +00:00
a080ce656c datalog: magic-sets rewriter (Phase 6, 202/202)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
dl-magic-rewrite rules query-rel adn args returns:
  {:rules <rewritten-rules> :seed <magic-seed-fact>}

Worklist over (rel, adn) pairs starts from the query and stops
when no new pairs appear. For each rule with head matching a
worklist pair:
  - Adorned rule: head :- magic_<rel>^<adn>(bound), body...
  - Propagation rules: for each positive non-builtin body lit
    at position i:
      magic_<lit-rel>^<lit-adn>(bound-of-lit) :-
        magic_<rel>^<adn>(bound-of-head),
        body[0..i-1]
  - Add (lit-rel, lit-adn) to the worklist.

Built-ins, negation, and aggregates pass through without
generating propagation rules. EDB facts are unchanged.

3 new tests cover seed structure, equivalence on chain-3 (full
closure, 6 ancestor tuples — magic helps only when the EDB has
nodes outside the seed's transitive cone), and same-query-answers
under the rewritten program. Total 202/202.

Wiring up a `dl-saturate-magic!` driver and large-graph perf
benchmarks is left for a future iteration.
2026-05-08 09:58:36 +00:00
2a01d8ac91 datalog: magic-sets building blocks (199/199)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 22s
Adds the primitives a future magic-sets rewriter will compose:

  dl-magic-rel-name rel adornment    → "magic_<rel>^<adornment>"
  dl-magic-lit rel adn bound-args    → magic literal as SX list
  dl-bound-args lit adornment        → bound-position arg values

Rewriter algorithm (worklist over (rel, adornment) pairs,
generating seed, propagation, and adorned-rule outputs) is still
TODO — these helpers are inspection-only for now.

4 new magic tests cover naming, lit construction, and bound-args
extraction (mixed/free).
2026-05-08 09:53:38 +00:00
71b73bd87e datalog: Phase 6 adornments + SIPS analysis (194/194)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
New lib/datalog/magic.sx — first piece of magic-sets:

  dl-adorn-arg arg bound          → "b" or "f"
  dl-adorn-args args bound        → adornment string
  dl-adorn-goal goal              → adornment under empty bound set
  dl-adorn-lit lit bound          → adornment of any literal
  dl-vars-bound-by-lit lit bound  → free vars this lit will bind
  dl-init-head-bound head adn     → bound set seeded from head adornment
  dl-rule-sips rule head-adn      → ({:lit :adornment} ...) per body lit

SIPS walks left-to-right tracking the bound set; recognises `is` and
aggregate result-vars as new binders, lets comparisons and negation
pass through with computed adornments.

Inspection-only — saturator doesn't yet consume these. Lays
groundwork for a future magic-sets transformation.

10 new tests cover pure adornment, SIPS over a chain rule,
head-fully-bound rules, comparisons, and `is`. Total 194/194.
2026-05-08 09:51:05 +00:00
88b3db2e9f js-on-sx: delete obj.key actually removes the key
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
js-delete-prop was setting value to js-undefined instead of
removing the key, so 'key' in obj remained true and proto-chain
lookup didn't fall through. Switched to dict-delete!.
Now delete Boolean.prototype.toString; Boolean.prototype.toString()
walks up to Object.prototype.toString and returns "[object Boolean]".
built-ins/Boolean: 21/27 → 22/27. conformance.sh: 148/148.
2026-05-08 09:49:18 +00:00
e2c149e60a datalog: comprehensive integration test (184/184)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 47s
Single program exercising recursion + stratified negation +
aggregation + comparison composed end-to-end via dl-eval. Confirms
the full pipeline (parser → safety → stratifier → semi-naive +
aggregate post-pass → query) on a non-trivial program.

  edge graph + banned set →
    reach transitive closure →
    safe (reach minus banned) →
    reach_count via count aggregation grouped by source →
    popular = reach_count >= 2
2026-05-08 09:47:56 +00:00
d66ddc614b datalog: aggregates work as top-level query goals (183/183)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 40s
Bug: dl-match-lit (the naive matcher used by dl-find-bindings)
was missing dl-aggregate? dispatch — it was only present in
dl-fbs-aux (semi-naive). Symptom:
  (dl-query db '(count N X (p X)))
silently returned ().

Two fixes:
- Add aggregate branch to dl-match-lit before the positive case.
- dl-query-user-vars now projects only the result var (first arg)
  of an aggregate goal — the aggregated var and inner-goal vars
  are existentials and should not leak into substitutions.

2 new aggregate tests cover count and findall as direct query goals.
2026-05-08 09:45:15 +00:00
f33a8d69f5 datalog: dl-eval source + query convenience (181/181)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s
Single-call entry: dl-eval source-string query-string parses
both, builds a db via dl-program, saturates implicitly, runs
the query (extracted from the parsed `?- ...` clause), and
returns the substitution list.

Most user-friendly path:
  (dl-eval "parent(a, b). ..." "?- ancestor(a, X).")

2 new api tests cover ancestor and multi-goal usage.
2026-05-08 09:41:02 +00:00
148c3f2068 datalog: dl-set-strategy! hook (Phase 6 stub, 179/179)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s
Adds a user-facing strategy hook: dl-set-strategy! db strategy and
dl-get-strategy db. Default :semi-naive; :magic is accepted but
the actual transformation is deferred — the saturator currently
falls back to semi-naive regardless. Lets us tick the Phase 6
"Optional pass — guarded behind dl-set-strategy!" checkbox while
keeping the equivalence/perf tests pending future work.

3 new eval tests.
2026-05-08 09:38:59 +00:00
cf634ad2b1 datalog: shortest-path demo on weighted DAG (176/176)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 37s
dl-demo-shortest-path-rules: path enumerates X→Z with cost
W = sum of edge weights via is/+; shortest filters to the
minimum cost path per (X, Y) pair via min aggregation.

3 demo tests cover direct/multi-hop choice, multi-hop wins on
cheaper route, and unreachable-empty.

Note: cycles produce infinite distance values without a depth
filter; the rule docstring flags this and suggests adding
(<, D, MAX) for graphs that may cycle.
2026-05-08 09:35:38 +00:00
0e30cf1af6 plans: Phase 6 verified 399/399 — vwait :: deadlock fixed via tcl-var-lookup-or-nil
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 09:33:48 +00:00
b3c9d9eb3a HS: scoreboard 1511/1511 (3 architectural skips remaining)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
This session cleared 15 of the 18 documented skips:
  - Toggle parser ambiguity      (1) — 2-token lookahead in parse-toggle
  - Throttled-at modifier        (1) — parser + emit-on wrap + runtime hs-throttle!/hs-debounce!
  - Tokenizer-stream API        (13) — hs-stream wrapper + 15 stream primitives

Plus a perf fix in compiler.sx (hoisted throttle/debounce helpers to
module level so they don't get JIT-recompiled per emit-on call). Wall
time for full batched suite: 28m45s, was 26m17s before sync (so net
+18 tests cost only +2m even though 3x more work).

Remaining skips (3):
  - Template-component scope tests (2) — needs <script type="text/
    hyperscript-template"> custom-element bootstrap registrar.
  - Async event dispatch (1) — repeat until event needs the OCaml
    kernel to release the JS event loop between iterations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 09:31:06 +00:00
cc64ec5cf2 datalog: first-arg index per relation (Phase 5e perf, 169/169)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 33s
db gains :facts-index {<rel>: {<first-arg-key>: tuples}} mirroring
the membership :facts-keys index. dl-add-fact! populates the index;
dl-match-positive walks the body literal's first arg under the
current subst — when it's bound to a non-var, look up by (str arg)
instead of scanning the full relation.

For chain-style recursive rules (parent X Y), (ancestor Y Z) the
inner Y has at most one parent, so the inner lookup returns 0–1
tuples instead of N. chain-25 saturation drops from ~33s to ~18s
real (~2x). chain-50 still long but tractable; next bottleneck is
subst dict copies during unification.

dl-retract! refreshed to keep the new index consistent: kept-index
rebuilt during EDB filter, IDB wipes clear all three slots.

Differential semi-naive test bumped to chain-12, semi-only count
test to chain-25.
2026-05-08 09:27:44 +00:00
7fb65cd26a ocaml: phase 1+2 records {x=1;y=2} + with-update (+6 tests, 289 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 51s
Parser: { f = e; f = e; ... } -> (:record (F E)...). { base with f = e;
... } -> (:record-update BASE (F E)...). Eval builds a dict from field
bindings; record-update merges the new fields over the base dict — the
same dict representation already used for modules.

{ also added to at-app-start? so records are valid arg atoms. Field
access via the existing :field postfix unifies record/module access.

Record patterns deferred to a later iteration.
2026-05-08 09:26:24 +00:00
9473911cf3 ocaml: phase 5.1 conformance.sh + scoreboard (283 tests across 14 suites)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 45s
lib/ocaml/conformance.sh runs the full test suite, classifies each
result by description prefix into one of 14 suites (tokenize, parser,
eval-core, phase2-refs/loops/function/exn, phase3-adt, phase4-modules,
phase5-hm, phase6-stdlib, let-and, phase1-params, misc), and emits
scoreboard.json + scoreboard.md.

Per the briefing: "Once the scoreboard exists (Phase 5.1), it is your
north star." Real OCaml testsuite vendoring deferred — needs more
stdlib + ADT decls to make .ml files runnable.
2026-05-08 09:23:06 +00:00
74b80e6b0e ocaml: phase 1 unit/wildcard params + 180s timeout (+5 tests, 283 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 34s
Parser: try-consume-param! handles ident, wildcard _ (fresh __wild_N
name), unit () (fresh __unit_N), typed (x : T) (skips signature).
parse-fun and parse-let (inline) reuse the helper; top-level
parse-decl-let inlines a similar test.

test.sh timeout bumped from 60s to 180s — the growing suite was hitting
the cap and reporting spurious failures.
2026-05-08 09:21:06 +00:00
c7315f5877 datalog-plan: progress entry for tag co-occurrence demo
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
2026-05-08 09:21:00 +00:00
082749f0a9 js-on-sx: Boolean(NaN) === false
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 45s
js-to-boolean was returning true for NaN because NaN != 0 by IEEE
semantics — the (= v 0) test fell through to the truthy else.
Per ES, NaN is one of the falsy values. Added a
(js-number-is-nan v) clause.
built-ins/Boolean: 19/27 → 21/27. conformance.sh: 148/148.
2026-05-08 09:19:21 +00:00
408fc27366 datalog: dl-query accepts conjunctive goal lists (167/167)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
dl-query now auto-dispatches on the first element's shape:
- positive literal (head is a symbol) or {:neg ...} dict → wrap
- list of literals → conjunctive query

dl-query-coerce normalizes; dl-query-user-vars collects the union
of user-named vars (deduped, '_' filtered) for projection. Old
single-literal callers unchanged.

  (dl-query db '(p X))                   ; single
  (dl-query db '((p X) (q X)))           ; conjunction
  (dl-query db (list '(n X) '(> X 2)))   ; with comparison

2 new api tests cover multi-goal AND and conjunction with comparison.
2026-05-08 09:17:15 +00:00
b95d8c5a63 datalog: stratifier rejects recursion through aggregation (165/165)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 53s
Bug: dl-check-stratifiable iterated body literals looking only for
explicit :neg literals, missing aggregate cycles. Now also walks
aggregates via dl-aggregate-dep-edge — q(N) :- count(N, X, q(X))
correctly errors out at saturation time.

3 new tests cover:
- recursion-through-aggregation rejected
- negation + aggregation coexist when in different strata
- min over empty derived relation produces no result
2026-05-08 09:13:10 +00:00