fix(adwright): read budget_total from backend (was c.budget, undefined)
Some checks failed
plugin-tests / test (push) Failing after 5s

Backend AdwrightCore.list_cycles preserves proto snake_case via
MessageToDict(preserving_proto_field_name=True), so cycle JSON carries
`budget_total` (decimal string like "200.00"), not `budget`. Frontend
read c.budget which was always undefined → fell back to 0 in both the
Cycles row meta and the Overview spend bar (which then defaulted to
$6,000 budget per the `|| 6000` floor in _deriveKpis).

Added _cycleBudget + _cycleSpend helpers that parseFloat the decimal
strings, with c.budget fallback so any future renamed field still works.
Spend stays 0 until GetCycleMetrics is wired in — it doesn't live in
ListCycles.

Verified live: Cycles row now shows $0 / $200 (was $0 / $0). Overview
spend now shows $0 / $200 (was $0 / $6,000).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Svrnty 2026-05-24 17:24:56 -04:00
parent 6c88bf8899
commit 91c134c309

View File

@ -320,11 +320,20 @@
).join("") + ).join("") +
'</div>'; '</div>';
} }
// Backend proto field for cycle budget is `budget_total` (decimal string,
// e.g. "200.00"). Spend lives in cycle_metric (fetched via GetCycleMetrics
// — not in ListCycles), so it stays 0 until that wire lands.
function _cycleBudget(x) {
return parseFloat(x.budget_total || x.budget || 0) || 0;
}
function _cycleSpend(x) {
return parseFloat(x.spend || 0) || 0;
}
function _deriveKpis(cycles, recipes) { function _deriveKpis(cycles, recipes) {
const c = cycles || []; const c = cycles || [];
const r = recipes || []; const r = recipes || [];
const spend = c.reduce((s, x) => s + (x.spend || 0), 0); const spend = c.reduce((s, x) => s + _cycleSpend(x), 0);
const budget = c.reduce((s, x) => s + (x.budget || 0), 0) || 6000; const budget = c.reduce((s, x) => s + _cycleBudget(x), 0) || 6000;
const impressions = c.reduce((s, x) => s + (x.impressions || 0), 0); const impressions = c.reduce((s, x) => s + (x.impressions || 0), 0);
const ctrs = c.map((x) => x.ctr || 0).filter((v) => v > 0); const ctrs = c.map((x) => x.ctr || 0).filter((v) => v > 0);
const ctr = ctrs.length ? (ctrs.reduce((s, x) => s + x, 0) / ctrs.length) : 0; const ctr = ctrs.length ? (ctrs.reduce((s, x) => s + x, 0) / ctrs.length) : 0;
@ -374,7 +383,7 @@
'<div class="svrnty-aw-row-title">' + _esc(c.title || ("Cycle #" + c.id)) + '</div>' + '<div class="svrnty-aw-row-title">' + _esc(c.title || ("Cycle #" + c.id)) + '</div>' +
'<div class="svrnty-aw-row-sub">' + _esc(c.status || "") + ' · started ' + _esc(c.started_at || "") + '</div>' + '<div class="svrnty-aw-row-sub">' + _esc(c.status || "") + ' · started ' + _esc(c.started_at || "") + '</div>' +
'</div>' + '</div>' +
'<div class="svrnty-aw-row-meta">$' + _fmt(c.spend || 0) + ' / $' + _fmt(c.budget || 0) + '</div>' + '<div class="svrnty-aw-row-meta">$' + _fmt(_cycleSpend(c)) + ' / $' + _fmt(_cycleBudget(c)) + '</div>' +
'</div>' '</div>'
); );
} }