Persist builder cost/context telemetry into metrics.json + persisted-first read path (#83, #135)#199
Conversation
…on (#83, #135) - src/core/harness/telemetry.js: shared, pure extraction of the builder contract's structured cost/context/execution fields (legacy bare-number cost tolerated, non-numeric values ignored — the contract gate is what fails validation on them), pinned cost_recorded / context_recorded event payloads, and the updateRunMetrics payload with per-stage shares split evenly across the task's canonical stages (mirrors deriveStageElapsed). - updateRunMetrics gains an atomic in-lock 'increment' path: cumulative cost/tokens/tool-calls add instead of overwrite, per-stage stage_cost_usd / stage_tokens maps accumulate per key. cumulative_tokens doubles as the 'persisted totals are authoritative' marker, so unrelated updates never stamp it onto legacy runs. - sdlc_validate now records telemetry on every validation (retries cost money too) and fixes the v2 bug where an object builder.cost was written into the cost_recorded 'usd' field. - pipeline-state rollup: cost_context.cumulative_tokens totals plus per-stage cost_usd/tokens on each stage entry (additive, schema_version stays 1); pipeline status text shows the token total when present. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…path (#83) - derive.js: persistedTokenTotals reads the incremental metrics shape (cumulative_tokens object = authoritative marker); resolveRunTotals overlays persisted cost/token totals on the event-derived dimensions and falls back to full event recompute for legacy runs — so dashboard polls stop paying O(events) for numbers that are already on disk, and totals survive event rotation/archival. - dashboard state: runs.js resolves totals through metrics.json; the rollup index no longer collapses object-shaped cumulative_tokens to 0 and carries the per-stage cost/token maps into index-served lite runs; client state surfaces stageCost/stageTokens for Run Analytics (data flow now, UI rendering later); context_recorded excluded from notable events like its cost_recorded twin. - reporter: buildRunReport cost summary prefers persisted metrics (tagged source: metrics|events); context_recorded added to known event types. - alerts engine: plain-language feed line for context_recorded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ent contracts (#83, #135) New 'Run metrics' section only: schema, overwrite-vs-increment write semantics, the cumulative_tokens authoritative-marker rule for readers, per-stage splitting, and the pinned cost_recorded / context_recorded event shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
Warning Review limit reached
Next review available in: 2 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (20)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
…sibility, history, tool calls F1 (BLOCKING) double-count: increments now carry an idempotency key = the builder contract's canonical content hash; a replayed/re-validated identical contract is a no-op, while a genuine retry (new contract content) counts again. goal-loop resets clear the prior attempt's builder.json so a stale contract can't be replayed and re-costed. Keeps the loop budget cap enforcing on real spend, not phantom spend. F2: a failed persisted increment after its cost_recorded event landed now emits a metrics_write_failed event; resolveRunTotals detects the drift and falls back to event recompute instead of reporting a total it knows is stale. F3: the first increment that materializes cumulative_tokens on a run with prior cost_recorded history seeds totals from an event recompute — no dropped history. F4: cumulative_tool_calls is now fed by execution.tool_calls (invocations), distinct from tools_used_count (distinct names); docs match code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Adversarial review (FIX-THEN-MERGE) findings applied + branch brought up to date with main:
Gates: 530 tests, lint, validate, security-audit, diff-check all green (includes the merged #132/#133 tests). |
…emetry-83-135 # Conflicts: # src/index.js
Summary
Two halves of one data pipe, shipped together: builder-contract cost/context telemetry → persisted cumulative metrics.
Write path (BLE-6.1, #135) —
src/core/harness/telemetry.jsis the shared, pure extraction point for the builder contract's structuredcost/context/executionfields (legacy bare-numbercosttolerated; non-numeric values ignored by extraction — the contract gate'sbuilder_v2_cost_values_are_numericcheck is what fails validation on them).sdlc_validatenow records telemetry on every validation (retries cost money too): pinnedcost_recorded/context_recordedevents plus an incrementalupdateRunMetricswrite. This also fixes a latent bug where a v2 objectbuilder.costwas written directly into thecost_recordedevent'susdfield.Persistence (#83) —
updateRunMetricsgains an atomic in-lockincrementpath:cumulative_cost_usd,cumulative_tokens {input, output, total},cumulative_tool_callsadd instead of overwrite, and per-stagestage_cost_usd/stage_tokensmaps accumulate per key (cost/tokens split evenly across a task's canonical stages, mirroring the stage-elapsed normalization so multi-stage tasks are never double-counted). Existing overwrite/merge semantics for the pre-#83 fields are unchanged.Read path (#83) —
resolveRunTotalsprefers persisted cumulative metrics and falls back to event recompute for legacy runs, so dashboard polls stop paying O(events) for totals that are already on disk, and the numbers survive event rotation/archival. Wired through the dashboard state builder, the rollup index (which previously collapsed object-shapedcumulative_tokensto 0), index-served lite runs, the Run Analytics client payload (stageCost/stageTokens— data flows now, UI rendering is later), the run reporter's cost summary (source: metrics|events), the pipeline-state rollup (cost_context.cumulative_tokens+ per-stagecost_usd/tokens), andpipeline statustext/JSON.Schema-version decision
Additive-tolerant, no version bump.
metrics.jsonhas never carried aschema_version; every reader defaults missing fields, and the new fields are only materialized when data exists. Thecumulative_tokensobject doubles as the "persisted totals are authoritative" marker — unrelated metrics updates (goal-loop resets, harvest) never stamp it onto legacy files, so legacy runs keep rendering from event recompute (covered by tests).pipeline-state.jsonstays atschema_version: 1: the new fields are additive withnull/zero defaults, breaking no v1 reader. Nothing registers inmigrations.js.Acceptance criteria
cost_recordedevents update metrics.json token totals incrementally (in-lock, concurrent writers both land)stage_cost_usd/stage_tokensmaps accumulate alongside the existing fieldscost_recorded/context_recordedpinned event contracts (documented next to the schema in HARNESS.md)pipeline status --jsonexposes themsdlc_validateintegration, pipeline-state totalsNotes for #136 (not implemented here, not painted into a corner)
context.tokens_used/tokens_availablegauges persist ascontext_tokens_used/context_tokens_available(the fields pipeline-state already exposed), andcontext_recordedcarries them per task — the threshold classifier for context-pressure warnings can consume both without another schema change.Verification
npm test(505 pass) ·npm run lint·npm run validate(196 agents) ·node scripts/security-audit.mjs·git diff --check— all green.Closes #83
Closes #135
Part of #134
🤖 Generated with Claude Code