Skip to content

t27o: a fn returning Vec<T> built by push converts in the out-buffer form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073, Closes #11112) - #11109

Merged
gHashTag merged 5 commits into
masterfrom
t27o/vec-out-buffer-a4
Oct 19, 2026

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Closes #11073
Closes #11112

Step 2 of #10546 (part of #10522; step 1 is #10648). A fn that returns Vec<T> and builds it by push / extend_from_slice converts in the out-buffer form, the move #9098 made for an owned String. The last commit fixes #11112, which this form exposed (see "#11112" below).

The rule, and where it lives

specs/tools/t27o/rust_convert.t27 (header paragraph "The Vec out-buffer form", the section "the Vec out-buffer form (#11073)", vectors / put_vec_record for the oracle). gen/rust/tools/t27o/rust_convert.rs is t27c gen-rust of it; no hand-written Rust, no cli/ change.

A fn whose result is Vec<T>, T an integer, float or bool type, whose body makes the Vec as one local (Vec::new(), Vec::with_capacity(n), vec![]), changes it only by push(e) and extend_from_slice(s) and hands it back (return v, the tail v, an empty Vec in an early return), takes a last out: []T and returns usize, the number of elements the Rust fn returns:

fn evens(n: u32) -> Vec<u32> { let mut v = Vec::new(); .. v.push(i * 2); .. v }
fn evens(n: u32, out: []u32) -> usize {
    var t27o_w : usize = 0;
    ..
    const t27o_e104 = i * 2;
    if (t27o_w < out.len) { out[t27o_w] = t27o_e104; }
    t27o_w = t27o_w + 1;
    ..
    return t27o_w;
}
  • The capacity is the caller's and is never guessed: an element past out.len is counted and not written (the String form's convention), so the count is the same whatever room the buffer has. with_capacity(n) is a hint: read for what reading it does, then dropped.
  • The element of a push is evaluated once, whether it fits or not (as Rust does).
  • Refused, each with a reason that names the use (new R_VECOUT): a read of the Vec (len, an index), any other change (insert, pop, sort, an index assignment), a borrow, a rebinding, a second Vec local, a result made another way (a vec! literal, a clone). A Vec that grows without a bound the caller states has no t27 form; the reason says so.
  • A call of a fn in this form is refused (new R_VECCALL): the caller would own a buffer of no stated length. (The String form leaves its callers to call it without the buffer, see "Found, not fixed".)
  • The oracle records the count and every element of the written prefix (a result of at most 256 elements) in a 256-element buffer, and asserts that the same call with a zero-length buffer answers the same count.

Measure (the five repositories at the commits of step 1: t27 7496ed2, trios 483dd9ee, trinity 0770abb9, trinity-fpga 20bf4c418, 999-multibots-telegraf 6e5512881; 1,388 tracked .rs files, gen/ and target/ left out; the converter built from the generated Rust, one file per process, 60 s cap)

