You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
t27o Python debt census (measure first for #8995): lines, functions and the share that fits a convertible subset, ranked #11168
Measure the hand-written Python in our repositories, as the measure-first step of the Python front end (#8995, #9006): how many lines and functions, and what share fits a subset t27 can express today, so the first Python port is chosen from numbers. This is analysis only.
Why
Four measurements on 2026-10-19/20 show that converting existing Rust deletes at most about 1% of the hand-written lines: 3,006 lines in whole-converting files (0.69%, #11149) and 1,375 lines in movable fns of partly converting files (0.32%, #11159), because the converted share is bounded by what t27 cannot say (heap collections, owned strings and paths, iterators with closures, tuples). #9000's baseline puts Python at 16% of the t27 repository (against Rust 25%), and #8995 names scripts/*.py and tools/*.py as the largest hand-written foreign debt in our own repos. Nobody has counted it with the discipline used for Rust.
Boundary
docs/now/2026-10-20-python-debt.md
User Scenarios
Given the tracked .py files of the five repositories, when the census runs, then it prints per file the physical lines, the functions, the share of functions in the subset and whether the file has tests.
Given a file with only pure functions over numbers, bytes and lists, when it is ranked, then it is marked as a whole-file candidate with its line count.
Given a function that reads files, runs a process, uses a class with state or a dynamic feature, when it is classified, then the reason is named.
Requirements
FR-001: The census MUST parse with Python's own ast module (no regexes), exclude vendored, generated and test-only paths with the reason, and count lines the way the own-language gate does.
FR-002: The subset rules MUST be written down in the document (allowed types, calls and imports) so the number can be reproduced, and 30 functions classified by hand MUST be compared with the scanner to report its precision.
FR-003: This issue is analysis only: no Python is deleted and no spec is added before the table is on the issue.
Success Criteria
The table is on this issue and in docs/now/2026-10-20-python-debt.md, with at least 20 rows ranked by lines.
It names the first whole-file candidate of at least 150 lines of Python whose functions all fit the subset, or states in numbers why none does.
Python debt census for #11168 (analysis only; no Python is deleted and no spec is added). The same tables, the full ranked list (64 typed-subset files, 25 shape-subset files, the 20 largest files) and the 30-row hand-check table are in docs/now/2026-10-20-python-debt.md, PR #11176.
Measured at t27 master 0e00974 (this repository), trios main 78671ba794, trinity main 8e535bc9bb, trinity-fpga main c9b180bf78, 999-multibots-telegraf main fcdbb2f7dc: the commits #11149 and #11159 used. The local checkouts of the four sibling repositories were not used (stale feature branches); the commits were fetched into scratch. python3 -I on Python 3.14.6, ast and tokenize only: no regular expression classifies code.
Answer
Prize, in one sentence: 812 of 331,183 distinct hand-written, non-test Python lines (0.25%) sit in the 105 distinct functions that fit the typed subset today, and 4,090 lines (1.23%) in the 454 that fit once their parameter types are inferred from traces; no file is a whole-file candidate of 150 lines or more, so a Python port deletes functions, not files.
Scale: 2,126 tracked .py files hold 434,986 gate-counted lines (t27 alone 153,503, which equals git diff --numstat of deleting every tracked .py there, checked). After 23 generated, 22 vendored and 138 test-only files, the census holds 1,943 files and 412,066 lines; 1,906 files parse (12,547 functions, 1,001 classes) and 37 do not. Counting identical contents once (230 of trinity's 306 scanned files are byte-identical files of trinity-fpga) that is 1,618 files, 331,183 lines and 8,501 distinct function bodies.
The functions that fit are small: the median in-subset function has 6 lines (T) and 6 lines (S), the largest 34 (T) and 89 (S); 4 of the 105 T bodies and 34 of the 454 S bodies have 20 lines or more. The median function of the whole census has 13 lines.
Ceiling if t27 could say heap values: a further 1,293 distinct fns / 16,577 lines (5.0%) are pure but blocked only by owned strings, dict/set, comprehensions, union or None returns, or a pure standard-library import (re, struct, hashlib, fractions, ...). That is the same wall that bounded the Rust census: what t27 cannot say, not what a converter has not learned.
Whole-file candidates: T none; S one, tools/ternary_model.py (93 lines, 12 fns, no test, imported by tools/verify_exhaustive.py, and it already has a spec twin specs/port/tools/ternary_model.t27). The first whole-file candidate of 150 lines or more whose functions all fit: none. Of 737 distinct files with 150 lines or more, 0 have every function in T and 1 has every function in S (archive/experiments/kinetic_sacred_pure.py, 256 lines, 3 functions) but it also runs 82 module-level statements (a report script made of top-level print calls), so it is not whole. The closest real candidate is tools/gft_train_demo.py (201 lines): 16 of 18 functions fit the shape subset (130 of 201 lines), but none is typed and main (33 lines) reads random and prints.
Oracles: of the 64 distinct files that hold a T function, 3 have a test file that imports them and none has a doctest; 20 contain assert statements or inline test functions. 62 of the 64 are scripts with an if __name__ guard. The original itself, run on sampled inputs, is the only oracle for most of them (t27o: Python front end, with types inferred from oracle traces #8995).
Hand check: 30 functions classified by hand against the written rules before looking at the scanner's verdict. First round 29 of 30 agreed (one false positive: a function returning None or bytes; the rule "optional return" was added). Fresh sample of 30 with the final scanner: 30 of 30 agree (15 of 15 in-subset, 15 of 15 out; 95% lower bound for the in-class precision, one-sided, 82%).
Entry points: no whole-file candidate means a port deletes functions, and t27c gen-python lowers no function (it emits consts, enums and structs only; a fn block is announced in a comment and no def is ever written, see bootstrap/src/codegen_python.rs). A script whose functions move to a spec therefore keeps calling them through a hand-written loader such as scripts/tri_loop/t27b_rules.py (compiles the generated C and calls it with ctypes), or its callers change. Section "Callers and entry points" has the numbers.
the own-language gate's generated roots (specs/policy/own_language.t27); no tracked .py sits there
generated header
23
1,699
a comment line among the first 8 lines says one of: do not edit, auto-generated, autogenerated, this file is generated, generated by, @generated, code generated, automatically generated. 9 VIBEE multi-language generator outputs in each of trinity and trinity-fpga, plus 5 *_params.py copies of a spec in trinity-fpga. A docstring that says "generated by t27c" is prose and does not count (2 hand-written t27 files had it)
vendored
22
8,180
a path component in node_modules, vendor, vendored, third_party, third-party, site-packages, venv, .venv, pycache, zig-pkg, dist, build, target. All 22 are the zig-pkg/<hash>/ emsdk checkout (11 files, 4,090 lines in each of trinity and trinity-fpga)
test-only
138
22,920
a component tests, test, __tests__, or a file named test_*.py, *_test.py, conftest.py. Excluded from the ranking (a port deletes the tests together with the code or not at all), used as oracles in the "oracle" column
parse failures
37 (+1 test-only)
8,084
ast.parse raises (Jupyter magics such as !pip and %choose, a line of JavaScript in a .py file, a truncated try block, unmatched brackets, an em dash in code, an unescaped brace in an f-string). They stay in the line counts, because the gate counts them, and carry no classified function
census
1,943
412,066
what is left: 1,906 parsed files (403,982 lines) and 37 unparsed (8,084)
The subset (what "fits" means)
Rules are applied to every function in source order; the first violation by position is the "first blocker" (signature first; optional return is positioned at the last line so that it is first only when nothing else blocks). A function is in the typed subset T when no rule fires and every parameter is typed; in the shape subset S when the same holds but a parameter may be untyped.
R1 kind. A plain def. Out: async, yield, await, lambda, a nested def or class, global/nonlocal, del, the walrus, match, try, with, a decorator other than staticmethod (@property, @classmethod, @functools.lru_cache, @torch.no_grad() and every framework decorator), *args/**kwargs. Keyword-only parameters are allowed.
R2 types. A parameter is typed when its annotation is int, float, bool, bytes, str, list/List/Sequence/tuple/Tuple of those (recursively), or a value class of the same file (R7); or when it has no annotation and a literal int/float/bool/str/bytes default (the type is inferred from the literal), or a default that is a module constant of such a type. An annotation outside that grammar (Optional, Union, X | None, dict, set, Any, Callable, Path, Fraction, a class with state, np.ndarray) is out as param type; the return annotation follows the same grammar plus None (return type). A function without a return annotation that returns None on one path and a value on another, or falls off the end after returning a value elsewhere, is out as optional return. A parameter that has no annotation and no literal default is untyped: the function is in S only.
R3 names. A name that is read must be a parameter, a local, a module-level constant, a same-module function or value class (R9), math.*, or one of the builtins len abs min max sum range int float bool bytes bytearray round pow divmod ord chr list tuple sorted reversed enumerate zip all any. A module-level constant is a name assigned at module level from literals, lists/tuples of literals, arithmetic and comparisons over them, math.* calls, or other constants (tuple targets allowed); a constant that a function mutates (TABLE.append, TABLE[i] = x) is module state. Everything else is out with a named reason: io builtin (open, print, input, exit), dynamic (eval, exec, compile, getattr, setattr, hasattr, globals, locals, vars, type, id, isinstance, issubclass, callable, dir, super, hash), dict/set (dict, set, frozenset, defaultdict, Counter, deque, a dict or set literal or comprehension, a dict or set method), iterator (map, filter, iter, next), module state (a module-level name that is not a constant, __file__ included), unknown name.
R4 imports. Only math, typing, dataclasses, enum, collections.abc (and __future__). A function that reads a name bound by any other import is out: io module when the module is one of os, sys, subprocess, socket, requests, urllib, http, pathlib, shutil, glob, tempfile, io, logging, argparse, getpass, sqlite3, asyncio, threading, multiprocessing, signal, json, csv, pickle, time, datetime, random, secrets and a few more network, archive and config modules; import use for every other module (numpy, torch, re, struct, hashlib, fractions, a local module). An import the function never reads is ignored.
R5 strings are read-only text. Allowed: indexing, slicing, len, comparison, in, iteration, ord, chr, startswith, endswith, find, rfind, index, count and the is* tests. Out as owned string: an f-string with a field, str(), repr, format, hex, bin, oct, +, * or % on a str, and the methods lower upper strip lstrip rstrip replace join split rsplit splitlines format zfill ljust rjust center title capitalize swapcase hex decode encode removeprefix removesuffix partition and their kin. The message of a raise or an assert is exempt.
R6 lists and tuples are allowed: literals, indexing, slicing, element assignment, append/extend/pop/insert/sort/reverse/copy, list comprehensions, tuple unpacking, returning a tuple. Out: generator expressions (generator expression), set and dict comprehensions, starred expressions. Use of list growth, tuple values and element writes is recorded as a flag and does not exclude (they are the features the Rust census found t27 cannot say, so they are reported below as a second number).
R7 methods and attributes. A method is classified like a function only when its class is a value class: @dataclass(frozen=True) with annotated fields that fit R2, an Enum, a NamedTuple, or a namespace class that holds only staticmethods. self.x may be read when x is a declared field. Any assignment to self.x, a @property, a @classmethod, or a method of any other class is out (stateful class method, self state, decorator). An attribute or method on any other value is out as attribute or method outside table; the allowed methods are the string and list ones named above plus bit_length, bit_count, to_bytes and int.from_bytes.
R8 exceptions. A plain raise of a built-in exception (ValueError, TypeError, IndexError, KeyError, ZeroDivisionError, AssertionError, NotImplementedError, OverflowError, RuntimeError, ArithmeticError, Exception) is allowed. try, a re-raise, raise ... from and every other exception class are out (try, exceptions).
R9 calls. A call to a same-module function or value class is allowed only when the callee is in the same tier (a fixpoint over the module; calls a function that is out). A call through a local name or a computed callee is out (call).
R10 whole file. Every function and class of the file is in the tier, the module level holds only a docstring, imports, constants (R3), defs and in-subset classes, and there is no if __name__ == "__main__". Near-whole: the same, with main and its nested defs left out.
Line counts. Physical lines are what git diff --numstat reports for a deleted file (newline-terminated lines plus an unterminated last line), i.e. what the own-language gate counts. Code lines carry at least one token other than a comment or layout token (tokenize), docstring lines included. A function's lines are its span from the first decorator line to end_lineno (blank lines, comments and docstring included). Functions are every def (module-level, method, nested); lambdas are not counted as functions.
Columns: gate-counted lines is every tracked .py including generated, vendored and test files, counted as git diff --numstat would; generated / vendored and parse failures and test-only are file counts; lines / code are the scanned (parsed, non-test) files; fns are module-level functions + methods + nested defs; classes in subset / all are module-level classes; 999-multibots is 999-multibots-telegraf; whole T / S and near-whole S count whole-file candidates (R10) with their physical lines in parentheses; near-whole leaves main out. The raw row repeats copies (trinity and trinity-fpga share byte-identical files); the distinct row counts identical files once and identical function bodies once, so its T/S counts are bodies, and its line count adds up only the parsed files (325,897; with 5,286 lines in unparsed files the census is 331,183 lines).
Files ranked by the lines of their typed-subset (T) functions (top 30 of 64 distinct files)
Files ranked by the lines of their shape-subset (S) functions (top 15 of 275)
#
repo
path
lines / code
fns f+m+n / classes
T fns / lines
S fns / lines
oracle
entry
callers
copies
verdict
1
trinity-fpga
fpga/witness/gf_decode/rtl_bit_model.py
423 / 317
13+0+0 / 0
0 / 0
6 / 169
1 asserts
script
py 1
0
partial
2
trinity-fpga
formal/verify_adder_oracle.py
329 / 259
6+0+0 / 0
0 / 0
3 / 144
none
script
ci 1
0
partial
3
t27
tools/gft_train_demo.py
201 / 168
17+0+1 / 0
0 / 0
16 / 130
none
script
py 1, doc 3
0
near-whole (S)
4
trinity-fpga
conformance/corona_decode_host_ax7203.py
381 / 304
16+0+0 / 0
0 / 0
8 / 129
1 inline test fn
script
ci 1, sh 3, py 2
0
partial
5
t27
tools/gft_backprop_microcode.py
967 / 684
19+0+24 / 0
0 / 0
13 / 114
1 inline test fn, 38 asserts
script
ci 1, py 4, code 1, doc 10
0
partial
6
trinity
archive/experiments/golden_key_proof.py
442 / 317
12+0+0 / 0
8 / 96
8 / 96
none
script
amb 1
3
partial
7
trinity-fpga
conformance/gf96_bitexact_oracle.py
326 / 249
7+0+0 / 0
0 / 0
2 / 69
none
script
none found
0
partial
8
t27
tools/trinity_tri_api.py
2334 / 2004
103+4+13 / 3
5 / 43
9 / 65
1 inline test fn, 1 asserts
script
py 3, code 4, doc 3
0
partial
9
trinity-fpga
conformance/gf128_bitexact_oracle.py
273 / 226
7+0+0 / 0
0 / 0
2 / 62
none
script
none found
0
partial
10
trinity-fpga
conformance/gf48_bitexact_oracle.py
295 / 218
9+0+0 / 0
0 / 0
2 / 59
none
script
py 1
0
partial
11
trinity-fpga
conformance/gf256_bitexact_oracle.py
253 / 222
7+0+0 / 0
0 / 0
2 / 59
none
script
none found
0
partial
12
trinity-fpga
conformance/gf512_bitexact_oracle.py
223 / 196
7+0+0 / 0
0 / 0
2 / 59
none
script
none found
0
partial
13
trinity-fpga
conformance/gf1024_bitexact_oracle.py
221 / 194
7+0+0 / 0
0 / 0
2 / 59
none
script
none found
0
partial
14
trinity-fpga
conformance/top_decode_conformance_ax7203.py
134 / 110
7+0+0 / 0
0 / 0
4 / 55
none
script
py 1
0
partial
15
trinity
archive/experiments/trinity_benchmarks.py
389 / 283
11+9+0 / 2
6 / 51
6 / 51
none
script
none found
3
partial
Reading the ranked tables: lines / code are physical and code lines; fns f+m+n are module-level functions, methods and nested defs; classes are module-level classes; T and S are the distinct-file's own in-subset function counts and spans; oracle lists test files that import the module, inline test functions, assert statements in the file, doctests; entry is script when the file has an if __name__ guard; callers counts other files: ci workflows and other YAML, sh shell, Makefile, Dockerfile, py other .py files that import it or name it, code Rust, t27, Zig, TypeScript, JavaScript, Go and C sources, doc Markdown and text, amb mentions by a basename that other files of the repository share; copies is the number of other paths or repositories with byte-identical content (counted once in the table and in the distinct totals). For trios, trinity, trinity-fpga and 999-multibots-telegraf only the checked-out file types were searched for callers (.py, shell, YAML, Makefile, Dockerfile, package.json, pyproject.toml), so code and doc are undercounts there.
First blockers (distinct function bodies)
first blocker
distinct fns
lines
share of fns
stateful class method
1,195
22,315
14.1%
io module
973
37,553
11.4%
import use
968
18,421
11.4%
owned string
717
25,750
8.4%
param type
624
15,805
7.3%
nested def
588
9,791
6.9%
dict/set
427
12,671
5.0%
return type
353
7,480
4.2%
shape fits, parameter untyped
349
3,278
4.1%
io builtin
343
15,601
4.0%
module state
333
7,684
3.9%
method outside table
245
2,678
2.9%
decorator
191
1,791
2.2%
attribute
178
3,767
2.1%
Methods of classes with state are the largest wall (1,195 distinct functions, 14.1%), then imports of a module outside the allowed five (1,941, 22.8%; numpy 259, argparse 231, os 183, sys 179, random 105, re 102, serial 95, subprocess 94, torch 77, fractions 65), owned strings (717, 8.4%), annotations outside the grammar (977), nested defs (588) and dict/set (427).
Input and output dominate: imports of other modules, io builtin (343), with and try (226) are the first blocker of 29.5% of the distinct functions.
The functions that fail for exactly one category (allowing that category alone would admit them):
the only blocker
distinct fns
lines
owned string
166
2,075
decorator
88
268
dict/set
76
649
generator expression
64
477
method outside table
57
238
attribute
40
510
module state
39
292
import use (pure stdlib module)
35
617
nested def
31
117
optional return
25
355
stateful class method
25
166
import use
19
133
First whole-file candidate
Distinct files of 150 lines or more: 737. With every function in T: 0. With every function in S: 1 (archive/experiments/kinetic_sacred_pure.py, which runs 82 module-level statements and is therefore not whole). Files of any size with every function in S: 4 (tools/ternary_model.py (93 lines), archive/experiments/kinetic_sacred_pure.py (256 lines), parameter_golf_gf8_ablation/gfplus_line/testE_v3.py (57 lines), research/arxiv_tnf/gen_figures_prior.py (129 lines)); only the first has no module-level effect (the others run 82, 21 and 46 module-level statements).
Largest share of a 150-line-plus file inside S: tools/gft_train_demo.py 16 of 18 fns, 130 of 201 lines, formal/verify_adder_oracle.py 3 of 6 fns, 144 of 329 lines, fpga/witness/gf_decode/rtl_bit_model.py 6 of 13 fns, 169 of 423 lines, conformance/corona_decode_host_ax7203.py 8 of 16 fns, 129 of 381 lines.
Near-whole in S (everything but main fits): 5 files, tools/gft_train_demo.py (201 lines), conformance/binary256_decode_conformance_ax7203.py (91 lines), conformance/bram_test_conformance_ax7203.py (43 lines), research/arxiv_tnf/measurements/gen_topaligned_cost.py (71 lines), research/block/verify_phase_theorem.py (146 lines). Only tools/gft_train_demo.py is above 150 lines, and it is imported by tools/gft_deep_demo.py (six of its functions) and described in docs/GFT_TRAINING_DEMO.md; it has a spec twin specs/port/tools/gft_train_demo.t27 and no test.
Already ported: in t27, 57 of 596 scanned .py files have a spec of the same path under specs/port/ (published by the port bees, 93 docs/now/*-published-port-*-py-python-* entries, 92 of which name a script; that script is still tracked for 41 of them); 7 of the 76 t27 files that hold S functions have one (204 S lines). Equivalence of those twins was not checked here.
Hand check (30 functions)
Method. Sample drawn with a seeded generator (seed 20261021) from the functions of the distinct files (byte-identical copies counted once): 15 from the in-subset (T) set, 4 uniformly from the out set, 5 from the shape-fits-but-untyped set, 6 from out functions that have exactly one violation category (the borderline ones, where a scanner bug would flip the verdict). The 30 were shuffled, printed as source with their imports and no verdict, and classified by hand against R1 to R10 (the callee, class and module constant were looked up when the rule needed them); the verdicts were written to a file, then compared with the scanner's.
Round 1 (seed 20261020, scanner before the fix): 29 of 30 agreed. The disagreement was extract_field in tools/trinity_tri_api.py, which returns None on some paths and bytes on others: a union that the scanner passed because it checks annotations only. Rule optional return (R2) was added; one more rule expected to matter was added in the same edit, not found by the sample (a module list mutated through TABLE.append or TABLE[i] = x is module state). The classification of the 12,547 functions moved by 20 S and 6 T functions.
Round 2 (seed 20261021, final scanner, the table below): 30 of 30 verdicts agree on both tiers. In-class precision 15 of 15 (95% one-sided lower bound 82%); out-class 15 of 15; first-blocker reason agrees in 14 of 15 out functions (in accumulate the scanner found an import I had missed; the verdict agreed).
What the hand check does not show: the sample is small; the rules and the check are by the same author; recall is measured on 15 out functions (4 uniform, 5 shape-fits-but-untyped, 6 one-category), not over the 8,400 out functions.
Callers and entry points
Of the 64 distinct files that hold a T function: 62 are scripts (an if __name__ guard), 9 are run or named by a workflow, shell script, Makefile or Dockerfile, 15 are imported by another .py, and 29 have no reference found at all. Of the 275 files that hold an S function: 224 are scripts.
A port has to keep the entry point of a script (python3 path.py in a workflow, a shell script or a doc) and the import surface of a module (from tools.x import f). t27c gen-python cannot give back a function: bootstrap/src/codegen_python.rs states that a fn is "announced, not stubbed", and its test asserts the output contains no def . The only existing way for Python to call spec logic is a hand-written loader: scripts/tri_loop/t27b_rules.py (315 lines) compiles gen/c/tri/t27b/steward.c and calls it with ctypes. Of the 105 T bodies, 60 (361 lines) are flat numeric code with no list growth, no tuple value and no element write; the others use at least one of those, which a plain scalar C signature does not carry (my reading, not measured).
What a caller would call after a port: for the module-level pure functions, the same name through a loader shim that is itself hand-written Python and counts against the foreign-line budget (no net-negative diff unless the functions deleted outnumber the shim); or, if the caller is a script that only runs the spec, tri/t27c directly with the caller changed. With a median in-subset function of 6 lines, a shim of 15 to 40 lines costs more than it deletes unless several functions of one file move together. This is the reason to measure a file before choosing it, and why the whole-file number above is the one that counts.
What this does not establish
Not run: no t27c, no cargo, no tri build, no converter. There is no Python front end yet, so "fits the subset" means "passes the written rules", not "converts and verifies". t27c gen-python was read, not executed. No oracle replay and no equivalence check of any port twin.
Near-duplicates (copies that differ by a few bytes) are collapsed only when their function bodies are identical by ast.dump; files are collapsed only when byte-identical.
Callers in the four sibling repositories were searched in the checked-out file types only; basename matches are labelled amb when another file of the same repository shares the name. Dynamic imports (importlib, runpy) are found only when the path or file name appears as a string token.
The local checkouts under the user's home were not used (stale feature branches); the numbers are for the pinned commits. A run on a later master will differ.
The hand check was done by the author of the rules; an independent reviewer would be a stronger check.
Activity
gHashTag commentedon Oct 19, 2026
Python debt census for #11168 (analysis only; no Python is deleted and no spec is added). The same tables, the full ranked list (64 typed-subset files, 25 shape-subset files, the 20 largest files) and the 30-row hand-check table are in
docs/now/2026-10-20-python-debt.md, PR #11176.Measured at t27 master 0e00974 (this repository), trios main 78671ba794, trinity main 8e535bc9bb, trinity-fpga main c9b180bf78, 999-multibots-telegraf main fcdbb2f7dc: the commits #11149 and #11159 used. The local checkouts of the four sibling repositories were not used (stale feature branches); the commits were fetched into scratch.
python3 -Ion Python 3.14.6,astandtokenizeonly: no regular expression classifies code.Answer
.pyfiles hold 434,986 gate-counted lines (t27 alone 153,503, which equalsgit diff --numstatof deleting every tracked.pythere, checked). After 23 generated, 22 vendored and 138 test-only files, the census holds 1,943 files and 412,066 lines; 1,906 files parse (12,547 functions, 1,001 classes) and 37 do not. Counting identical contents once (230 of trinity's 306 scanned files are byte-identical files of trinity-fpga) that is 1,618 files, 331,183 lines and 8,501 distinct function bodies.tools/ternary_model.py(93 lines, 12 fns, no test, imported bytools/verify_exhaustive.py, and it already has a spec twinspecs/port/tools/ternary_model.t27). The first whole-file candidate of 150 lines or more whose functions all fit: none. Of 737 distinct files with 150 lines or more, 0 have every function in T and 1 has every function in S (archive/experiments/kinetic_sacred_pure.py, 256 lines, 3 functions) but it also runs 82 module-level statements (a report script made of top-levelprintcalls), so it is not whole. The closest real candidate istools/gft_train_demo.py(201 lines): 16 of 18 functions fit the shape subset (130 of 201 lines), but none is typed andmain(33 lines) readsrandomand prints.assertstatements or inline test functions. 62 of the 64 are scripts with anif __name__guard. The original itself, run on sampled inputs, is the only oracle for most of them (t27o: Python front end, with types inferred from oracle traces #8995).t27c gen-pythonlowers no function (it emits consts, enums and structs only; afnblock is announced in a comment and nodefis ever written, seebootstrap/src/codegen_python.rs). A script whose functions move to a spec therefore keeps calling them through a hand-written loader such asscripts/tri_loop/t27b_rules.py(compiles the generated C and calls it with ctypes), or its callers change. Section "Callers and entry points" has the numbers.Scope and exclusions
gen/,bootstrap/gen/,bootstrap/src/memory/generated/)specs/policy/own_language.t27); no tracked.pysits there*_params.pycopies of a spec in trinity-fpga. A docstring that says "generated byt27c" is prose and does not count (2 hand-written t27 files had it)zig-pkg/<hash>/emsdk checkout (11 files, 4,090 lines in each of trinity and trinity-fpga)tests,test,__tests__, or a file namedtest_*.py,*_test.py,conftest.py. Excluded from the ranking (a port deletes the tests together with the code or not at all), used as oracles in the "oracle" columnast.parseraises (Jupyter magics such as!pipand%choose, a line of JavaScript in a.pyfile, a truncatedtryblock, unmatched brackets, an em dash in code, an unescaped brace in an f-string). They stay in the line counts, because the gate counts them, and carry no classified functionThe subset (what "fits" means)
Rules are applied to every function in source order; the first violation by position is the "first blocker" (signature first;
optional returnis positioned at the last line so that it is first only when nothing else blocks). A function is in the typed subset T when no rule fires and every parameter is typed; in the shape subset S when the same holds but a parameter may be untyped.def. Out:async,yield,await,lambda, a nesteddeforclass,global/nonlocal,del, the walrus,match,try,with, a decorator other thanstaticmethod(@property,@classmethod,@functools.lru_cache,@torch.no_grad()and every framework decorator),*args/**kwargs. Keyword-only parameters are allowed.Optional,Union,X | None,dict,set,Any,Callable,Path,Fraction, a class with state,np.ndarray) is out asparam type; the return annotation follows the same grammar plusNone(return type). A function without a return annotation that returns None on one path and a value on another, or falls off the end after returning a value elsewhere, is out asoptional return. A parameter that has no annotation and no literal default is untyped: the function is in S only.math.*, or one of the builtins len abs min max sum range int float bool bytes bytearray round pow divmod ord chr list tuple sorted reversed enumerate zip all any. A module-level constant is a name assigned at module level from literals, lists/tuples of literals, arithmetic and comparisons over them,math.*calls, or other constants (tuple targets allowed); a constant that a function mutates (TABLE.append,TABLE[i] = x) ismodule state. Everything else is out with a named reason:io builtin(open, print, input, exit),dynamic(eval, exec, compile, getattr, setattr, hasattr, globals, locals, vars, type, id, isinstance, issubclass, callable, dir, super, hash),dict/set(dict, set, frozenset, defaultdict, Counter, deque, a dict or set literal or comprehension, a dict or set method),iterator(map, filter, iter, next),module state(a module-level name that is not a constant,__file__included),unknown name.__future__). A function that reads a name bound by any other import is out:io modulewhen the module is one of os, sys, subprocess, socket, requests, urllib, http, pathlib, shutil, glob, tempfile, io, logging, argparse, getpass, sqlite3, asyncio, threading, multiprocessing, signal, json, csv, pickle, time, datetime, random, secrets and a few more network, archive and config modules;import usefor every other module (numpy, torch, re, struct, hashlib, fractions, a local module). An import the function never reads is ignored.in, iteration, ord, chr, startswith, endswith, find, rfind, index, count and the is* tests. Out asowned string: an f-string with a field,str(),repr,format,hex,bin,oct,+,*or%on a str, and the methods lower upper strip lstrip rstrip replace join split rsplit splitlines format zfill ljust rjust center title capitalize swapcase hex decode encode removeprefix removesuffix partition and their kin. The message of araiseor anassertis exempt.generator expression), set and dict comprehensions, starred expressions. Use of list growth, tuple values and element writes is recorded as a flag and does not exclude (they are the features the Rust census found t27 cannot say, so they are reported below as a second number).@dataclass(frozen=True)with annotated fields that fit R2, anEnum, aNamedTuple, or a namespace class that holds onlystaticmethods.self.xmay be read whenxis a declared field. Any assignment toself.x, a@property, a@classmethod, or a method of any other class is out (stateful class method,self state,decorator). An attribute or method on any other value is out asattributeormethod outside table; the allowed methods are the string and list ones named above plusbit_length,bit_count,to_bytesandint.from_bytes.raiseof a built-in exception (ValueError, TypeError, IndexError, KeyError, ZeroDivisionError, AssertionError, NotImplementedError, OverflowError, RuntimeError, ArithmeticError, Exception) is allowed.try, a re-raise,raise ... fromand every other exception class are out (try,exceptions).calls a function that is out). A call through a local name or a computed callee is out (call).if __name__ == "__main__". Near-whole: the same, withmainand its nested defs left out.git diff --numstatreports for a deleted file (newline-terminated lines plus an unterminated last line), i.e. what the own-language gate counts. Code lines carry at least one token other than a comment or layout token (tokenize), docstring lines included. A function's lines are its span from the first decorator line toend_lineno(blank lines, comments and docstring included). Functions are everydef(module-level, method, nested); lambdas are not counted as functions.Totals per repository
Columns:
gate-counted linesis every tracked.pyincluding generated, vendored and test files, counted asgit diff --numstatwould;generated / vendoredandparse failuresandtest-onlyare file counts;lines / codeare the scanned (parsed, non-test) files;fnsare module-level functions + methods + nested defs;classes in subset / allare module-level classes;999-multibotsis 999-multibots-telegraf;whole T / Sandnear-whole Scount whole-file candidates (R10) with their physical lines in parentheses; near-whole leavesmainout. The raw row repeats copies (trinity and trinity-fpga share byte-identical files); the distinct row counts identical files once and identical function bodies once, so itsT/Scounts are bodies, and its line count adds up only the parsed files (325,897; with 5,286 lines in unparsed files the census is 331,183 lines).Files ranked by the lines of their typed-subset (T) functions (top 30 of 64 distinct files)
archive/experiments/golden_key_proof.pyarchive/experiments/trinity_benchmarks.pyconformance/gen_structural_instances.pydeploy/scripts/multi_provider_hybrid.pytools/scripts/scripts/multi_provider_hybrid.pytools/trinity_tri_api.pytools/queen/propose_boundary.pyconformance/wasm_board_vectors.pyscripts/cocotb_ref_model.pytools/trinity_manifest.pydeploy/trinity-nexus/tools/bindings/python/igla.pyresearch/verify_lucas_product.pyconformance/gf16_conformance_ax7203.pytools/trinity_build_receipt.pydocs/notebooks/quantum/e8_particles.pytools/dupe_scan.pyresearch/spectrum/spectrum.pycontrib/backend/github/auth.pyconformance/decimal_ref.pyscripts/trinity-pellis-pipeline/task1_monte_carlo/monte_carlo_exact_pvalue.pyconformance/trinet_mac32_conformance_ax7203.pytools/trinity_vsa_compat.pyresearch/synth_check.pyconformance/fp8_ref.pydeploy/trinity-nexus/docs/book/generator/book_generator_v2.pydocs/book/book/generator/book_generator_v2.pydeploy/trinity-nexus/docs/book/generator/templates.pydocs/book/book/generator/templates.pydeploy/trinity-nexus/docs/book/generator/book_generator.pydocs/book/book/generator/book_generator.pyFiles ranked by the lines of their shape-subset (S) functions (top 15 of 275)
fpga/witness/gf_decode/rtl_bit_model.pyformal/verify_adder_oracle.pytools/gft_train_demo.pyconformance/corona_decode_host_ax7203.pytools/gft_backprop_microcode.pyarchive/experiments/golden_key_proof.pyconformance/gf96_bitexact_oracle.pytools/trinity_tri_api.pyconformance/gf128_bitexact_oracle.pyconformance/gf48_bitexact_oracle.pyconformance/gf256_bitexact_oracle.pyconformance/gf512_bitexact_oracle.pyconformance/gf1024_bitexact_oracle.pyconformance/top_decode_conformance_ax7203.pyarchive/experiments/trinity_benchmarks.pyReading the ranked tables:
lines / codeare physical and code lines;fns f+m+nare module-level functions, methods and nested defs;classesare module-level classes;TandSare the distinct-file's own in-subset function counts and spans;oraclelists test files that import the module, inline test functions,assertstatements in the file, doctests;entryisscriptwhen the file has anif __name__guard;callerscounts other files:ciworkflows and other YAML,shshell, Makefile, Dockerfile,pyother.pyfiles that import it or name it,codeRust, t27, Zig, TypeScript, JavaScript, Go and C sources,docMarkdown and text,ambmentions by a basename that other files of the repository share;copiesis the number of other paths or repositories with byte-identical content (counted once in the table and in the distinct totals). For trios, trinity, trinity-fpga and 999-multibots-telegraf only the checked-out file types were searched for callers (.py, shell, YAML, Makefile, Dockerfile, package.json, pyproject.toml), socodeanddocare undercounts there.First blockers (distinct function bodies)
io builtin(343),withandtry(226) are the first blocker of 29.5% of the distinct functions.The functions that fail for exactly one category (allowing that category alone would admit them):
First whole-file candidate
archive/experiments/kinetic_sacred_pure.py, which runs 82 module-level statements and is therefore not whole). Files of any size with every function in S: 4 (tools/ternary_model.py(93 lines),archive/experiments/kinetic_sacred_pure.py(256 lines),parameter_golf_gf8_ablation/gfplus_line/testE_v3.py(57 lines),research/arxiv_tnf/gen_figures_prior.py(129 lines)); only the first has no module-level effect (the others run 82, 21 and 46 module-level statements).tools/gft_train_demo.py16 of 18 fns, 130 of 201 lines,formal/verify_adder_oracle.py3 of 6 fns, 144 of 329 lines,fpga/witness/gf_decode/rtl_bit_model.py6 of 13 fns, 169 of 423 lines,conformance/corona_decode_host_ax7203.py8 of 16 fns, 129 of 381 lines.mainfits): 5 files,tools/gft_train_demo.py(201 lines),conformance/binary256_decode_conformance_ax7203.py(91 lines),conformance/bram_test_conformance_ax7203.py(43 lines),research/arxiv_tnf/measurements/gen_topaligned_cost.py(71 lines),research/block/verify_phase_theorem.py(146 lines). Onlytools/gft_train_demo.pyis above 150 lines, and it is imported bytools/gft_deep_demo.py(six of its functions) and described indocs/GFT_TRAINING_DEMO.md; it has a spec twinspecs/port/tools/gft_train_demo.t27and no test..pyfiles have a spec of the same path underspecs/port/(published by the port bees, 93docs/now/*-published-port-*-py-python-*entries, 92 of which name a script; that script is still tracked for 41 of them); 7 of the 76 t27 files that hold S functions have one (204 S lines). Equivalence of those twins was not checked here.Hand check (30 functions)
Method. Sample drawn with a seeded generator (seed 20261021) from the functions of the distinct files (byte-identical copies counted once): 15 from the in-subset (T) set, 4 uniformly from the out set, 5 from the shape-fits-but-untyped set, 6 from out functions that have exactly one violation category (the borderline ones, where a scanner bug would flip the verdict). The 30 were shuffled, printed as source with their imports and no verdict, and classified by hand against R1 to R10 (the callee, class and module constant were looked up when the rule needed them); the verdicts were written to a file, then compared with the scanner's.
extract_fieldintools/trinity_tri_api.py, which returns None on some paths and bytes on others: a union that the scanner passed because it checks annotations only. Ruleoptional return(R2) was added; one more rule expected to matter was added in the same edit, not found by the sample (a module list mutated throughTABLE.appendorTABLE[i] = xismodule state). The classification of the 12,547 functions moved by 20 S and 6 T functions.accumulatethe scanner found an import I had missed; the verdict agreed).Callers and entry points
if __name__guard), 9 are run or named by a workflow, shell script, Makefile or Dockerfile, 15 are imported by another.py, and 29 have no reference found at all. Of the 275 files that hold an S function: 224 are scripts.python3 path.pyin a workflow, a shell script or a doc) and the import surface of a module (from tools.x import f).t27c gen-pythoncannot give back a function:bootstrap/src/codegen_python.rsstates that afnis "announced, not stubbed", and its test asserts the output contains nodef. The only existing way for Python to call spec logic is a hand-written loader:scripts/tri_loop/t27b_rules.py(315 lines) compilesgen/c/tri/t27b/steward.cand calls it with ctypes. Of the 105 T bodies, 60 (361 lines) are flat numeric code with no list growth, no tuple value and no element write; the others use at least one of those, which a plain scalar C signature does not carry (my reading, not measured).tri/t27cdirectly with the caller changed. With a median in-subset function of 6 lines, a shim of 15 to 40 lines costs more than it deletes unless several functions of one file move together. This is the reason to measure a file before choosing it, and why the whole-file number above is the one that counts.What this does not establish
t27c, nocargo, notribuild, no converter. There is no Python front end yet, so "fits the subset" means "passes the written rules", not "converts and verifies".t27c gen-pythonwas read, not executed. No oracle replay and no equivalence check of any port twin.ast.dump; files are collapsed only when byte-identical.ambwhen another file of the same repository shares the name. Dynamic imports (importlib,runpy) are found only when the path or file name appears as a string token.docs(t27o): python debt census -- give the lines of the whole-file an…
docs(t27o): RFC for heap-free collections, owned strings and inlined …