Skip to content

feat(evidence): symbol-bounded code_evidence chunks — measured negative for the #93 eval - #140

Closed
2233admin wants to merge 3 commits into
mainfrom
rung-b/symbol-bounded-code-evidence-chunks
Closed

feat(evidence): symbol-bounded code_evidence chunks — measured negative for the #93 eval#140
2233admin wants to merge 3 commits into
mainfrom
rung-b/symbol-bounded-code-evidence-chunks

Conversation

@2233admin

@2233admin 2233admin commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Refs #93

Rung (b): make code_evidence chunks carry real per-symbol line ranges instead of one whole-file chunk anchored at line 1.

Measured outcome: negative. q03 does not move, and nothing else moves either. Arm A pays 24.7% more bytes per covered question for zero coverage. I recommend this is not merged as-is — see "Recommendation" at the bottom.

Everything below was measured on this machine at base 6a6dd20, each configuration run twice.


1. Prediction (written before the after-run, verbatim)

q03 will NOT change. It stays pointer_found_window_excludes_golden_span and its Arm A byte count stays exactly 1,015,011. Three independent reasons, any one sufficient:

  1. q03 never reads chunks. eval/arms.py::arm_a_answer walks ARTIFACT_KIND_ORDER = (symbols, imports, chunks) and breaks at the first kind with any match. Keyword coupling_limit matches two symbol ids (#function:coupling_limit at line 1203, #function:coupling_limit_reads_ladder_grades_and_bare_numbers at line 1434), so Arm A stops at code_evidence.symbols and never opens the chunks artifact. Nothing I do to chunks can be observed.
  2. Even if it did read chunks, the pointer would be the same line. Arm A windows on entry["startLine"] only — endLine is never read (arms.py _KIND_SPEC, line_key "startLine"). A per-symbol chunk bounding coupling_limit starts at line 1203, i.e. the identical pointer the symbol already gave.
  3. No pointer can reach q03's golden span from this keyword. The golden span is sentrux_gate.rs lines 16–25 (the module //! doc comment). With WINDOW=10 a pointer line L covers it only if 15 ≤ L ≤ 26. The literal string coupling_limit does not occur anywhere in lines 1–26 of that file, and no emitted evidence links the identifier to the prose block. Arm A matches identifier text only.

Nothing else changes state either. q04/q06/q08/q11/q12 stop at code_evidence.symbols, which I am not touching. q10 stays covered — I keep the whole-file chunk (.github/workflows/ci.yml#file, startLine 1), which is the pointer it uses; ci.yml has zero extracted symbols so it gains no symbol chunks. q05 (edit.ast-grep-plan.compat, a match-arm string literal), q07 (DEFAULT_EXCLUDES, a Rust const, and the extractor only recognises fn), q09 (authorityBoundary, a JSON field name) all stay no_pointer_found. q01/q02 stay BROKEN.

Aggregate: A 5/10, B 8/10, A=2 B=8 tie=0 neither=0, broken=2, by category how A 4/4, where A 1/2, why A 0/4 — all unchanged.

Byte prediction: strictly worse for Arm A. Coverage constant, bytes up on the 4 of 10 questions that reach the chunks stage (q05, q07, q09, q10).

Falsifier: if q03 flips to covered, my model of arm_a_answer is wrong and I must find out how, not book the win.

2. Result

Every predicted covered-state held. Nothing changed state in either direction.

before after
Arm A covered 5/10 graded 5/10
Arm B covered 8/10 graded 8/10
head-to-head A=2 B=8 tie=0 neither=0 A=2 B=8 tie=0 neither=0
broken (ungraded) 2 (q01, q02) 2 (q01, q02)
by category, A how 4/4 · where 1/2 · why 0/4 how 4/4 · where 1/2 · why 0/4
by category, B how 3/4 · where 1/2 · why 4/4 how 3/4 · where 1/2 · why 4/4
A failure reasons no_pointer_found=3, pointer_found_window_excludes_golden_span=2 identical
B failure reasons golden_file_outside_top_cap=2 identical

Per question — Arm A. stop is stopped_at_kind; covered never changes:

q stop covered A bytes before A bytes after Δ
q03 code_evidence.symbols no → no 1,015,011 1,015,981 +970
q04 code_evidence.symbols yes → yes 1,014,065 1,015,035 +970
q05 (exhausted) no → no 1,721,917 3,145,979 +1,424,062
q06 code_evidence.symbols yes → yes 1,014,796 1,015,766 +970
q07 (exhausted) no → no 1,721,917 3,145,979 +1,424,062
q08 code_evidence.symbols yes → yes 1,014,193 1,015,163 +970
q09 (exhausted) no → no 1,721,917 3,145,979 +1,424,062
q10 code_evidence.chunks yes → yes 1,722,045 3,146,107 +1,424,062
q11 code_evidence.symbols yes → yes 1,014,207 1,015,177 +970
q12 code_evidence.symbols no → no 1,014,207 1,015,177 +970

q03's pointers are byte-for-byte what they were: sentrux_gate.rs:1203 and sentrux_gate.rs:1434, window read 1,632 bytes, reason pointer_found_window_excludes_golden_span.

Why rung (b) cannot move q03

arm_a_answer breaks out of the kind loop at the first artifact kind with any match. For q03 that kind is code_evidence.symbols. The chunks artifact is never opened for q03 — confirmed directly by the baseline's own stopped_at_kind field, not inferred. Improving chunks is unobservable there.

Even removing that stop rule would not help. Arm A resolves a pointer from entry["startLine"] and reads startLine ± 10; endLine is never consulted, so a symbol chunk bounding coupling_limit yields pointer 1203 — exactly what the symbol already yielded. And q03's golden span is prose in the module //! header at lines 16–25, which contains no occurrence of coupling_limit. Arm A matches identifier text (symbol id, import file::target, chunk id); there is no identifier-to-prose edge in this evidence model for it to traverse. Reaching q03 requires evidence that links a symbol to the module documentation that explains it, or a retrieval mode that searches text rather than identifiers — a different rung, not this one.

3. Surprises

Three, all investigated rather than booked. None of them moved a covered-state.

3a. The code_evidence.symbols artifact grew 970 bytes — but symbol emission did not change

The prediction said symbols would be unchanged (1,013,379). It measured 1,014,349. I did not book it; I ran a decomposition.

The benchmark is self-hosted — code-intel . --mode lite scans the working tree the eval lives in — so my own patch added source lines to the corpus being measured. To separate "format cost" from "I made the repo bigger", I ran the new binary against the base tree (changes stashed, binary unchanged):

  • symbols artifact object digest 7520a936…, size 1,013,379 — byte-identical to the baseline. So symbol emission is unchanged; all 970 bytes are the three fn declarations this patch adds to the scanned repo (symbol_region_chunks, fallback_chunk_rate, and the new test).
  • files.json, imports.json, coverage.json, ranking.json, inventory.files, repository.snapshot — all byte-identical too. Exactly three artifacts changed: chunks, symbol_chunks, scorecard. That is precisely the set this patch touches, with no collateral.
  • On that identical corpus q03 measured 1,015,011 bytes, same two pointers, same reason — i.e. the baseline value exactly.

3b. Editing the legacy producer invalidated five in-flight retirement packets

CI caught what cargo test --workspace --locked could not: the PowerShell job windows-build-test-package failed its Compatibility retirement packets step, 5 of 10 checks — E02, E03, E04, E07, E08, all packet is stale relative to its frozen source set (E08: snapshot drift).

Mechanism: those packets freeze a source set that includes legacy/run-code-intel.ps1, and E07 additionally asserts that its rollback-rehearsal/run-code-intel.ps1 is byte-identical to the live facade. Rung (b) cannot be implemented in Rust alone — tests/native_code_evidence.rs compares the Rust and legacy producers' chunks.json byte-for-byte — so the legacy facade must change, and changing it invalidates those five approvals.

Resolved the sanctioned way, following the precedent set in #134: regenerated each packet with its original EvaluatedAt (E02/E03/E04/E08 1785441780, E07 1785748660), so re-freezing does not restamp the governance timestamps. The suite now passes 8 packets + 2 audits, 0 known-blocked.

This is a real cost of the rung, not routine churn. A chunk-format experiment that buys zero coverage should not be re-freezing five in-flight retirement approvals. It is an independent argument against merging.

3c. Arm B's q08 byte count moved +15,161 — through the self-hosting loop, not through retrieval

After the packet regeneration, q08's Arm B cost went 2,206,091 → 2,221,252. Arm A on q08 is untouched, and q08's Arm B verdict is unchanged (golden_file_outside_top_cap before and after).

Mechanism: q08's keywords are scan, repin, and the five files Arm B ranks highest are the retirement compatibility-retirement-deletion-diff.json files — which embed the PowerShell hunks slated for deletion from run-code-intel.ps1. My added lines sit inside that region, so four of those five JSON files grew. Same five files read, ~3.8 KB more each.

Worth flagging because q08 is one of only two questions Arm A wins, and it wins precisely because Arm B overspends on those packet files. My patch made Arm B's q08 marginally more expensive. That is a self-hosting artifact, not a retrieval result, and I am not counting it as anything.

No other outcome moved in either direction.

4. Byte cost — this buys nothing and costs real bytes

Artifact sizes on the identical corpus (base tree; old binary vs new), so this is pure format cost:

artifact before after
code_evidence.chunks 555,144 1,976,596 ×3.56
code_evidence.symbols 1,013,379 1,013,379 unchanged
code_evidence.imports 153,394 153,394 unchanged

code_evidence.symbol_chunks roughly doubles (708,397 on the base corpus → 1,559,657 on the final corpus — two mappings per symbol instead of one). Arm A never reads it, so it costs setup bytes only; the two figures are from slightly different corpora and are not a clean before/after pair.

Arm A bytes-per-covered-question: 1,155,861 → 1,441,450 (+24.7%) across an unchanged 5 covered questions. The rise comes entirely from q10, the one covered question that reaches the chunks stage; the other four pay only the +970 self-hosting cost.

Against the acceptance criterion (Arm A ≤ ~2× Arm B on the questions A covers), on q04/q06/q08/q10/q11:

Arm A Arm B ratio
before 5,779,306 (1,155,861/q) 2,553,351 (510,670/q) 2.26×
after 7,207,248 (1,441,450/q) 2,568,512 (513,702/q) 2.81×

The baseline was already over the ~2× bar at 2.26×; this change pushes it to 2.81×. Coverage did not go up, so no score was bought — but bytes were spent, and the criterion is failed harder than before. (Arm B's figure includes the +15,161 self-hosting movement on q08 described in §3c; without it the ratio is 2.82×. Either way, worse.)

5. Reproducibility

Every configuration run twice. Comparison ignores only the top-level meta block (timestamps, wall-clock, nonce-bearing run directory) and the two published objects that carry the run nonce by design.

configuration harness output (setup+questions+aggregate) published artifact corpus
base 6a6dd20, base binary byte-identical (13,108 chars) 12/14 objects byte-identical; the 2 that differ are the run manifest and repository.iteration
final tree, new binary byte-identical (13,108 chars) same: 12/14 identical, manifest + repository.iteration differ

All three artifacts Arm A consumes (symbols, imports, chunks) were byte-identical across repeated runs in both configurations. No nondeterminism had to be fixed.

6. Gates

  • cargo test --workspace --lockedgreen, 0 failures.
  • cargo fmt -p code-intel -- --check — clean.
  • Retirement packet suite (legacy/scripts/tests/test-retirement-packets.ps1) — 8 packets + 2 audits pass, 0 known-blocked after the re-freeze in §3b.
  • Authoritative self-scan code-intel run executeexit 0 before and after.
  • code-intel sentrux --operation checkgod files 33 → 33, "No degradation detected".

One local-only false alarm worth recording: the packet generators leave scratch copies of the 4400-line facade in legacy/work/, which is gitignored but not in the gate's SKIP_DIRECTORIES, so the self-scan counted them and reported god files 33 → 36. Reproduced on a pristine HEAD tree, so it is pre-existing environmental noise, not this change; deleting legacy/work/ restores 33 → 33. CI checks out fresh and never sees it.

Fixtures that legitimately changed

  • crates/code-intel-cli/tests/native_code_evidence.rs, native_atom_preserves_…: scorecard.metrics.chunks 2 → 3. The fixture is 2 files; index.js has one extracted symbol (greet) and index.test.js has none, so 2 file chunks + 1 symbol chunk. Added an assertion that fallbackChunkRate is now 2/3 rather than the previously hardcoded 1.0.
  • orchestration/schemas/code-evidence-native-artifacts.v1.schema.json: chunk kind {"const": "file"}{"enum": ["file", "symbol"]}. Widening, consistent with the schema's declared additive-only compatibility policy.
  • legacy/run-code-intel.ps1 mirrors the new chunk emission. a01_a09_artifacts_match_the_real_legacy_producer_on_the_same_fixture compares both producers' chunks.json byte-for-byte after canonical sorting over 10 legacy runs; it passes, so the two producers agree exactly, including the region textHash.
  • Digest re-pins across orchestration/ are repin --write output plus the two manual fixes above.

No question in eval/questions.json was edited, no coverage or grading criterion was relaxed, and there is no question id, golden path, or keyword list anywhere in the Rust, the PowerShell, or the harness.

eval/BASELINE.md and eval/baseline-*.json are deliberately left at their committed state: the numbers above are the deliverable, and the harness names its output after HEAD, which cannot exist before the commit.

7. Recommendation

Do not merge as-is. On the benchmark this is strictly negative: identical coverage, +24.7% bytes per covered question, and the chunks artifact ×3.56. It also costs a re-freeze of five in-flight retirement packets (§3b), which is a disproportionate price for a format change that buys nothing.

The chunk shape itself is genuinely more honest than a whole-file chunk claiming to point at a symbol, so this is worth keeping on a branch as the reference implementation. If it is ever pursued it should land only alongside a consumer that actually uses endLine (Arm A ignores it entirely today), and the extractors in native_code_evidence.rs should be split into their own module first: this patch pushes that file from 748 to 838 non-blank lines, over the 800 threshold. It was already one of the 33 god files, so god_file_count is unchanged and the gate is green, but growing it further is the wrong direction.

For issue #93 the actionable finding is elsewhere: Arm A's ceiling on why questions (0/4) is not chunk granularity. All three no_pointer_found cases (q05, q07, q09) fail because their keyword is a match-arm string literal, a Rust const, and a JSON field name respectively — none of which the line heuristic extracts as a symbol at all — and q03/q12 fail because the answer is prose that no identifier-keyed index points to. Those are extractor coverage and a text-bearing evidence kind, not chunk line ranges.

…ve for the #93 eval

Every file used to emit exactly one chunk: startLine 1, endLine <file length>,
kind "file". A consumer that matched a chunk got line 1 as its pointer no
matter which symbol the chunk's containsSymbols had named. This adds one chunk
per extracted symbol, bounded by the declaration line through the line before
the next declaration (last runs to EOF), so a chunk hit resolves near the thing
it names. The whole-file chunk is retained — it is the only pointer available
for a file with no extracted symbols (e.g. every .yml), and eval q10 depends on
exactly that.

Also emitted honestly: each symbol now maps to both the file chunk and its own
symbol chunk, and scorecard fallbackChunkRate stops being hardcoded 1.0.

Measured result on the issue #93 eval: this does NOT move q03, and moves
nothing else either. Coverage is unchanged (A 5/10, B 8/10, A=2 B=8) and Arm A
reads 24.7% more bytes per covered question. Full numbers, prediction, and
mechanism are in the PR body. Rung (b) is a negative result.

Refs #93
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@repowise-bot

repowise-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

🔒 Repowise is not analyzing this repository

The PR bot is free on public repositories. This one is private, which needs a Pro plan.

See plans · Manage this repository

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fa2e3457-133f-4b2c-a673-751ebb2c17ea

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@2233admin
2233admin marked this pull request as draft August 3, 2026 13:35
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Code Intel change risk

Score Percentile Level
66/100 60th (vs last 47 commits) 🟡 medium

Top signals

  • Diff shape: 110 file(s), +400/-120 (max file share 0.19)
  • Test asymmetry: source changed, tests touched
  • Bug-magnet: 569 fix commit(s) in touched files (180d)
  • Churn: 1053 commit(s) touching these files (90d)

revspec: origin/main..HEAD · threshold: percentile >= 90 blocks unless labeled risk-accepted · code-intel change risk

`cargo fmt -p code-intel -- --check` is a CI gate and the new test in
tests/native_code_evidence.rs was not formatted. Formatting-only change plus
the `code-intel repin --write` cascade it triggers (the test file's sha256 is
pinned by orchestration/internalization/native-code-evidence.json, which
cascades into the c03-r05-r12 measurement digest).

Re-verified after: cargo test --workspace --locked green, `run execute`
self-scan exit 0, god files 33 -> 33, repin clean, and the eval harness
reproduces byte-identical per-question numbers (Arm A 5/10, Arm B 8/10,
A=2 B=8) across two runs.

Refs #93
…cy facade

CI's retirement packet suite failed 5 of 10 checks: editing
legacy/run-code-intel.ps1 moves the frozen snapshot identity of every packet
whose frozen source set contains it, and E07 additionally requires
rollback-rehearsal/run-code-intel.ps1 to be byte-identical to the live facade.
`cargo test --workspace` does not cover this — the suite is a separate
PowerShell CI job.

Regenerated with each packet's ORIGINAL EvaluatedAt (E02/E03/E04/E08
1785441780, E07 1785748660), following the precedent in #134, so re-freezing
does not restamp the governance approvals. Verified: suite passes 8 packets +
2 audits, 0 known-blocked.

This is the honest cost of rung (b): it cannot be done in Rust alone, because
tests/native_code_evidence.rs compares the Rust and legacy producers'
chunks.json byte-for-byte, and touching the legacy producer invalidates five
in-flight retirement packets. Recorded in the PR body as an argument against
the rung, not as routine churn.

Refs #93
@2233admin

Copy link
Copy Markdown
Owner Author

关闭:这是一次成功的负结果,不合并。

实现者动手前写下预测「q03 不会动」,理由是 eval/arms.py::arm_a_answersymbols → imports → chunks 顺序遍历并在第一个命中处 break——coupling_limit 在 symbols 层就命中,chunks 层永远走不到。跑完完全符合预测:零题状态变化,Arm A 5/10 不变,head-to-head A2:B8 不变,失败原因分布逐项相同。

代价是实打实的:code_evidence.chunks 从 555,144 涨到 1,976,596 字节(×3.56),Arm A 每覆盖题字节数 1,155,861 → 1,441,450(+24.7%),覆盖数一题没涨。

三个独立验伪 agent 全部 refuted=false 并逐项复现了数字;其中一个的原话是「没有可推翻的胜利——这份报告是作者自己论证不该合并的负结果」。另两个分别确认:eval/ 目录 diff 为空(窗口、file_cap、评分谓词均未被碰),代码 diff 里没有任何 question id / golden 路径 / 关键词字面量;同一 commit 连跑两次产物与 harness 输出逐字节相同。

分支保留作为证据,不删。真正的结论记在后续 issue:Arm A 的开销 99.8% 是产物全量扫描,把产物做得更精确只会让它更贵。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant