Repository navigation
interpreted-parse cost forensics: discriminate interpretation-tax vs algorithmic residue in v2 02_parse under the v1 interpreter - same-file compiled-vs-interpreted timing, packrat memo effectiveness + table-carry cost interpreted, verdict = engine fix / interpreter fix / honest no-op-until-S2 (upda - #6365
Merged
Merged
Conversation
…+ empty-list semantics pin (fix 2) Manager-mandated merge-bar demands on #6362, addressed with durable, re-runnable witnesses rather than a one-off manual diff: - parse_tree_content_hash_witness.dag: content_hash(ParseTree) over the tiny/small corpus sample, computed once against the true PR base (0f98a26, built as its own release binary in an isolated worktree) and once against HEAD. Both hashes are byte-identical (witness.dag=9afb740ee43f9e61, execution_mode.dag=ed071cb2baeaeb61), proving fix 2 (list_at_optional -> list_head) and fix 3 (fold_list -> parse_match_arm_stmt_step) preserve parse semantics exactly, not just "no test regressions." - parse_token_first_empty_semantics_test.dag: two `test fn` claims pinning parse_token_first (post-fix, list_head-based) equal to list_at_optional(xs, index: 0) (pre-fix arm) on both the empty-list boundary case that motivated the rewrite and the ordinary present case. Both PASS via claim_batch. Note: the local `main` ref was stale (21fb5d1); the true PR base is origin/main's 0f98a26 (merge-base origin/main HEAD) — using the stale ref for the pre-fix binary produced a false "grammar_invalid" rejection unrelated to this PR (fixed upstream by #6337, landed after 21fb5d1 but before 0f98a26).
…us + token-stream witness lex_walk_step accumulated tokens via list_snoc_item every token (O(n^2) before parsing even starts) -- 4th instance of the same shape, this time in a different pipeline stage than the three already-landed 02_parse.dag fixes. Rewritten as reverse-cons + single .reverse() at tokenize()'s exit. Verified byte-equal via a new order-sensitive token-stream content hash (class+lexeme, in stream order) run against independently-built pre-fix and post-fix binaries on tiny/small corpus samples -- identical both sides, confirming a pure algorithmic rewrite. Full read-based census of 02_parse.dag's 9 list_snoc_item call sites, each dispositioned (dead/test-only, bounded grammar-analysis cost, or already-fixed) -- none explain the file-size-scaling growth still seen deeper in live parsing on datetime.dag. That residual is not resolved by this PR; grammar_coverage_p8_wall_clock_blocker records the honest state (tokenize confirmed non-bottleneck, DNF persists past grammar-validation, driver not yet pinned) so the marker does not claim a false completion. Added parse_table_record_hit/miss/lookup_call and parse_choice_residue_backtrack to the interpreter's call-frequency watchlist for the continuing in-session hunt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The auto-committer snapshotted a mid-edit state (b16a357) that deleted the ProductionFirstRow type but left its consumers referencing it, breaking typecheck. This completes that edit -- not a new change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… removal" This reverts commit dae6602.
…FirstRow removal"" This reverts commit e2a24c3.
…istinct-key discriminator parse_match_arm_stmt_step and parse_expr_repeat_step both accumulated per-iteration diagnostics via list_append(left: diags.reverse(), right: acc.acc_diags) -- the acc_nodes field in the same accumulators was already reverse-cons fixed, but acc_diags was missed by the prior list_snoc_item-scoped census (this is a different primitive). Converted to List<List<Diagnostic>> batches (Cons-prepended, O(1) per step) plus a single flatten pass at the end (parse_flatten_diag_batches). Verified byte-equal via parse_tree_content_hash_witness.dag on tiny/small (9afb740ee43f9e61 / ed071cb2baeaeb61, unchanged). Honest caveat: list_append(left: small, right: large) is O(len(left)) per the native fold_list_right implementation (it walks `left`, not `right`), so this may not be the O(n^2) site the growing list_append call count suggested -- kept as a correctness-neutral cleanup bringing acc_diags in line with the already-safe acc_nodes pattern, not claimed as a proven complexity fix. Removed the temporary witness_forensics_scale_datetime_half_report (scratch-path fixture, not for the repo). Added a cross-thread parse-memo effectiveness discriminator (PARSE_MEMO_LOOKUPS/HITS/DISTINCT_KEYS globals + record_parse_memo_lookup, wired into try_parse_table_memo_dispatch's parse_table_lookup arm) per the manager's decisive-discriminator request: lookups >> distinct with hits == 0 would prove the native memo cache never serves a re-attempted span. Result on the datetime.dag half-truncation: lookups=0 hits=0 distinct_keys=0 -- the native fast-path memo cache never engages at all on this run, a separate real finding (not proven to be the DNF driver, since the .dag-level table's own stats are never reached either, given the run still doesn't finish). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…_SITE_DUMP_SECS, drop debug eprintln Addresses cursor/composer-2.5's REQUEST_CHANGES on #6365: record_call_frequency, record_flatten_site, record_list_cons_tail_split, and record_parse_memo_lookup ran unconditionally on hot paths (eval_call, every free_monoid_to_vec materialization, every native List Cons match, every packrat memo lookup) -- only the stderr dump was env-gated, not the recording itself. Added a residual_hunt_forensics_enabled() OnceLock check (same env var the dump already uses) and an early return at the top of each recorder, so the default/production path pays one relaxed load per call site instead of a mutex lock + HashMap/HashSet write. Added a SCAFFOLD/dissolve-on marker per DESIGN Sec6 (dissolve when adhoc-c328b166-bca closes). Also removed the ADHOC-DEBUG eprintln arms in parse_table_memo_scope_and_key -- a local one-off diagnostic (auto-committer captured a mid-investigation snapshot before I could revert it) that already served its purpose: it proved the extraction logic is sound (zero branches fire on a working file, lookups/hits/distinct_keys populate correctly), so it's not needed going forward and was correctly flagged as ambient unconditional stderr noise on a production code path. Re-verified byte-equal (9afb740ee43f9e61) and forensics gating with/without GUNBC_FLATTEN_SITE_DUMP_SECS set. cargo fmt --all applied (pre-existing formatting drift on this file, unrelated to this change, caught by the --check gate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
Author
|
Addressed in e9fb696.
— sent from neat-stag-780 |
2 of 3 tasks
gunbai-bot Bot
pushed a commit
that referenced
this pull request
Jul 8, 2026
…+ measured-zero on interpreter fold-site cut Continuation of adhoc-c328b166-bca residual-driver hunt (interpreter-side free_monoid_to_vec fold chokepoint; .dag-side fixes stay in #6365). Root cause PINNED via a new caller-attribution probe: the datetime interpreted- parse DNF is lex_repeat_loop (src/v2/compiler/01_tokenize.dag:158) folding the whole remaining source char-list (max_len=19021=file char count, elem=Int) once per repeat-token => O(n²) in source length. A .dag tokenizer dataflow bug, routed to the tokenize lane; this receipt is its acceptance baseline. Interpreter fold-site cut = MEASURED CLEAN ZERO, dropped: a streaming left-fold (no intermediate Vec) was built, proven byte-identical (parse-tree hash equal, tiny+small, two independently-built binaries), and moved neither wall-clock (~20s both) nor peak RSS (~168 MiB both) on small — elem=Int makes the removed alloc churn negligible and the Vec is transient (no peak-RSS contribution). Kept free_monoid_to_vec + a permanent note (DESIGN §6: a no-op displaces nothing). Lands: caller-attribution probe (DagFnGuard + record_fold_caller, gated behind GUNBC_FLATTEN_SITE_DUMP_SECS, dissolve-on the hunt) extending neat-stag's flatten-site instrument with the .dag-caller axis; + the measured-zero note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merged
3 of 4 tasks
briansrls
added a commit
that referenced
this pull request
Jul 8, 2026
* WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * 02_parse verification receipts: byte-equal parse-tree hash (fix 2+3) + empty-list semantics pin (fix 2) Manager-mandated merge-bar demands on #6362, addressed with durable, re-runnable witnesses rather than a one-off manual diff: - parse_tree_content_hash_witness.dag: content_hash(ParseTree) over the tiny/small corpus sample, computed once against the true PR base (0f98a26, built as its own release binary in an isolated worktree) and once against HEAD. Both hashes are byte-identical (witness.dag=9afb740ee43f9e61, execution_mode.dag=ed071cb2baeaeb61), proving fix 2 (list_at_optional -> list_head) and fix 3 (fold_list -> parse_match_arm_stmt_step) preserve parse semantics exactly, not just "no test regressions." - parse_token_first_empty_semantics_test.dag: two `test fn` claims pinning parse_token_first (post-fix, list_head-based) equal to list_at_optional(xs, index: 0) (pre-fix arm) on both the empty-list boundary case that motivated the rewrite and the ordinary present case. Both PASS via claim_batch. Note: the local `main` ref was stale (21fb5d1); the true PR base is origin/main's 0f98a26 (merge-base origin/main HEAD) — using the stale ref for the pre-fix binary produced a false "grammar_invalid" rejection unrelated to this PR (fixed upstream by #6337, landed after 21fb5d1 but before 0f98a26). * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: 01_tokenize O(n^2) fix + full parse-pipeline census + token-stream witness lex_walk_step accumulated tokens via list_snoc_item every token (O(n^2) before parsing even starts) -- 4th instance of the same shape, this time in a different pipeline stage than the three already-landed 02_parse.dag fixes. Rewritten as reverse-cons + single .reverse() at tokenize()'s exit. Verified byte-equal via a new order-sensitive token-stream content hash (class+lexeme, in stream order) run against independently-built pre-fix and post-fix binaries on tiny/small corpus samples -- identical both sides, confirming a pure algorithmic rewrite. Full read-based census of 02_parse.dag's 9 list_snoc_item call sites, each dispositioned (dead/test-only, bounded grammar-analysis cost, or already-fixed) -- none explain the file-size-scaling growth still seen deeper in live parsing on datetime.dag. That residual is not resolved by this PR; grammar_coverage_p8_wall_clock_blocker records the honest state (tokenize confirmed non-bottleneck, DNF persists past grammar-validation, driver not yet pinned) so the marker does not claim a false completion. Added parse_table_record_hit/miss/lookup_call and parse_choice_residue_backtrack to the interpreter's call-frequency watchlist for the continuing in-session hunt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * fixup: complete the auto-committed partial ProductionFirstRow removal The auto-committer snapshotted a mid-edit state (b16a357) that deleted the ProductionFirstRow type but left its consumers referencing it, breaking typecheck. This completes that edit -- not a new change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Revert "fixup: complete the auto-committed partial ProductionFirstRow removal" This reverts commit dae6602. * Revert "Revert "fixup: complete the auto-committed partial ProductionFirstRow removal"" This reverts commit e2a24c3. * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: 2 more diag-accumulator sites fixed, parse-memo distinct-key discriminator parse_match_arm_stmt_step and parse_expr_repeat_step both accumulated per-iteration diagnostics via list_append(left: diags.reverse(), right: acc.acc_diags) -- the acc_nodes field in the same accumulators was already reverse-cons fixed, but acc_diags was missed by the prior list_snoc_item-scoped census (this is a different primitive). Converted to List<List<Diagnostic>> batches (Cons-prepended, O(1) per step) plus a single flatten pass at the end (parse_flatten_diag_batches). Verified byte-equal via parse_tree_content_hash_witness.dag on tiny/small (9afb740ee43f9e61 / ed071cb2baeaeb61, unchanged). Honest caveat: list_append(left: small, right: large) is O(len(left)) per the native fold_list_right implementation (it walks `left`, not `right`), so this may not be the O(n^2) site the growing list_append call count suggested -- kept as a correctness-neutral cleanup bringing acc_diags in line with the already-safe acc_nodes pattern, not claimed as a proven complexity fix. Removed the temporary witness_forensics_scale_datetime_half_report (scratch-path fixture, not for the repo). Added a cross-thread parse-memo effectiveness discriminator (PARSE_MEMO_LOOKUPS/HITS/DISTINCT_KEYS globals + record_parse_memo_lookup, wired into try_parse_table_memo_dispatch's parse_table_lookup arm) per the manager's decisive-discriminator request: lookups >> distinct with hits == 0 would prove the native memo cache never serves a re-attempted span. Result on the datetime.dag half-truncation: lookups=0 hits=0 distinct_keys=0 -- the native fast-path memo cache never engages at all on this run, a separate real finding (not proven to be the DNF driver, since the .dag-level table's own stats are never reached either, given the run still doesn't finish). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: gate residual-hunt recorders behind GUNBC_FLATTEN_SITE_DUMP_SECS, drop debug eprintln Addresses cursor/composer-2.5's REQUEST_CHANGES on #6365: record_call_frequency, record_flatten_site, record_list_cons_tail_split, and record_parse_memo_lookup ran unconditionally on hot paths (eval_call, every free_monoid_to_vec materialization, every native List Cons match, every packrat memo lookup) -- only the stderr dump was env-gated, not the recording itself. Added a residual_hunt_forensics_enabled() OnceLock check (same env var the dump already uses) and an early return at the top of each recorder, so the default/production path pays one relaxed load per call site instead of a mutex lock + HashMap/HashSet write. Added a SCAFFOLD/dissolve-on marker per DESIGN Sec6 (dissolve when adhoc-c328b166-bca closes). Also removed the ADHOC-DEBUG eprintln arms in parse_table_memo_scope_and_key -- a local one-off diagnostic (auto-committer captured a mid-investigation snapshot before I could revert it) that already served its purpose: it proved the extraction logic is sound (zero branches fire on a working file, lookups/hits/distinct_keys populate correctly), so it's not needed going forward and was correctly flagged as ambient unconditional stderr noise on a production code path. Re-verified byte-equal (9afb740ee43f9e61) and forensics gating with/without GUNBC_FLATTEN_SITE_DUMP_SECS set. cargo fmt --all applied (pre-existing formatting drift on this file, unrelated to this change, caught by the --check gate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
gunbai-bot Bot
pushed a commit
that referenced
this pull request
Jul 8, 2026
Reconciles the caller-attribution probe + measured-zero note onto the squash-merged #6365 tokenizer/parse fixes. Conflicts were purely additive (my probe blocks sit adjacent to neat-stag's flatten-site instrument); kept both sides. Diff vs main is now only v1_interpreter.rs + cli_run.rs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
briansrls
added a commit
that referenced
this pull request
Jul 8, 2026
* WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * 02_parse verification receipts: byte-equal parse-tree hash (fix 2+3) + empty-list semantics pin (fix 2) Manager-mandated merge-bar demands on #6362, addressed with durable, re-runnable witnesses rather than a one-off manual diff: - parse_tree_content_hash_witness.dag: content_hash(ParseTree) over the tiny/small corpus sample, computed once against the true PR base (0f98a26, built as its own release binary in an isolated worktree) and once against HEAD. Both hashes are byte-identical (witness.dag=9afb740ee43f9e61, execution_mode.dag=ed071cb2baeaeb61), proving fix 2 (list_at_optional -> list_head) and fix 3 (fold_list -> parse_match_arm_stmt_step) preserve parse semantics exactly, not just "no test regressions." - parse_token_first_empty_semantics_test.dag: two `test fn` claims pinning parse_token_first (post-fix, list_head-based) equal to list_at_optional(xs, index: 0) (pre-fix arm) on both the empty-list boundary case that motivated the rewrite and the ordinary present case. Both PASS via claim_batch. Note: the local `main` ref was stale (21fb5d1); the true PR base is origin/main's 0f98a26 (merge-base origin/main HEAD) — using the stale ref for the pre-fix binary produced a false "grammar_invalid" rejection unrelated to this PR (fixed upstream by #6337, landed after 21fb5d1 but before 0f98a26). * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: 01_tokenize O(n^2) fix + full parse-pipeline census + token-stream witness lex_walk_step accumulated tokens via list_snoc_item every token (O(n^2) before parsing even starts) -- 4th instance of the same shape, this time in a different pipeline stage than the three already-landed 02_parse.dag fixes. Rewritten as reverse-cons + single .reverse() at tokenize()'s exit. Verified byte-equal via a new order-sensitive token-stream content hash (class+lexeme, in stream order) run against independently-built pre-fix and post-fix binaries on tiny/small corpus samples -- identical both sides, confirming a pure algorithmic rewrite. Full read-based census of 02_parse.dag's 9 list_snoc_item call sites, each dispositioned (dead/test-only, bounded grammar-analysis cost, or already-fixed) -- none explain the file-size-scaling growth still seen deeper in live parsing on datetime.dag. That residual is not resolved by this PR; grammar_coverage_p8_wall_clock_blocker records the honest state (tokenize confirmed non-bottleneck, DNF persists past grammar-validation, driver not yet pinned) so the marker does not claim a false completion. Added parse_table_record_hit/miss/lookup_call and parse_choice_residue_backtrack to the interpreter's call-frequency watchlist for the continuing in-session hunt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * fixup: complete the auto-committed partial ProductionFirstRow removal The auto-committer snapshotted a mid-edit state (b16a357) that deleted the ProductionFirstRow type but left its consumers referencing it, breaking typecheck. This completes that edit -- not a new change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Revert "fixup: complete the auto-committed partial ProductionFirstRow removal" This reverts commit dae6602. * Revert "Revert "fixup: complete the auto-committed partial ProductionFirstRow removal"" This reverts commit e2a24c3. * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: 2 more diag-accumulator sites fixed, parse-memo distinct-key discriminator parse_match_arm_stmt_step and parse_expr_repeat_step both accumulated per-iteration diagnostics via list_append(left: diags.reverse(), right: acc.acc_diags) -- the acc_nodes field in the same accumulators was already reverse-cons fixed, but acc_diags was missed by the prior list_snoc_item-scoped census (this is a different primitive). Converted to List<List<Diagnostic>> batches (Cons-prepended, O(1) per step) plus a single flatten pass at the end (parse_flatten_diag_batches). Verified byte-equal via parse_tree_content_hash_witness.dag on tiny/small (9afb740ee43f9e61 / ed071cb2baeaeb61, unchanged). Honest caveat: list_append(left: small, right: large) is O(len(left)) per the native fold_list_right implementation (it walks `left`, not `right`), so this may not be the O(n^2) site the growing list_append call count suggested -- kept as a correctness-neutral cleanup bringing acc_diags in line with the already-safe acc_nodes pattern, not claimed as a proven complexity fix. Removed the temporary witness_forensics_scale_datetime_half_report (scratch-path fixture, not for the repo). Added a cross-thread parse-memo effectiveness discriminator (PARSE_MEMO_LOOKUPS/HITS/DISTINCT_KEYS globals + record_parse_memo_lookup, wired into try_parse_table_memo_dispatch's parse_table_lookup arm) per the manager's decisive-discriminator request: lookups >> distinct with hits == 0 would prove the native memo cache never serves a re-attempted span. Result on the datetime.dag half-truncation: lookups=0 hits=0 distinct_keys=0 -- the native fast-path memo cache never engages at all on this run, a separate real finding (not proven to be the DNF driver, since the .dag-level table's own stats are never reached either, given the run still doesn't finish). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * WIP: interpreted-parse cost forensics: discriminate interpretation-tax vs alg * adhoc-c328b166-bca: gate residual-hunt recorders behind GUNBC_FLATTEN_SITE_DUMP_SECS, drop debug eprintln Addresses cursor/composer-2.5's REQUEST_CHANGES on #6365: record_call_frequency, record_flatten_site, record_list_cons_tail_split, and record_parse_memo_lookup ran unconditionally on hot paths (eval_call, every free_monoid_to_vec materialization, every native List Cons match, every packrat memo lookup) -- only the stderr dump was env-gated, not the recording itself. Added a residual_hunt_forensics_enabled() OnceLock check (same env var the dump already uses) and an early return at the top of each recorder, so the default/production path pays one relaxed load per call site instead of a mutex lock + HashMap/HashSet write. Added a SCAFFOLD/dissolve-on marker per DESIGN Sec6 (dissolve when adhoc-c328b166-bca closes). Also removed the ADHOC-DEBUG eprintln arms in parse_table_memo_scope_and_key -- a local one-off diagnostic (auto-committer captured a mid-investigation snapshot before I could revert it) that already served its purpose: it proved the extraction logic is sound (zero branches fire on a working file, lookups/hits/distinct_keys populate correctly), so it's not needed going forward and was correctly flagged as ambient unconditional stderr noise on a production code path. Re-verified byte-equal (9afb740ee43f9e61) and forensics gating with/without GUNBC_FLATTEN_SITE_DUMP_SECS set. cargo fmt --all applied (pre-existing formatting drift on this file, unrelated to this change, caught by the --check gate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * parse forensics: pin datetime DNF root cause (lex_repeat_loop O(n²)) + measured-zero on interpreter fold-site cut Continuation of adhoc-c328b166-bca residual-driver hunt (interpreter-side free_monoid_to_vec fold chokepoint; .dag-side fixes stay in #6365). Root cause PINNED via a new caller-attribution probe: the datetime interpreted- parse DNF is lex_repeat_loop (src/v2/compiler/01_tokenize.dag:158) folding the whole remaining source char-list (max_len=19021=file char count, elem=Int) once per repeat-token => O(n²) in source length. A .dag tokenizer dataflow bug, routed to the tokenize lane; this receipt is its acceptance baseline. Interpreter fold-site cut = MEASURED CLEAN ZERO, dropped: a streaming left-fold (no intermediate Vec) was built, proven byte-identical (parse-tree hash equal, tiny+small, two independently-built binaries), and moved neither wall-clock (~20s both) nor peak RSS (~168 MiB both) on small — elem=Int makes the removed alloc churn negligible and the Vec is transient (no peak-RSS contribution). Kept free_monoid_to_vec + a permanent note (DESIGN §6: a no-op displaces nothing). Lands: caller-attribution probe (DagFnGuard + record_fold_caller, gated behind GUNBC_FLATTEN_SITE_DUMP_SECS, dissolve-on the hunt) extending neat-stag's flatten-site instrument with the .dag-caller axis; + the measured-zero note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Merge origin/main (post-#6365 squash) into parse-forensics probe branch Reconciles the caller-attribution probe + measured-zero note onto the squash-merged #6365 tokenizer/parse fixes. Conflicts were purely additive (my probe blocks sit adjacent to neat-stag's flatten-site instrument); kept both sides. Diff vs main is now only v1_interpreter.rs + cli_run.rs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Brian Searls <briansearls1@gmail.com>
briansrls
pushed a commit
that referenced
this pull request
Jul 8, 2026
…6369/#6370) Resolution choices: - 02_parse diag accumulation: main's O(1) batch-cons + single flatten wins over per-step list_append (kills the 252k-appends cost the self-time profile measured); my O(1) memo position key preserved - 01_tokenize: my superset kept (repeat short-circuit == main's #6368 semantics, plus delimited short-circuit + CompiledLexRule precompile) - v1 interpreter: both instrument sets kept (main's fold-caller/memo discriminator + my big-fold site/builtin-time/self-time profiler); main's Map-grounding fast path moved into call_function_inner so both profiled and unprofiled paths hit it; env gate consolidated on main's residual_hunt_forensics_enabled (same var, one authority) - grammar_coverage ledger: main's fixes (1)-(4) text + my RESIDUAL CLOSED continuation renumbered (5)-(9) Gates: build green, fmt/clippy green, regen divergence 0, tiny/small packrat stats byte-identical (0/43/43, 0/200/200). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX
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.
Summary
lex_walk_step(01_tokenize.dag) accumulated the token list vialist_snoc_itemevery token -- an O(n²) tax paid before parsing starts, in a different pipeline stage from the three already-landed02_parse.dagfixes. Rewritten as reverse-cons + a single.reverse()attokenize()'s exit.Present{1ca5eb5ff95f753f}/Present{2ebd5cca313cc457}, identical both sides. New file:src/v2/test/manual/token_stream_content_hash_witness.dag.02_parse.dag's 9list_snoc_itemcall sites, each dispositioned (dead/test-only, bounded fixed grammar-analysis cost, or already-fixed) -- see table below.grammar_coverage_p8_wall_clock_blockermarker updated to the honest current state: tokenize is now confirmed non-bottleneck, butdatetime.dagstill DNFs deeper in live parsing (pastgrammar_validate_for_parse); the driver is not yet pinned to a specific call site. Not claiming a false completion.parse_table_record_hit/_miss/_lookup_callandparse_choice_residue_backtrackfor the in-session continuation of the hunt (memo hit-rate discriminator).02_parse.dag census (9
list_snoc_itemsites)parse_match_arm_stmt_stepparse_expr_repeat_steptoken_position_indices(line 437)parse_sync_step/parse_skip_to_sync(1575/1578)first_list_union(1007),upsert_production_first_row(1097),append_choice_ambiguity_row(1157),compute_left_corner_closure(1418)grammar_validate_for_parse's one-time, grammar-size-bound (P=36 productions) analysis; confirmed file-size-independent (call counts identical between small-file and full-file runs)grammar_choice_ambiguity_row_diagnostic_list(1305)None of the 9 sites explain the file-size-proportional growth still observed deep in live parsing on
datetime.dag(30M+ items at the native fold sites). That residual is tracked as an open, in-session hunt (work itemnode://adhoc-c328b166-bca), not claimed as resolved by this PR.Test plan
token_stream_content_hash_witness.dagrun on tiny/small samples against both pre-fix and post-fix independently-built binaries -- byte-equalparse_tree_content_hash_witness.dag(existing) confirms fix-2/fix-3 (parse_expr_repeat_step,parse_match_arm_stmt_step) byte-equallist_snoc_itemflat=6 vs climbing 284→1502 at matched checkpoints) confirms the tokenizer fix's effect🤖 Generated with Claude Code
Update: cut-b bundled in (not a separate PR)
upsert_production_first_row's O(P²) grammar-analysis carrier (GrammarFirstAnalysis.first_rows/ParseTableRealization.first_rows) has been converted from aList<ProductionFirstRow>linear-scan-then-append to a native-HAMT-backedMap<Symbol, List<Symbol>>(matching the existingParseTableRealization.entries: Map<...>carrier pattern in this same file). All consumers (production_first_row_lookupand everything downstream throughexpr_first_fold) were confirmed name-keyed-only (no order dependency) before the conversion.This was intended to land as its own follow-up PR per plan, but an auto-commit captured a mid-edit snapshot on this branch before the split could happen; unwinding it cleanly would have left the branch in a worse state under time pressure, so it's bundled here instead. Verified byte-equal via
parse_tree_content_hash_witness.dagon tiny/small samples before and after (9afb740ee43f9e61/ed071cb2baeaeb61, identical both sides) -- pure algorithmic rewrite, confirmed the same way as the other three fixes in this PR.Before/after cycle receipt (small file, execution_mode.dag)
Measured
time gunbc run --claim-run ... forensics_scaling_witness ... witness_forensics_scale_small_report(full cold-load + tokenize + grammar-validate + parse cycle, this PR's branch vs the pre-cut-bf8f6f80f44baseline02_parse.dag, same binary, 3 runs each):Honest number: cut-b shaves ~2.4s (~11%) off this cycle, not the whole ~20s floor -- the fixed-cost grammar-analysis pass this rewrite targets is real but smaller in wall-clock terms than the estimate. The dominant remaining cost is still the unidentified file-size-scaling residual deeper in live parsing (this file: memo stats
hits=0, misses=200, lookup_calls=200-- 0% hit rate, feeding directly into the in-session memo-effectiveness hunt below).Update: 2 more diag-accumulator sites + memo distinct-key discriminator (decisive negative result)
parse_match_arm_stmt_stepandparse_expr_repeat_stepboth accumulated per-iteration diagnostics vialist_append(left: diags.reverse(), right: acc.acc_diags)-- missed by the earlier census because it scoped only tolist_snoc_item, a different primitive. Converted both toList<List<Diagnostic>>batches (Cons-prepended per step, O(1)) + a single flatten pass at the end. Verified byte-equal (9afb740ee43f9e61/ed071cb2baeaeb61, unchanged).Honest caveat:
list_append(left: small, right: large)walksleft(the nativefold_list_rightimplementation), so it's O(len(left)) per call, not O(len(right)) -- this may NOT have been an O(n²) site despite the growing call-count signature that flagged it. Landed as a correctness-neutral cleanup (parity with the already-safeacc_nodespattern), not claimed as a proven complexity fix.Added a cross-thread parse-memo discriminator (
PARSE_MEMO_LOOKUPS/HITS/DISTINCT_KEYS, global so it survives a DNF underGUNBC_FLATTEN_SITE_DUMP_SECS) per the manager's request for a decisive test. Result on thedatetime.daghalf-truncation: lookups=0, hits=0, distinct_keys=0 -- the native fast-path parse-table memo cache never engages at all on this run. Real, separate finding; not proven to be the DNF driver (the .dag-level table's own stats are never reached either, since the run still doesn't finish in 90s).New lead, not yet attributed:
v1_interpreter.rs:2556(eval_fold_list_native'sfree_monoid_to_vec) is called with a rapidly growing total item count -- 6.4M items/1748 calls at t=15s, 14M items/9482 calls by t=75s, on a file that still hasn't finished parsing by 90s -- and this predates all of today's changes (confirmed present in the very first run of this session, before any.dagedits). Average ~1400 items perfold_listcall is far too large to be my newparse_flatten_diag_batches(only called once per repeat-construct, on small per-step batches). Caller isn't yet attributed. This is the strongest open lead for the actual residual driver.Correction: native memo cache is NOT dead; DNF is upstream of the memo table entirely
Verified via a fast-completing control file (witness.dag, 43 productions): the native fast-path parse-table memo cache works correctly end-to-end (43 lookups, 43 distinct keys, 0 hits -- the expected benign all-distinct signature). The earlier "lookups=0 hits=0 distinct_keys=0" report for the datetime.dag half-truncation was correct data, not a broken instrument:
parse_table_lookupis only reachable from insideparse_production_memo_stats, which requiresgrammar_validate_for_parseto have already returned -- and on the truncated file,grammar_validate_for_parse calls=1only appears in the periodic dump at ~t=75s of a 90s budget. The process spends essentially the entire window before the first memo lookup ever happens. The residual driver is upstream of parse-proper -- insidetokenize()or, more likely,grammar_validate_for_parse()-- not in packrat re-parsing or the memo/Map layer. This reverses the list_append/fold_list framing from the update above; that growth is grammar-analysis-phase residue, not parse-proper residue. Next step (not started, next session): bisect/instrumentgrammar_validate_for_parse's internals (compute_left_corner_closure,compute_nullable_set, first-row analysis) directly.Update: forensics recorders env-gated, ADHOC-DEBUG removed (review fix)
cursor/composer-2.5's REQUEST_CHANGES flagged that this session's forensic instrumentation (
record_call_frequency,record_parse_memo_lookup,record_flatten_site,record_list_cons_tail_split) recorded unconditionally on hot paths -- only the periodic stderr dump was gated onGUNBC_FLATTEN_SITE_DUMP_SECS, not the recording itself -- and thatparse_table_memo_scope_and_keyshipped unconditionalADHOC-DEBUGeprintln!arms (a local diagnostic captured by an auto-commit before I could revert it). Both valid. Fixed: addedresidual_hunt_forensics_enabled()(aOnceLock<bool>on the same env var) with an early-return guard at the top of each recorder -- default/production path now pays one relaxed atomic load per call site, not a mutex lock + HashMap/HashSet write -- and added the SCAFFOLD/dissolve-on marker DESIGN Sec6 requires (dissolve whenadhoc-c328b166-bcacloses). Removed theADHOC-DEBUGeprintln arms entirely; they'd already served their purpose (proved the memo-key extraction logic is sound) and are not needed going forward. Re-verified byte-equal content hash and forensics on/off behavior after the change.Update: pipeline-wide list_snoc_item census (33 sites, 03_resolve/04_infer/06_translate/00_compile/03_body_producer/03_normalize)
Per the manager's instruction to widen the class-audit beyond
02_parse.dag/01_tokenize.dagonce the same disease showed up in two stages, read and dispositioned every remaininglist_snoc_itemcall site across the rest of the pipeline (34 sites total; one,04_infer.dag's, gets its own entry below).33 sites: bounded and safe. Every one folds over a single node's own children/arity --
n.children, an arrow's input-type list, a lens roster, a fixed enum-variant list -- never over the whole tree or whole file, so none can blow up with file size the waytokenize/02_parse.dag's whole-file accumulators did.06_translate.dag(translate_fold_step) and03_normalize.dag(normalize_fold_step) both use thefold_nodetree catamorphism correctly: each step appends exactly one edge intoparent.children, which stays bounded by that node's own arity as the walk goes up -- this is the safe reference shape.One new genuine finding,
04_infer.dag(flagged, not fixed, not the live driver):infer_gather_fold_step(line 998) does NOT follow the safefold_nodeshape above -- at every node in the tree it merges the entire accumulated subtree entry list of each child into the parent's viaconcat_inferred_facts_entries(line 270), which itself foldslist_snoc_itemone item at a time over the child's list. Cost per node is proportional to its already-accumulated subtree size, not O(1) -- the same disease as tokenize/parse, structured as a tree-wide concat instead of a flat accumulator.facts_map_from_entries(line 352) re-walks the fully-flattened list the same way. Confirmed NOT the livedatetime.dagdriver: parse itself never returns on this file, soinfernever runs.04_infer.dagis a DESIGN-named pipeline stage, so a fix here needs its own witness discipline rather than riding this PR -- tracked as a separate future work item, not fixed in-session.