feat(dashboard): account for every LLM call on the comparison page #92
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/per-pass-telemetry"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A full review makes four kinds of call — preflight, context discovery, 0–5 parallel fragment extracts, then one review per enabled config. A two-config fan-out with five fragments is nine calls; the comparison page could account for two.
Every telemetry field on
review_events(input_tokens,output_tokens,duration_ms,finish_reason,prompt_*) describes the review call and nothing else. The other passes' numbers existed only in alog.Infoline.Two problems, not one
Cost was incomplete. A column reading
1,200+800 tokomitted preflight, discovery, and up to five extracts. On a full review with fragments the shared spend can exceed the review call it's being compared against.What was shown was misattributed. Preflight and discovery run on different models than the config in the column. Most visibly
complexity: preflight's output, on preflight's model, rendered inside every config's meta line as though that config produced it (admin_compare.html:45, fed byshadowEventFromcopying it to every row).Schema
review_passes, one row per call, anchored oncomparison_group_id— preflight/discovery/extract run once and feed every config, so they belong to the group, not to a row.config_idis NULL for those and set for review calls.seqorders the extract fan-out, which completes out of order.Page
Groups predating the migration have no pass rows: the section and totals disappear, columns render as before.
Notes
Prompts are captured pre-call, with the same helpers the backends use, so a pass that fails still records what it was asked. That required lifting the extract user message out of all three backends — which had built it inline and identically — into
reviewer.BuildExtractUserMessage. A second rendering that merely looked similar would be a reconstruction, and would drift.Two smaller things fell out:
Runner.PassSinkseam, so the telemetry a review emits is assertable without a database.compareView. It was anonymous, so every render test restated it — adding a field broke all four at render time rather than compile time. Now they bind the handler's own type.Storage: prompts stored per pass, following migration 000011's precedent. Expect roughly 2–3x the prompt bytes per review. The admin storage page reads
pg_stat_user_tables, so the new table appears there with no changes — I checked rather than assumed.Tests: pass rows emitted per call including failed calls, group/config attribution,
splitPasses, pipeline rendering, drill-down, failed-pass display, the pre-migration empty case, and a guard that complexity appears once rather than per column.🤖 Generated with Claude Code
Automated review by pr-reviewer v0.41.5 | Safety Check | Claude Sonnet 5 | tracking id
r-683867-aab533This is an AI-generated review and may contain mistakes.
Status: ✅ Completed
✅ Verdict: LGTM — Large but well-tested, backward-compatible feature addition with additive migration, best-effort telemetry writes, and no signs of secrets, injection, or breaking changes.
Went through the diff carefully given the size and the migration touch.
RecordPass/ListPassesForGroupare guarded fors.pool == nil(degraded store), and pass recording throughoutrunner.goanddiscovery.gois explicitly best-effort — errors are logged and swallowed, never propagated to fail a review. This matches the stated goal of not letting telemetry break the actual review flow.passCols/placeholder consistency is directly tested (TestPassColsMatchPlaceholders), which is a nice guard against the classic INSERT column/placeholder drift bug.BuildExtractUserMessageextraction removes duplicated inline logic from three backends into one shared helper — behavior-preserving refactor, and it's exercised by existing backend tests presumably still passing since the format string is identical.Complexitywas removed from the per-column meta line (intentionally, per description) and moved to the shared/page-level section — consistent with the PR's stated fix for misattribution, and covered byTestComparePageDoesNotAttributeComplexityToConfigs.compareViewstruct is now named instead of anonymous, reducing test/handler drift risk — reasonable.array_positionwith a Go slice param for ordering — fine, not injection prone).recordPass: it bails out ift.Event == nil || t.Event.ComparisonGroupID == nil, avoiding a nil pointer dereference for reviews that fail before a group is minted.Nothing here looks like it would break existing functionality or leak sensitive data; the storage growth (2-3x prompt bytes) is called out explicitly and is a capacity/cost consideration rather than a bug. Tests cover the new code paths reasonably (pass emission, failure paths, split logic, template rendering, degraded-store behavior).
This is a large, well-tested, backward-compatible feature addition with no signs of accidentally committed files, secrets, or logic that would break production.
709c565a7ca144776b79Automated review by pr-reviewer v0.41.7 | Safety Check | Claude Sonnet 5 | tracking id
r-684697-31cde4This is an AI-generated review and may contain mistakes.
Status: ✅ Completed
✅ Verdict: LGTM — Additive migration and best-effort telemetry plumbing, well-tested including a guard against the column/placeholder mismatch risk in the raw SQL; nothing alarming found.
Went through the diff carefully given its size.
Key things checked:
000013_review_passes.up/down.sqlis additive (new table + index), with a matching down migration that drops both. No destructive change to existing tables.RecordPass/ListPassesForGroupboth checks.pool == niland no-op/return nil rather than erroring, consistent with the "telemetry must never fail a review" invariant, and covered byTestPassesDegradedStoreIsInert.TestPassColsMatchPlaceholdersguarding against drift, which is a reasonable mitigation. I double-checkedpassColshas 16 comma-separated fields and the VALUES clause has $1..$16 — they match.recordPass/recordReviewPass/discovery/preflight pass-recording: all wrapped as best-effort (log and continue), never propagated as fatal errors — consistent with "telemetry must never fail a review."t.Event == nil || t.Event.ComparisonGroupID == nilguarded before dereferencing inrecordPass.rr(configRun) fields used inrecordReviewPass(rr.start,rr.end,rr.promptSystem, etc.) aren't shown being initialized in this diff, but that's pre-existing code (configRun struct isn't touched here) so out of scope for this diff's introduced risk.BuildExtractUserMessage: mechanical extraction of previously duplicated inline logic into a shared helper, used identically by all three backends — low risk, well justified for the drift concern.Shared pipeline), gated behind{{if .SharedPasses}}/{{if .TotalCalls}}, so old rows (pre-migration groups) fall through gracefully to prior behavior, matching the described backward-compat story and covered byTestComparePageHidesPipelineWhenNoPasses.Nothing here looks like an accidental commit, injection vector, auth bypass, or a change likely to take down the service — it's additive schema plus best-effort telemetry capture with tests backing the trickiest bit (column/placeholder alignment).