Skip to content

fix(analytics): the call scanner read JSDoc examples as live calls — 3 of 4 'Potential Bugs' were documentation (#17668) - #17670

Merged
mrveiss merged 8 commits into
mainfrom
issue-17668-comment-scan
Sep 28, 2026
Merged

mrveiss merged 8 commits into
mainfrom
issue-17668-comment-scan

Conversation

@mrveiss

@mrveiss mrveiss commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Thinking Path

Four findings on the live "Missing Endpoints — Potential Bugs" panel. I checked each against the source before touching anything:

# reported reality verdict
1 GET /api/export @ useFileDownload.ts:11 inside the /** … */ opening at 6, closing at 17 — a Usage: example false
2 GET /api/export @ useFileDownload.ts:16 same block, Or inline: example false
3 GET /api/users @ apiErrorHandler.ts:222 inside the JSDoc ```typescript fence opening at 212 false
4 POST /api/themes @ ThemeManagerView.vue:35 real call, and no backend route matches true

The panel was wrong in both directions

Running the real scanner to settle the fourth finding surfaced something the panel never reported: DELETE /api/themes/${id} at ThemeManagerView.vue:49 — a second genuine call, on the same missing route, absent from the panel's four.

So this surface was over-reporting documentation and under-reporting real calls at the same time. That is a stronger and more useful statement than "3 of 4 were false": precision and recall were both wrong, in opposite directions, on one panel. It appeared only because the verification ran the scanner rather than reasoning about it — and it means "make the findings precise" is not the whole remedy, because the same panel is also missing things.

3 of 4 false, on a panel whose label invites action. That is worse than an empty panel: an empty one gets investigated, a wrong one gets acted on — and the one real finding gets discounted along with the noise.

Mechanism

api_endpoint_scanner.py decided "is this a comment?" per line, by prefix:

stripped = line.strip()
if stripped.startswith("//") or stripped.startswith("/*"):
    continue

Two spellings; the class has at least three:

  1. Block continuation — * const r = await ApiClient.get('/api/export') starts with neither marker. All three false positives.
  2. Block interior with no leading star — any line inside /* … */.
  3. Trailing comment — doThing() // apiClient.get('/api/legacy') does not start with the marker.

"Is this position inside a comment" is not a property of one line, so a per-line prefix test cannot answer it however many prefixes it learns.

Why string awareness is the load-bearing part

An https scheme contains a slash pair. A comment stripper without string handling blanks the rest of that line — silencing a genuine call and reporting nothing, which is the failure direction that looks like success. The tests are grouped by failure direction for exactly this reason: a false positive shows up as a wrong finding, a false negative shows up as a clean panel.

What Changed

  • api/codebase_analytics/comment_blanking.py (new) — blank_comments() carries block state across lines and replaces comment bodies with spaces, so every file:line the scanner reports still points at the same place. Handles //, /* … */, and <!-- … --> for Vue templates; string literals pass through verbatim.
  • api/codebase_analytics/api_endpoint_scanner.py — blanks before scanning instead of skipping by prefix. 1445 → 1444 lines, both baselines ratcheted down. The helper is a separate module because the scanner sat at its frozen ceiling.
  • comment_blanking_test.py (new) — 17 tests.

blank_comments is four small state consumers plus a five-branch driver, not one loop: the function-length gate caught it at 67 body lines, and the split reads better — each consumer answers one question.

Verification

Settled with the scanner, not a proxy — the first version of this verification used my own regex, which is a different instrument than _API_CALL_PATTERNS:

useFileDownload.ts    before [(11, GET /api/export), (16, GET /api/export)]  after []
apiErrorHandler.ts    before [(222, GET /api/users)]                         after []
ThemeManagerView.vue  before [(35, POST /api/themes),                        after [(35, POST /api/themes),
                              (49, DELETE /api/themes/${id})]                       (49, DELETE /api/themes/${id})]

Pinned in frontend_call_scanner_comments_test.py, which names the true positive rather than implying it. Mutation-proved with the mutation that matters: making the blanker blank code as well as comments — the fix that silences everything — fails 2 of 5. When a fix removes findings, the test must name a finding it keeps, or "fixed the false positives" and "broke the detector" have the same signature.

Against the three real files rather than synthetic input:

useFileDownload.ts    /api/ visible before [11, 16] -> after []
apiErrorHandler.ts    /api/ visible before [222]    -> after []
ThemeManagerView.vue  /api/ visible before [35, 49] -> after [35, 49]

The false positives go; POST /api/themes survives. The fix must not silence the true positive, and that is asserted rather than assumed.

17 tests pass. Mutation-proved, each verified to have applied before its result was read:

mutation tests failed
identity (_blank_like returns input) 6
delete rather than blank 5
drop string awareness 1
never enter block state 4

Two of those first read as "not caught" — a shell heredoc mangled the replacement and the edit never landed. A mutation that did not apply is not evidence that a test is weak, and it points the wrong way: it invites weakening the code to satisfy a check that never ran. The harness now asserts the anchor appears exactly once and that the file changed before reading any result.

A non-vacuity test fails on an identity implementation, because every "this call survives" assertion passes when nothing is blanked at all.

Known limit, in the module rather than left to be rediscovered: a JS regex literal containing a slash pair is not distinguished from a line comment. The scanner's input is API-path string literals where that shape does not arise; the fix would be a tokenizer, not another special case.

Model Used

Claude Opus 5 (1M context)

Closes #17668

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • API scanning now ignores references inside JavaScript, TypeScript and Vue comments, reducing false-positive findings while preserving genuine API calls.
    • Comment handling covers inline, block and HTML comments, including comments spanning multiple lines. Strings and template text remain scannable, and reported source positions are preserved.

…17668)

Three of the four findings on the live "Missing Endpoints — Potential Bugs" panel
were documentation. Verified line by line before changing anything:

  useFileDownload.ts:11  inside the /** block opening at 6, closing at 17  FALSE
  useFileDownload.ts:16  same block, "Or inline:" example                  FALSE
  apiErrorHandler.ts:222 inside the ```typescript fence opening at 212      FALSE
  ThemeManagerView.vue:35 real call, and no backend route matches           TRUE

The scanner decided "is this a comment?" per line, by prefix:

    stripped = line.strip()
    if stripped.startswith("//") or stripped.startswith("/*"):

That knows two spellings and the class has at least three. A JSDoc example lives on
a `*` continuation line, which starts with neither -- all three false positives. A
`//` trailing real code is scanned too, because the line does not *start* with it.
And any line inside a `/* */` block that has no leading star. "Is this position
inside a comment" is not a property of one line, so a per-line prefix test cannot
answer it.

`blank_comments` carries block state across lines and replaces comment bodies with
**spaces**, so every `file:line` the scanner reports still points at the same place.
It lives in its own module because the scanner is at its frozen size ceiling; the
scanner shrinks 1445 -> 1444 and both baselines ratchet down.

String awareness is the part that is not optional: `'https://example.test'` contains
`//`, and a stripper without it blanks the rest of that line -- silencing a real
call and reporting nothing, which is the failure direction that looks like success.
Vue `<!-- -->` is handled too, since a commented-out template call is the same
defect in a different syntax.

Verified against the three real files rather than synthetic input:

  useFileDownload.ts    /api/ visible before [11, 16] -> after []
  apiErrorHandler.ts    /api/ visible before [222]    -> after []
  ThemeManagerView.vue  /api/ visible before [35, 49] -> after [35, 49]

The false positives go, the true positive stays. `POST /api/themes` is a theme
upload that can only 404 and was previously indistinguishable from noise.

Tests are organised by failure *direction*, because only one direction is visible:
a false positive shows up as a wrong finding, a false negative as a clean panel. A
non-vacuity test fails on an identity implementation, since every "this call
survives" assertion passes when nothing is blanked at all.

Mutation-proved, each verified to have applied before its result was read: identity
fails 6, deleting rather than blanking fails 5, dropping string awareness fails 1,
not entering block state fails 4. Two of those first read as "not caught" because a
shell heredoc mangled the replacement and the edit never landed -- a mutation that
did not apply is not evidence that a test is weak, and the harness now asserts the
file changed before running anything.

`blank_comments` is split into small state consumers rather than one loop: the
function-length gate caught it at 67 body lines, and the split is better anyway --
each consumer answers one question and the driver is a five-branch dispatch.

One limit stated in the module rather than left to be rediscovered: a JS regex
literal containing a slash pair is not distinguished from a line comment. The
scanner's input is API-path string literals where that shape does not arise, and
the fix would be a tokenizer rather than another special case.

Closes #17668
@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

Next included review available in 33 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: mrveiss/AutoBot-AI/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ff92b418-f87e-48d3-96ce-77d894e58f83

📥 Commits

Reviewing files that changed from the base of the PR and between be2031a and c24bd1d.

📒 Files selected for processing (2)
  • autobot-backend/api/codebase_analytics/comment_blanking.py
  • autobot-backend/api/codebase_analytics/comment_blanking_test.py
📝 Walkthrough

Walkthrough

The frontend API scanner now blanks comments before scanning, while preserving source positions and quoted strings. Tests cover comment handling and retained API calls. The module registry test records a new measurement and raises its REACH floor.

Changes

Frontend API scanning

Layer / File(s) Summary
Comment blanking and validation
autobot-backend/api/codebase_analytics/comment_blanking.py, autobot-backend/api/codebase_analytics/comment_blanking_test.py
Adds comment blanking for JavaScript, TypeScript and Vue source. Tests cover comment forms, quoted strings, and preservation of source length and line positions.
Scanner integration and regression coverage
autobot-backend/api/codebase_analytics/api_endpoint_scanner.py, autobot-backend/api/codebase_analytics/frontend_call_scanner_comments_test.py
The scanner processes comment-blanked source and uses it for fallback call context. Regression tests check that documented examples are excluded and a real API call remains detectable.

Module registry floor

Layer / File(s) Summary
REACH floor update
repo_tests/one_claim_registry_16653_test.py
Updates the documented module-count measurement and raises the REACH floor from 2,976 to 3,002.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: 🔵 Low · up to be203

An unusual template comment can still produce a false API-call finding. The remaining issue is narrow and can be fixed with brace-aware comment handling.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to be203

Comment filtering should remove documentation-only findings, but a valid source-code pattern can also hide real calls from endpoint reports. The effect is limited to analysis results; no change to authorization or code execution is established.

Retained concerns

  • Medium · reliability · inferred: A regex literal containing <!-- can make comment blanking suppress subsequent live calls in the same frontend file, producing incomplete public endpoint findings and coverage results.
Security review details

Security Blast Radius

  • inferred — A source author who can place the marker in an analyzed frontend file could suppress later findings from that file. The inspected cache is keyed to the selected source; broader exposure is not established.

Security Findings and Attack Paths

  • inferred — The demonstrated source path supports an analytics-blind-spot scenario, not a verified authorization bypass: a valid regex marker can be mistaken for a comment opener before later live API calls are scanned.

Trust Boundaries and Controls

  • observed — The scanner processes selected repository content as data and returns findings through source-scoped analysis. Route-level authorization was not established by the inspected evidence.

Resilience and Maintainability Implications

  • inferred — Because blanking precedes every call pattern, misclassifying one marker can make otherwise readable calls absent from cached analysis rather than reporting a scan error.

Hardening Proposals

  • proposed — Distinguish regex literals from comment openers before blanking, and verify that a live call after a regex containing <!-- remains in scanner output.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The changes to repo_tests/one_claim_registry_16653_test.py raise the REACH floor and update measurement comments. The supplied evidence links these changes to module-count drift, not to comment bl… Remove the unrelated repo_tests/one_claim_registry_16653_test.py changes from this pull request, or provide evidence that they directly support the coding requirements in [#17668].
Docstring Coverage ⚠️ Warning Docstring coverage is 45.16% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarises the main change: preventing the frontend API-call scanner from treating JSDoc examples as live calls. It is specific and related to the changeset.
Linked Issues check ✅ Passed The pull request meets the coding requirements in [#17668]. blank_comments removes JavaScript, TypeScript and Vue comments while preserving source positions, strings, URLs, and template-literal inte…
Full details: Out of Scope Changes check

Explanation

The changes to repo_tests/one_claim_registry_16653_test.py raise the REACH floor and update measurement comments. The supplied evidence links these changes to module-count drift, not to comment blanking or frontend API-call scanning. They do not implement, test, or document [#17668].

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No new hardcoded values of either class — ssot and other both block.

Known backlog in pipeline-scripts/hardcoded_values_baseline.txt is suppressed and tracked in #14371.

@mrveiss mrveiss left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-author review of 64103ecaa54f, on scope: does the fix cover the class or the instance?

It covers the class, and it covers the inverse hazard too

comment_blanking.py is not a JSDoc special case. It handles the three comment forms a Vue/TS tree actually contains — // (_LINE), /* … */ (_BLOCK_OPEN/_CLOSE, of which /** */ is a case) and <!-- … --> (_HTML_OPEN/_CLOSE) — and the tests exercise each: a // trailing real code (:59), a Vue template comment (:64), a block interior with no leading star (:55), a JSDoc continuation line (:43), and a multi-line block whose close restores scanning for the code after it (:68).

So the answer to "does it strip the specific form it found?" is no — a //-prefixed example scans as a comment as well, which is the case that would have made this the class repeating inside its own repair.

And it handles the hazard in the other direction, which is the part I would look at first in a comment stripper, because over-blanking corrupts scanning rather than merely under-blanking it:

test what it stops
:79 a URL containing // does not start a comment "https://x" being eaten
:92 a block marker inside a string is not a comment "/*" in a literal
:96 an escaped quote does not end the string "a\"b" desynchronising the scan
:100 a template literal is passed through backtick content
:88 a plain call is untouched the base case

_consume_string honouring backslash escapes is what makes those hold rather than a regex that would get them wrong.

Offset integrity is pinned, and it is the property this fix needed most. :121 length and line count unchanged (parametrised), :128 the line numbers of surviving calls unchanged. Blanking rather than deleting is the right choice for a scanner that reports line numbers, and it is asserted rather than assumed.

And :139 test_the_blanker_actually_blanks_something is the vacuity guard — without it a no-op blanker passes every test above. Present without anyone asking for it.

The fourth finding: proxied, not verified — and I cannot settle it by reading

Three of four findings were documentation; the fourth was presumably real, and "a fix that silences all four is worse than the defect" is the right test. What the PR gives is the structural proxy: code after a closed block is still scanned (:68) and a plain call is untouched (:88).

That is not the same as the fourth finding surviving. Settling it means running the scanner over the same tree before and after and diffing the finding set — a run, not a read, and I am not going to assert a result I did not produce. Whoever merges should ask for that diff, or for the one finding named so it can be looked for by hand. If it turns out the real finding was itself inside a comment, the defect was never a precision problem at all.

Precision on the panel: unchanged, and I could not locate where the label lives

The PR touches the scanner, the new module, its tests, and two ratchet entries. No consumer of the scanner's output is modified, so nothing about how findings are presented changes — this fixes the findings, not the framing.

I went looking for the label to say whether it is qualified and could not find it: no Potential Bugs or potential_bugs in api/codebase_analytics/ or autobot-frontend/src. The scanner's own language is "orphaned" (api_endpoint_scanner.py:149). So I am not claiming the label is unqualified — I am saying I could not establish where it is set, and that is a question for whoever knows the panel. The argument stands either way: at 25% precision a finding label that invites action costs investigation time on the false ones and discredits the true one, and that half is untouched here.

Ratchet banked, measured between revisions

api_endpoint_scanner.py 1445 → 1444 in both scripts/python_file_size_known_large.py and repo_tests/python_file_size_ratchet_baseline.py. Read from git diff origin/main 64103ecaa54f -- <path> so both sides name their revision — I got this wrong on #17647 by reading one side from the working tree, so it is worth saying how it was measured rather than just that it was.

…oxy (#17668)

Review condition on #17670: the PR showed three findings silenced and argued the
fourth survives from structural proxies -- "code after a closed block is still
scanned", "a plain call is untouched". Those show the mechanism is *capable* of
keeping a call, not that it kept *this* call. The corollary is what makes it
non-optional: **a fix that silenced all four would look identical to a correct one**
if only the three were checked.

So this runs `FrontendAPICallScanner._parse_api_call` over the same three files with
comments intact and with them blanked, and asserts both directions:

  useFileDownload.ts    before [(11, GET /api/export), (16, GET /api/export)]  after []
  apiErrorHandler.ts    before [(222, GET /api/users)]                         after []
  ThemeManagerView.vue  before [(35, POST /api/themes),                        after [(35, POST /api/themes),
                                (49, DELETE /api/themes/${id})]                       (49, DELETE /api/themes/${id})]

The real finding is named rather than implied: **`POST /api/themes` at
`ThemeManagerView.vue:35`**, a theme upload with no matching backend route. A second
real call at `:49` (`DELETE /api/themes/${id}`) survives too and was not in the
panel's four -- worth noting, since it shares the missing route.

Three tests, one per direction plus one against vacuity: if the pre-fix scan found
nothing, every "absent after" assertion would be trivially satisfied, so the
comparison asserts at least four pre-fix findings exist.

Mutation-proved by the mutation that matters here -- making the blanker blank *code*
as well as comments, i.e. the fix that silences everything -- fails 2 of 5. That is
the assertion the proxies could not make.

The pre-fix side is reconstructed by scanning with comments left intact, which is
what the prefix test did for every shape not starting with a marker. That keeps both
sides comparable without depending on the old revision, and both sides name how they
were produced.

Refs #17668
…on (#17668)

CI red after merging main into this PR: the floor described a tree two merges old.

    [one-claim-registry] floor 2976 sits 51 below its live population of 3027
    Python modules swept for claim-or-lock primitives, which exceeds the declared
    allowance of 50 (skips=0 + growth=50).

Re-pinned to 3,002 -- mid-window, which is the convention this declaration
documents for itself and explains: pinning at `population - growth` leaves zero
headroom, so the next module anyone adds reds the meta-test (#17142). 3,002 leaves
25 before the next bump is due. The allowance is untouched.

Only **one** of those 51 modules came from this PR. The sweep skips `_test.py`, so
of the three files added here -- `comment_blanking.py` and two test modules -- one
is swept. The other 50 arrived with base.

The measurement is worth recording because I got it wrong first. I measured
`len(REACH.discover())` in my worktree and got **3025** against CI's **3027**, and
the two-module gap was not a discrepancy to explain: my worktree was still at
`495c4811f4` and had never pulled the `update-branch` merge. I was measuring a tree
two merges older than the one CI tested, which is the same shape as reading one side
of a diff from the working tree and the other from a revision. Fast-forwarded to
`b2f41ad3c694` and re-measured: **3027**, matching CI exactly.

So both numbers in this commit name their revision: 3,027 live at `b2f41ad3c694`,
by `len(REACH.discover())`, not by grep.

Mutation-proved the meta-test still does its job: setting the floor to 2,900 fails
`test_every_declared_floor_is_pinned_to_its_population`. A re-pin that quietly broke
the check it satisfies would look identical to a correct one.

289 tests pass across `reach_declarations_test.py` and the registry guard.

Refs #17668

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: mrveiss/AutoBot-AI/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f34822d9-b347-4ab3-bfdd-8afddeff75e5

📥 Commits

Reviewing files that changed from the base of the PR and between f9e7ff6 and 579ead7.

⛔ Files ignored due to path filters (2)
  • repo_tests/python_file_size_ratchet_baseline.py is excluded by !repo_tests/python_file_size_ratchet_baseline.py
  • scripts/python_file_size_known_large.py is excluded by !scripts/python_file_size_known_large.py
📒 Files selected for processing (5)
  • autobot-backend/api/codebase_analytics/api_endpoint_scanner.py
  • autobot-backend/api/codebase_analytics/comment_blanking.py
  • autobot-backend/api/codebase_analytics/comment_blanking_test.py
  • autobot-backend/api/codebase_analytics/frontend_call_scanner_comments_test.py
  • repo_tests/one_claim_registry_16653_test.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread autobot-backend/api/codebase_analytics/comment_blanking.py Outdated
Comment thread autobot-backend/api/codebase_analytics/frontend_call_scanner_comments_test.py Outdated
…as code (#17668)

Two review findings, batched into one push. The one rated Trivial is the serious one.

**The test reimplemented what it verified.** `_scan` applied `blank_comments` and the
call patterns itself rather than calling `FrontendAPICallScanner._scan_file`, so it
would have passed with the production blanking removed entirely. Proved rather than
argued -- deleting the `blank_comments` call from `_scan_file`:

    before this commit:  both suites pass        <- the hole
    after  this commit:  scanner test 2 failed, blanker test 17 passed

The blanker test correctly stays green there, because the blanker is fine; only the
wiring broke. That split is the signal the old arrangement could not produce.

This is the same defect as verifying with a private regex instead of the scanner's
own patterns -- which this PR already fixed once, one level down. I replaced the
regex and kept a parallel copy of the loop around it. A verification that
reimplements its subject tests its own copy, and the copy cannot drift from itself.

The two sides are now named for what they are: `_scan_production` calls `_scan_file`,
and `_scan_prefix_era` is an explicit reconstruction of the pre-fix behaviour, kept
separate because it can no longer be obtained from the production path.

**A `${...}` interpolation is code, not template text.** `_consume_string` copies a
backtick literal verbatim so that a URL's slash pair survives -- correct for the
text, wrong for interpolations, which can contain comments. Interpolations now go
back through `blank_comments` recursively, with brace matching so a nested `{}` does
not end one early. Length is preserved, so positions still hold.

    comment inside ${}              hidden -> blanked
    nested braces in ${}            hidden -> blanked
    `/api/items/${id}`              kept    <- template text is still text

Mutation-proved: disabling interpolation handling fails 2.

25 tests across the two files. All functions under the 30-line gate; the scanner
stays at its re-pinned 1444.

Refs #17668

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: mrveiss/AutoBot-AI/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 53236ccb-e941-448e-8a37-a5ed789b3803

📥 Commits

Reviewing files that changed from the base of the PR and between 579ead7 and be2031a.

⛔ Files ignored due to path filters (2)
  • repo_tests/python_file_size_ratchet_baseline.py is excluded by !repo_tests/python_file_size_ratchet_baseline.py
  • scripts/python_file_size_known_large.py is excluded by !scripts/python_file_size_known_large.py
📒 Files selected for processing (4)
  • autobot-backend/api/codebase_analytics/api_endpoint_scanner.py
  • autobot-backend/api/codebase_analytics/comment_blanking.py
  • autobot-backend/api/codebase_analytics/comment_blanking_test.py
  • autobot-backend/api/codebase_analytics/frontend_call_scanner_comments_test.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread autobot-backend/api/codebase_analytics/comment_blanking.py Outdated
`_matching_brace` counted raw braces, so a `}` inside a comment or a string ended the
interpolation early and everything after it was copied out as template text. Verified
before fixing -- both shapes leaked a path the scanner would then report:

    const x = `${/* } api.get('/api/hidden') */ ''}`     leaked /api/hidden
    const y = `${ m['}'] /* api.get('/api/gone') */ }`   leaked /api/gone

The review named the comment case; the string case has the identical cause and would
have survived a fix aimed only at comments. A brace inside either is not a delimiter.

The counting view comes from `blank_comments` itself, with an internal flag that
blanks string bodies as well, rather than from a second brace scanner. That is the
point: a separate scanner could disagree with this one about where a string ends, and
then the two would drift -- which is the defect this module was written to fix,
appearing one level down inside the fix. Whatever the real pass treats as a comment
or a string is exactly what the counter refuses to count. Blanking preserves length,
so indices in the view are indices in the source.

Recursion is broken by not processing interpolations in the counting view: a brace
inside a nested template is not a delimiter of the interpolation being measured, so
the whole literal blanks and `_matching_brace` cannot re-enter itself.

Two regression tests, one per shape. Mutation-proved: reverting the counter to raw
characters fails both. 27 tests across the two files, function-length gate clean.

This is the fourth finding on this PR that was the same class as the PR's own subject
-- private regex, parallel scan loop, interpolation contents, and now brace counting
-- each one a level further in. Every one was found by review, none by a tool.

Refs #17668
@mrveiss
mrveiss merged commit 7adaca8 into main Sep 28, 2026
79 checks passed
@mrveiss
mrveiss deleted the issue-17668-comment-scan branch September 28, 2026 02:07
@mrveiss

mrveiss commented Sep 28, 2026

Copy link
Copy Markdown
Owner Author

Provenance disclosure: the file-size figures in this PR came from invoking scripts/check_python_file_size.py directly

Per the ruling that only what hooks or CI already run may be executed locally, disclosing rather than leaving it standing.

Affected figure: api_endpoint_scanner.py 1445 → 1444, and the matching baseline edits. I ran scripts/check_python_file_size.py <paths> directly to confirm the ceiling before and after.

Two things that make this weaker than a bare disclosure suggests:

  1. The same numbers are obtainable without executing anything. The ceiling is a literal in repo_tests/python_file_size_ratchet_baseline.py and scripts/python_file_size_known_large.py; the count is wc -l. Both are reads. So the figure is reproducible by an allowed path and does not rest on my invocation.
  2. The pre-commit hook ran the same script on every commit in this PR anyway — .pre-commit-config.yaml:966 has entry: python3 scripts/check_python_file_size.py. Each commit here was gated by it, and it is what told me 1445 was over after the formatter shaved two lines. CI runs it too, at code-quality.yml:701 with --audit-ceilings.

And that is a conflict inside the rule worth surfacing rather than resolving myself. The principle is only what the hooks or CI already run. The path rule is nothing under scripts/. This script is a pre-commit hook entry, so the principle admits it and the path rule excludes it. I am not going to pick the reading that happens to exempt me.

If the path rule governs, then the ceiling checks in this PR should be treated as CI-confirmed rather than locally-confirmed — which they are, since every commit passed the hook. Nothing in the PR depends on a figure only I have seen.

Unaffected, for completeness: the blocking-IO counts (192 enforced / 18 skipped) came from tools/lint/check_no_blocking_io_in_async.py, also a pre-commit hook entry but not under scripts/. The comment-blanking and scanner verifications ran under pytest on test files. The host probes on #17500 — ufw, ss, redis-cli, systemctl — are not repo code.

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.

bug(analytics): the frontend call scanner reads JSDoc examples as live calls — 3 of 4 'Potential Bugs' are documentation

1 participant