Repository navigation
Conversation
…the measurement Two of #1563's follow-ups: - N3: transport.omission_register@1 now reads the calibration solution beside the problem. It decodes the solution against that problem and its axis, requires every household on the axis to hold a person, and refuses a frame whose person weights differ, bit for bit, from the solution's household weights. The register's totals still use the problem's pre-fit weights. NZ's graph and the toy give the register an edge from nz.calibrate. - Nit 1, readers only: the three income evidence readers now select their `measurement` from income_measurements' own measurement_id, so they move with that resource. The stand-in keeps its literal measurement_id, because R2C-1's proof reads a producer's measurement_id as a literal string in the declared rows and refuses any other value. The toy's income measurements carry the id the same way. Not yet in this commit: the engine pins (753ce7d9) and the input surface refreshed at that engine, the closure re-review, the activation test flips, the regenerated declarations and golden, O2's static test, and the differential docstring fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine 753ce7d9, G8-x2's pin, emits artifact format 3, and the refresh tool refused it before compiling anything. Format 3 adds program.interface, engine_build and source_closure, which the walk never reads. The tool now reads formats 2 and 3, and each artifact must carry the format the engine's capabilities names. From 4d7ec14f (#292) on, the engine follows a cross-entity dense error with ". " and advice. A cross-entity blocker now also explains its own text followed by ". " and any advice, and the snapshot keeps the walk's text. be.json's seven cross-entity modules need this at 753ce7d9; NZ's one blocker, a versioned formula, keeps its exact text. The docs name each snapshot's own engine (nz 753ce7d9, be 04315d94). New engine-free tests drive a stand-in CLI, and Hypothesis checks the error matcher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- axiom_rules_bindings.json: engine.commit 753ce7d9 and wheel_sha256 054c9196, the dense-extension wheel the NZ hub built at that commit (maturin build --release --locked; CPython 3.14, macOS arm64). They were the spec's last two activation gaps. The description's relations sentence now says what assert_no_relations checks. - nz.json: the refresh at 753ce7d9, with the walk that reads format 3, moves only engine.commit. The dense-root differential agreed on every module. - axiom_input_closure.json: the surface engine and the four engine source pins move to 753ce7d9. engine_optional_evidence and the undetermined judgment cite 753ce7d9's lines, each one read again at that commit. - test_nz_axiom_input_closure.py: the closure's surface engine commit equals the bindings' engine pin. - test_transport_composed_graph.py: the packaged spec activates, and each absent engine pin is the named gap. Preparation and the CLI now refuse at the missing RuleSpec tree, after the CLI opens its empty graph store. The inventory-store test drops the pins from its copy of the spec. - The input-surface README names each snapshot's own engine, as the refresh tool's docstring does. - transport_bridge_differential.py: the docstring describes the bridge as it stands (a counterfactual base rate and a solve_zero cutout). It drops the three-evaluation recipe and why_not_solve_zero, which as_rate_bridge.json no longer has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…O2) The trace test checks the modules a kernel's run() executes, and can't see a module the run only reads constants from. test_support's static_reach walks run()'s source instead: every branch, with default argument values, decorators, class bases and attributes, and the module-level constants it reaches, each name followed through its imports to the module that defines it. It imports nothing from the repository. - test_each_kernel_hashes_every_module_its_run_can_reach: for each of the three kernels, the walk reaches exactly the listed modules outside microcosm.graph. - One cut, which the test names: Target.__post_init__ reads microcosm.calibrate.hierarchy only under `self.hierarchy is not None`. test_no_decoded_target_carries_a_hierarchy checks the premise: _read_target, which builds every decoded target, passes no hierarchy. test_the_walk_cuts_only_the_hierarchy_guard checks that the cut removes that one module and nothing else. - test_the_walk_sees_a_constant_the_trace_cant: with artifact_types dropped from the native report's list, the trace test still passes and the walk names the module. - The kernel module's docstring describes both tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/build_nz_transport_graph.py and the golden writer, run on this branch: - transport_graph.json: the three income evidence readers select their measurement from income_measurements' measurement_id (nit 1), and the omission register gains its solution edge from nz.calibrate (N3). - export_replay_bindings.json: the input closure's new sha256. - tests/golden/nz_country_spec.json: the fingerprint and the hashes of the four resources that changed. Every generator's --check passes on the result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Belgium's review of d40c004 asked for two changes before landing, and this commit makes both, plus three of their optional ones. - A stand-in --dense-python drives build_snapshot in dense mode. It ignores the probe after -c, records the jobs it reads from stdin, and answers each entity from the outcomes its test gives it. A Person rule that reads a Household rule gives the walk one cross-entity blocker. - With the engine's error as the blocker's text, or that text followed by each of the engine's four advice forms, the module records dense_unsupported with the walk's text, and the differential counts two entity programs and one dense compile. - The tool refuses an error the walk can't explain (another cross-entity read, a new limitation, an advised error on an entity the walk doesn't block), a missing program, another root and duplicate root inputs. - The differential records an input, a status and a catalog mismatch where dense and the walk disagree. - Both Hypothesis properties carry deadline=None and suppress the too_slow health check, as test_be_target_references.py does. The cross-entity property failed that check in 3 of 13 runs on Belgium's host. - The versioned property now checks the blocker's own text, another rule's versioned text, and its text with advice after it. The cross-entity property checks its own text with and without advice. - The off-format test adds an engine that names format 2 and writes 3. - The advice list adds the engine's fourth form (a relation read where the program declares no relation). - The tool's docstring says what the advice suggests (compile for the other entity, read through a relation, or compile only the outputs that don't reach the reading rule) and drops two passives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cd85cff review found four ways a run can reach a module that static_reach.py missed: a module alias held in a module-level constant, getattr with a literal name, __float__ and __add__. None occurs in the modules the three income kernels reach today, and their lists stand. The walk now - resolves a name to every definition that can bind it, through try/except alternatives, star imports and a package's lazy __getattr__ exports; - follows module-level constants that alias a module, class or function; - runs a module-level statement that changes a reached name in place (X.update(...), X[k] = v) along with that name; - reaches every dunder and sunder method of a referenced class; - reads the literal names in getattr, hasattr, setattr, delattr, attrgetter, methodcaller, import_module and __import__; - sends an attribute of an object it can't type to every same-named member of each referenced class and of each module used as a value; - starts from the root's class as well as its run(); - binds names by scope as Python does: comprehensions, lambdas, class bodies, global, nonlocal and local imports. Its docstring lists each of these and what it still can't see, which now includes a module that only an annotation names. static_reach_cases.py writes 32 synthetic roots, each reaching its targets one of those ways, and a parametrized test checks that each walk reaches exactly its targets. The cd85cff walk misses a target on 25 of the 32 and reaches an extra one on a 26th. Turning off any one of the 15 mechanisms fails at least one case. Under the new walk each kernel still reaches exactly its listed modules outside microcosm.graph, and only the hierarchy guard's cut applies. income_evidence_kernels.py: the docstring describes the new walk, and the solution check's comment now names what np.array_equal compares, float64 values (finding 2), instead of "bit for bit". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1567) The delta review of d403cce found that a class-body name lost its module-level binding. Python reads a name the class body binds from the class namespace only once a top-level statement of the body has bound it. Before that, or when only a branch, a loop or a bare annotation binds it, Python reads the module's binding. The walk now follows that rule, and a class inside a function reads its own binding or the module's, never the function's, on 3.13 and 3.14 alike. The commit also closes each miss the review listed rather than documenting it: statement headers at module and class level; filler calls and other import-time effects in each module that holds a reached item; changes in place to a reached name (method calls, stores, dels and call arguments, also through an alias); dotted module values; function-level alternative imports; subscripted bases; match class patterns; getattr, hasattr, setattr, delattr, attrgetter and methodcaller with a literal or constant name; __getattr__ assigned rather than defined; __import__ with a fromlist; a star import of a lazy package; class-level imports used through self; and a relative import_module. settle now counts only real pushes, and the walk raises after 10,000 rounds without settling, so a namespace sub-package can no longer hang it. The self/cls owner push goes: the class-attribute fallback reaches the same members, and no module set moves on any of NZ's 8 kernels. static_reach_cases.py grows from 32 to 80 roots and gains a runtime oracle. Each target module records the reads Python makes, and python_reads runs every root in one isolated interpreter. A new test asserts that Python reads exactly ROOTS less OVER plus BLIND for each root, so ROOTS can't record a walk's mistake as the answer. Another checks OVER, BLIND and the two decoys. A Hypothesis property composes 2 to 6 roots and checks that the walk loses no target and that Python reads the union of the parts' reads. Belgium's seven import-time forms became roots, and BLIND holds their registry decorator. Each of 71 one-edit knockouts of the walk fails at least one root. The income kernels' lists still equal the walk's reach outside microcosm.graph, with the one cut as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es (#1567) eb236a6's 71 knockouts left some branches of the walk's helpers with no knockout. Each branch now has one, and a root fails when it goes: - Bindings: a for or with target, a match capture (plain, star and mapping rest) and a walrus target, each imported from the module that binds it. That import alone leads the walk to the module. - Aliases: or, a walrus, a starred list, and __import__'s top package, each as a class base. - Import-time code: match patterns and guards, except* types, and effects inside if, for-else, finally, except and match-case blocks. The walk's docstring now names these forms; its code doesn't change. static_reach_cases.py grows to 91 roots, and each of 91 one-edit knockouts fails at least one of them, on Python 3.13 and 3.14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1567) The delta review of 005844b asked for one change and offered four more. This commit takes all five. - Class-body globals (required). An assignment in a class body to a name that the body declares global rebinds the module's name. The walk now follows its value whether or not it reaches the class (r_class_global, r_class_nested_fill). - Misses that both walks shared. The walk now follows: - a class-level import that the class body, a default value or a decorator reads (r_class_import_scope); - a nested class body's changes in place (r_class_nested_fill); - a for or with target that stores into a reached name's item (r_for_store); - a change inside a comprehension (r_comprehension_fill); - an inherited __match_args__ (r_match_inherited); - __import__ with a level (r_import_level); - import_module relative to __spec__.parent (r_import_spec); - these callables under another module-level name (r_import_renamed); - += on a name (r_augassign). - Branches that no root pinned. 005844b's message said "Each branch now has one, and a root fails when it goes". That was wrong. The review found seven branches whose knockout failed no root, and this commit's own sweep found an eighth. Each live one now has a root: - del in a class body (r_body_del); - __import__'s top package (r_dunder_import_top); - a class member's change (r_class_member_change); - the global filter for a nested function (r_global); - changes in every module the walk has read: r_registry's registrar now holds no reached item, so only that pass reaches its change; - comprehension targets as locals (r_comprehension_decoy); - import_module relative to __name__ (r_import_name), from a plain module, whose __name__ differs from its __package__. The redundant pop of global names in _own_names goes, since _visits already drops them. - Cost. Each lookup now runs once per walk (_Walk._settled, which follows Tarjan's strongly connected components). That covers what a name binds in a module, what a constant stands for, a package's lazy exports, and a class's inherited __match_args__. Lookups in a cycle settle on the same items, whichever the walk met first. - Nine Cost roots pin it: - diamonds 22 levels deep of star imports, re-exports, constants, bases and import alternatives; - a clique of 8 modules that star-import each other; - a cycle of 3 lazy packages; - two cycles of constants. - On the same shapes (CPython 3.14.7), the old lookups ran past a 20 s limit on the 8-module clique, and took 11.8 s, 11.7 s and 19.2 s on the 22-level diamonds of constants, re-exports and bases. With this commit each Cost root takes at most 4.1 ms on 3.14.7 and 4.5 ms on 3.13.15 (the fastest of 5 runs). - Two new tests check that each lookup runs once and returns each item once, and that each lookup the walk settles holds what a fresh walk's same lookup finds. Checks outside pytest, on CPython 3.14.7 and 3.13.15: - The walk as committed passes every check on all 115 roots: the targets, the run-once check and the fresh-walk check. - Each of 125 one-edit knockouts of the walk fails at least one root by one of those checks. Both versions agree on every knockout. - A differential against the same walk with the old lookups found no difference in items, sites or cuts (3.14.7). It covered NZ's 8 kernels, with and without the cut (16 walks), the 106 roots before the Cost roots, and 200 seeded composites of them. - On NZ's 8 kernels, with and without the cut, the module sets equal d403cce's (3.14.7). Local run of the three test files that exercise the walk and the income kernels (test_transport_income_evidence_kernels.py, test_nz_transport_toy_graph.py, test_nz_spec_package.py) on this tree, CPython 3.14.7: 1,564 passed in 130.4 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1567) The delta review of c622fc2 asked for one change and offered six more. Belgium's look at c622fc2 asked for two changes and four cases, and its OK at 005844b asked for one open form and twelve roots. This commit takes all of them. - Lookup cycles (required). c622fc2 gave every lookup in a cycle the items its first lookup ended with. A constant that maps another's items through an attribute (X = Y.sub, in a cycle with Y) then settled on less than a fresh lookup finds, and what it lost depended on which lookup the walk met first. 005844b reached what it lost. Now, when a cycle's first lookup ends, the cycle's lookups run again, each meeting what the others hold so far, until a pass adds nothing (_Walk._cycle). So each settles on what it finds once the others are complete, whichever the walk met first. New roots: - r_alias_cycle_dotted and r_alias_cycle_dotted_first, the review's shape met from each end; - r_alias_self_dotted, a lookup that waits on itself; - r_alias_cycle_join, a lookup that a pass begins and that joins the cycle. - A module's __getattr__ in a cycle (Belgium). exported() added a module's __getattr__ only when the name's lookup had found nothing. Inside a cycle that lookup hasn't settled, and Python can read the module part-built, before it binds the name. So what the walk reached depended on which lookup it met first. exported() now leaves the getter out only when the name's lookup has settled with items (r_getattr_cycle, r_getattr_cycle_first). OVER holds the getter that Python's import order doesn't pick, since the walk doesn't track that order. r_getattr_self pins the older rule that Python finds a module's __getattr__ in its namespace only. - Belgium's roots. - Form 1, the last of the three forms Belgium found at 005844b. A class body's X += 1 reads X before it binds it, so it reads the module's X until the body has bound it (r_aug_class). - Belgium's four probes become roots: r_aug_class, r_nested_change, r_global_setter and r_global_read. So do its eight roots for rules that no NZ root pinned: r_del_class, r_self_ref, r_with_class, r_ann_class, r_aug_store, r_kw_fill, r_comp_first_iter and r_walrus_comp. OVER takes the target that the walk reaches and Python doesn't read in r_del_class, r_global_read and r_global_setter. - Belgium's two controls at c622fc2 join too (r_class_iadd, r_class_comp_fill), and r_base_set passes an alias through a set display, which no root did. - Class-body globals at import. In a class the walk reaches, an assignment to a name the body declares global binds outside the class, but it runs as Python creates the class. The walk now follows it there (r_class_global_aug: X += 1 calls GlobalBox's +). - Knockouts that failed no root (review finding 5). Each now fails one: - _CALLABLES narrowed to the importers (r_getattr_renamed: getattr under a module-level name); - the class table for a class that a class body declares global (r_class_global_inherit); - __getattr__ as a lazy export of itself (r_getattr_self); - _members' filter of global names (r_global_read); - body= for a class-body global's value (r_class_global, whose module now binds _source to a decoy); - _met.add (r_alias_self_dotted), and the cut that a lookup under way gives back (seven roots, r_lazy_cycle and r_star_clique among them). The _own_names revert stays equivalent, as c622fc2's message said. - Recursion depth (finding 2). The docstring now says how deep a chain of re-exports, star imports, constants or inherited __match_args__ can go before the walk raises RecursionError (about 200, 250 and 330), and that the kernels' lookups nest at most four deep. - Misses the docstring didn't list (findings 3, 4 and 7). "What it can't see" now lists each, and a BLIND root pins each: - a nested class's global value, and the bases, keywords and decorators of a nested class that the walk runs whole (r_nested_global_value, r_nested_base_scope); - a match class pattern through a class-body global bound to the body's own import (r_class_global_match), and a name that a function binds through global (r_function_global, r_function_global_import); - a change inside a lambda that a statement calls (r_lambda_change); - import_module with another package (r_spec_name), and importers that partial wraps or a call returns (r_partial_import, r_getattr_importer); - an explicit __match_args__ that names a constant (r_match_args_constant); - an operator's side effect inside a statement that binds a name (r_aug_module_effect). The literal-constant sentence now says that each binding of the constant must set it to a string, and the annotations sentence names class bodies and modules as well as def statements. - Tests (finding 6). - test_the_walk_runs_each_lookup_once becomes test_the_walk_runs_each_lookup_once_outside_a_cycle. A lookup in a cycle runs once more for each pass that runs the cycle again (the walk's own count), and every lookup a walk begins settles. - test_the_walk_makes_few_lookups_on_the_cost_roots counts every call of the four lookup methods, the memo's answers too, and fails at the first call past 10,000. So a lookup that skips the memo, or keys it more finely than what it looks up, fails there instead of hanging. With the memo, the most any of the six roots makes is 1,257; with each lookup run afresh, each passes 300,000. - The fresh-walk test now runs on the new cycle shapes too. c622fc2's message said "r_registry's registrar now holds no reached item". The walk does reach registrar._register in the end, through the change pass itself: registrar holds no reached item until that pass finds its change, so only that pass reaches it. Checks outside pytest, on CPython 3.14.7 and 3.13.15, which agree: - The walk passes every check on all 151 roots: the targets, the runtime reads, the run-count check, the fresh-walk check and the lookup budget. - Each of the hub's 139 one-edit knockouts of the walk fails at least one root, and so does each of Belgium's 51. Of the c622fc2 review's 51, 50 fail a root, and the 51st, the _own_names revert, is equivalent. Both Pythons fail the same roots. - Against c622fc2's walk, the walk loses no item on NZ's 16 kernel walks, the 151 roots or 200 seeded composites of them. Twelve roots differ, each by a change above: ten gain items and two gain sites only. On three cycle roots, a site that settle() recorded for a module used as a value goes, since the walk now reaches the item first through the root's own lines. No kernel walk changes. - On NZ's 8 kernels, with and without the hierarchy cut, the module sets equal d403cce's, and no kernel walk has a lookup cycle. CI's engine-free jobs run the three test files; this commit had no local pytest run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The delta review of e6e1f4c asked for two changes, offered three more and listed four nits. Belgium's review of e6e1f4c asked for the same two changes and two roots. This commit takes all of them. - A cycle that meets an earlier lookup (required; Belgium's first change). e6e1f4c settled a cycle when its first lookup ended, even when a pass had met a lookup that began before the cycle and hadn't settled. The cycle's lookups then froze with that lookup's partial items, so what the walk reached still depended on which lookup it met first. Now such a cycle stays open, as a single lookup that meets an earlier one already did, and joins the earlier lookup's cycle, which runs it again with the rest (_settled, as both reviews proposed). New roots: - r_alias_cycle_outer, the review's shape: a pass meets a lookup under way; - r_alias_cycle_two_up, with that lookup two lookups up; - r_alias_cycle_sibling, with a lookup that waits rather than runs; - Belgium's r_outer_cycle_first, where only a later pass meets the earlier lookup, and r_outer_cycle, which meets the same lookups in the other order. Their modules take the prefix ocyc, since cyco already names r_alias_cycle_outer's package. On e6e1f4c's walk the first four miss their target and fail the fresh-walk check, and r_outer_cycle fails the fresh-walk check. - The composing property (required; Belgium's second change). r_getattr_cycle and r_getattr_cycle_first shared one pair of modules, whose reads depend on which root imports them first, and Python imports a module once. So a composite that held both read only the first part's target, and the property failed in CI on both Pythons. r_getattr_cycle_first now imports its own copy of the pair (gcyf_a and gcyf_b), so no two roots share a module whose reads depend on import order. Belgium proposed skipping the Python check on such draws; the copy keeps that check on every draw. - Lines that no root pinned (finding 3). Each of the review's four knockouts now fails a root: - the += branch's use of the name's value (r_aug_value: X += value hands X's module to Adder.__radd__, which reads an attribute that the module binds); - plain assignments among a class body's global stores (r_class_global_store); - exported()'s settled check (r_getattr_bound, whose module binds the name that its __getattr__ would answer, and r_getattr_settled, where the name's lookup settles before the getter counts). Each holds a decoy target that the walk reaches without the check; - the pass that a join forces (r_join_no_growth). The review's three survivors from c622fc2 fail a root too: getattr under another name in a constant's value (r_getattr_named), a reached class's decorators (r_class_decorated) and keyword-only defaults (r_kw_default). - Module __getattr__ calls outside a cycle of lookups (finding 4). "What it can't see" now lists the three other times Python calls a module's __getattr__: for a name the module binds, when an import cycle reads the module part-built; for a sub module's name, which a from-import asks the package for before it imports the sub module; and for __path__, which a from-import asks a module that isn't a package for. BLIND roots pin each: r_getattr_import_cycle, r_getattr_import_cycle_from and r_getattr_init_cycle (the review's e1 to e3), r_getattr_submodule (e4) and r_getattr_path (e5). No kernel meets them. Of the 565 first-party modules, two define a module-level __getattr__, and the kernels' walks parse one, the package microcosm.graph. Its getter answers only its 48 lazy exports, and the package binds none of them and holds no sub module of the same name. A package has __path__, so Python never asks its getter for it. - The pass log and two tests (finding 5). - _Walk.cycles records each cycle's passes: the lookups each pass ran and how many items and lookups it added. reruns, which tools read, now counts from that log. - test_the_walk_runs_each_lookup_once_outside_a_cycle counts each lookup's runs itself rather than reading the walk's count. Each lookup must run once, and once more for each pass that runs it, and in each cycle every pass but the last must add something and the last nothing. Six knockouts of the pass log each fail it: one more pass after the fixpoint, each member running twice in a pass, a pass that logs that it added nothing, no log, and reruns counting the first pass only (18 cycle roots each), and a log that names the members after the pass rather than the lookups it ran (4 roots). - test_each_lookup_in_a_random_tree_settles_on_what_a_fresh_walk_finds walks 300 seeded random trees (static_reach_cases.random_tree): four modules, a package pk with two sub modules and a getter, and a root whose run() and run2() make the same reads in opposite orders. Each walk passes the once test's checks, each lookup it settles holds what a fresh walk's same lookup finds, and the two walks reach the same items. More than half of the 600 walks must run a cycle again. e6e1f4c's walk fails 7 of the 300 trees, and 31 of the first 1,000. - Long cycles (the review's note). The budget test's comment now says that its 10,000 lookups hold for the six Cost roots, not for every cycle: a cycle that gathers one module a pass, over N modules, takes N + 3 passes, and 18,023 lookups at N = 100. - Corrections and nits. - e6e1f4c's message said that the walk passed every check on all 151 roots. Each root passed alone, but a composite of r_getattr_cycle and r_getattr_cycle_first failed the composing property, which only CI ran. - It also said that a site goes on each of three cycle roots. Four (value) sites go: one on r_alias_cycle_dotted, two on r_alias_cycle_dotted_first and one on r_alias_self_dotted. - The __match_args__ entry in "What it can't see" stays. The walk could resolve a constant bound once to a tuple of literals, as it resolves a string constant, but no first-party module assigns __match_args__, so the rule would serve no kernel. Checks outside pytest, on CPython 3.14.7 and 3.13.15, which agree: - Each of the 169 roots passes every check: the targets, the runtime reads, the once check, the fresh-walk check and the lookup budget. - The composing property's two checks pass on every pair of the 169 roots (14,196), on 2,000 seeded draws of 3 to 6 roots and on the composite of all 169. - On seeds 0 to 2,999 of random_tree, each walk passes the once checks, each of the 301,826 lookups it settles holds what a fresh walk's same lookup finds, and both orders reach the same items. On the review's 3,000 random 7-module trees, e6e1f4c's walk fails the fresh-walk check on 73, and this walk on none. - One-edit knockouts of the walk, run outside the repository: each of the hub's 148 fails a root but two. So do 50 of the c622fc2 review's 51, 57 of the e6e1f4c review's 61, each of that review's ports of Belgium's 51, and each of Belgium's 51 under Belgium's own runner. The seven that fail none change nothing a test can see, and the PR body says why for each. - Against e6e1f4c's walk, no item goes on NZ's 16 kernel walks, the 169 roots or 200 seeded composites of them. 24 differ (four roots and 20 composites), each holding one of the four roots that miss their target on e6e1f4c's walk: 20 gain items, and the other four trade a (value) site for the root's own lines. No kernel walk changes, and none has a lookup cycle. Local run: pytest -n 0 passes the three test files with this commit's text on CPython 3.14.7 (1,679 passed in 611 s on a loaded host). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Belgium session's review of 6d0a1a0 found a gap in exported(). It skipped a module's __getattr__ whenever the name's resolve lookup had settled with any items, and its comment called that "bound for sure", so any binding counted: - one in a branch, in a try, or under if TYPE_CHECKING; - one that a del or the end of an except clause undoes; - one a star import brings in from a module whose __all__ leaves it out; - a walrus, or a comprehension's name, inside a subscript in an assignment's target. A package's sub module that nothing has imported, read as pkg.sub, counted too. Python calls the getter in each of those cases, so the walk missed what the getter reads. The class-body rule in _bound_before shared two of the gaps: the end of an except clause, and a walrus or a comprehension's name inside a subscript target. This commit applies that session's suggested-getter-v5.diff verbatim: git diff 6d0a1a0 against this commit matches the file byte for byte (sha256 fb084e9e0488f01b...). - _undoes() returns the name a del target or an except clause unbinds, and _stored_here() returns only the names an assignment target spells out. _binds() uses _stored_here(), and _bound_before() uses _undoes(). - _Module gains deleted, sure, sure_stars and names_all, and the new _Walk._binds_for_sure() reads them. exported() skips the getter only when the name's lookup has settled with items and the module's top level binds the name for sure: directly, or through a star import of a public name from a module that binds it for sure and nowhere names __all__. - The docstring's Bindings, Scopes and "What it can't see" entries and the OVER comment follow. "What it can't see" drops the sub module's name, which the walk now sees. It adds a function the module calls while it runs, a name another module deletes or the module removes without del, and an __all__ the walk can't see. - The cases gain ten getter roots for a name a module binds only maybe, and r_getattr_sub_attribute; each reaches its own target. r_getattr_submodule moves from BLIND to ROOTS. r_except_class and r_walrus_class pin the class-body rule, and r_getattr_call_cycle, r_getattr_outside_del and r_getattr_hidden_all pin the new blind spots. The cases hold 185 roots, 222 targets, 14 in OVER, 20 in BLIND and seven decoys. The next commit adds o8's changes on top, and its message gives the checks of both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The delta review of 6d0a1a0 approved it with no required change and offered four optional findings and two nits. This commit takes the four findings and adds four roots that pin the getter change in 2278fb3. The nits correct the PR body. - The once test checks what each lookup meets (finding 1). The test took the walk's own pass log as its allowance for extra runs, so a walk that did extra work and logged it still passed. _counted now also records, from the calls themselves, each lookup that a call met before the lookup settled: one that had begun and that the memo didn't hold yet. _check_runs adds three checks: each pass runs distinct lookups; each logged cycle's first pass runs more than one lookup, or its one lookup met itself; and no two logged cycles run the same lookups, since a cycle runs its passes once and then settles or joins a larger one. The review's five edits that passed 6d0a1a0's test now fail it: - _cycle called twice, and each member run twice in a pass (each on the 18 cycle roots); - True in place of the cycle condition, and one more logged pass for a lookup that settled outside a cycle (each on all 191 roots); - an open cycle that runs its passes again before it joins (4 roots). They join the hub's knockouts. - Two more getter calls (finding 2). The review named three more times Python calls a module's __getattr__ outside a cycle of lookups. 2278fb3 makes the walk see the first: reading a package's attribute asks it for a sub module's name until something imports the sub module (r_getattr_sub_attribute). "What it can't see" now lists the other two: a star import asks a module that doesn't define __all__ for it, and a star import asks for each name that __all__ lists and the module doesn't bind. BLIND roots pin each: r_getattr_star_noall and r_getattr_star_lazy. Python reads each target, and the walk reaches neither. No kernel meets them: no first-party module star-imports. - Nested cycles (finding 3). The budget test's comment names a second shape past its 10,000 lookups: nested cycles, each of which a pass of the next meets. Each then stays open and runs again in every pass of each cycle around it, and K of them make 9,916 lookups at K = 10 and 43,026 at K = 20. The comment's staircase figure moves to 18,125 lookups at N = 100, since 2278fb3's walk also looks up the getter of a module that binds a name only maybe. No kernel walk has a lookup cycle. - Random trees (finding 4). random_tree gains an eleventh form, a class Base whose base is another name's Base or the Base of another name's attribute, with a __match_args__ that names one of a, b and c or with none, so that it takes its base's. Before, no tree settled a match lookup. Now, on the test's 300 seeds, 33 trees settle one and 14 run one in a cycle. The random test now requires a walk that runs a match lookup in a cycle (28 of the 600 do), and its floor counts walks that run a cycle through two passes or more (384 do; it needs more than 300). e6e1f4c's walk fails 7 of the 300 trees, and 22 of the first 1,000. - Four getter roots for 2278fb3: a star import's private name (r_getattr_maybe_star_private), and a walrus inside a subscript of a with target, an annotated target and an augmented target (r_getattr_maybe_with, r_getattr_maybe_annotated and r_getattr_maybe_augmented). Python reads each target through the module's getter, and the walk reaches it; 6d0a1a0's walk doesn't. Without them, two of the hub's one-edit knockouts of 2278fb3 failed no root. The cases hold 191 roots, 228 targets, 14 in OVER, 22 in BLIND and seven decoys. Checks outside pytest, on CPython 3.14.7 and 3.13.15, which agree: - The walk's code is 2278fb3's: only its docstring changes. - Each of the 191 roots passes every check: the targets, the runtime reads, the once check, the fresh-walk check and the lookup budget. - The composing property's two checks pass on every pair of the 191 roots (18,145), on 2,000 seeded draws of 3 to 6 roots and on the composite of all 191. - On seeds 0 to 2,999 of random_tree, each walk passes the once checks, each of the 287,246 lookups it settles holds what a fresh walk's same lookup finds, and both orders reach the same items. - The test's own _counted and _check_runs, run outside pytest, pass on every root and on seeds 0 to 2,999, and fail each of the five edits. Belgium's four mutants that 6d0a1a0's tests didn't catch (M2, M3, M8 and M9) pass them too; Belgium's review reports that none changes an item or a settled lookup. - One-edit knockouts of the walk, run outside the repository: each of the hub's 164 fails a root or a tree but two that only cost a pass. So do 50 of the c622fc2 review's 51, 57 of the e6e1f4c review's 61, each of that review's ports of Belgium's 51, and each of Belgium's 51 under Belgium's own runner, with two of its anchors re-pointed to 2278fb3's text. The PR body says why each of the rest changes nothing a test can see. - Against 6d0a1a0's walk, no item goes on NZ's 16 kernel walks, the 191 roots or 200 seeded composites of them; the 90 that differ each hold one of the 18 roots it misses and gain items. Against e6e1f4c's walk, no item goes either. 104 walks differ there: the 18, the four roots that miss their target on e6e1f4c's walk, and 82 composites that hold one of the 22. 101 gain items, and the other 3 trade a (value) site for the root's own lines. Local run: pytest -n 0 passes the three test files with this commit's text on CPython 3.14.7 (1,723 passed in 138 s). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WIP. G8-x2 sets NZ's Axiom engine pins, refreshes NZ's input surface at that engine, and closes #1563's three follow-ups. NZ's first real-data run (G8-x, step 4) waits on this PR.
Plan
N3.
transport.omission_register@1reads the calibration solution beside the problem and decodes it against that problem's sha256 and ordered axis. The people's households must be exactly the axis: the register refuses a person whose household lies off it, and a household on it with no person. Each person's frame weight must equal its household's solution weight as a float64 value (np.array_equal: -0.0 matches 0.0, NaN matches nothing, and a one-ulp difference refuses). NZ graph: three follow-ups from #1555's review (register-fit tie, measurement id selection, constant-read check) #1563 named household weights; the register compares every person's. Its totals still use the problem's pre-fit weights. NZ's graph and the toy give the register an edge fromnz.calibrate.Nit 1, readers only. The three income evidence readers select their
measurementfromincome_measurements' ownmeasurement_id, so they move with that resource. The stand-in keeps its literalmeasurement_id. R2C-1's proof (compose._measurement_declaration) reads a producer'smeasurement_idas a literal string in the declared rows and refuses any other value, so selecting it there would break the proof. The declarations test pins the stand-in's literal to the resource's id.O2.
test_support/microcosm_build/static_reach.pywalks a kernel's class andrun()from source. It parses each first-party module underpackages/*/srcand imports nothing underpackages/. Its docstring names eleven groups of what it follows, then what its lookups cost, then what it can't see:tryor anif, at module or function level, star imports, re-exports, lazy__getattr__exports (defined or assigned), every form of assignment (forandwithtargets,matchcaptures and walrus targets included), and a name that a class body declaresglobal, which binds at module level;delcan undo it, and from the module otherwise, and a class body'sX += 1reads the module'sXuntil the body has bound it;andoror, a walrus, a tuple, list or set (starred elements too), a subscript, andgetattr,import_moduleor__import__with a literal name;selforclsinto a module the class body imports, and a name the class body imports where the body, a default value or a decorator reads it;dels, stores to an item or an attribute, each compound statement's header and targets, in any block, and, in a reached class, each assignment to a name the body declaresglobal;dels (through afororwithtarget too),+=, and calls that take the name;getattr,hasattr,setattr,delattr,attrgetter,methodcaller,matchclass patterns (a class's own or inherited__match_args__),import_module(relative to a literal package,__package__,__spec__.parentor__name__) and__import__(with aleveltoo), also under a module-level name that an import or an assignment binds to them, and through a constant that each of its bindings sets to a string.Each lookup outside a cycle runs once per walk. Lookups that wait on each other in a cycle run again, each meeting what the others hold so far, until a pass over the cycle adds nothing. A cycle whose pass meets a lookup that began before the cycle and hasn't settled joins that lookup's cycle and runs again with it. So each settles on what it finds once the others are complete, whichever the walk met first. A round counts only what it adds, and the walk ends at the first round that adds nothing. A chain of about 200 re-exports, 250 star imports, or 330 constants or inherited
__match_args__passes Python's default recursion limit; the kernels' lookups nest at most four deep.test_each_kernel_hashes_every_module_its_run_can_reachchecks that, for each of the three income kernels, the walk reaches exactly the listed modules outsidemicrocosm.graph. The walk leaves out one guarded branch, which the test names (HIERARCHY_GUARD):Target.__post_init__readsmicrocosm.calibrate.hierarchyonly underself.hierarchy is not None, and_read_targetbuilds every decoded target without a hierarchy.O2's cases.
static_reach_cases.pywrites 191 synthetic roots, each reaching its targets one of those ways, andtest_the_walk_reaches_each_way_code_names_a_modulechecks that each walk reaches exactly its targets. Each target defines only a module__getattr__that records a read, sotest_a_run_reads_what_the_walk_reachesruns every root for real in onepython -I -S -Binterpreter. Python must read exactly the walk's targets, lessOVER(a referenced class's other dunders, and the branch, operand or tuple element a run doesn't take) and plusBLIND(22 roots, each a form on the docstring's list of what the walk can't see).test_the_walk_cases_account_for_every_targetchecksOVER,BLINDand the seven decoys.test_property_composing_roots_loses_no_target(Hypothesis) runs 2 to 6 roots from onerun(): the walk still reaches every part's targets, and Python reads the union of the parts' reads. No two roots share a module whose reads depend on import order, since Python imports a module once.test_the_walk_runs_each_lookup_once_outside_a_cyclecounts each lookup's runs and checks that, on every root, each lookup outside a cycle runs once, each lookup in a cycle once more for each pass over it, and each returns each item once. In each cycle, every pass but the last adds items or lookups, and the last adds nothing (_Walk.cycleslogs each pass). The test also records which lookups a lookup met before they settled, so each pass must run distinct lookups, a logged cycle's lookups must have met each other, and no two logged cycles may run the same lookups.test_a_settled_lookup_holds_what_a_fresh_walk_findschecks that each lookup a root's walk settles holds what the same lookup finds in a fresh walk.test_each_lookup_in_a_random_tree_settles_on_what_a_fresh_walk_findschecks both on 300 seeded random trees (static_reach_cases.random_tree: modules that bind names to each other, star-import, define__getattr__and define classes whose__match_args__a class pattern reads), each walked fromrun()and fromrun2(), which make the same reads in opposite orders and must reach the same items.test_the_walk_makes_few_lookups_on_the_cost_rootscounts every lookup call, the memo's answers too, and fails past 10,000 on the six diamond and clique roots.Engine pins.
axiom_rules_bindings.json: engine commit753ce7d9ac4cfb161f6aa4f281f5a3980e67a57d, wheel sha256054c9196d5371f13bb7c2b28f8161ac92294e5c8543aeb6e221fde243897ed42. The hub built that wheel at 753ce7d9 (maturin build --release --locked; CPython 3.14, macOS arm64). The RuleSpec pin stays8dc2507d.Input surface. The refresh of
fixtures/axiom_input_surfaces/nz.jsonat 753ce7d9 moves onlyengine.commit. The dense-root differential agreed on every module (39 entity-programs, 0 input, status or catalog mismatches). The closure's surface engine and its four engine source pins move to 753ce7d9.engine_optional_evidenceandundetermined_judgmentsnow cite 753ce7d9's lines, each read again at that commit.Activation tests. In
test_transport_composed_graph.py:prepare_transport_buildwith no sources refuses on the RuleSpec tree's path;Docs. The surface README and the refresh tool's docstring name each snapshot's own engine (NZ at 753ce7d9, Belgium at 04315d94).
tools/transport_bridge_differential.py's docstring drops the three-evaluation recipe andwhy_not_solve_zero, whichas_rate_bridge.jsonno longer has.Regeneration (002b6c2).
transport_graph.json: the readers'measurementselectsincome_measurements'measurement_id, and the register readsnz.calibrate'ssolution.export_replay_bindings.jsontakes the new closure sha256, and the golden takes the new fingerprint and resource hashes. Every--checkpassed.Refresh-tool tests, after Belgium's review (cd85cff). A stand-in
--dense-pythondrivesbuild_snapshotin dense mode, and both Hypothesis properties carrydeadline=Noneand suppresstoo_slow.Local run of the three test files that exercise the walk and the income kernels (
test_transport_income_evidence_kernels.py,test_nz_transport_toy_graph.py,test_nz_spec_package.py) with 65e3e79's text: 1,723 passed in 138 s (pytest -n 0, CPython 3.14.7). CI's engine-free jobs run these files and every other NZ and transport file.Local run of the engine-gated tests at d403cce (the closure, the engine-ref goldens and the Axiom adapter tests, with the 753ce7d9 wheel; CI has no Axiom engine job): 356 passed, 6 skipped. The later commits change only the walk, its cases and their test file, which no engine-gated test imports.
Independent review at cd85cff (Opus 5.5, in-session; no Subfleet lane was open): APPROVE with no required findings. d403cce takes its three optional findings: the static walk's blind spots, "bit for bit" and "the frame's households".
Delta review of d403cce (Opus 5.5, in-session): REQUEST_CHANGES, with one required finding and six optional. eb236a6 and 005844b take all seven (below).
Delta review of d403cce..005844b (Opus 5.5, in-session): REQUEST_CHANGES, with one required finding and four optional. c622fc2 takes all five (below).
Delta review of 005844b..c622fc2 (Opus 5.5, in-session): REQUEST_CHANGES, with one required finding and six optional. e6e1f4c takes all seven (below).
Delta review of c622fc2..e6e1f4c (Opus 5.5, in-session): REQUEST_CHANGES, with two required findings, three optional and four nits. 6d0a1a0 takes all of them (below).
Delta review of e6e1f4c..6d0a1a0 (Opus 5.5, in-session): APPROVE, with four optional findings and two nits. 65e3e79 takes all of them (below).
Delta review of 6d0a1a0..65e3e79.
Reviews of 6d0a1a0
Two reviews of 6d0a1a0 came back. Belgium OK'd e6e1f4c..6d0a1a0 and asked for one change, which 2278fb3 makes with Belgium's own diff. The delta review approved 6d0a1a0 with no required change and offered four optional findings and two nits. 65e3e79 takes the four findings and adds four roots that pin Belgium's change, and this body takes the nits.
Belgium's getter change (2278fb3)
exported()skipped a module's__getattr__whenever the name'sresolvelookup had settled with any items, so any binding counted as bound for sure:try, or underif TYPE_CHECKING:;delor the end of anexceptclause undoes;__all__leaves it out;A package's sub module that nothing has imported, read as
pkg.sub, counted too. Python calls the getter in each of those cases, so the walk missed what the getter reads. The class-body rule in_bound_beforeshared two of the gaps: the end of anexceptclause, and a walrus or a comprehension's name inside a subscript target.2278fb3 applies Belgium's
suggested-getter-v5.diffverbatim:git diff 6d0a1a040 2278fb3d7matches it byte for byte.exported()skips the getter only when the name's lookup has settled with items and the module's top level binds the name for sure: directly, or through a star import of a public name from a module that binds it for sure and nowhere names__all__._Walk._binds_for_suredecides, from_Module's newdeleted,sure,sure_starsandnames_all._bindscounts only the names a target spells out (_stored_here)._undoesmakes the end of anexceptclause undo a binding asdeldoes, at module level and in a class body.del, and an__all__the walk can't see.r_getattr_sub_attribute; each reaches its own target.r_getattr_submodulemoves fromBLINDtoROOTS.r_except_classandr_walrus_classpin the class-body rule, andr_getattr_call_cycle,r_getattr_outside_delandr_getattr_hidden_allpin the new blind spots.65e3e79 adds four roots in the same pattern: a star import's private name (
r_getattr_maybe_star_private), and a walrus inside a subscript of awithtarget, an annotated target and an augmented target (r_getattr_maybe_with,r_getattr_maybe_annotatedandr_getattr_maybe_augmented). With them, each of the hub's 11 one-edit knockouts of the change fails a root; before them, two of the first ten failed none. 6d0a1a0's walk misses all 18 roots that the two commits add toROOTS.What it costs. The walk now looks up a module's
__getattr__for each name the module binds only maybe.r_import_diamond, whose modules bind the target inside atry, makes 263 lookups (6d0a1a0: 182). The most any makes is 1,261 (r_star_clique; 6d0a1a0: 1,257), of the 10,000 the test allows.if True:, a loop, atrythat binds in its body), the walk also reaches what the getter reads. That widens a hash; it never misses a read. No kernel walk changes (Checks, below).The delta review's findings (65e3e79)
The once test checks what each lookup meets. The test took the walk's own pass log as its allowance for extra runs, so a walk that did extra work and logged it still passed.
_countednow also records, from the calls themselves, each lookup that a call met before the lookup settled: one that had begun and that the memo didn't hold yet._check_runsadds three checks:The review's five edits that passed 6d0a1a0's test now fail it.
_cyclecalled twice, and each member run twice in a pass, each fail on the 18 cycle roots.Truein place of the cycle condition, and one more logged pass for a lookup that settled outside a cycle, each fail on all 191 roots. An open cycle that runs its passes again before it joins fails on 4 roots. Each also fails random trees. The five join the hub's knockouts (Cost, below). Belgium's four mutants that no test caught at 6d0a1a0 (M2, M3, M8 and M9 in Belgium's review) pass the new checks too, on every root and on seeds 0 to 2,999. Belgium's review reports that none changes an item or a settled lookup over 24,455 walks, only how many lookups a walk runs.Two more getter calls. The review named three more times Python calls a module's
__getattr__outside a cycle of lookups. Belgium's change makes the walk see the first: reading a package's attribute asks it for a sub module's name until something imports the sub module (r_getattr_sub_attribute, the review's a). "What it can't see" now lists the other two: a star import asks a module that doesn't define__all__for it, and a star import asks for each name that__all__lists and the module doesn't bind.BLINDroots pin each:r_getattr_star_noallandr_getattr_star_lazy(the review's b and c). Python reads each target, and the walk reaches neither. No kernel meets them: no first-party module star-imports.Nested cycles. The budget test's comment now names a second shape that passes its 10,000 lookups: nested cycles, each of which a pass of the next meets. Each then stays open and runs again in every pass of each cycle around it. On the hub's build of that shape, K of them make 9,916 lookup calls at K = 10 and 43,026 at K = 20 with 2278fb3's walk (9,506 and 41,806 with 6d0a1a0's; the review's build there gave 9,668 and 42,118). No kernel walk has a lookup cycle.
Random trees.
random_treegains an eleventh form: a classBasewhose base is another name'sBaseor theBaseof another name's attribute, with a__match_args__that names one ofa,bandc, or with none, so that it takes its base's. On the test's 300 seeds:Nits. In the e6e1f4c section below:
CI at 6d0a1a0.
engine-free (3.14)failed one US test,test_us_release_head_to_head_scorer.py::test_spawned_workers_score_identically_to_sequential_cli, outside this PR's files: the job got anubuntu-26.04runner, where uv took the image's Python 3.14.4, and the test's--worker-max-slicesguard refuses 3.14.4. Main's run gotubuntu-24.04and Python 3.14.10 and passed, and another branch fails the same way. The Microcosm hub owns that test and the workflow. Its #1576, which pins the runner image and uses uv's managed Python, merged at 02:32Z on 2026-11-11, before 65e3e79's push.Checks
On 65e3e79, outside pytest, on CPython 3.14.7 and 3.13.15, which agree:
git diff 6d0a1a040 2278fb3d7is Belgium's file, byte for byte.random_tree, each walk passes the once checks, each lookup it settles holds what a fresh walk's same lookup finds (287,246 lookups, 620 of them match lookups), and both orders reach the same items. 4,902 of the 6,000 walks run a cycle again (14,560 cycles, 29,803 passes); 84 trees run a match lookup in a cycle._countedand_check_runs, run outside pytest, pass on every root and on seeds 0 to 2,999, and fail each of the review's five edits (item 1).(value)site for the root's own lines.Delta review of e6e1f4c
A cycle that meets an earlier lookup (required; Belgium asked for the same change). e6e1f4c settled a cycle when its first lookup ended, even when a pass had met a lookup that began before the cycle and hadn't settled. The cycle's lookups then froze with that lookup's partial items, so what the walk reached still depended on which lookup it met first. Now such a cycle stays open, as a single lookup that meets an earlier one already did, and joins the earlier lookup's cycle, which runs it again with the rest (
_settled, as both reviews proposed). Five roots pin it:r_alias_cycle_outer, the review's shape: a pass meets a lookup under way;r_alias_cycle_two_up, with that lookup two lookups up;r_alias_cycle_sibling, with a lookup that waits rather than runs;r_outer_cycle_first, where only a later pass meets the earlier lookup, andr_outer_cycle, which meets the same lookups in the other order. Their modules take the prefixocyc, sincecycoalready namesr_alias_cycle_outer's package.On e6e1f4c's walk the first four miss their target and fail the fresh-walk check, and
r_outer_cyclefails the fresh-walk check. On seeds 0 to 2,999 of the review's random 7-module trees, e6e1f4c's walk fails the fresh-walk check on 73, and the walk now fails none, on both versions. (The review's own 3,000, seeds 300 to 3,299, give 78 and none.) With the new lines undone, the walk reaches other items, or settles a lookup on other items, on 74 of seeds 0 to 2,999.The composing property (required; Belgium asked for a fix too).
r_getattr_cycleandr_getattr_cycle_firstshared one pair of modules, whose reads depend on which root imports them first, and Python imports a module once. So a composite that held both read only the first part's target, and the property failed in CI on both Pythons.r_getattr_cycle_firstnow imports its own copy of the pair (gcyf_aandgcyf_b), so no two roots share a module whose reads depend on import order. Belgium proposed skipping the Python check on such draws; the copy keeps that check on every draw. Outside pytest, on every pair of the 169 roots (14,196), on 2,000 seeded draws of 3 to 6 roots and on the composite of all 169, the walk reaches every part's targets and Python reads the union of the parts' reads, on both versions.Lines that no root pinned. Each of the review's four knockouts now fails a root:
+=branch's use of the name's value (r_aug_value:X += valuehandsX's module toAdder.__radd__, which reads an attribute that the module binds);r_class_global_store);exported()'s settled check (r_getattr_bound, whose module binds the name its__getattr__would answer, andr_getattr_settled, where the name's lookup settles before the getter counts). Each holds a decoy target that the walk reaches without the check;r_join_no_growth).The review's three survivors from c622fc2 fail a root too:
getattrunder another name in a constant's value (r_getattr_named), a reached class's decorators (r_class_decorated) and keyword-only defaults (r_kw_default).Module
__getattr__calls outside a cycle of lookups. "What it can't see" now lists three other times Python calls a module's__getattr__(the reviews of 6d0a1a0 found more, which the section above handles): for a name the module binds, when an import cycle reads the module part-built; for a sub module's name, which a from-import asks the package for before it imports the sub module; and for__path__, which a from-import asks a module that isn't a package for.BLINDroots pin each:r_getattr_import_cycle,r_getattr_import_cycle_fromandr_getattr_init_cycle(the review's e1 to e3),r_getattr_submodule(e4) andr_getattr_path(e5). No kernel meets them. Of the 565 first-party modules, two define a module-level__getattr__, and the kernels' walks parse one, the packagemicrocosm.graph. Its getter answers only its 48 lazy exports, and the package binds none of them and holds no sub module of the same name. A package has__path__, so Python never asks its getter for it.The pass log and two tests.
_Walk.cyclesrecords each cycle's passes: the lookups each pass ran and how many items and lookups it added.reruns, which tools read, now counts from that log.test_the_walk_runs_each_lookup_once_outside_a_cyclecounts each lookup's runs itself instead of reading the walk's count. Each lookup must run once, and once more for each pass that runs it, and in each cycle every pass but the last must add something and the last nothing. The review's three edits that passed e6e1f4c's test (one more pass after the fixpoint, each member run twice in a pass, a join that forces no pass) now fail it or a root.test_each_lookup_in_a_random_tree_settles_on_what_a_fresh_walk_findswalks 300 seeded random trees (static_reach_cases.random_tree), each fromrun()and fromrun2(), which make the same reads in opposite orders. Each walk passes the once test's checks, each lookup it settles holds what a fresh walk's same lookup finds, and both walks reach the same items. More than half of the 600 walks must run a cycle again. e6e1f4c's walk fails 7 of the 300 trees, and 31 of the first 1,000.Nits.
(value)sites go, and names their roots.__match_args__entry in "What it can't see" stays. The walk could resolve a constant bound once to a tuple of literals, as it resolves a string constant, but no first-party module assigns__match_args__, so the rule would serve no kernel.Claims. e6e1f4c's Checks line said that the walk passed every check on all 151 roots. Each root passed alone, but a composite of two of them failed the composing property (item 2), which only CI ran; that line below now says so. The O2 cycle sentence and the composing and fresh-walk invariants hold at 6d0a1a0.
Belgium's asks. Belgium's review of e6e1f4c asked for the same two changes and two roots, and 6d0a1a0 takes them, with two differences: the roots' modules take the prefix
ocyc, and the composing fix copies the modules instead of skipping the Python check. Belgium also found thatnative_band_report's hash on a merge with main matches neither e6e1f4c's nor main's, because main changed a file it hashes. No file in the tree pins it.Checks on 6d0a1a0's walk, outside pytest, on CPython 3.14.7 and 3.13.15, which agree:
BLINDholds.random.Random(20261110)draws all 200, eachsample(sorted(ROOTS), randint(2, 6))). 24 differ (four roots and 20 composites), and each holds one of the four roots in item 1 that miss their target on e6e1f4c's walk. 20 gain items, and the other four trade a(value)site for the root's own lines; no other site goes. No kernel walk changes, and none of them has a lookup cycle (16 walks, 8,086 lookups).Delta review of c622fc2
Lookup cycles (required). c622fc2 gave every lookup in a cycle the items its first lookup ended with. A constant that maps another's items through an attribute (
X = Y.sub, in a cycle withY) then settled on less than a fresh lookup finds, and what it lost depended on which lookup the walk met first. 005844b reached what it lost. Now, when a cycle's first lookup ends,_Walk._cycleruns the cycle's lookups again, each meeting what the others hold so far, until a pass adds nothing. So each settles on what it finds once the others are complete, whichever the walk met first (except where a pass met an earlier lookup that hadn't settled, which 6d0a1a0 fixes in the section above). The review's four cycle probes reach their targets, and four roots pin the fix:r_alias_cycle_dottedandr_alias_cycle_dotted_first, the review's shape met from each end;r_alias_self_dotted, a lookup that waits on itself;r_alias_cycle_join, a lookup that a pass begins and that joins the cycle.Recursion depth. The walk's depths match c622fc2's. The docstring now says that a chain of about 200 re-exports, 250 star imports, or 330 constants or inherited
__match_args__passes Python's default recursion limit (196, 246, 327 and 326 on 3.14.7). It also says that the kernels' lookups nest at most four deep.A nested class's
global, and 4. a class-bodyglobalas a match class. "What it can't see" now lists both, with Belgium's form for a nested class's header, and aBLINDroot pins each:r_nested_global_valueandr_nested_base_scope;r_class_global_match;r_function_globalandr_function_global_import, for a name that a function binds throughglobal, which 005844b missed too.A scan of the tree's 565 first-party modules at c622fc2 finds no class nested in a class body and no
globalstatement in a class body, as Belgium's scans did. It finds 19 function-levelglobalstatements, all inus_runtimeanduk_runtimemodules, which none of NZ's 8 kernels reaches.Knockouts that failed no root. Seven of the review's eight now fail a root on both versions:
_CALLABLESnarrowed to the importers (r_getattr_renamed,getattrunder a module-level name);global(r_class_global_inherit);name == "__getattr__"inexported(r_getattr_self);_members' filter ofglobalnames (r_global_read);body=for a class-bodyglobal's value (r_class_global, whose module now binds_sourceto a decoy);r_alias_cycle_dotted,r_alias_cycle_join,r_alias_self_dotted,r_getattr_cycle,r_getattr_cycle_first,r_lazy_cycleandr_star_clique);_met.add(r_alias_self_dotted).The eighth, the
_own_namesrevert, stays equivalent, as c622fc2's message said. On the review's 51 knockouts at e6e1f4c, 50 fail a root on both versions, and both versions fail the same roots.Tests.
test_the_walk_runs_each_lookup_oncebecomestest_the_walk_runs_each_lookup_once_outside_a_cycle. A lookup in a cycle runs once more for each pass that runs the cycle again, by the walk's own count (reruns), and every lookup a walk begins settles.test_the_walk_makes_few_lookups_on_the_cost_rootscounts every call of the four lookup methods, the memo's answers too, and fails at the first call past 10,000. So a lookup that skips the memo, or keys it more finely than what it looks up, fails there instead of hanging. Five such knockouts each fail at least one of its six roots, in at most 0.1 s.Claims and docs.
r_registryin the 005844b section below, said thatregistrar"now holds no reached item". The walk does reachregistrar._registerin the end, through the change pass itself:registrarholds no reached item until that pass finds its change. The line below now says so.__match_args__ = _FIELDSjoins "What it can't see" (r_match_args_constant).defstatements.BLINDroot: a change inside a lambda that a statement calls (k05,r_lambda_change),import_modulewith another package (i03,r_spec_name), and importers thatpartialwraps or a call returns (n02 and n03,r_partial_import,r_getattr_importer).Also. In a class the walk reaches, an assignment to a name the body declares
globalbinds outside the class but runs as Python creates it, so the walk now follows it there (r_class_global_aug). An operator inside a statement that binds a name joins "What it can't see" (r_aug_module_effect).Belgium's asks. Belgium's look at c622fc2 asked for two changes and four cases, and e6e1f4c takes them:
exported()now leaves a module's__getattr__out only when the name's lookup has settled with items. Inside a cycle, Python can read a module part-built, before it binds the name, so the getter counts. Belgium'sb3_getattr_orderandb3_getattr_firstbecamer_getattr_cycleandr_getattr_cycle_first.OVERholds the getter that Python's import order doesn't pick, since the walk doesn't track that order.r_nested_global_value,r_nested_base_scope).r_class_iadd,r_class_comp_fill).Belgium's OK at 005844b had left form 1 open and asked for its four probes and eight roots as cases. A class body's
X += 1readsXbefore it binds it, so it reads the module'sXuntil the body has bound it (r_aug_class). The four probes arer_aug_class,r_nested_change,r_global_setterandr_global_read. The eight roots arer_del_class,r_self_ref,r_with_class,r_ann_class,r_aug_store,r_kw_fill,r_comp_first_iterandr_walrus_comp.OVERholds the target that the walk reaches and Python doesn't read inr_del_class,r_global_readandr_global_setter.r_base_setpasses an alias through a set display, which no root did before (Belgium'snamed_no_setknockout).Checks on e6e1f4c's walk, outside pytest, on CPython 3.14.7 and 3.13.15, which agree:
BLINDholds.settlerecorded for modules used as values go (one onr_alias_cycle_dotted, two onr_alias_cycle_dotted_firstand one onr_alias_self_dotted), since the walk now reaches each item first through the root's own lines. No kernel walk changes, and none has a lookup cycle.Delta review of 005844b
Class-body globals (required). An assignment in a class body to a name that the body declares
globalrebinds the module's name. 005844b dropped such names from the class's members and recorded no module binding, a regression against d403cce. The module now binds the name to each such value, whether or not the walk reaches the class, and the value reads the class body's names (r_class_global, andr_class_nested_fillfor a nested class).Misses that both walks shared. The walk now follows each one, and a root pins each:
r_class_import_scope);r_class_nested_fill);fororwithtarget that stores into a reached name's item (r_for_store);r_comprehension_fill);__match_args__(r_match_inherited);__import__with alevel(r_import_level),import_modulerelative to__spec__.parent(r_import_spec), and these callables under another module-level name (r_import_renamed);+=on a name (r_augassign).Branches that no root pinned. 005844b's message said "Each branch now has one, and a root fails when it goes", and the O2 invariant said that each knockout fails a root. The review found seven branches whose knockout failed no root, and c622fc2's own sweep found an eighth. Each live one now has a root:
delin a class body (r_body_del);__import__'s top package (r_dunder_import_top);r_class_member_change);globalfilter for a nested function (r_global);r_registry'sregistrarholds no reached item until that pass finds its change, which then reachesregistrar._register;r_comprehension_decoy, whose module binds the same name to theshadoweddecoy);import_modulerelative to__name__(r_import_name), from a plain module, whose__name__differs from its__package__._own_namesno longer pops global names, since_visitsalready drops them. The c622fc2 review found eight more knockouts that failed no root; the section above covers them.Cost. Each lookup outside a cycle now runs once per walk (
_Walk._settled, which follows Tarjan's strongly connected components): what a name binds in a module, what a constant stands for, a package's lazy exports, and a class's inherited__match_args__. At c622fc2 a cycle's lookups all took its first lookup's items; e6e1f4c runs the cycle to a fixpoint instead (the section above).__getattr__, andr_getattr_self.r_star_clique), counting the memo's answers. Both Pythons give the same counts.r_join_no_growthandr_getattr_settled) takes under 7 ms on 3.14.7 and 3.13.15 (the fastest of 5 runs). Run alternately with e6e1f4c's walk onr_alias_modules,r_import_diamond,r_star_diamondandr_star_clique, the two walks take the same time to within 0.4 ms.Sentences. The owner-push sentence and the parent-packages sentence (in the next section) and the knockout table's labels now match what the code does.
r_self_method's comment now says that the class-attribute fallback reaches it.On c622fc2's walk, on CPython 3.14.7 and 3.13.15, the d403cce review's 46 probes still pass, and Belgium's 52 cases still give the same one miss, the registry decorator that
BLINDholds. The 005844b review's own probe script, run against c622fc2's walk on 3.14.7, finds the target of each of its 46 probes, with no runtime error.Delta review of d403cce
r_class_decoratorstill expects no target: its body bindstargetbefore the decorator reads it, and the runtime test confirms that Python reads nothing there. New roots:r_body_before,r_body_conditional,r_body_annotation,r_body_decoratorandr_body_nested.settlecounts an item only whenpushadds it, and the walk raises after 10,000 rounds without settling (r_namespace).r_headers,r_class_header), filler calls (r_fill_global, with Belgium'sr_setup_callandr_fill_call), dotted module values (r_dotted), function-level alternatives (r_local_alternative,r_local_alternative_first), subscripted bases (r_subscript), match class patterns (r_match_keyword,r_match_positional), agetattralias (r_getattr_alias,r_base_getattr), a module-levelsetattr(r_setattr_patch), an assigned__getattr__(r_lazy_assigned),__import__with a fromlist (r_import_from),setdefaultinside an assignment (r_setdefault), a module-level match capture (r_bind_match), a star import of a lazy package (r_star_lazy), a class-level import used throughself(r_class_import), a relativeimport_module(r_import_relative), andgetattrwith a string constant (r_getattr_constant).r_alternative's live import now sits in theexceptbranch, andr_alternative_firstkeeps the other order. New roots coverhasattr(r_hasattr),delattr(r_delattr),methodcaller(r_methodcaller),__import__with a fromlist (r_import_from), a lambda that shadows a name (r_lambda_shadow), and a nested class body's names kept out of its methods (r_nested_scope). Each alias form now has a root whose alias names a class base, which only the alias path follows. The review suggested an alias through a dotted chain, but that no longer isolates the path, because the walk now records a dotted module value too (finding 3). The self/cls owner push goes: restoring it fails no root. Without the class-member attribute fallback, the push still reaches one root's target on its own,r_self_method's, so the fallback is now that root's only path (on c622fc2's 115 roots, CPython 3.14.7, the fallback's knockout fails 17 roots, and 16 with the push restored). On the 8 kernels (3 income, 5 evidence), with and without the cut, the module sets match d403cce's, and the 30 items only the push reached name attributes that their class body doesn't define, such asAxiomEngine._schema.r_sunder's_missing_now returns a member, so no root raises, and a root that raises fails the runtime test. The docstring says "imports nothing underpackages/", and that__import__reaches its top package as well as the module it names.Belgium's seven import-time forms became roots (
r_setattr_patch,r_fill_call,r_del_item,r_mutation_alias,r_delattr_patch,r_class_body_updateandr_setup_call), andBLINDholds their registry decorator (r_registry_decorator). Of Belgium's 52 cases, 51 match Python exactly, and the 52nd is that decorator. The review's 46 probes all pass. The walk follows import-time code only in modules that hold a reached item and in reached classes, as Belgium proposed. Following each reached module's parent packages as well would addmicrocosm.build,microcosm.build.transportandmicrocosm.frameto all 8 kernels' reach,microcosm.calibrateto 3 (the omission register, the native band report and the weights audit), andmicrocosm.frame.adaptersto the input closure, with or without the cut (a variant of c622fc2's walk that pushes each first-party parent package, CPython 3.14.7).microcosm.framecomes through the frame-version check thatmicrocosm/build/__init__.pyruns at import (line 50). The docstring names that gap.The knockouts
Each of the hub's 164 one-edit knockouts of
static_reach.pyat 65e3e79 fails at least one root or one of the test's 300 random trees, except 2 that change nothing a test can see (below), on CPython 3.14.7 and 3.13.15, and both versions fail the same roots and the same first tree. The walk as committed passes every check on every root and tree. A root fails by its targets unless a line saysonce(each lookup runs once, and once more for each pass over its cycle; every pass but a cycle's last adds something, and the last adds nothing; each pass runs distinct lookups; a logged cycle's lookups met each other, and no two logged cycles run the same lookups; each lookup returns each item once) orhistory(each lookup the walk settles holds what a fresh walk's same lookup finds). No knockout fails only a random tree. With the memo off (settled lookups reused), 177 of the 191 roots fail, by targets and once, on both versions. Each line is a group from the walk's docstring, where Cost is the paragraph after the groups, then each knockout and the roots it fails. The Bindings group'so9lines knock out Belgium's getter change (2278fb3) one edit at a time._Module.__init__reads imports through_statements, the same function that import-time code reads, so a knockout of one of its blocks can fail a root through bindings. Split between the two uses (both versions agree), the bodies knockout failsr_alternative_firstandr_lazy_cyclethrough bindings andr_blocksthrough an effect, and the except-handlers knockout failsr_alternativethrough bindings andr_blocksthrough an effect.r_class_import_scope,r_default,r_kw_default; by targets, once); decorators (r_body_decorator,r_class_import_scope,r_decorator; by targets, once); class keywords (r_metaclass; by targets, once); class bases (r_class_global_inherit,r_match_diamond,r_root_base; by targets, once); class attributes (r_factory,r_subclass); constant values (r_alias_cycle_join,r_aug_class,r_bind_walrusand 8 more); a class-bodyglobal's value knows what the body bound (r_class_global).r_alternative); module alternatives, last only (r_alternative_first,r_lazy_cycle); function alternatives, last visited (r_local_alternative); function alternatives, first visited (r_local_alternative_first); star imports (r_getattr_hidden_all,r_getattr_settled,r_starand 3 more); star import of a lazy package (r_star_lazy); lazy__getattr__(r_getattr_cycle,r_getattr_cycle_first,r_getattr_maybe_annotatedand 19 more); assigned__getattr__(r_lazy_assigned); assignments (r_alias,r_alias_base,r_alias_cycleand 77 more; by targets, once); annotated and augmented assignments (r_ann_class,r_aug_class,r_class_global_augand 1 more); for targets (r_bind_for); with targets (r_bind_with,r_with_class); match captures (r_bind_match,r_bind_rest,r_bind_star); match star captures (r_bind_star); match mapping rests (r_bind_rest); walrus targets (r_bind_walrus); re-exports (r_add,r_alias,r_alias_baseand 161 more); class-body globals, assignments (r_class_global,r_global_setter); class-body globals, imports (r_class_global); class-body globals, defs and classes (r_class_global,r_class_global_inherit); class-body globals in nested classes (r_class_nested_fill,r_nested_change); a class-bodyglobal's value reads the class's names (r_class_global); a lookup in a cycle counts the module's__getattr__(r_getattr_cycle,r_getattr_cycle_first; by targets, history);__getattr__is no lazy export of itself (r_getattr_self); a class-bodyglobalclass is a class (r_class_global_inherit); the getter skips a settled name that binds only maybe (6d0a1a0's rule) (r_getattr_maybe_annotated,r_getattr_maybe_augmented,r_getattr_maybe_branchand 13 more); a module'sdelor except clause undoes nothing (r_getattr_maybe_deleted,r_getattr_maybe_except,r_getattr_maybe_global_del); an except clause undoes nothing (r_except_class,r_getattr_maybe_except); adelthroughglobalundoes nothing (r_getattr_maybe_global_del); a star import never binds for sure (r_getattr_hidden_all,r_getattr_settled); a star import binds for sure whatever__all__says (r_getattr_maybe_star_all); a star import's private name binds for sure (r_getattr_maybe_star_private); the importer'sdeldoesn't stop a star import's binding (r_getattr_maybe_star_del); an assignment binds the names inside a subscript target (r_getattr_maybe_target,r_getattr_maybe_walrus,r_walrus_class); an annotated or augmented assignment binds the names inside a subscript target (r_getattr_maybe_annotated,r_getattr_maybe_augmented); a with target binds the names inside a subscript (r_getattr_maybe_with).r_comp_first_iter,r_comprehension; by targets, once); lambdas (r_lambda_change,r_lambda_shadow); nested class names out of methods (r_nested_scope); class names out of methods (r_class_scope,r_lambda_shadow; by targets, once); class body, never the module (r_aug_class,r_body_annotation,r_body_beforeand 7 more; by targets, once); class body, always the module (r_ann_class,r_class_decorator,r_class_globaland 1 more); nested class body falls back to the module (r_body_nested); nested class body falls back to the function (r_body_nested);nonlocal(r_nonlocal);global(r_aug_value,r_global; by targets, once);delundoes a class-body binding (r_body_del,r_del_class,r_except_class; by targets, once); comprehension targets (r_comprehension_decoy);+=reads its target (r_aug_class,r_aug_value,r_class_global_aug; by targets, once); a class body'sglobalnames aren't its members (r_global_read).r_alias_base,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 20 more); conditional body (r_base_conditional); conditional orelse (r_base_conditional);orandand(r_base_or); walrus (r_base_walrus); starred (r_base_set,r_base_starred);__import__'s top package (r_base_dunder_import); tuple elements (r_base_set,r_base_starred,r_base_tuple); getattr (r_base_getattr,r_getattr_named); subscript (r_base_set,r_base_starred,r_base_subscript); import_module (r_base_dunder_import,r_import_alias_base).r_alias_base,r_base_conditional,r_base_dunder_importand 13 more); subscripted bases (r_subscript).r_class_import); names the class body imports (r_class_import_scope).r_add,r_aug_class,r_aug_valueand 7 more); sunders (r_sunder); the root's class (r_ann_class,r_aug_class,r_body_annotationand 21 more; by targets, once).r_aug_store,r_blocks,r_del_hiddenand 4 more; by targets, once); expression statements (r_blocks,r_fill_global,r_setup_call);del(r_del_hidden); stores into items (r_aug_store,r_store_hidden); if headers (r_class_header,r_headers; by targets, once); while headers (r_headers); for headers (r_for_store,r_headers); with headers (r_for_store,r_headers); match subjects (r_headers); match patterns (r_headers); match guards (r_headers);except*headers (r_headers); effects in bodies (r_alternative_first,r_blocks,r_lazy_cycle); effects in else branches (r_blocks); effects in finally (r_blocks); effects in except handlers (r_alternative,r_blocks); effects in match cases (r_blocks); except headers (r_headers); class bodies (r_class_header; by targets, once); for targets (r_headers); with targets (r_for_store,r_headers); a reached class'sglobalstores (r_class_global_aug,r_class_global_store; by targets, once);globalstores include augmented ones (r_class_global_aug).r_aug_module_effect,r_augassign,r_class_comp_filland 12 more; by targets, once); method calls (r_class_comp_fill,r_class_fill,r_class_member_changeand 5 more; by targets, once); stores and dels (r_class_fill,r_for_store,r_setitem); call arguments (r_class_fill,r_kw_fill,r_registry); through aliases (r_class_fill); class bodies (r_class_comp_fill,r_class_fill,r_class_iaddand 2 more; by targets, once);+=on a name (r_aug_module_effect,r_augassign,r_class_iadd; by targets, once); inside comprehensions (r_class_comp_fill,r_comprehension_fill); in every module read (r_comprehension_fill,r_for_store,r_registryand 2 more); a class member's change (r_class_member_change); a header runs whole (r_for_store); nested classes run whole (r_class_nested_fill,r_nested_change).r_alias_cycle_dotted,r_alias_cycle_dotted_first,r_alias_cycle_joinand 26 more; by targets, once); value modules (r_aug_value,r_dotted,r_dunder_import_topand 9 more); dotted values (r_dotted); bare-name values (r_value).r_getattr,r_getattr_constant,r_getattr_namedand 1 more); hasattr (r_hasattr); setattr (r_setattr); delattr (r_delattr); attrgetter (r_attrgetter); methodcaller (r_methodcaller); match keywords (r_match_keyword); match positional (r_alias_cycle_dotted,r_alias_cycle_dotted_first,r_alias_cycle_joinand 12 more); import_module (r_import_alias_base,r_import_module,r_import_nameand 4 more);__import__(r_base_dunder_import,r_dunder_import_top,r_import_fromand 1 more); relative import_module (r_import_name,r_import_relative,r_import_spec); module constants (r_getattr_constant); inherited__match_args__(r_class_global_inherit,r_match_diamond,r_match_inherited);__import__level (r_import_level);__package__(r_import_relative);__name__as package (r_import_name);__name__names the module, not its package (r_import_name);__spec__.parent(r_import_spec); callables under imported names (r_import_renamed); callables under assigned names (r_getattr_named,r_getattr_renamed,r_import_renamed);__import__'s top package (r_dunder_import_top); getattr and the namers under module-level names (r_getattr_named,r_getattr_renamed).r_add,r_alias,r_alias_baseand 174 more; by targets, once); one copy of each item (r_alias_diamond,r_alias_modules,r_import_diamondand 2 more; by once); a lookup under way gives its cut (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by targets, once, history); meeting a lookup under way joins its cycle (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 13 more; by targets, history); a cycle settles together (r_alias_cycle_dotted,r_alias_cycle_dotted_first,r_alias_cycle_joinand 7 more; by once, history); a cycle settles on each one's cut (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 14 more; by targets, history); a constant under way stands for itself (r_alias_cycle_dotted,r_alias_cycle_dotted_first,r_alias_cycle_joinand 7 more; by history); the walk ends when a round adds nothing (r_namespace; by targets, once, history); a cycle runs again until a pass adds nothing (r_alias_cycle_dotted,r_alias_cycle_dotted_first,r_alias_cycle_joinand 12 more); a cycle runs one pass only (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by targets, once, history); a lookup a pass begins joins the cycle (r_alias_cycle_join,r_alias_cycle_sibling,r_alias_cycle_two_upand 3 more; by once, history); a pass keeps what each member held (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_outerand 6 more; by targets, history); a lookup that meets itself runs again (r_alias_self_dotted,r_outer_cycle,r_outer_cycle_first); a pass that meets an earlier lookup joins its cycle (r_alias_cycle_outer,r_alias_cycle_sibling,r_alias_cycle_two_upand 2 more; by targets, history); a joined cycle stays unsettled (r_alias_cycle_outer,r_alias_cycle_sibling,r_alias_cycle_two_upand 2 more; by targets, history); a pass logs that it added nothing (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); the log names the members after the pass (r_alias_cycle_join,r_join_no_growth,r_outer_cycleand 1 more; by once); one more pass after the fixpoint (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); each member runs twice in a pass (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); the walk keeps no pass log (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); reruns counts each pass once (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); a cycle runs its passes twice (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); every lookup runs as a cycle (r_add,r_alias,r_alias_baseand 188 more; by once); each member runs twice in a pass, logged twice (r_alias_cycle,r_alias_cycle_dotted,r_alias_cycle_dotted_firstand 15 more; by once); an open cycle runs its passes again before it joins (r_alias_cycle_outer,r_alias_cycle_sibling,r_alias_cycle_two_upand 1 more; by once); a lookup outside a cycle runs once more as a logged pass (r_add,r_alias,r_alias_baseand 188 more; by once).Knockouts that change nothing a test sees.
a waiting lookup passes its cycle up(a lookup that waits on an earlier one stays open, so the lookup that roots the next cycle runs it again, meets the earlier lookup and keeps the cycle open: it costs a pass);a joined cycle passes its start up(the cycle stays open either way, so the lookup that roots the next cycle runs it again and meets the earlier lookup itself: it costs a pass).The c622fc2 review's knockouts. The review wrote 49 one-edit knockouts and two extras. Applied to 65e3e79's walk, with the one anchor that moved since c622fc2 rewritten to make the same change, and checked on all 191 roots and the 300 trees: 50 of the review's 51 fail at least one root or tree on both versions, and both versions fail the same roots. The other one changes nothing a test can see:
global names stay in _own_names(_visitsalready drops a function's global names).Belgium's knockouts. Belgium wrote 51 one-edit knockouts of 005844b's walk. With the anchors that moved since then re-pointed to 65e3e79's text, each fails at least one of NZ's 191 roots by its targets, on both versions (Belgium's own runner, over a copy of the tree). The e6e1f4c review's port of the same 51, run with the test's checks: 51 of Belgium's 51 fail at least one root or tree on both versions, and both versions fail the same roots. Its port of the c622fc2 review's 51: 50 of the review's 51 fail at least one root or tree on both versions, and both versions fail the same roots. The other one changes nothing a test can see:
global names stay in _own_names(_visitsalready drops a function's global names).The e6e1f4c review's knockouts. The review wrote 61 one-edit knockouts in 12 groups, over every line of
_cycle,_computes, the_settledtail,exported()'s settled check, the+=branch and_global_stores. With the eight anchors in_cyclethat 6d0a1a0 rewrote, and the four inexported(),_bound_beforeand_bindsthat 2278fb3 rewrote, re-pointed to their text: 57 of the review's 61 fail at least one root or tree on both versions, and both versions fail the same roots. The other 4 change nothing a test can see:first-begun first (reversed)(with the ancestor fix in, a pass's order changes only how many passes a cycle takes);met keys never discarded(_metmatters only for a lookup that has just begun, and a settled lookup never begins again);waiting lookup drops its low(the hub'sa waiting lookup passes its cycle up, from the other side: it costs a pass);+= read node is the statement(a bare name's node and its statement start at the same line and column).What the refresh found
program.interface,engine_buildandsource_closure, none of which the walk reads. The engine'sdocs/artifact-format.mdsays that, for source without elections,programwithoutinterface, plusmetadata, are what format 2 emits. The tool now reads formats 2 and 3, and each artifact must carry the format the engine'scapabilitiesnames.cross_entity_advice,src/dense.rs:560-590). The tool now accepts a cross-entity blocker's exact text followed by ". " and any advice, and the snapshot keeps the walk's text. NZ's only blocker is the versioned-formula one, whose text 753ce7d9 keeps word for word. be.json's sevendense_unsupportedmodules, each a cross-entity error at 04315d94, would need the change at any engine from 4d7ec14f on.evidence_contract.py. A follow-up handles them, because a list change re-keys Belgium's evidence nodes too.Invariants
The register:
Activation:
The refresh tool:
trueand"3"refuse). An artifact whose format differs from its engine's refuses, in either direction.O2:
run()can reach outsidemicrocosm.graph, less the one named cut.microcosm.calibrate.hierarchyand nothing else._read_targetpasses no hierarchy, so a decoded target has none.artifact_typesdropped from the native report's list, the trace test still passes and the walk names the module.OVERplusBLIND(a differential test against CPython).OVERonly removes targets a root's walk reaches,BLINDonly adds targets it doesn't, and every target is a root's,BLIND's or a decoy.random.Random(20261110)draws all 200, eachsample(sorted(ROOTS), randint(2, 6))), on both versions. Against 6d0a1a0's, the 90 that differ each hold one of the 18 roots its walk misses, and each gains items. Against e6e1f4c's, the 104 that differ each hold one of those 18 or of the four roots that miss their target on e6e1f4c's walk: 101 gain items, and the other 3 trade a(value)site for the root's own lines.__getattr__counts for a name unless the module's top level binds the name for sure (a test, on the 18 roots that 6d0a1a0's walk misses).Keys
N3, nit 1, and the docstring and comment edits change
income_evidence_kernels.py, so the three income kernels' implementation hashes change, and with them their nodes' keys. Only NZ's graph uses these kernels. The module stays outside the gate battery's binding closure (test_the_module_stays_outside_the_batterys_binding_closure), so no battery node re-keys. The commits after d403cce change onlytest_support/and a test file, which no kernel's list names, so they re-key nothing.Shared with Belgium
Belgium also uses these parts:
test_transport_composed_graph.py;tools/refresh_axiom_input_surface.pyand its new test;tools/transport_bridge_differential.py;test_support/microcosm_build/static_reach.pyandstatic_reach_cases.py.Belgium OKs those hunks before this lands. Their OK covers d403cce for every hunk, and 005844b for
static_reach.pyandstatic_reach_cases.py. c622fc2, e6e1f4c, 6d0a1a0, 2278fb3 and 65e3e79 change those two files again. Belgium's review of c622fc2..e6e1f4c asked for two changes and two roots, which 6d0a1a0 takes. Belgium OK'd e6e1f4c..6d0a1a0 and asked for one more change, which 2278fb3 makes with Belgium's own diff, so the two files wait on Belgium's look at 2278fb3..65e3e79.Closes #1563.
🤖 Generated with Claude Code