Skip to content

feat(scan): report token budget stop in JSON summary.budget_exceeded - #25

Open
chethanuk wants to merge 1 commit into
mainfrom
feat/issue-771-scan-budget-exceeded
Open

feat(scan): report token budget stop in JSON summary.budget_exceeded#25
chethanuk wants to merge 1 commit into
mainfrom
feat/issue-771-scan-budget-exceeded

Conversation

@chethanuk

Copy link
Copy Markdown
Owner

Description

ocr scan --format json --max-tokens-budget N already detects the aggregate budget stop — it records a token_budget_reached warning and stops dispatching — but summary.budget_exceeded stayed false, because scan.Agent.BudgetExceeded() was hardcoded to return false (internal/scan/agent.go:229). Automation consuming the JSON had to parse the warning list to tell a complete scan from one truncated by the budget.

The signal already existed inside scan; it just never reached the result provider.

dispatchBatch (agent.go:626)
  recordWarning("token_budget_reached", …)
  budgetHit = true            ← per-batch local, dies with the call
                              ← now also: a.budgetExceeded = true
  break
      │
      ├─ normal return  :683 ─┐
      ├─ ctx-cancel     :638 ─┤→ dispatchSubtasks
      └─ (err path)           ┘   if err != nil { return }   :528  ← returns first
                                  if budgetHit { break }     :547

emitRunResult → ag.BudgetExceeded() → summary.budget_exceeded

The flag is set where budgetHit is set, not at the break. dispatchBatch has three exits that carry budgetHit, and the ctx-cancel exit at :638 reaches dispatchSubtasks' err != nil return at :528 — which fires before the if budgetHit check at :547. Writing the flag at the break would silently lose it on cancel-after-budget-hit. One write at :628 covers all three exits.

No mutex or atomic: budgetHit = true runs in dispatchBatch's own loop body, before sem <- struct{}{} and outside the worker closure, and dispatchBatch has one caller in a sequential batch loop — one writer on one goroutine, read only after Run returns. internal/agent/agent.go:176 stores the same flag as a plain bool on the diff-review path. make test runs with -race, so this is enforced rather than argued.

Scan's status semantics are unchanged: it publishes no run manifest, so status stays success, and omitempty keeps budget_exceeded out of the JSON entirely when the gate does not trip.

Limitation

The new CLI-level test drives the real *scan.Agent and the real emitRunResult, not a spawned ocr binary — no test in this repo spawns it, and doing so would need live provider credentials. The flag-parsing layer between parseScanFlags and scan.Args.MaxTokensBudget is covered separately by cmd/opencodereview/scan_cmd_test.go:145.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

How Has This Been Tested?

  • make test passes locally
  • Manual testing (describe below)

make test (with -race) and make check both pass.

  • cmd/opencodereview/scan_budget_json_test.go (new) — drives a real *scan.Agent over eight fixture files through the real budget gate and emitRunResult, asserting summary.budget_exceeded == true plus the token_budget_reached warning at MaxTokensBudget=120_000, and that the raw JSON contains no budget_exceeded key at all when no budget is set. Both subtests also assert status == "success", guarding against this leaking into scan's status semantics.
  • internal/scan/budget_exceeded_test.go (new) — table-driven, both directions, through dispatchSubtasks.
  • Mutation check: deleting only the a.budgetExceeded = true line fails both.

Checklist

  • My code follows the project's coding style (go fmt, go vet)
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly (if applicable)
  • I have signed the CLA

budget_exceeded is currently undocumented under pages/ for the review path too, so documenting it belongs in a separate docs PR rather than this one.

Related Issues

closes alibaba#771

scan already detects the aggregate token-budget stop (it prints the
"[ocr] token budget reached" line and records a token_budget_reached
warning) but BudgetExceeded() was hard-coded false, so
summary.budget_exceeded never appeared in `ocr scan --format json`.

The write goes next to `budgetHit = true` in dispatchBatch's per-file
gate. That is the only site that sets budgetHit, and it covers all three
exits that carry the stop out of dispatchBatch: normal return, ctx-cancel
return, and the caller's `if budgetHit { break }`. Setting it at the
dispatchSubtasks break instead would lose it on the ctx-cancel path.

Plain bool, no mutex: dispatchBatch's loop is the only writer, it runs on
the caller's goroutine, and the value is read by emitRunResult after Run
returns. The spawned subtask goroutines never touch it. Matches the
existing internal/agent.Agent.budgetExceeded field.

Status and exit code are untouched — reaching the budget is a controlled
truncation, so out.Status stays the warning-derived value.
@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 3f1bea5 Aug 08, 2026 · 07:13 07:16

@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 36dc60e3-c052-4aca-9539-eed3a3972812

📥 Commits

Reviewing files that changed from the base of the PR and between f8f0851 and 3f1bea5.

📒 Files selected for processing (4)
  • cmd/opencodereview/scan_budget_json_test.go
  • internal/scan/agent.go
  • internal/scan/budget_exceeded_test.go
  • internal/scan/getters_test.go

📝 Walkthrough

Walkthrough

The scan agent now records aggregate token-budget exhaustion during dispatch. Tests verify the state through direct dispatch and end-to-end JSON scan reporting, including warnings and optional field behavior.

