feat: quality report — GET /api/report and jig report (U2, U3) - #24
Merged
Merged
Conversation
…(U2) Store.Report aggregates one [since, until) window of terminal jobs: jobs by state, clean vs person-fixed accepts from the publish ledger, publish outcomes and held rate, CI repair entry/success/rounds/stop codes, flaky re-runs, KTD1's two revisit rates, and agent_end spend per outcome bucket with spend per clean accept. It reads publish_history (U8), ci_reruns (U4) and unmetered_sends (U1) when present and tolerates their absence. Read-only, no migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…signals Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… sums Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 37 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (7)
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 |
`jig report [--server] [--since 7d|<RFC3339>] [--until <RFC3339>] [--json]` reads GET /api/report. A duration --since converts to RFC3339 against now; --json prints the API object verbatim; the prose form is one short table per section (jobs, accepts, publish, CI repair, re-runs, spend), prints null rates as n/a, and states in one line each what jig cannot see (R4) and the unmetered-send count. Exit codes follow def.go: 0, 1 when the control plane is unreachable or rejects, 2 on usage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Implements U2 of the factory-quality plan in #21 (
docs/plans/2026-09-28-001-feat-factory-quality-followups-plan.md):Store.ReportbehindGET /api/report(R2, R3, R4, R6, R15; KTD1, KTD3, KTD4). It is read-only and has no migration. This PR also carries U3, thejig reportCLI over it (see the U3 section below).Endpoint
GET /api/report?since=<RFC3339>&until=<RFC3339>. The window is[since, until).untildefaults to now andsinceto seven days beforeuntil. A malformed value returns 400invalid_query_parameter.since >= untilreturns 400invalid_report_window. Duration parsing (7d) is left to U3's CLI.Response (
controlplane.Report, kept next toQueueView/FleetViewbecause that is where the repo's read-model views live):Counts are always numbers. A rate or per-accept figure is null when its denominator is 0, because 0 there would look like a measurement (for example, $ spent with no clean accept).
Definitions
accepted,accepted_unpublished,failed,cancelled) andupdated_at∈ [since, until)acceptedand one of: (a) green CI on a head jig pushed, meaning thecirecord'sremote_refequals the proof ref or a round'shead_after; or (b) the frozen definition does not wait for CI. Read from the ledger, never from the worker's resultacceptedwith the greencirecord on any other headaccepted, but the ledger cannot classify it: the snapshot no longer parses, or the definition waits for CI and there is nocirecord. Never cleanpublished(the R12 ledger rule).accepted_unpublishedjobs are classified from the latest attempt'spublish: the"held"marker or aheldsummary is held;"not_attempted"is not_attempted; afailedsummary is failed (by code); anything else is unreadable.held_rate= held / eligibleproofrecord, meaning publish reached the CI wait. This is the denominator for entry, timeout and retry-signal ratespublish_history(oldest first, U8) followed by the currentpublishsummary. Each stop code, round and re-run counts once per attemptci_repairs(this catches a round that stopped before pushing)ci_repairsispublished. Exhausted and then publish-retried to green counts as entered, unsuccessful, with its stop codepublish_ci_repairs(KTD4)ci_rerunsentries (U4's pinned name), de-duplicated per attempt byattemptnumber.flaky_passes= attempts with a re-run whoseoutcomeispassedci_timeoutrate (KTD1)ci_timeout, divided by waitedci_failedor aci_failuresentry with verdictfail), so a timeout is not redSUM(json_extract(CAST(payload AS TEXT), '$.payload.cost'))and$.payload.unmetered_sendsoveragent_endevents of every attempt of each window job. A missing field adds 0unreadable_resultspublish, or has a history/repair/re-run entry that does not decodeR4:
person_fixedandclean_no_ci_waitare the two things jig cannot vouch for. The report makes no post-merge claim.Verification
just checkpasses (format, vet, boundary, definitions, full test suite, build).report_test.goseeds ledger rows directly, includingpublish_history,ci_rerunsandunmetered_sends. U1/U4/U8 are not needed. It asserts:Reportmatch over 14 in-window jobs, one per outcome, plus jobs beforesince, exactly atuntil, and still active;Store.Report, and the default window is correct;Mutation results (26/27 killed)
Each mutant compiled (
go vet), and theReporttests were run against it. Every mutant was killed except one:>=→>,<→<=, terminal filter dropped;cirecord counted clean;publishaccepted;MAXforSUM, any event type, latest attempt only, unmetered not summed, per-accept over clean spend only;Survived (equivalent): dropping the latest-attempt filter from the ledger subquery. The Go side already keys ledger rows by latest attempt id, so the SQL filter only narrows the read.
Not tested / known gaps
JobDetail, because_txlock=immediatewould take the write lock. A job that finishes between queries can skew one report slightly.events(type)index only if realistic volume shows a need.U3 —
jig reportCLIjig report [--server <url>] [--since 7d|<RFC3339>] [--until <RFC3339>] [--json](R3, R4). Files:cmd/jig/report.go,cmd/jig/report_test.go,cmd/jig/main.go(dispatch and usage),README.md(new "Measuring the factory" section).--sincetakes a positive duration back from now (7d,24h,90m: Go units plus whole days) or RFC3339. It is converted to RFC3339 before the call.--untilis RFC3339 only. Omitted flags fall through to the endpoint's defaults.--jsonprints the response body verbatim (decoded asjson.RawMessage, never re-encoded).n/a. Two lines always follow:def.go: 0 on success, 1 when the server is unreachable or rejects the request, 2 on usage (an unparseable--since/--untilor a stray positional; usage is printed).Verification
just checkpasses.jig serve(startServe) with the ledger seeded by SQL. They cover:n/afor empty-denominator rates, and $/clean accept;--jsondeep-equalsGET /api/reportfor the same window, ignoringobserved_at;--since 7d/90m/30mand an RFC3339 value select the right jobs, and7dis sent as now−7d;24h→1h;--jsonbranch disabled; bad--sinceexit 2→1; R4 caveat line removed.Known gaps
🤖 Generated with Claude Code