Repository navigation
Reserve the numbered tuple element bindings, and pin the string-history refusal rows against the pinned reference commit - #357
Conversation
…ename a stale list name The census of generated names (#350) holds one representative for each numbered family, and its test requires the emitter's reserved spellings to cover every one. The element bindings that a tuple result is destructured into, _tuple_result_<n>_elem_<m>, are declared by the same lowering as _tuple_result_<n> but had no representative. The row adds _tuple_result_0_elem_0. The list of reference words in the helper series words test is derived from the reference tokens, so it is no longer a list of introduced words. It is renamed to say so. Nothing else in that file changes, and the test ids stay the same. Tests only. The census test fails on this commit, because _tuple_result_0_elem_0 is not reserved yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A tuple assignment that the generator materializes declares a temporary, _tuple_result_<n>, and then destructures it into the bindings _tuple_result_<n>_elem_<m>. The temporary pattern reserved the first spelling but not the second, so a script variable spelled like _tuple_result_0_elem_0 kept its name and could redeclare the generated binding (#350). The pattern now also accepts the optional _elem_<m> suffix of that family. It matches only the complete spelling with both numbers, so ordinary names that merely start with _tuple_result_ keep their spelling. The census row added in the previous commit covers the new spelling. The changelog lists the change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…, and run the refusal pairs of the compile rows without a compiler (#351) The refusal of a string local spelled like a price field and read with history in a requested helper is keyed on a non-var local declaration whose authored spelling is one of the nine price names. Rows now pin that keying against the reference commit: a string global, a string parameter and a library local of those names, read with history in a requested helper, give the same C++ as the reference where it accepts the script and the same diagnostics (severity, code, message, line, column) where it refuses it. One more row pins a positional read, str.length(close[1]) directly in the helper, which keeps the reference's PF-E3011 at the same position. The annotation key "authored_local_names" had a private constant in the analyzer and two copies of the literal, one in the refusal rule and one in the analyzer's declaration visitor. The constant is now public, keeps its one definition and its value, and both places import it. The module that defines it imports only the syntax tree, the limits, the errors and the analyzer tables at load time, so the new imports add no cycle, and the behaviour is unchanged. In the compile rows, the pairs that pin the base's refusal for close in the shapes typed, nested and two-sites move into their own test, so that they run on a host without a compiler. Every compile comparison keeps its skip, its id and its assertions. The module docstring now says that these rows pin the refusal instead of a compile outcome. Tests, and one constant made public and imported in two places. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Graphify reviewed this change.
No issues found by static checks — no coupling regressions or blocking issues in the code graph. That is not the same as safe to merge: see what was not checked.
Not checked: tests were not run; formal verification proved 0 of 5 changed function(s) (5 not verified).
Formal verification. PR-changed functions: 0/5 verified (0 proven, 0 may-equivalent, 0 distinguished) · 5 not verified (3 vacuous, 2 unsupported).
Not verified on this run: \_visit\_VarDecl (unsupported), authored\_callable\_text (vacuous: never exercised), restore\_callable\_diagnostics (vacuous: never exercised), separate\_builtin\_callable\_locals (vacuous: never exercised), \_security\_check\_price\_named\_local\_history (unsupported).
Graphify review — findings
Fixes a name collision where a script variable spelled like a generated tuple element binding (_tuple_result_0_elem_0) redeclared that binding; the C++ name allocator now reserves _tuple_result_N_elem_M spellings, so such a variable gets a private name. Also exports the authored_local_names annotation key as the public AUTHORED_LOCAL_NAMES constant, so the analyzer and security emitter share it instead of repeating the string literal. Test changes move the price-field string-history refusal checks into their own transpile-only test that needs no C++ compiler, and a changelog line records the fix.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 4803 functions depend on the 975 functions this change touches.
Health — grade A; 10 existing hotspot(s) in the area this change touches (pre-existing, not introduced here):
Analyzer— 105 callers, 15 callees (high)_generate()— 131 callers, 9 callees (high)_generate_raw()— 29 callers, 9 callees (high)_generate()— 9 callers, 25 callees (high)_analyze()— 30 callers, 6 callees (high)_check()— 31 callers, 3 callees (high)resolve()— 25 callers, 3 callees (high)_codegen()— 10 callers, 7 callees (high)- …and 2 more
Verification — 4803 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 3936 function(s) in the blast radius were not formally verified this run
Cross-repo impact
Cross-repo impact
This change impacts 2 symbol(s) across 1 peer repo(s) — blast radius over derived cross-repo edges:
- pineforge-4pass/pineforge-hpo —
python/pineforge_hpo/transpile.py(via import_moniker, heuristic),tests/python/test_transpile.py(via import_moniker, heuristic)
1 peer repo(s) in this group are not yet indexed — cross-repo impact may be incomplete.
Cross-repo linkage is derived (SCIP-moniker matches are sound; name/contract matches are heuristic) and ADVISORY — it never affects this check's conclusion.
Test selection
Test selection
508 of 508 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety (
noncode-change,uncovered-code) — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_action_pins.py— full-run-safetytests/test_allow_entry_in_qualifier.py— impact, full-run-safetytests/test_allow_entry_in_request_const.py— impact, full-run-safetytests/test_analyzer.py— impact, full-run-safetytests/test_analyzer_matrix_inference.py— impact, full-run-safetytests/test_analyzer_ta_return_types.py— impact, full-run-safetytests/test_anchor_tf_change.py— impact, full-run-safetytests/test_anchor_time.py— impact, full-run-safetytests/test_anchor_vwap.py— impact, full-run-safetytests/test_array_bounds_insert_fill_slice.py— impact, full-run-safetytests/test_array_checked_access.py— impact, full-run-safetytests/test_array_empty_aggregates.py— impact, full-run-safetytests/test_array_history.py— impact, full-run-safetytests/test_array_missing_integer_index.py— impact, full-run-safetytests/test_array_new_color_fill_and_na_size.py— impact, full-run-safetytests/test_array_new_defaults_and_order.py— impact, full-run-safetytests/test_array_reference_semantics.py— impact, full-run-safetytests/test_array_slice_view.py— impact, full-run-safetytests/test_array_terminal_returns.py— impact, full-run-safetytests/test_arrseg_coded_run_stops.py— impact, full-run-safetytests/test_arrseg_review_fixes.py— impact, full-run-safetytests/test_binop_operand_order.py— impact, full-run-safetytests/test_block_shadow_primitive_types.py— impact, full-run-safetytests/test_bool_na_refusal.py— impact, full-run-safetytests/test_bool_na_refusals_2.py— impact, full-run-safetytests/test_bool_na_values.py— impact, full-run-safetytests/test_bool_string_inference.py— impact, full-run-safetytests/test_builtin_name_shadow.py— impact, full-run-safetytests/test_builtin_named_locals_compile.py— impact, changed-test, full-run-safetytests/test_builtin_named_locals_price_refusal.py— impact, changed-test, full-run-safetytests/test_builtin_named_locals_receipt.py— impact, full-run-safetytests/test_builtin_named_locals_scope.py— impact, full-run-safetytests/test_calc_on_order_fills_codegen.py— impact, full-run-safetytests/test_calendar_lambda_locals.py— impact, full-run-safetytests/test_call_argument_order.py— impact, full-run-safetytests/test_callable_local_histories.py— impact, full-run-safetytests/test_callable_series_param_types.py— impact, full-run-safetytests/test_callable_string_series_type.py— impact, full-run-safetytests/test_callable_ta_forwarded_length.py— impact, full-run-safetytests/test_callable_var_first_reach.py— impact, full-run-safetytests/test_checked_settings.py— impact, full-run-safetytests/test_ci_engine_main_touched.py— full-run-safetytests/test_closed_trade_fold.py— full-run-safetytests/test_closed_trade_fold_emission.py— impact, full-run-safetytests/test_closed_trade_text_equals.py— impact, full-run-safetytests/test_coded_run_stops.py— impact, full-run-safetytests/test_codegen_ascii.py— impact, full-run-safetytests/test_codegen_audit_fixes.py— impact, full-run-safetytests/test_codegen_determinism.py— impact, full-run-safetytests/test_codegen_drawing_data.py— impact, full-run-safety- … and 458 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
Could not verify: Could not verify \_visit\_VarDecl.
The verifier did not have enough to check \_visit\_VarDecl, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Could not verify: Could not verify authored\_callable\_text.
The verifier did not have enough to check authored\_callable\_text, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 262 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)
Could not verify: Could not verify restore\_callable\_diagnostics.
The verifier did not have enough to check restore\_callable\_diagnostics, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 80 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)
Could not verify: Could not verify separate\_builtin\_callable\_locals.
The verifier did not have enough to check separate\_builtin\_callable\_locals, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 80 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)
Could not verify: Could not verify \_security\_check\_price\_named\_local\_history.
The verifier did not have enough to check \_security\_check\_price\_named\_local\_history, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)
Follow-up to the fixes for #350 and #351 (already on main). It adds the pieces that the reviews of those two changes left open. It is related to both issues and closes neither.
What changes
Three commits, tests first.
_tuple_result_<n>_elem_<m>had no representative; the row adds_tuple_result_0_elem_0. The commit also renames a stale list name in the helper-series-words test (the list is derived from the reference tokens, so it is no longer a list of introduced words); the test ids do not change. The census test fails on this commit, as intended._tuple_result_<n>_elem_<m>when the lowering decomposes the result of a tuple assignment (a call of a user-defined function or of a typed method). The temporary pattern reserved_tuple_result_<n>but not that second spelling, so a script variable spelled like one of the bindings kept its name and could redeclare the generated binding. The pattern now accepts the optional_elem_<m>suffix. It matches only the complete spelling with both numbers, so names that merely start with_tuple_result_keep their spelling. One changelog line.authored_local_nameshad a private constant and two copies of the literal; the constant is now public and both places import it (the defining module loads only the syntax tree, the limits, the errors and the analyzer tables, so there is no import cycle). The refusal pairs forclosein the compile rows move into their own test, so they run on a host without a compiler; every compile comparison keeps its skip, its id and its assertions.Evidence
_tuple_result_0_elem_0; on the second commit none fails.Not shown
_tuple_result_0_elem_0was run; that the generated C++ collided rests on reading the emitter.🤖 Generated with Claude Code