[object Object]

← back to Dw Photo Capture

TK-12126: never report Gemini OCR cost for a call that errored

83646156be1b51b6c9ebe45135db2ab76412af90 · 2026-09-24 12:11:32 -0700 · Steve Abrams

The live run surfaced it: server.js's /api/extract returns a hardcoded cost_usd 0.0006
even when the Gemini call failed (credits depleted), so the proof script echoed spend
that never happened. Now trusts cost_usd only when the response carries no err.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUWK5VKgXgemKLA9UqwMZ

Files touched

Diff

commit 83646156be1b51b6c9ebe45135db2ab76412af90
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 24 12:11:32 2026 -0700

    TK-12126: never report Gemini OCR cost for a call that errored
    
    The live run surfaced it: server.js's /api/extract returns a hardcoded cost_usd 0.0006
    even when the Gemini call failed (credits depleted), so the proof script echoed spend
    that never happened. Now trusts cost_usd only when the response carries no err.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017uUWK5VKgXgemKLA9UqwMZ
---
 scripts/camera-committrue-proof.mjs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/scripts/camera-committrue-proof.mjs b/scripts/camera-committrue-proof.mjs
index 5210c18..df10f43 100644
--- a/scripts/camera-committrue-proof.mjs
+++ b/scripts/camera-committrue-proof.mjs
@@ -312,8 +312,13 @@ async function runLive(o) {
   if (!o.skipOcr) {
     try {
       const r = await requestJson(`${baseUrl}/api/extract`, { method: 'POST', headers: { Authorization: authHeader, 'Content-Type': 'application/json' }, body: JSON.stringify({ dataUrl }) });
-      ocrCost = (r.json && r.json.cost_usd) || 0;
-      costLine('Gemini OCR (/api/extract)', ocrCost, r.json && r.json.err ? `err: ${r.json.err}` : 'actual, per response');
+      // NOTE: server.js's /api/extract returns a hardcoded cost_usd: 0.0006 EVEN WHEN the Gemini
+      // call errored (e.g. depleted credits / bad key) — a rejected call is never billed, so
+      // echoing that number would report spend that did not happen. Trust the cost ONLY when the
+      // response carries no err (don't report an unmeasured/failed call as a measured cost).
+      const ocrErr = r.json && r.json.err;
+      ocrCost = (!ocrErr && r.json && r.json.cost_usd) || 0;
+      costLine('Gemini OCR (/api/extract)', ocrCost, ocrErr ? `NOT BILLED — call failed: ${String(ocrErr).slice(0, 160)}` : 'actual, per response');
       if (r.json && r.json.fields) console.log('  OCR fields (expected mostly empty — fixture is a roll photo, not a label):', JSON.stringify(r.json.fields));
     } catch (e) { console.log(`  OCR call failed (non-fatal, proceeding): ${e.message}`); }
   } else {

← d9c9612 TK-12126: add camera commit:true round-trip proof script (mo  ·  back to Dw Photo Capture  ·  TK-12090: decouple exo VLM ring from HAS_MACVISION, make it 8452fcc →