How the 626 fns that return a bare Vec<T> (360 outside #[cfg(test)] modules; 123 more return an Option / Result of a Vec) make the result:

result made by fns
a vec![..] literal as the tail 251
collect() 135 + 16 (a local started by one)
push / extend only, from an empty local 91
a local started as a vec! literal, or by a call 44 + 4
a delegated call 25
other Vec methods (sort, insert, ..) 23
push plus reads of the Vec 11 + 1
a clone / copy, an empty literal, other tails 10 + 3 + 12

Of the 91 push / extend fns the element type is an integer, float or bool in 19, a struct or enum of the file in 32, a tuple in 21, a text in 15, other in 4. This form takes the 19 (the oracle can record only scalars).

first refusal of a fn (the five files bootstrap/src/compiler.rs, service.rs, cli/t27b/src/lower.rs, cli/tri/src/fpga.rs, gates.rs left out, as in step 1) before after
type Vec 1,126 1,108
a Vec result that is not one local built only by push (R_VECOUT) 0 4
a call of a fn whose Vec result is the caller's out buffer (R_VECCALL) 0 1
macro vec, a vec! the fn changes / hands on, element type or length unknown, path Vec::new 529, 75, 19, 71, 66 unchanged
uses refused (cascade) 3,717 3,718
fns converted of 16,765 1,653 1,657

All files: converted 1,820 to 1,824 of 19,392. The 18 fns that left type Vec (outside the five files): 4 convert (from_bits, to_bytes, uniform_lengths, regex_lite_global), 3 are R_VECOUT (they read the Vec: crc32(&buf) in both encode, iter in self_attention), and 11 pass the Vec and stop at the next refusal. Over all files the first refusal of 25 fns moved: 4 convert, 4 are R_VECOUT, 1 is R_VECCALL, and 16 stop at the next refusal (to_le_bytes / to_be_bytes 5, lines 4, a refused self 2, five others). So this form reaches 4 fns of 626 today, and the numbers say why: the Vec-returning fns are mostly literals and collects, not pushes.

Measured and not shipped: allowing struct, enum and &str elements converts 8 more fns, but the oracle cannot record them element by element yet, so the form stays at scalars.

Per-file outputs: 1,368 of 1,388 are byte-identical to the merge base; the 20 that differ are exactly the files of the fns above and their callers. Dogfood, as in #11064:

Measure Before After
the 29 files of the night's sample list: fns seen / converted 571 / 40 571 / 40 (1 output differs: firmware.rs, a refusal reason)
every tracked .rs of t27 at 7496ed2 (481 files, gen/ included; compiler.rs timed out at 60 s under load in both runs): fns seen / converted 10,522 / 3,052 10,522 / 3,053 (9 outputs differ)
.rs of trios, trinity, trinity-fpga, 999-multibots-telegraf (1,006 files, gen/ left out) 9,657 / 1,025 9,657 / 1,028 (10 outputs differ)

Replay of --check (rustc harness, run, t27b test of spec plus samples), measured on 46b3eff, the head before the rebase (the t27o files did not change on master since; the rebased gen file is byte-identical to t27c gen-rust of the spec)

  • Oracle harnesses: 9 of 1,388 differ. Four because of a Vec result (bitstream.rs +5 sample calls, padding_length_distribution_guard.rs +1, trios-phd/src/main.rs +8, jepa_t_ingest/src/lib.rs the converted item text only). Four because of the comma fix below (5 zero-parameter String fns). compiler.rs differed only because the 60 s cap hit under load; alone, its harness is byte-identical.
  • Replayed end to end, base and head converters, the 17 files whose conversion changed and that fit: 14 have the same verdict (jepa_t_ingest fails the same oracle_token_to_q15 u16 as i16 before and after), bitstream.rs PASS with 0 tests to PASS with 1, trios-phd/src/main.rs PASS with 3 to PASS with 4, and one file went the wrong way at that head: padding_length_distribution_guard.rs PASS with 0 tests (vacuous) to t27b "unsupported" and t27c test-report BLOCKED (tuple field index must be comptime-known). That was the untyped array constant of [bug] t27o: a read-only integer array local iterated by reference converts to an untyped array that t27c rejects #11112, below; after the last commit the file is a PASS with 1 test. Files that go from pass to not pass: 0.

Found by the replay, fixed here (each test written first and failing)

  • The first harness of regex_lite_global (s[i..].find(needle) with the sampled needle "" pushes for ever) ate the memory of the machine. A Vec result is an input-dependent allocation, so the harness now carries t27o_guard when some fn is in this form: the original runs on a thread with 3 s and a counting global allocator that parks the thread at 16 MiB; the sample is skipped like one on which Rust panics, two such samples end the sampling of that fn. Verified on a small program: a runaway is skipped in 3 s and costs 16 MiB.
  • uniform_lengths() was written uniform_lengths(, t27o_o0[0 .. 256]): the comma before the buffer was written even with no argument. The String form had the same latent defect (chrono_now_iso(, t27o_o0[..]); 5 fns in 4 files of the five repositories), fixed by the same line.
  • A body that says out for something else (not the Vec local, not a field) would meet the buffer parameter of that name: it is not the form, the old refusal stands.

#11112 (the last commit): a list that is looped over gets its element type, or the fn is refused

let classes = [64, 128, 256, 512]; for &c in &classes { lengths.push(c); } converted to const classes = [64, 128, 256, 512];, an untyped array that t27c reads as a tuple and a for cannot walk. The merge base writes the same constant for any fn with that pattern (fn total() -> u32 { let classes = [64, 128, 256]; .. for &c in &classes .. }); uniform_lengths was the first fn to reach it from a refusal, which is why padding_length_distribution_guard.rs flipped from a vacuous pass to BLOCKED.

  • let_array: when the element type is unknown and the list is written into or looped over (array_iterated: by name, by reference, .iter()), the fn is refused (R_VECTYPE, "a vec! or array literal whose element type or length t27o cannot tell"), and the token is now the list's name (classes, not its bracket). A list only indexed by number, or handed to a call, stays what it was.
  • put_vec_elem has a new rung, array_push_elem: in a fn in the Vec out-buffer form, a list whose loop binding is pushed as it is to the result Vec (loop_pushes: v.push(c), v the result local) has the Vec's element type, because what is pushed has it. v.push(c * 2) tells t27o nothing about c and is not guessed: it is refused.
  • Result on the file: const classes : [4]usize = [64, 128, 256, 512]; and for c in classes. The spec t27o writes for padding_length_distribution_guard.rs passes t27b test (1 passed) and t27c test-report (1 of 1, 10 runtime asserts, vacuous 0) instead of BLOCKED.
  • Tests first (four failed on the previous head): the pinned array-local test (its nums loop now refuses; the old comment said such a list "is left as it was"), the padding shape, the negative controls (a list looped over by reference, by .iter() and by value is refused naming the list; c * 2 is refused; a suffixed list is typed by its first element; a list only indexed by number is unchanged), and a direct test of fn_params_open, loop_pushes and array_push_elem. The refusal of a written list had named [; it names the list now.
  • The 17 files of the replay were converted again with the converter of the previous head and with this one: 16 are byte-identical, the 17th is the padding file (the typed array). The effect on the whole corpus of refusing an untyped list that is looped over (a fn that converted into an invalid spec before) is not measured, see "Not run".

Found, not fixed (filed as #11111 and #11113)

Checks

  • t27b test specs/tools/t27o/rust_convert.t27: 353 passed (333 before: 9 body and oracle tests and 8 direct tests for the Vec form, 2 body tests and 1 direct test for [bug] t27o: a read-only integer array local iterated by reference converts to an untyped array that t27c rejects #11112; every group failed first on the head before it). t27c test-report: vacuous passes 0 of 353. t27c coverage: 417 of 417 fns (149 of 149 for rust_std.t27, untouched, 51 of 51 pass).
  • Negative controls: a returned Vec that is read (len), inserted into, assigned into by index, sorted, popped, borrowed or rebound; a second Vec; a returned vec![n] or clone; a push whose own argument reads the Vec; a parameter already named out or a body that says out; elements that are String, tuple or char; collect, a vec! literal, vec![0u8; 4] and Option<Vec<u8>> results; a scratch Vec that is not returned; a call by name, by method and by path.
  • t27c gen-rust of the spec is byte-identical to the committed gen/rust/tools/t27o/rust_convert.rs, which compiles with rustc; zig_convert.t27 and spice_convert.t27 generate byte-identical Rust.
  • t27c seal --save for rust_convert (353 of 353 under Zig); --verify MATCH on rust_convert, rust_std, zig_convert, spice_convert, zig_std, ledger, golden, install, service (no dependent seal re-saved; spice_convert.t27 untouched).
  • python3 -I tools/dupe_scan.py: 738 of 15,920 bodies in 218 groups at the merge base, 738 of 15,941 at the head, the same 15 findings (none new); t27c dupes --name for each new helper: found only in this spec. The spec has 0 non-ASCII bytes and 0 home-directory literals.
  • Own-language gate, compiled from the merge base: 3 files (spec 970 / 28, generated Rust 561 / 21, seal 9 / 9 added / deleted lines), hand-written foreign lines added 0; the gate prints nothing and exits 0.

Not run

  • The replays of bootstrap/src/compiler.rs, service.rs, cli/tri/src/gates.rs (three of the five big files; their conversion changed) and of the four zero-parameter String files of the comma fix (trios-ui/rings/UR-04/src/lib.rs, archive/vibee-browser/src-tauri/src/main.rs in trinity and trinity-fpga, 999-multibots-telegraf/rust/rings/GOLD-RING-PR00/src/replicate.rs).
  • A sweep of the five repositories after the [bug] t27o: a read-only integer array local iterated by reference converts to an untyped array that t27c rejects #11112 commit: how many fns that converted into an untyped looped-over list are refused now is not measured (the 17 files above are the only check). Any sweep or replay on the rebased head itself, and cargo build -p tri with the real tri t27o --check (the driver I compiled with rustc makes the same calls as cmd_t27o; no hand Rust was added).
  • t27c suite, ./scripts/tri test, the CI workflows beyond the gates listed, tools/check_devhome_paths.py on a full tree (this checkout is sparse; the three changed files hold none), docs/reports/t27b_expectations.json and every ledger.
  • The commit hooks printed "no tri binary is built", so their gates did not run locally; each commit message carries Closes #11073 and the co-author line.

Draft; not set to auto-merge.

🤖 Generated with Claude Code

Whole-corpus sweep (added before merge)

All 1,388 tracked Rust files of the five repositories, merge-base converter against this head, one job at a time, 30 s cap per file, both ran every file to completion (rc 0, no timeouts), five big files included. Not the real tri binary: both converters compiled with rustc -O2 into the same per-file driver.

Measure Merge base This head Change
fns seen 19,392 19,392 0
fns converted 1,820 1,824 +4
tests converted (of 9,230 seen) 619 619 0
first refusal type Vec 1,312 1,289 -23
first refusal, the new array refusal 0 11 +11
first refusal, a Vec result not built only by push 0 4 +4
first refusal, a call of an out-buffer fn 0 1 +1

30 of 1,388 output specs differ; 4 differ in code (all gains: bitstream.rs, jepa_t_ingest/src/lib.rs, padding_length_distribution_guard.rs, trios-phd/src/main.rs), 26 only in a refusal comment line. Fns that dropped from converted to refused: 0. Files from pass to not-pass: 0 (end-to-end replay of the four code-changing files: bitstream.rs 0 -> 1 tests, padding_length_distribution_guard.rs 0 -> 1 test, trios-phd 3 -> 4 tests, jepa_t_ingest the same existing failure oracle_token_to_q15). The 11 fns now refused by the array rule were already refused for a later reason. The payoff is small, as the measurement above says: 4 fns.

claude and others added 4 commits October 20, 2026 00:17
…form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073)

Step 2 of #10546. A fn whose result is Vec<T> (T an integer, float or bool type), made as one
local by Vec::new() / Vec::with_capacity(n) / vec![], changed only by push(e) and
extend_from_slice(s) and handed back, takes the caller's buffer as a last out: []T and returns
how many elements the Rust fn returns. An element past out.len is counted, not written, as the
String form counts bytes; with_capacity(n) is a hint, read and dropped. A read of the Vec, any
other change, a second Vec, any other result and a call of a fn in this form refuse, each with a
reason that names the use (R_VECOUT, R_VECCALL). The oracle records the count and every element
of the written prefix in a 256-element buffer and the same count in a zero-length one.

Tests first (nine failed on the merge base), a negative control per rule, a direct test for every
new fn (coverage 100 %). gen/rust/tools/t27o/rust_convert.rs is t27c gen-rust of the spec.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…16 MiB, a Vec that never stops growing is skipped; a fn with no parameter takes the buffer without a comma; a body that says out for something else is not the form (Closes #11073)

Found by the first replay of --check on a real file: crates/trios-phd regex_lite_global
(s[i..].find(needle) with the sampled needle "") pushes for ever, and its harness ate the
memory of the machine. A Vec result is an input-dependent allocation, so the harness now carries
t27o_guard (VEC_GUARD) when some fn is in the Vec out-buffer form: the original runs on a thread
with 3 seconds and a counting global allocator that parks the thread at 16 MiB; the sample is
skipped like one on which Rust panics, two such samples end the sampling of that fn, and the
cost of a skipped sample is a bounded 16 MiB.

The same replay found padding_length_distribution_guard uniform_lengths() written as
uniform_lengths(, t27o_o0[0 .. 256]) -- the comma was written before the buffer even with no
argument (the String form had the same latent defect). And a body that says out for something
else (not the Vec local, not a field) would meet the buffer parameter of that name: it is not the
form, the old refusal stands.

Tests first (each failed before its fix): a zero-parameter call, the guard in the harness and its
absence for a String result, has_vecfn, three out-name rows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ust takes the state by &mut and compiles (Closes #11073)

The read-only form of the previous commit made t27c gen-rust type the state as impl AsRef<[usize]>,
which moves the &mut [usize] of oracle() (E0382). The generated file is now compiled with rustc
(the driver of cmd_t27o's calls) before every commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…er -- 350 of 350 tests, vacuous 0 (Closes #11073)

t27c seal --save of specs/tools/t27o/rust_convert.t27; --verify MATCHes on rust_convert, rust_std,
zig_convert, spice_convert, zig_std, ledger, golden, install and service, so no dependent seal was
re-saved. gen/rust/tools/t27o/rust_convert.rs is byte-identical to t27c gen-rust of the spec.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-19 17:25:29 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 44
PRs with All Checks Green 6
READY 2
FAILING 44
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 44 + 0 + 0 = 46, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=e34e1b174c96 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

…ming the list, and one whose binding is pushed to the Vec result takes the Vec's element type (Closes #11112)

let classes = [64, 128, 256, 512]; for &c in &classes { lengths.push(c); } converted to an untyped array
constant, which t27c reads as a tuple and a for cannot walk: padding_length_distribution_guard.rs went
from a vacuous pass to BLOCKED once uniform_lengths started to convert (#11073). The merge base writes the
same untyped constant for any fn with that pattern.

- let_array: when the element type is unknown and the list is written into or looped over (array_iterated:
  by name, by reference, .iter()), the fn is refused (R_VECTYPE), the token now the list's name, not its
  bracket. A list only indexed by number or handed to a call stays what it was.
- put_vec_elem has a new rung, array_push_elem: in a fn in the Vec out-buffer form, a list whose loop binding is
  pushed as it is to the result Vec (loop_pushes) has the Vec's element type -- what is pushed has it. v.push(c * 2)
  tells nothing and is not guessed.

Tests first (four failed on the previous head): the pinned array-local test, the padding shape, the negative
controls (by reference, .iter(), by value, c * 2 refused; a suffixed list typed; a list only indexed by number
unchanged), and a direct test of the three new fns. The spec t27o writes for the padding file now passes
t27c test-report (1 of 1, 10 runtime asserts, vacuous 0) instead of BLOCKED.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@gHashTag gHashTag changed the title t27o: a fn returning Vec<T> built by push converts in the out-buffer form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073) t27o: a fn returning Vec<T> built by push converts in the out-buffer form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073, Closes #11112) Oct 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-19 17:38:46 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 46
PRs with All Checks Green 4
READY 2
FAILING 46
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 46 + 0 + 0 = 48, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=e34e1b174c96 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag marked this pull request as ready for review October 19, 2026 17:50
@gHashTag
gHashTag merged commit 2e2ca5f into master Oct 19, 2026
37 of 40 checks passed
gHashTag pushed a commit that referenced this pull request Oct 19, 2026
…stack, in both orders, and each body literal beside a sample that holds it -- regex_lite_global records a match (Closes #11113)

The oracle calls a fn with parameter i taking sample j + i. regex_lite_global(s, needle) of trios-phd
was called with ("", "a"), ("a", "abc"), ("abc", "0") ... : the needle was never inside the haystack, so
every count the harness recorded was 0, the oracle test asserted only the empty case, and a conversion
that returned nothing for every input would have passed it. Its body has no string literal, so the
literal samples of #9102 could not help.

vectors now counts the direct texts of the fn (text_count, kept in the new PAIRS slot and cleared at
the end). With two or more, derived_at gives each text parameter three fixed samples first, a text, a text
inside it and the first text again (put_pair_sample: "abcabc", "abc", "abcabc"), so one call has the needle inside
the haystack, the next the haystack second, and "abc" occurs twice in "abcabc" (offsets 0 and 3, the
second ending at the end). Each string literal of the body then comes alone, wrapped in one space, alone,
so the wrapped sample sits next to the literal in both orders. The sampler stays bounded: three fixed
6-byte texts, the DCAP of 64 samples a parameter (a test with thirty literals), and the guard of 3 s and
16 MiB of #11109, which still skips the empty needle. A fn with one text, or a text and a number, is
sampled as before (negative control); a number never reads the count of texts.

Evidence: the harness of crates/trios-phd/src/main.rs now records count 2 and the offsets 0 and 3 for
regex_lite_global (rustc, run), the zero-length buffer answers 2, and t27b test of the converted spec
passes 4 of 4 as before. Over the 1,388 files of the five repositories the converted specs are byte
for byte the same; 5 oracle harnesses change (compiler.rs, gates.rs, ring-090 lib.rs, trios-phd main.rs,
defense_gate lib.rs); the three that t27b judges (ring-090 25 of 25, trios-phd 4 of 4, defense_gate 4 of 4)
pass before and after, the two it cannot judge (unsupported construct, @max) stay so.

Tests first (the two oracle tests failed on the merge base, the negative control passed), a direct test for each
new fn (is_text_kind, text_count, put_pair_sample), derived_at with the count set, the cap of 64 with pairs.
Three tests that give the name table exactly one slot got one more: the state vector has one more slot (PAIRS).
t27b test 362 of 362, t27c coverage 100 % (420 of 420), seal --save 362 of 362 vacuous 0, --verify MATCH on
rust_convert, rust_std, zig_convert, spice_convert, zig_std, ledger, golden, install, service.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
gHashTag added a commit that referenced this pull request Oct 19, 2026
… match in the oracle of a two-text fn, refused receivers named (#11130)

* t27o: a caller of an out-buffer String fn is refused with a reason that names the form -- R_STRCALL, as the Vec form does with R_VECCALL (Closes #11111)

A fn whose result is an owned String lowers to the out-buffer form: a last out: []u8, the result the
byte count. The Rust source calls it without that argument, so a caller came out as tag(n).len or
const t = tag(n); -- a call with the buffer missing, which t27c rejects at best and at worst reads as
another meaning of the same arity. The converter must emit valid output or refuse (#10976).

deps now treats a fn in the String form (K_STRFN, registered before its body is read) the way it
treats one in the Vec form: a free fn is hit by a call, a method by a call after a dot or a path
through its owner or Self, and the caller is refused with R_STRCALL, whose reason names the form
and whose token is the callee. The buffer is not guessed: a caller that owned one would have to
state a length the source never states. A fn outside the form keeps its old reason (uses refused),
the split chain, which names the fn it calls on each piece without calling it, still converts.

Tests first (two of the three new convert tests failed on the merge base, the third is the
negative control and passed): a free fn in either declaration order, a method called as x.m() and
S::m(x), a caller of a String fn outside the form, and a direct deps test with K_STRFN names
(call, bare name, declaration, method, path, wrong owner, Self). The reason table test has the new row.

Evidence: t27b test 357 of 357; t27c coverage 100 % (417 of 417); t27c seal --save 357 of 357,
vacuous 0, --verify MATCH on rust_convert, rust_std, zig_convert, spice_convert, zig_std, ledger,
golden, install, service. The converter over all 1,388 tracked Rust files of the five repositories
changes no output: 13 fns in 9 files are in the String form and none is called in its own file.

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

* t27o: the oracle of a fn with two texts samples a needle inside a haystack, in both orders, and each body literal beside a sample that holds it -- regex_lite_global records a match (Closes #11113)

The oracle calls a fn with parameter i taking sample j + i. regex_lite_global(s, needle) of trios-phd
was called with ("", "a"), ("a", "abc"), ("abc", "0") ... : the needle was never inside the haystack, so
every count the harness recorded was 0, the oracle test asserted only the empty case, and a conversion
that returned nothing for every input would have passed it. Its body has no string literal, so the
literal samples of #9102 could not help.

vectors now counts the direct texts of the fn (text_count, kept in the new PAIRS slot and cleared at
the end). With two or more, derived_at gives each text parameter three fixed samples first, a text, a text
inside it and the first text again (put_pair_sample: "abcabc", "abc", "abcabc"), so one call has the needle inside
the haystack, the next the haystack second, and "abc" occurs twice in "abcabc" (offsets 0 and 3, the
second ending at the end). Each string literal of the body then comes alone, wrapped in one space, alone,
so the wrapped sample sits next to the literal in both orders. The sampler stays bounded: three fixed
6-byte texts, the DCAP of 64 samples a parameter (a test with thirty literals), and the guard of 3 s and
16 MiB of #11109, which still skips the empty needle. A fn with one text, or a text and a number, is
sampled as before (negative control); a number never reads the count of texts.

Evidence: the harness of crates/trios-phd/src/main.rs now records count 2 and the offsets 0 and 3 for
regex_lite_global (rustc, run), the zero-length buffer answers 2, and t27b test of the converted spec
passes 4 of 4 as before. Over the 1,388 files of the five repositories the converted specs are byte
for byte the same; 5 oracle harnesses change (compiler.rs, gates.rs, ring-090 lib.rs, trios-phd main.rs,
defense_gate lib.rs); the three that t27b judges (ring-090 25 of 25, trios-phd 4 of 4, defense_gate 4 of 4)
pass before and after, the two it cannot judge (unsupported construct, @max) stay so.

Tests first (the two oracle tests failed on the merge base, the negative control passed), a direct test for each
new fn (is_text_kind, text_count, put_pair_sample), derived_at with the count set, the cap of 64 with pairs.
Three tests that give the name table exactly one slot got one more: the state vector has one more slot (PAIRS).
t27b test 362 of 362, t27c coverage 100 % (420 of 420), seal --save 362 of 362 vacuous 0, --verify MATCH on
rust_convert, rust_std, zig_convert, spice_convert, zig_std, ledger, golden, install, service.

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

* t27o: a refusal caused by a refused receiver names the receiver type, not `self` or `Self` -- 649 fns of the sweep can be followed to the type's own reason (Closes #11128)

A method of a type the converter refuses (a struct with a heap field, an enum with data, a refused item)
is refused with it, and its refusal line said "uses refused `self`" or "uses refused `Self`". Neither is the
name of any refusal in the file, so a lookup by name found nothing and the sweep, which follows a named
callee to its root (#11122), had to leave the cascade as it was: 696 fn of the 4,468 cascades.

deps now refuses at the receiver (the `self` of the signature, or the `Self` of a body) with the impl
type as the token, the line staying the receiver's: "uses refused `Foo` at line 3", and `Foo` has its
own line, "refused struct Foo (line 1): type `String`". Nothing else changes: a static fn of the same impl
that names neither the type nor `self` converts, the methods of a type that converts convert, a method
that uses a refused method still names that method, and an impl of a type declared nowhere in the file
stays "undeclared" (that check comes first).

Tests first (the new convert test and the two new asserts of the direct deps test failed on the merge
base): `&self`, a `Self` constructor, a method calling another, a refused enum, the free fn that takes the
type, and the controls; one pinned line of an older test, `uses refused `Self``, now names the type.

Measured on the 1,388 tracked Rust files of the five repositories (19,392 fn): the sweep's root
attribution of #11127, replayed on the converted text (its numbers reproduced on the merge base: 4,531
cascade lines, 3,824 attributed, 696 fn and 707 items left, 570 + 86 of them self and Self), leaves
58 fn and 69 items unattributed after this change, none of them a receiver. Fns converted 1,824 before and
after; none converted becomes refused, none refused becomes converted; 649 first refusals change their
token and nothing else. What is left are names the file's own refusal lines do not carry: the type
aliases the generic item refusal prints as "refused type" (47 fn), extern fns and an assert.

t27b test 363 of 363, t27c coverage 100 % (420 of 420), seal --save 363 of 363 vacuous 0, --verify MATCH on
rust_convert, rust_std, zig_convert, spice_convert, zig_std, ledger, golden, install, service.

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

---------

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag deleted the t27o/vec-out-buffer-a4 branch October 20, 2026 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants