fieldtest: raw-buf comprehensive — 4 examples, 8 findings (refs #7)
Comprehensive usability re-test of the RawBuf kernel extension in natural LLM-author decompositions the prior field test (0058) did not exercise: a Float RawBuf in a user ADT read through two borrow helpers, a Bool flag buffer filled with a computed value, an Int fib buffer whose fill reads its own writes plus two composed borrow summaries, and a forbidden core-primitive element. All three working fixtures build, run to expected values, and report live=0 across Float/Bool/Int widths — the core RawBuf surface (borrow-helper composition, fill loops, RawBuf-in-ADT, element widths) genuinely holds together. Orchestrator triage corrected the fieldtester's run, which executed a stale target/release/ail (built before the #50 fix). Every outcome was re-verified against a fresh build: - F2 (bare RawBuf ADT field unresolved) — RETRACTED: a stale-binary false positive. On a fresh build the bare name resolves in every configuration (ctor name == or != type name; builds/runs live=0). The #50 fix is correct and general. - F7 (NEW, issue #51) — a `check`-clean program crashes `build`: a buffer whose element type is never observed by a later get/set defaults its element to Unit in monomorphisation and hits an unregistered `RawBuf_new__Unit` intercept. Affects a legitimate `RawBuf<Int>` used only for its size AND a forbidden locally- constructed element. Root: the `(new T ...)` desugar drops the explicit element annotation; honouring it reverses the milestone's § Term::New desugar decision, so it routes through brainstorm. - F8 (process) — the field test ran stale; the fieldtester agent now builds from the current tree before running (plugin fix). F1 (spec_gap) resolved here: the design ledger's §Series substrate ctor wrote the storage field `(own (RawBuf a))`, which does not parse (`own` is fn-param/ret only). Rewritten to the verified-authorable `(con RawBuf a)`. The rest of the §Series listing is illustrative and its element- less `(new RawBuf lookback)` construction is entangled with #51; a full compile-verification of that listing belongs with the Series-substrate work. F5 (param-in rejects a forbidden core primitive, message names the set) and F4/F3 (borrow composition; substrate composite) carry on. F6 (param-in set rendered as a Rust-debug list) filed as #52. refs #7
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
; Fieldtest raw-buf comprehensive .1 (Axes 1+2+3+4 combined — the
|
||||
; "Series substrate" shape with a Float element width).
|
||||
;
|
||||
; Task an LLM author is naturally given: "model a fixed-size window of
|
||||
; Float samples with a running total, fill it from a loop, then report
|
||||
; the window mean and the window maximum through read-only helpers."
|
||||
;
|
||||
; The natural decomposition wraps a RawBuf<Float> together with a
|
||||
; bookkeeping `count` field in a user ADT (Window), exactly the Series
|
||||
; substrate the ledger (design/models/0007 §Series) describes — an ADT
|
||||
; holding `(own (RawBuf a))` plus Int bookkeeping. The buffer is filled
|
||||
; via a (loop ...)/recur (runtime-N, not literal indices), and the
|
||||
; read-back is factored into two `borrow (Window)` helpers (`mean`,
|
||||
; `wmax`) that each pattern-match the ADT and drive a read loop off the
|
||||
; bookkeeping count, reading the buffer through `RawBuf.get` on a borrow.
|
||||
;
|
||||
; This stresses, in one program:
|
||||
; - Float element width through a fill loop (not just literal sets).
|
||||
; - A RawBuf stored in a user ADT field (the #50 substrate shape).
|
||||
; - TWO borrow-receiver helpers composing over the same wrapped buffer
|
||||
; (the #46 borrow-receiver-read fix, under composition + behind a
|
||||
; match on the ADT).
|
||||
; - The drop cascade: the Window ADT owns the buffer; dropping the
|
||||
; Window frees the slab. Leak-clean expected under AILANG_RC_STATS.
|
||||
;
|
||||
; Window of 4 samples: 2.0, 4.0, 6.0, 8.0.
|
||||
; mean = 20.0 / 4 = 5.0
|
||||
; wmax = 8.0
|
||||
; Expected stdout: two lines, "5.0" then "8.0".
|
||||
|
||||
(module rbx_1_float_window_stats
|
||||
|
||||
; NOTE (field test): the ledger's §Series substrate form writes the
|
||||
; storage field as `(own (RawBuf a))`. That does NOT parse here — `own`
|
||||
; in a ctor field position is rejected (surface-parse-error). And the
|
||||
; bare `(con RawBuf (con Float))` field gives a type-mismatch
|
||||
; (expected RawBuf<Float>, got raw_buf.RawBuf<Float>). The only form
|
||||
; that checks is the fully-qualified `raw_buf.RawBuf`. See findings.
|
||||
(data Window
|
||||
(ctor W (con raw_buf.RawBuf (con Float)) (con Int)))
|
||||
|
||||
(fn build_window
|
||||
(doc "Allocate a 4-slot Float buffer, fill slot i with (2*(i+1)), wrap in a Window with count=4.")
|
||||
(type (fn-type (params (con Int)) (ret (own (con Window)))))
|
||||
(params n)
|
||||
(body
|
||||
(let buf (new RawBuf (con Float) 4)
|
||||
(let filled
|
||||
(loop (b (con RawBuf (con Float)) buf) (i (con Int) 0)
|
||||
(if (app ge i n)
|
||||
b
|
||||
(recur (app RawBuf.set b i (app int_to_float (app * 2 (app + i 1))))
|
||||
(app + i 1))))
|
||||
(term-ctor Window W filled n)))))
|
||||
|
||||
(fn mean
|
||||
(doc "Average of the first count slots, read through a borrow of the Window.")
|
||||
(type (fn-type (params (borrow (con Window))) (ret (con Float))))
|
||||
(params w)
|
||||
(body
|
||||
(match w
|
||||
(case (pat-ctor W buf count)
|
||||
(app /
|
||||
(loop (acc (con Float) 0.0) (i (con Int) 0)
|
||||
(if (app ge i count)
|
||||
acc
|
||||
(recur (app + acc (app RawBuf.get buf i))
|
||||
(app + i 1))))
|
||||
(app int_to_float count))))))
|
||||
|
||||
(fn wmax
|
||||
(doc "Maximum of the first count slots, read through a borrow of the Window.")
|
||||
(type (fn-type (params (borrow (con Window))) (ret (con Float))))
|
||||
(params w)
|
||||
(body
|
||||
(match w
|
||||
(case (pat-ctor W buf count)
|
||||
(loop (mx (con Float) 0.0) (i (con Int) 0)
|
||||
(if (app ge i count)
|
||||
mx
|
||||
(recur (if (app float_gt (app RawBuf.get buf i) mx)
|
||||
(app RawBuf.get buf i)
|
||||
mx)
|
||||
(app + i 1))))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(let w (app build_window 4)
|
||||
(seq (seq (app print (app mean w)) (do io/print_str "\n"))
|
||||
(seq (app print (app wmax w)) (do io/print_str "\n")))))))
|
||||
@@ -0,0 +1,57 @@
|
||||
; Fieldtest raw-buf comprehensive .2 (Axes 1+2+3 — Bool element width
|
||||
; through a fill loop, then counted via a borrow helper).
|
||||
;
|
||||
; Task an LLM author is naturally given: "mark which of the numbers
|
||||
; 0..N are even in a flag buffer, then count how many flags are set."
|
||||
; A flat Bool RawBuf is the natural storage for a flag/bitset array.
|
||||
;
|
||||
; The prior field test only stored a single Bool at a literal index
|
||||
; (rawbuf_3_sensor_pair). This drives the i1/i8 Bool packing edge
|
||||
; through a (loop ...)/recur FILL of runtime length N (one RawBuf.set
|
||||
; per slot, the stored value being a *computed* Bool — the result of
|
||||
; `eq (i % 2) 0`), and reads the flags back through a `borrow` helper
|
||||
; (`count_set`) that drives off RawBuf.size and accumulates an Int.
|
||||
;
|
||||
; This stresses:
|
||||
; - Bool stored/loaded across a loop, not a literal set — does the
|
||||
; i1/i8 round-trip hold when the value is computed, not a `true`
|
||||
; literal?
|
||||
; - A borrow-receiver helper over a Bool buffer (the #46 fix on the
|
||||
; Bool width).
|
||||
; - `RawBuf.get` of a Bool used directly as an `if` condition inside
|
||||
; the count loop.
|
||||
;
|
||||
; N = 6 -> flags for 0,1,2,3,4,5 -> even at 0,2,4 -> 3 set.
|
||||
; Expected stdout: "3".
|
||||
|
||||
(module rbx_2_bool_sieve
|
||||
|
||||
(fn mark_even
|
||||
(doc "Set slot i to (i is even) for i in 0..n. Linear own->own.")
|
||||
(type (fn-type (params (own (con RawBuf (con Bool))) (con Int)) (ret (own (con RawBuf (con Bool))))))
|
||||
(params buf n)
|
||||
(body
|
||||
(loop (b (con RawBuf (con Bool)) buf) (i (con Int) 0)
|
||||
(if (app ge i n)
|
||||
b
|
||||
(recur (app RawBuf.set b i (app eq (app % i 2) 0))
|
||||
(app + i 1))))))
|
||||
|
||||
(fn count_set
|
||||
(doc "Count the set flags, reading the Bool buffer through a borrow.")
|
||||
(type (fn-type (params (borrow (con RawBuf (con Bool)))) (ret (con Int))))
|
||||
(params buf)
|
||||
(body
|
||||
(loop (acc (con Int) 0) (i (con Int) 0)
|
||||
(if (app ge i (app RawBuf.size buf))
|
||||
acc
|
||||
(recur (if (app RawBuf.get buf i) (app + acc 1) acc)
|
||||
(app + i 1))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(let buf (new RawBuf (con Bool) 6)
|
||||
(let buf (app mark_even buf 6)
|
||||
(app print (app count_set buf)))))))
|
||||
@@ -0,0 +1,29 @@
|
||||
; Fieldtest raw-buf comprehensive .3 (Axis 5 — the param-in element-type
|
||||
; restriction on a forbidden *core primitive*).
|
||||
;
|
||||
; The prior field test rejected RawBuf<Str> (the shipped fixture) and
|
||||
; RawBuf<Tick> (a user ADT). This probes the third natural mistake: a
|
||||
; RawBuf of `Unit` — a core primitive that is NOT in the allowed set
|
||||
; {Int, Float, Bool}. An LLM author might reach for `RawBuf<Unit>` as a
|
||||
; "presence buffer" / counter-of-slots before realising a Bool flag
|
||||
; buffer is the right tool. The restriction must reject it, and per the
|
||||
; B3 fix (#48) the diagnostic should now NAME the allowed set
|
||||
; {Int, Float, Bool}, not just the offending type.
|
||||
;
|
||||
; Expected: `ail check` exits 1 with [param-not-in-restricted-set]
|
||||
; naming `Unit` AND the allowed set {Int, Float, Bool}.
|
||||
|
||||
(module rbx_3_unit_element_reject
|
||||
|
||||
(fn make_presence
|
||||
(doc "Try to allocate a RawBuf of Unit — forbidden element type.")
|
||||
(type (fn-type (params (con Int)) (ret (own (con RawBuf (con Unit))))))
|
||||
(params n)
|
||||
(body (new RawBuf (con Unit) n)))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(let buf (app make_presence 3)
|
||||
(do io/print_str "unreachable\n")))))
|
||||
@@ -0,0 +1,76 @@
|
||||
; Fieldtest raw-buf comprehensive .4 (Axes 1+2+3 — Int buffer, an
|
||||
; own->own fill helper across a function boundary, plus TWO distinct
|
||||
; borrow-receiver helpers composed over the same buffer).
|
||||
;
|
||||
; Task an LLM author is naturally given: "fill a buffer of N slots with
|
||||
; the Fibonacci sequence, then report both the total and the index of
|
||||
; the largest element." The natural decomposition is three helpers:
|
||||
; - `fill` : (own RawBuf, Int) -> own RawBuf (loop/recur, runtime N)
|
||||
; - `total` : (borrow RawBuf) -> Int (read loop off .size)
|
||||
; - `argmax`: (borrow RawBuf) -> Int (read loop, tracks idx)
|
||||
; and a main that threads the owned buffer through `fill`, then borrows
|
||||
; it TWICE in sequence (`total buf`, then `argmax buf`) — the natural
|
||||
; "compute several summaries of one read-only buffer" shape.
|
||||
;
|
||||
; This stresses the #46 borrow-receiver fix under composition: two
|
||||
; independent borrows of the same owned binder, each a helper that does
|
||||
; multiple RawBuf.get / RawBuf.size calls on its borrow parameter. The
|
||||
; prior rawbuf_1 had a single borrow helper; this has two, called back
|
||||
; to back on the same buffer, with the buffer still owned (and dropped)
|
||||
; by main afterwards.
|
||||
;
|
||||
; Fib(0..5) = 1,1,2,3,5,8 (seeding fib(0)=fib(1)=1).
|
||||
; total = 1+1+2+3+5+8 = 20
|
||||
; argmax = index 5 (value 8 is largest)
|
||||
; Expected stdout: "20" then "5".
|
||||
|
||||
(module rbx_4_int_two_borrow_helpers
|
||||
|
||||
(fn fill
|
||||
(doc "Fill slot i with fib(i) for i in 0..n. Linear own->own.")
|
||||
(type (fn-type (params (own (con RawBuf (con Int))) (con Int)) (ret (own (con RawBuf (con Int))))))
|
||||
(params buf n)
|
||||
(body
|
||||
; Seed slots 0 and 1 to 1, then each later slot = sum of prior two,
|
||||
; read back from the buffer itself via RawBuf.get on the owned `b`.
|
||||
(loop (b (con RawBuf (con Int)) buf) (i (con Int) 0)
|
||||
(if (app ge i n)
|
||||
b
|
||||
(recur (app RawBuf.set b i
|
||||
(if (app le i 1)
|
||||
1
|
||||
(app + (app RawBuf.get b (app - i 1))
|
||||
(app RawBuf.get b (app - i 2)))))
|
||||
(app + i 1))))))
|
||||
|
||||
(fn total
|
||||
(doc "Sum every slot, borrow receiver.")
|
||||
(type (fn-type (params (borrow (con RawBuf (con Int)))) (ret (con Int))))
|
||||
(params buf)
|
||||
(body
|
||||
(loop (acc (con Int) 0) (i (con Int) 0)
|
||||
(if (app ge i (app RawBuf.size buf))
|
||||
acc
|
||||
(recur (app + acc (app RawBuf.get buf i))
|
||||
(app + i 1))))))
|
||||
|
||||
(fn argmax
|
||||
(doc "Index of the largest slot, borrow receiver. Tracks (best_i, best_v).")
|
||||
(type (fn-type (params (borrow (con RawBuf (con Int)))) (ret (con Int))))
|
||||
(params buf)
|
||||
(body
|
||||
(loop (best_i (con Int) 0) (best_v (con Int) (app RawBuf.get buf 0)) (i (con Int) 0)
|
||||
(if (app ge i (app RawBuf.size buf))
|
||||
best_i
|
||||
(if (app gt (app RawBuf.get buf i) best_v)
|
||||
(recur i (app RawBuf.get buf i) (app + i 1))
|
||||
(recur best_i best_v (app + i 1)))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(let buf (new RawBuf (con Int) 6)
|
||||
(let buf (app fill buf 6)
|
||||
(seq (seq (app print (app total buf)) (do io/print_str "\n"))
|
||||
(seq (app print (app argmax buf)) (do io/print_str "\n"))))))))
|
||||
Reference in New Issue
Block a user