Changes

Scan budget reporting

Layer / File(s) Summary
Budget state and dispatch
internal/scan/agent.go, internal/scan/budget_exceeded_test.go, internal/scan/getters_test.go
The agent records token-budget dispatch stops. BudgetExceeded() returns this state. Tests cover limited and unlimited budgets, plus zero-value getter behavior.
JSON reporting validation
cmd/opencodereview/scan_budget_json_test.go
The end-to-end test validates JSON status, summaries, budget warnings, and omission of the optional budget field for unlimited budgets.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestScanBudgetJSON
  participant ScanAgent
  participant FixedUsageFakeClient
  participant JSONResultEmitter
  TestScanBudgetJSON->>ScanAgent: run scan
  ScanAgent->>FixedUsageFakeClient: request analysis
  FixedUsageFakeClient-->>ScanAgent: return fixed token usage
  ScanAgent->>JSONResultEmitter: emit scan result
  JSONResultEmitter-->>TestScanBudgetJSON: validate status and warnings
Loading

Suggested reviewers: lizhengfeng101

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: reporting token budget stops in the JSON summary.
Description check ✅ Passed The description completes the required sections and clearly documents the change, testing, checklist status, limitation, and related issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 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.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 8, 2026
@codeant-ai

codeant-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

User description

Description

ocr scan --format json --max-tokens-budget N already detects the aggregate budget stop — it records a token_budget_reached warning and stops dispatching — but summary.budget_exceeded stayed false, because scan.Agent.BudgetExceeded() was hardcoded to return false (internal/scan/agent.go:229). Automation consuming the JSON had to parse the warning list to tell a complete scan from one truncated by the budget.

The signal already existed inside scan; it just never reached the result provider.

dispatchBatch (agent.go:626)
  recordWarning("token_budget_reached", …)
  budgetHit = true            ← per-batch local, dies with the call
                              ← now also: a.budgetExceeded = true
  break
      │
      ├─ normal return  :683 ─┐
      ├─ ctx-cancel     :638 ─┤→ dispatchSubtasks
      └─ (err path)           ┘   if err != nil { return }   :528  ← returns first
                                  if budgetHit { break }     :547

emitRunResult → ag.BudgetExceeded() → summary.budget_exceeded

The flag is set where budgetHit is set, not at the break. dispatchBatch has three exits that carry budgetHit, and the ctx-cancel exit at :638 reaches dispatchSubtasks' err != nil return at :528 — which fires before the if budgetHit check at :547. Writing the flag at the break would silently lose it on cancel-after-budget-hit. One write at :628 covers all three exits.

No mutex or atomic: budgetHit = true runs in dispatchBatch's own loop body, before sem <- struct{}{} and outside the worker closure, and dispatchBatch has one caller in a sequential batch loop — one writer on one goroutine, read only after Run returns. internal/agent/agent.go:176 stores the same flag as a plain bool on the diff-review path. make test runs with -race, so this is enforced rather than argued.

Scan's status semantics are unchanged: it publishes no run manifest, so status stays success, and omitempty keeps budget_exceeded out of the JSON entirely when the gate does not trip.

Limitation

The new CLI-level test drives the real *scan.Agent and the real emitRunResult, not a spawned ocr binary — no test in this repo spawns it, and doing so would need live provider credentials. The flag-parsing layer between parseScanFlags and scan.Args.MaxTokensBudget is covered separately by cmd/opencodereview/scan_cmd_test.go:145.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

How Has This Been Tested?

  • make test passes locally
  • Manual testing (describe below)

make test (with -race) and make check both pass.

  • cmd/opencodereview/scan_budget_json_test.go (new) — drives a real *scan.Agent over eight fixture files through the real budget gate and emitRunResult, asserting summary.budget_exceeded == true plus the token_budget_reached warning at MaxTokensBudget=120_000, and that the raw JSON contains no budget_exceeded key at all when no budget is set. Both subtests also assert status == "success", guarding against this leaking into scan's status semantics.
  • internal/scan/budget_exceeded_test.go (new) — table-driven, both directions, through dispatchSubtasks.
  • Mutation check: deleting only the a.budgetExceeded = true line fails both.

Checklist

  • My code follows the project's coding style (go fmt, go vet)
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly (if applicable)
  • I have signed the CLA

budget_exceeded is currently undocumented under pages/ for the review path too, so documenting it belongs in a separate docs PR rather than this one.

Related Issues

closes alibaba#771


CodeAnt-AI Description

Report scan token-budget stops in JSON summaries

What Changed

  • ocr scan --format json now sets summary.budget_exceeded to true when the aggregate token budget stops the scan before all files are reviewed.
  • Budget-limited scans still return their partial results and warning-based status, including the token_budget_reached warning.
  • Unlimited scans continue to omit budget_exceeded from JSON output.
  • Added coverage for budget-limited and unlimited scans, including the end-to-end JSON output.

Impact

✅ Clearer truncated-scan results
✅ Reliable automation detection of token-budget stops
✅ Unchanged status and partial-result handling

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scan: expose token budget stop state in JSON output

1 participant