Repository navigation
02_parse interpreted-cost forensics: refute memo-table-carry, fix 3 O(n)/O(n^2) drivers, name honest residual - #6362
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).
Contributor
Author
|
Re: dashboard "CI FAILING" notification for the `ci` check — this is the known era-4 10-minute job-kill (`##[error]The action 'gunbc ci (.dag witnesses + gates)' has timed out after 10 minutes.`), not a regression from this PR's changes. Per the current CI regime ruling (#6323), a cancelled/timed-out `ci` job is expected; merge basis is dashboard approvals + `rust_tests` + `mergeable`, all of which are green (2/2 fresh approvals, rust_tests pass, ci_regen pass, mergeable=CLEAN). No fix pushed — nothing to fix here. — sent from neat-stag-780 |
briansrls
pushed a commit
that referenced
this pull request
Jul 7, 2026
The `compile` command took all `.dag` files in the first --source-root as entries, so `--source-root src/v2 --source-root dag` compiled the whole 1867-module tree — reconcile-OOM before emit (the missing scoped-compile mode #6362 flagged). `--entry <file>` makes exactly that one module the entry; its transitive imports resolve from the full index as before, so a small closure emits without a whole-tree pass. Mirrors `run --entry`. Receipt (local): `gunbc compile --source-root src/v2 --source-root dag --entry src/v2/test/claim/manual/s1_opt_probe.dag --target rust` indexes 1873 modules, resolves 61 (transitive closure), emits 66 files in 10s, no OOM — vs whole-tree OOM at ~67s. HAND file (main.rs); regen unaffected (not in the GENERATED roster). fmt + clippy -D warnings clean. Unlocks compiled-parse iteration for S1 (v2 parser emitted native and run in ~ms, vs ~278s/file interpreted) and scoped emit-on-demand generally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX
briansrls
added a commit
that referenced
this pull request
Jul 7, 2026
…tion (#6359) * emit_host: wire run_host_process to a real host transport (kernel-D S0 slice) The fail-closed run_host_process stub becomes a real typed-argv host tap: - v1_interpreter.rs gains the emit_host_run_transport builtin (wet-only; hermetic mode refuses -- no mock arm): materialize workspace files under a temp workspace (path-escape refused), run the build argvs then the run argv via std::process::Command (typed argv, no shell), return exit/stdout/stderr octets + build log as data. - 04_method.dag + generated v1_compiler_infer_method.rs register the builtin name (in-sync pair, the #6270 backfill pattern). - emit_host.dag folds HostTransportDescriptor -> builtin call -> typed EmitHostRunReceipt; unknown host tool is a typed refusal; the not-wired diagnostic is deleted (wire-or-delete). - rust.dag MVP1 descriptor gains the runnable workspace its codec always implied: Cargo.toml (FixedText) + main harness (EmittedWithSuffix, prints add(2,3) as the 5-byte codec value) + --quiet flags. - rung_3_4_common fixture repaired: per-node-coherent InferredFacts (grounding.node == queried node, structured algebra evidence) and the real rust_mvp1_target_model_staging() instead of a hollow TargetModel. Receipts (local, wet): - NEW emit_host_transport_wire_test.dag: green run (stdout == [0,5,0,0,0], runtime_value_parse Accepted) + 2 REDs (nonzero exit -> logical_run Rejected; 4-byte stdout -> codec width Rejected): gunbc run --claim-run emit_host_transport_wire_all_holds -> true. - rust_add_emit_add_fn_accepts_holds -> true (emit side unchanged). - rung3 roundtrip -> Pass (unchanged); rung4 emit-vs-eval -> Fail at the pre-existing target_use_site_ownership_lookup_miss (unchanged; the claim subject has never had a translate-accepted shape). Phase pin stays ModelAndWitnessOnly: the kernel-D flip criterion is the rung-4 EqualsClaim green-not-Deferred, which now waits only on the emit side accepting a shared subject, not on transport. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * emit_host: close S0 — genuine emit(add-fn) host-run == eval end-to-end; flip kernel-D pin Completes the kernel-D flip criterion (doc §4: run_test_claim_emit_vs_eval GREEN on a rust EqualsClaim, no Deferred). A dedicated end-to-end witness now composes the full pure-eval-emit path and passes by structural equality, not fabrication: eval(add-subgraph, octet-interpretation) -> RuntimePrimitive{P, octets(5)} emit(add-fn) -> cargo build -> cargo run -> stdout 5 bytes runtime_value_parse(stdout) -> RuntimePrimitive{P, octets(5)} runtime_value_eq (==) -> Pass The two sides meet only because they share the host row's primitive_type node P (rust_emit_host_runtime_primitive_type_node) AND the octet byte encoding (emit_host_octets_byte_string) — reconciling the value-representation fork that made the pre-existing nat_semiring rung-4 subject uncomparable. New witness (src/v2/test/claim/manual/emit_host_add_equals_eval_test.dag): - GREEN: emit_host_add_equals_eval_holds (Pass). - RED control: emit_host_add_wrong_oracle_refuses_holds — a wrong eval oracle (returns 6) must NOT Pass, proving the comparison discriminates rather than always-greening. - one subject.tree serves both stages: emit walks tree.root (the rust add-fn, real rust grounding facts); eval walks claim.rhs (the computation subgraph, generic coherent facts) via a composed facts lookup (rust-detail then generic fallback whose algebra == P to satisfy eval's resolved_type check). Interpreter fix (v1_interpreter.rs): emit_host_run_transport now flattens rope-shaped strings (free_monoid_to_string) for workspace path/text and argv elements — emit(...).carried materializes as a FreeMonoid Cons-chain, not a flat Value::Str, so the earlier expect_str rejected it (the transport wire test passed only because it fed a String literal). Phase pin: interpreter_kernel_d_current_phase ModelAndWitnessOnly -> PureEvalEmitWired (transport is wired and proven), with a new interpreter_kernel_d_phase_is_pure_eval_emit_wired predicate; the kernel-D witness updated to assert the advanced phase. Receipts (local, wet): - emit_host_add_equals_eval_all_holds -> true (green + wrong-oracle RED) - emit_host_transport_wire_all_holds -> true (unchanged) - interpreter_kernel_model_witnesses -> true (phase now PureEvalEmitWired) Not claimed: the nat_semiring rung-4 subject still Fails at translate's target_use_site_ownership_lookup_miss — that is a translate limitation for law-shaped subjects, a separate open item, not an emit_host/transport gap. The kernel-D criterion is met by the dedicated witness above. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * fmt: rustfmt v1_interpreter emit_host_run_transport builtin (rust gate) Multi-line format! wrapping to satisfy cargo fmt --check on the HAND interpreter file. Fixes the rust_tests fmt-diff failure on #6359. The ci_regen failure was pre-existing divergence on the stale base (pre-#6357 seed convergence), resolved by merging origin/main; regen --verify now reports regen_divergence_count=0 and the generated v1_compiler_infer_method.rs (carrying the emit_host_run_transport row) is byte-identical to a fresh self-compile. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1 grammar: `?` optional sugar + keyword-as-name (field/param), toward v2 parsing its own closure Two additive wave1-grammar extensions so v2's parser accepts constructs its own compiler source already uses (verified by interpreted execution; no Rust rebuild — grammar is .dag, read at interpret time): - `?` optional type sugar: `^dag_token_question` lexer rule + trailing `optional(?)` on `qualified_type_expr`. `Int?`, `Outcome<Symbol?>` parse CLEAN; `Optional<T>` is the emit-ready lowering target (v2 Node has no cardinality field — Cardinality connective already has translate support). Stash-verified additive: the deeper rejects it unmasks pre-date this change. - keyword-as-name: `dag_grammar_binding_name_terminal` = ident | any wave1 keyword, wired into `field_decl` + `typed_param` name positions. v2 source already uses `module:`/`loop:`/`match:` as field/param names (11+2+2 sites across 5 closure files); the grammar just didn't accept existing valid code. Name positions are type-context (name `:` type), so keyword tokens there carry no expression-parse ambiguity — grammar validates clean, disjoint FIRST sets. Receipts (interpreted, inline via grammar_coverage_ingest): - Int? / Outcome<Symbol?> / nested generics / `type X = A|B` → CLEAN - `type Scope = ScopeRoot { module: Namespace } | ScopeFrame { locals: Map<Symbol, Symbol>, outer: Scope }` (the 03_resolve blocker) → CLEAN - keyword field/param names (module/loop) → CLEAN - regression: plain record type / coproduct / fn-with-params → CLEAN S1 is not complete: full 74-file closure parse still iterating (masked layers surface as each tokenize/parse gap clears). s1_closure_parse_probe.dag is the closure receipt harness; s1_opt_probe.dag is the inline bisect tool. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1 diag: no-op probe to isolate interpreted-parse startup (3s) from parse cost Startup (load+compile probe closure interpreted) measured at 3s via s1_noop; so the ~5min/file S1 cycle is the interpreted parse itself, not startup. Manual diagnostic harness (test/claim/manual, non-CI). * cli: add `compile --entry` to scope emit to a subtree's import closure The `compile` command took all `.dag` files in the first --source-root as entries, so `--source-root src/v2 --source-root dag` compiled the whole 1867-module tree — reconcile-OOM before emit (the missing scoped-compile mode #6362 flagged). `--entry <file>` makes exactly that one module the entry; its transitive imports resolve from the full index as before, so a small closure emits without a whole-tree pass. Mirrors `run --entry`. Receipt (local): `gunbc compile --source-root src/v2 --source-root dag --entry src/v2/test/claim/manual/s1_opt_probe.dag --target rust` indexes 1873 modules, resolves 61 (transitive closure), emits 66 files in 10s, no OOM — vs whole-tree OOM at ~67s. HAND file (main.rs); regen unaffected (not in the GENERATED roster). fmt + clippy -D warnings clean. Unlocks compiled-parse iteration for S1 (v2 parser emitted native and run in ~ms, vs ~278s/file interpreted) and scoped emit-on-demand generally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * test: add s1_parse_harness (clean scoped parse entry), drop scratch probes s1_parse_harness.dag calls tokenize -> parse_module -> normalize directly (no grammar_coverage wrapper), so `compile --entry` emits its closure with 0 compiler diagnostics — the minimal entry for probing v2-parser emit health. Receipt (local, via compile --entry): the v2 parse closure resolves to 41 sources, emits 45 Rust files in 8s. But the emitted Rust is NOT cargo-green: 4259 rustc errors, 84% (3567) a single E0308 type-mismatch class — the same shape as the v1 seed's fresh-emit (1667 -> ~2 emitter root causes). So a runnable compiled parser is blocked on emitter restoration for v2 code (the S2 self-emit lane), not on scoping. `compile --entry` (prior commit) makes this emit-health measurable cheaply; the near-term S1 iteration unlock stays the interpreted-parse fix (list_snoc_item O(n^2) accumulation), owned in the parse-perf lane. Removes s1_opt_probe.dag / s1_closure_parse_probe.dag (bisect scratch with hardcoded temp paths). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX --------- Co-authored-by: Claude <noreply@anthropic.com>
briansrls
added a commit
that referenced
this pull request
Jul 8, 2026
…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) * 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> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Sonnet 5 <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> * 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>
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
added a commit
that referenced
this pull request
Jul 8, 2026
…arness (#6371) * 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 * Interpreted-parse superlinear drivers closed: medium fixture DNF(1200s+) -> 88s Continuation of neat-stag's adhoc-c328b166-bca forensics (fixes 1-3 merged from session/neat-stag-780). Three new env-gated instruments in the v1 interpreter named each residual driver; each was then killed at its single authority in v2 source: - 02_parse: memo position key O(1) via head-token start+1 (was length(all) - length(remaining) per nonterminal attempt; v2's length() is a .dag fold_list body, so the seed's native_len fast path never fired) - 01_tokenize: lex_repeat_loop + delimited combinator short-circuit recursion (were done-flag no-op folds over the entire remaining source per attempt); lex rule matcher thunks compiled once per tokenize (CompiledLexRule) instead of fold_lex_pattern per (rule, position) - std/nat: nat_compare grounded on the realization's native < / == (ordering side of the #5428 numeric-tower grounding; the Peano walk cost ~66 frames per char-class range check, 5.2M frames/min) - std/provenance: SpanIndex assoc list -> Map<OccurrenceId, OriginEvent> (ParseTable.entries carrier pattern; lookup was 13.4M frames / 242s self-time on one medium parse; merge stays base-wins) - v1 interpreter instruments (recording gated on GUNBC_FLATTEN_SITE_DUMP_SECS, off = one atomic load): big-fold .dag-site attribution, per-builtin inclusive wall time, per-.dag-fn self-time profile Receipts: datetime.dag DNF>1200s/4.3GB RSS -> 88s; node.dag 116s; grammar.dag 201s (class break closed, ~linear in content); tiny/small packrat stats byte-identical (0/43/43, 0/200/200); 13 targeted claims green; compile --entry 0 diagnostics; regen divergence 0; fmt/clippy green. P8 wall-clock blocker ledger updated with the closure and the two named, priced residuals (delimited lexeme O(k^2) accumulation, per-file grammar-analysis base). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1 groundwork: closure receipt harness + dissolve the one v1-only construct in the parser's closure - dag/std/algebra.dag: kernel_algebra_profile's map literal (the only string-keyed brace literal in the parse pipeline's transitive closure) becomes an ordinary builder fn over empty_map/map_insert -- same map value, one dialect construct fewer; std_algebra.rs regenerated (regen_stage0, divergence 0 after) - s1_closure_receipt_test.dag: S1 self-hosting receipt harness. Subject = the parse pipeline's transitive import closure (40 files rooted at 01_tokenize/02_parse/03_normalize/extdeps-languages-dag), which is "v2's parser parsing itself"; the harness's own filesystem plumbing is test infrastructure and deliberately outside the subject (note in file). Grammar validated once per run; per-file tokenize -> parse_production -> normalize; failures collected by path, claim = failures == []. Full-closure census run in flight; receipt lands with its result. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S2 strategic-lane worker brief + target_model parse probe - docs/plans/s2-v2-self-emit-brief.md: hand-off brief for the parallel v2-emits-v2 lane (receipt ladder, measured landmines incl. the Symbol carrier seam = 1,790 of 3,560 E0308s on fresh v1-emit of the closure, file-ownership split vs the tactical lane) - tm_probe.dag: profiled single-file parse probe for target_model.dag (census residency diagnosis; forensics-enabled run) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: dissolve target_model's two pipeline-operator sites + stall-offset diagnosis probe - target_model.dag: the closure's only live |> uses migrate to the v2 surface (length(xs:), any(xs:, predicate: fn)) -- v1 frontend 0 diags; these were two of the census-named parse failures' construct class - s1_stall_probe.dag: parses a file at the start production via parse_expr directly and reports the byte offset of the first token the parse could not consume (greedy repeat => Accepted-with-remaining pinpoints the first uncovered construct); batch fns for the remaining census failures (runtime, refinement, node, grammar, languages/dag, algebra post-migration re-verify) Census receipt (interpreted, 68 min, pre-fix tree): 35/45 parsed clean; subject-relevant failures under diagnosis: runtime, refinement, node, grammar, target_model (pipes, fixed here), languages/dag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: keyword-after-dot grammar row + dissolve negative-literal sites - languages/dag.dag: the postfix projection name after '.' uses dag_grammar_binding_name_terminal() (the soft-keyword choice already used for field/param names), so interpretation.loop / .match parse -- the runtime.dag census failure's construct class - refinement.dag, grammar.dag: the subject's three negative int literals (-1/-2) become parenthesized binary minus (0 - 1); the wave1 grammar has no negative-literal lexeme and three sites do not justify the lexer/normalize lever yet -- class noted for the tree-wide census All three v1-frontend green (0 diagnostics). Stall probes re-verifying under the new grammar; node.dag + languages/dag.dag offsets pending. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: dissolve node.dag's nine arrow-lambda sites to fn-lambdas The content-hash canonicalizer block used v1 arrow lambdas (e => match ...) with comma-separated inline match arms at two sites -- node.dag's census failure class (stall byte 13535 = the first such fn). All nine sites become fn(e) { ... } with newline arms; pure syntax migration, identical behavior, v1 frontend 0 diagnostics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: dquote lex rule via CharPattern + node.dag's last arrow lambda - languages/dag.dag: the string-literal rule's own delimiters were LiteralPattern { text: "\"" } -- an escaped-quote string the wave1 lexer cannot tokenize when reading this file itself (the stream garbles silently and the parse dies ~2,400 lines later; stall probe receipt). Now CharPattern { char: 34 }, the exact idiom the string-BODY escape element two rules up already uses. - node.dag: sort_by(xs, h => h) -> fn(h) { h } (the census's ninth-plus arrow site, hidden earlier by a head-truncated grep). Both v1-frontend 0 diagnostics. Full 40-file receipt run in flight. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: add target_model stall probe fn Merged-tree receipt: 38/40 subject files parse clean; the two giants (target_model.dag, languages/dag.dag) each have a residual construct behind the first fix -- stall probes running to name them. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX * S1: rename dag.dag's keyword let-binding + explicit field puns in target_model - languages/dag.dag: `let module = ...` used the bare `module` keyword as a let-binding name (lexes as kw_module, so the whole dag_wave1_grammar_root decl failed); renamed to module_prod -- a local binding, so a rename beats extending keywords into let-name/expr positions where they would collide with the match/if productions - target_model.dag: NamedMetadataFoldOk field puns made explicit (name: name); NOTE the sweep shows shorthand patterns parse fine in green files (integer.dag's Cons { head, tail }), so this may be hygiene rather than the poison -- fresh stall probes running to arbitrate Both v1-frontend 0 diagnostics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZSaWfysRfg28bNVS7ueX --------- Co-authored-by: Claude <noreply@anthropic.com>
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
Work item
node://adhoc-c328b166-bca: discriminate interpretation-tax vs algorithmic residue in v202_parse.dagrun under the v1 seed interpreter.Prime-suspect hypothesis refuted. The packrat memo table (
ParseTable) was suspected of O(table-size) carry cost under the interpreter's persistent-value semantics. Direct read ofv1_interpreter.rs'sValueenum showsParseTableRealization's record fields areRc-shared (cheap rebuild) and itsentries: Mapis backed by a genuineim_rc::HashMapHAMT (O(log n) insert/lookup), not a full clone. The memo mechanism itself is fine.Same-file compiled-vs-interpreted timing (v1 seed's own generated parser, native, vs
v1_interpreter.rstree-walking the same02_parse.dag): the compiled realization scales linearly across 43w-6173w files (~350-450 words/ms, no complexity-class break). The interpreted realization showed a genuine complexity-class break, not just the constant-factor tax a tree-walker should honestly pay.Three real O(n)/O(n^2) drivers found and fixed:
length/count/sizefell back tofree_monoid_to_vec's O(n) clone even forValue::List/Map/Set, which already track their length natively.parse_current_position(02_parse.dag) callslength()on the full token stream on every parse attempt -- an O(n) tax per attempt the compiled realization never pays. Fix:native_lenO(1) fast path inv1_interpreter.rs, checked before thefree_monoid_to_vecfallback.parse_token_firstusedlist_at_optional(xs, 0)(itselffold_list-based, no short-circuit) to peek the first token on every lookahead/terminal-check. Swapped to the already-existinglist_head(directEmpty/Conspattern match, genuine O(1)) -- verified empirically first that nativeValue::Listcorrectly matchesEmpty/Consbefore editing this load-bearing file.parse_match_arm_stmt_bodyfolded over the entire remaining token list per match-arm-body parse viafold_list-- becausefold_listhas no short-circuit, even after the accumulator'sdoneflag flipped true it kept no-op-iterating every remaining token to EOF: an O(remaining-tokens-to-EOF) cost per match-arm body, i.e. O(n^2) across a file full ofmatchexpressions (which real.dagsource is). Rewritten asparse_match_arm_stmt_step, a genuine short-circuiting recursion that stops as soon asdoneis true.Discriminating agreement test (
native_list_length_equals_freemonoid_cons_chain_length,src/v1/tests/src/list_free_monoid_chokepoint_test.rs): pins the newnative_lenfast path and thefree_monoid_to_vecfallback equal on an equivalent native-list vsCons/Empty-chain -- this repo's cross-representation-equality precedent (numeric tower, #5428).regen_stage0 --verify: divergence 0 -- the hand-maintainedv1_interpreter.rsedit is consistent with the committed stage0.Per-fix verification receipts (merge-bar demand):
Fix 1 (
native_lenfast path,v1_interpreter.rs):native_list_length_equals_freemonoid_cons_chain_length, a plain non-ignored#[test]insrc/v1/tests/src/list_free_monoid_chokepoint_test.rs-- pins the fast path and thefree_monoid_to_vecfallback equal.cargo test -p v1-compiler-tests list_free_monoid_chokepoint-- 9/9 passed.Fix 2 (
parse_token_first:list_at_optional(xs, 0)->list_head):src/v2/test/claim/parse/parse_token_first_empty_semantics_test.dag, twotest fnclaims pinning the two implementations equal on the empty-token-stream boundary case that motivated the rewrite (Absent==Absent) and the ordinary present case (same lexeme). Both PASS viaclaim_batch.Fix 3 (
parse_match_arm_stmt_body:fold_list->parse_match_arm_stmt_step, a rewrite inside DESIGN-named load-bearing02_parse.dag):src/v2/test/manual/parse_tree_content_hash_witness.dagcomputescontent_hash(ParseTree)(v2/std/node.dag's structural node hash) over thetiny/smallcorpus sample, run once against the true PR base (0f98a264dc, built as its own isolated release binary in a separate worktree -- the localmainref was stale at21fb5d1b2d; using it produced a falsegrammar_invalidrejection from an unrelated grammar-ambiguity fix, parse: nullable-only ambiguity rejection; non-nullable FIRST overlap becomes counted residue (fixes main parse refusing all input) #6337, that landed between the two) and once against this branch's HEAD. Hashes are byte-identical both ways:witness.dag:9afb740ee43f9e61==9afb740ee43f9e61execution_mode.dag:ed071cb2baeaeb61==ed071cb2baeaeb61This proves fix 2 and fix 3 together produce the exact same parse tree pre/post -- not just "no test regressions" on a load-bearing rewrite.
Honest residual, named with numbers, not absorbed into "fixed":
datetime.dag(1956 words) still does not finish after all three fixes -- DNF at 1200s+, RSS ~4.3GB at ~15min elapsed, essentially unchanged from the pre-fix baseline (DNF at 900s, RSS 4.35GB). The compiled-vs-interpreted gap is not yet flat across sizes; a further, unidentified superlinear driver remains in02_parse.dagand/orv1_interpreter.rsbeyond the three closed here.tiny/smallwitness files (43w/75w) complete correctly and unchanged both before and after (~20-25s each -- the interpreter's real combinator-heavy base tax, a separate, expected constant-factor cost, not this bug).Verdict (layered, per the brief): engine fix (#2, #3 in
02_parse.dag) + interpreter fix (#1 inv1_interpreter.rs) landed and verified individually correct; full resolution for realistic file sizes (~2000+ words) remains an open residual --grammar_coverage_p8_wall_clock_blocker(src/v2/lens/enforcement/grammar_coverage.dag:68) updated with full receipts. P8 full-corpus census stays blocked, narrowed but not closed.Emit-on-demand feasibility (deliverable 4): attempted
gunbc compile --source-root src/v2 --source-root dag --target rustas a same-realization double-check. There is no scoped/closure-only compile entry point today -- it always compiles the whole reachable transitive-import closure (indexed 1867 modules, resolved 1201 sources) and was OOM-killed during reconcile after ~67s / RSS 667MB+. Emit-on-demand is not viable via the existing CLI without a scoped compile mode; that is itself the answer, not something fixed in this PR.Test plan
cargo test -p v1-compiler-tests list_free_monoid_chokepoint-- 9 passed, including the new agreement test.cargo fmt --all --check-- clean.cargo clippy --all-targets -- -D warnings-- clean.regen_stage0 --verify--regen_divergence_count=0.claim_batch --entry src/v2/test/claim/parse/parse_token_first_empty_semantics_test.dag --function <both>-- PASS/PASS (fix 2 empty-list semantics pin).gunbc run --entry src/v2/test/manual/parse_tree_content_hash_witness.dagagainst the true PR base (0f98a264dc, isolated worktree + binary) and HEAD -- byte-identicalcontent_hash(ParseTree)on both corpus files (fix 2+3 byte-equal parse-output witness).src/v2/test/manual/parse_forensics_scaling_witness.dag): tiny/small unchanged and correct; medium (datetime.dag) still DNF, receipts and numbers above and in the updated blocker marker.src/v1/stage0/examples/parse_compiled_scale.rs(committed receipt harness, not wired into any build/CI gate).Closes node://adhoc-c328b166-bca