Skip to content

lab L2: the t27b lab's decisions as .t27 specs, lab.py as the oracle - #11079

Merged
gHashTag merged 1 commit into
masterfrom
claude/lab-l2-t27b-11042
Oct 19, 2026
Merged

gHashTag merged 1 commit into
masterfrom
claude/lab-l2-t27b-11042

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #11042. Part of the lab epic #11040.

Five specs under specs/lab/ port the pure decisions of the t27b lab as functions of text and numbers, with the Python as the oracle until the cutover: contrib/railway/t27b-lab/lab.py and the checker it runs, scripts/tri_loop/t27b.py ratchet, both unchanged. They name no host and assume no single machine: whoever runs a lab gate (one lab, or any node that takes a lab job, #11043) hands them the text and the facts and gets the decision back.

Functions ported

lab.py spec function
parse_test_report lab_t27b_report.t27 lr_report_verdict, lr_report_detail (the verdict as steward.t27's code)
parse_test_verdicts lab_t27b_report.t27 lr_verdicts (a table of three words a test), lr_table_text
disagreements lab_t27b_report.t27 lr_disagreements
parse_cargo_test lab_t27b_report.t27 lr_cargo_totals
reference_one, once the process has ended lab_t27b_report.t27 lr_ref_verdict, lr_ref_detail, lr_over_detail, lr_spawn_detail, lr_keeps_tests
the summary block of lab_run (run-document shape) lab_t27b_report.t27 lr_summary_field, lr_put_summary, lr_put_reference_summary, lr_summary_crash
reference_cacheable lab_t27b_cache.t27 lc_cacheable
the hit rule of reference_all, its log line and reused text lab_t27b_cache.t27 lc_hit_usable, lc_log_line, lc_reused
reference_stamp, first_line lab_t27b_cache.t27 lc_stamp, lc_first_line
use_closure lab_t27b_cache.t27 lc_closure (lc_reach, lc_path_cmp: pathlib's component order)
reference_key lab_t27b_cache.t27 lc_key_begin, lc_key_file, lc_key_hex (streaming sha256 over specs/tri/crypto/sha256.t27)
ratchet() of t27b.py: every ledger row against the run, the unlisted specs, the cap lab_t27b_ratchet.t27 lt_ratchet (reads the run and the ledger as written; counts, status, the lines and the summary line tri t27b ratchet prints)
run_done lab_t27b_run.t27 lt_run_done
admitted lab_t27b_run.t27 lt_admit (the judge is request_verdict and request_exit of corpus_receipt.t27, called as functions), lt_facts, lt_has_word, lt_age_u32
the loop's schedule question and answer (main) lab_t27b_run.t27 lt_schedule_facts, lt_schedule_next
ratchet(doc, log) of lab.py: how the checker's process is read lab_t27b_run.t27 lt_step_kind, lt_step_ok, lt_step_error
publish: the index of runs, paths of a run's files lab_t27b_run.t27 lt_index_publish, lt_run_path
universal-newline lines, \d, \w, saturating counts (what LabText lacks) lab_t27b_text.t27 lx_*

Left out, and why

Everything that starts a process, touches git or the disk or the network, or serves files: run, run_group, checkout, lab_run's steps, reference_one's process half and the worker pool, read_ref_cache/write_ref_cache, remote_sha, the receipt and ddc steps, the HTTP server, main's loop. That is the runtime, #11040 L3. The run document's step records and the toolchain/image blocks are written by it; what is here is the summary block, the keys of the index entry and the paths. lab.py has no self_check() (the t27c lab's has one), so there are no self-check cases to pin.

Cases, and the zero differences

Every table was computed by running the Python itself (lab.py imported unedited; the checker through its CLI; admitted with master's real judge t27c corpus-receipt admit and git's answers replaced by text; the two statements of main() taken out of lab.py's own source and run; publish, ratchet and reference_all with their processes replaced). The inputs are small texts written for the table: the real shapes of t27c test-report (a pass; a fail with a vacuous pass; a spec that does not compile; a machine with no zig), then cases that break each rule on its edge.

group cases differences
parse_test_report (verdict and detail) 99 0
parse_test_verdicts 70 0
disagreements 63 0
parse_cargo_test 62 0
reference_one after the process ended (+ 10 spawn errors, 6 timeouts) 61 0
summary block of a run (17 fields each; 12 layouts) 62 0
summary block, reference only 11 0
use_closure and reference_key 79 0
reference_cacheable 130 0
cache hit rule (reference_all itself) 100 0
cache log line and reused text 64 0
first_line 64 0
reference_stamp 8 0
t27b.py ratchet (exit code, nine counts, finding lines; 12 full outputs) 125 0
run_done 66 0
admitted (directories of requests, real judge) 62 0
judge schedule facts / answer read 50 / 48 0
ratchet step read from the process 92 0
publish index 60 0

1392 cases, 5676 runtime asserts in 84 tests, 0 vacuous.

Mutants

46 mutants, each a one-expression change in a function, each killed (a test fails; none fails to compile). text 8: a decimal that saturates a digit early, \w without the underscore, CR LF read as two breaks, a sum that wraps, a dropped sign, a pad that writes the byte at cap, a length compared with >, a digit run that ends late. report 10: a number that follows its key with no space, a later BLOCKED line winning, a fail called blocked, the first verdict of a repeated test kept, the reference-only line worded as the t27b-only one, ignored not required, the cut taken over the whole line, a summary count inverted, the last verdict word unreachable, the crash condition ignored. cache 9: a killed t27c's blocked verdict cached, a one-word entry used, directory-after-file order, the wildcard list ignored, a missing file hashed as 7 bytes, the NUL after the stamp dropped, stderr read for blank stdout, the closure written in reverse, the first tab field taken. ratchet 10: surrogate pairs not combined, a string read as a cap, the cap judged against one more row, asserts_counted read backwards, the repr quote choice, paths sorted backwards, a repeated row kept, no fall back to the detail, a search that walks the wrong way, an unknown word read as missing. run 9: run_done inverted, a dropped request counted as waiting, a negative age read as fresh, three words accepted from the judge, the exit code forgotten, any nonzero exit read as no ratchet, the old entry of a commit kept in the index, a word matched inside another, the known flag written backwards.

Reuse, nothing copied

specs/lab/text.t27 (LabText, L1 #11066, on master): lines, spaces, characters and spans, read there off Python 3.14. specs/tri/lab/receipt.t27 (the run layout reader), specs/tri/t27b/steward.t27 and ledger_steward.t27 (entry_code, unlisted, over_cap, ratchet_is_red, is_pass, the verdict and finding codes), specs/verified/corpus_receipt.t27 (request_verdict, request_exit), specs/tri/crypto/sha256.t27. python3 tools/dupe_scan.py --like on each new file: nothing in it is written elsewhere.

Found in lab.py while porting (reproduced, not repaired; lab.py is unchanged)

  • lab_run reads r["reference"] of every merged result before it builds the summary, so a run in which the reference step produced nothing for some file raises KeyError and is never published (and is retried every poll): lr_summary_crash is that condition; 12 of the 62 result sets are such runs.
  • run() drops the oldest 2000 lines whenever the list passes 4000, so parse_cargo_test sums a long cargo run from its tail.
  • first_line of a command that printed nothing is the words unavailable: list index out of range (an IndexError it catches).
  • A request whose file is dated in the future is expired by the judge (a negative age).

Limits, each pinned by a test

A count above 18446744073709551615 reads as that number (the verdict never differs; only a detail that prints such a count does); \d and \w are the ASCII classes; a table wider than the caller's buffer is no table; the checker's JSON is read in json.dumps(indent=1)'s layout and a ledger row must stay on one line; the repr of a bad reason is exact for ASCII and the listed Unicode spaces. Details are in each file's header.

Gates

  • t27c test-report on each new spec: FAIL 0, vacuous passes 0 (text 8 tests, report 29, cache 16, ratchet 14, run 17).
  • t27c seal --save then --verify on each: all MATCH (seals under .trinity/seals/lab_LabT27b*.json).
  • tri types ratchet: RATCHET: CLEAN.
  • Not touched: infra/, contrib/, cli/, scripts/, docs/reports/t27b_expectations.json, specs/analog/, the AnalogSar seals, .claude/.

🤖 Generated with Claude Code

…loses #11042)

Five specs under specs/lab/ port the pure decisions of the t27b lab
(contrib/railway/t27b-lab/lab.py and the checker it runs, scripts/tri_loop/t27b.py
ratchet; both unchanged) as functions of text and numbers: how test-report and cargo
output are read (parse_test_report, parse_test_verdicts, disagreements, parse_cargo_test,
the verdict of a reference run, the summary block of a run), the reference cache
(use_closure in pathlib's order, reference_key as a streamed sha256, reference_cacheable,
the hit rule, the stamp), the per-spec ratchet of a run against the ledger, and the
run's own rules (run_done, admitted with the judge as a function, the loop's schedule
question, how the checker's process is read, the index after a publish).

Every table was computed by running the Python itself: 1392 cases, 0 differences, 46
mutants killed. They name no host and assume no single machine. Reused, not copied:
specs/lab/text.t27 (L1), receipt.t27, steward.t27, ledger_steward.t27,
corpus_receipt.t27, sha256.t27.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@gHashTag
gHashTag enabled auto-merge (squash) October 19, 2026 15:01
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-19 15:01:49 UTC

Summary

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

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=57b91bb96334 != 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 merged commit 686f1aa into master Oct 19, 2026
34 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lab L2: the t27b lab's decisions as .t27 specs, lab.py as the oracle

2 participants