feat(devin-connect): surface real ACU usage - #256
Open
andya1lan wants to merge 3 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends DEVIN_CONNECT and GetUserStatus accounting to surface real ACU usage end-to-end: decode fractional ACU from protobuf frames, persist it independently from credit cost, and expose it in the Dashboard quota UI when personal quota dimensions are absent.
Changes:
- Added protobuf numeric decoding support for billing fields across varint + fixed64/double + fixed32/float, including paid-verified top-level
#22→committed_acu_cost. - Introduced a separate per-account lifetime
acuCostaccumulator and wired connect billing{ creditCost, acuCost }intorecordAccountSpend. - Normalized/GetUserStatus ACU fields (
acuConsumed, optionalacuLimit) and updated Dashboard/i18n to display ACU quota when applicable.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/strict-usage-total.test.js | Extends monotonic/poisoning tests to include acuCost in total spend counters. |
| test/devin-connect.test.js | Adds fixture + assertions for decoding top-level #22 fixed64/double committed ACU cost and updates default billing tag expectations. |
| test/devin-connect-openai.test.js | Verifies fractional ACU billing is preserved through both non-stream and SSE streaming completion paths (without exposing it in SSE chunks). |
| test/devin-connect-finish-callsite.test.js | Adds call-site guard ensuring finish events preserve paid ACU billing through the default billing map. |
| test/devin-connect-calibrate.test.js | Adds tests for persisted token lookup and new calibration classification behavior (including ACU tag #22 handling). |
| test/dashboard-syntax.test.js | Asserts Dashboard HTML/i18n wiring for ACU quota/spend rendering and raw-payload scrubbing. |
| test/connect-rate-table-wiring.test.js | Verifies connect billing maps credit vs ACU into separate spend units and accrues ACU independently. |
| test/billing-userstatus-decode.test.js | Adds fixed64/double helpers and verifies PlanStatus #19/#20 decode into acuConsumed/acuLimit. |
| test/auth-total-spend.test.js | Ensures acuCost is included in public totalSpend shape and survives serialize/load. |
| test/acu-discovery.test.js | New tests for ACU capability discovery (prefer upstream snapshot, preserve explicit zero, fallback to local billing, sentinel normalization). |
| src/windsurf-api.js | Normalizes ACU fields from GetUserStatus and treats negative legacy quota sentinels as absent. |
| src/handlers/chat.js | Switches connect spend attribution from credit-only to {creditCost, acuCost} via connectBillingSpend; exports it for tests. |
| src/devin-connect.js | Adds numeric scalar decoding across varint/fixed64/fixed32 for billing fields; enhances structured dump output for fixed-width fields; defaults billing tags include committed_acu_cost=^22. |
| src/devin-connect-catalog.js | Adds numericField helper and decodes PlanStatus ACU consumed/limit (19/20) from protobuf UserStatus. |
| src/dashboard/index.html | Renders ACU quota in the quota column/detail when personal quota dimensions are absent; shows separate lifetime ACU spend when relevant. |
| src/dashboard/i18n/zh-CN.json | Adds ACU-related quota/spend strings (Chinese). |
| src/dashboard/i18n/en.json | Adds ACU-related quota/spend strings (English). |
| src/dashboard/api.js | Scrubs any raw payload defensively from refresh-credits responses. |
| src/auth.js | Persists acuCost in _totalSpend, records ACU spend, derives acuUsage projection for Dashboard, and stops returning/persisting raw userstatus in refreshCredits output. |
| scripts/devin-connect-calibrate.mjs | Improves calibration classification (ACU #22, provider #21, actual model at #7.9), and resolves token from configured/persisted accounts.json path. |
| docs/DEVIN-CONNECT-CUTOVER.md | Updates documentation to reflect paid-verified committed ACU mapping and expanded dump semantics. |
| .env.example | Updates env docs for billing/cache decoding defaults and top-level ^N tag support. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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
GetUserStatus.0 ACUas discovered data while keeping missing data unknown.GetUserStatus.Why the existing #239 wiring is incomplete
The existing #239 implementation carries a
billingobject through the DEVIN_CONNECT completion path, but real ACU usage still cannot reach account totals or the Dashboard.There are two separate gaps.
First,
committed_acu_costis encoded as a protobuf fixed-width floating-point field. The billing decoder and calibration dump handled varints and length-delimited fields, so the ACU field remained invisible even when the upstream returned it.Second, the account accumulator only consumed credit cost. A decoded ACU value therefore had no independent storage or Dashboard consumer.
The incomplete flow was:
Validation also requires an upstream account that is eligible for ACU accounting, which limits who can confirm the wire format and billing semantics.
Fix
Per-request DEVIN_CONNECT accounting
#22fixed64 value ascommitted_acu_cost.{ creditCost, acuCost }separately intorecordAccountSpend.acuCostindependently under the account lifetime totals.ACU is never added to credit cost because they are different units.
Cycle-level usage discovery
GetUserStatusis used as the primary source for the current upstream cycle:PlanStatus #19→acu_consumedPlanStatus #20→acu_limit, when availableThe Dashboard projection is capability-based:
GetUserStatusACU fields.Dashboard behavior
When daily, weekly, Prompt, and Flex quota dimensions are absent but ACU accounting is discovered, the existing quota area shows:
GetUserStatuscycle snapshot or a local DEVIN_CONNECT lifetime total.An explicit zero remains visible as
0 ACU. Missing accounting data remains absent rather than being rendered as zero.Legacy
-1quota sentinels are normalized tonull, preventing values such as-0.01from appearing or being mistaken for personal quota data.Dashboard UI design
The ACU UI is implemented within the existing Dashboard quota area. No new Dashboard page, browser dialog, or separate ACU-only panel is introduced.
The screenshot below shows the expected UI states:

Upstream limitations
ACU limit visibility appears to be permission-scoped upstream.
Ordinary account credentials may return
acu_consumedwithout returningacu_limit. Organization or administrative reporting contexts may expose allocation information separately, butGetUserStatusdoes not guarantee that the current account can read it.The implementation therefore shows consumed ACU when available and leaves the limit unavailable instead of inferring an organization-wide allocation.
The local fallback is lifetime-local and is not presented as a billing-cycle value.
Verification
Automated verification:
GetUserStatusprojection behavior is covered.npm run secret-scanpasses.git diff --checkpasses.The full
npm testrun did not complete successfully because the upstreamtest/update-script-release-target.test.jsremained pending for more than 270 seconds and had to be stopped. That test is unchanged by this PR and is not reported as passing.Live verification used two accounts billed through ACU accounting:
acu_consumedvalue;GetUserStatus.The agreement after the reporting delay confirms that the decoded value represents real upstream ACU consumption rather than a local estimate.
Checklist
#22,PlanStatus #19/#20.Closes #239.