Skip to content

feat(api): publish the eval corpus so a stranger can actually verify a review - #9764

Merged
JSONbored merged 2 commits into
mainfrom
feat/public-eval-corpus
Jul 29, 2026
Merged

feat(api): publish the eval corpus so a stranger can actually verify a review#9764
JSONbored merged 2 commits into
mainfrom
feat/public-eval-corpus

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

The verifiability walkthrough tells a skeptic to "export the same corpus the numbers come from" — but the only exporter is scripts/backtest-corpus-export.ts, which shells out to wrangler d1 execute --remote and needs that deployment's own Cloudflare credentials. Step 1 was never runnable by a third party. #9636 fixed the claim by marking the step operator-only; this fixes the gap.

GET /v1/public/eval-corpus?ruleId=<id> serves one rule's labeled corpus over the same window the published per-rule precision covers, unauthenticated.

Closes #9636

Redaction is the design — and it costs nothing replay needs

Field Treatment Why
targetKey (owner/repo#number) dropped, not hashed scoreBacktest never reads it, and a hash is still a stable per-PR identifier — correlatable, for zero replay benefit
metadata narrowed to confidence, kept nested buildConfidenceThresholdClassifier reads metadata.confidence (backtest-threshold.ts:21). Flattening it would make every replay hit the ?? 1 fallback and label every case "confirmed" — a wrong answer that looks like a working one
firedAt / decidedAt truncated to the UTC day nothing in the replay path reads them; full-precision pairs were the one remaining way to line a case up against a private repo's PR timeline

The checksum commits to this artifact, not to the internal manifest. A reader can only re-derive what they can download, and a checksum over a preimage nobody can obtain verifies nothing — exactly the failure #9636 fixed on the eval-score records. It uses canonicalJson + Web Crypto, the same pair every other digest here uses, so a consumer learns one serialization rule rather than two.

Counterfactual-replay overrides are excluded, matching the per-rule precision this corpus explains — otherwise the corpus and the number it backs would disagree.

Docs

Step 1 is now a credential-free curl. Step 2's verification snippet imports nothing from LoopOver — canonical JSON is eight lines, and running our code to check our numbers is not much of a check. I executed that snippet against real output before writing it down; it prints checksum OK.

A callout records that the operator CLI's older canonicalization produces a different, deliberately non-comparable checksum, since each commits to the artifact it ships with. Without that note, an operator verifying a downloaded document with buildBacktestCorpusManifest would get a false CHECKSUM MISMATCH.

what-you-can-verify.mdx's "private repositories are the exception" callout is corrected rather than left flattering: a private repo's cases do appear here, because the published precision counts them and a corpus omitting them would not explain those numbers. They appear stripped of identity. What is still not published is any identifiable per-tenant history.

Validation

Check Result
public-eval-corpus.ts coverage 100% stmts / branches / funcs / lines (22/22, 18/18, 8/8, 21/21)
Changed lines in routes.ts + route-auth.ts 22 changed lines, 0 uncovered, 0 partial branches
Unit + integration + auth-parity suites 59 tests pass
typecheck · ui:openapi:check · docs:drift-check · ui:lint (0 errors) · ui:build · coverage-boltons · validate:no-hand-written-js · release-linked-versions:check all clean
git diff --check clean

Registered in the table-driven exemptPublicRoutes regression test whose stated purpose is "a future public route that forgets its requiresApiToken exemption fails HERE, not in prod", and openapi-security-parity passes.

Two invariant tests carry the weight: one asserts the serialized response never matches /acme|private-widgets|4242|targetKey/i against a deliberately identifying seed, the other pins metadata.confidence staying nested.

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests.
  • API/OpenAPI/MCP behavior is updated and tested where needed.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks.
  • Visible UI changes include a UI Evidence section below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs.

This adds a new unauthenticated route, so the negative paths are the point: 404 when LOOPOVER_PUBLIC_STATS is off (same flag as its siblings), 400 without ruleId rather than silently picking a rule, an empty-but-still-checksummed corpus for an unknown rule, and a fail-safe empty corpus when the store read throws rather than a 500 on a public endpoint. The exemption is declared in route-auth.ts — the single predicate both the auth middleware and the OpenAPI builder read — not in a second, driftable place.

UI Evidence

Captured at 1280×800, deviceScaleFactor: 2, dark build.

State Before After
Step 1 — corpus acquisition Before: export, operator/self-host only After: credential-free curl, anyone
Step 2 — checksum verification Before: imports buildBacktestCorpusManifest After: self-contained, imports nothing from LoopOver

Notes

On current production data this endpoint returns a real corpus for ai_consensus_defect and an empty one for slop_gate_score — correct on both counts, and consistent with what the fairness table now shows after #9720.

…a review

The verifiability walkthrough tells a skeptic to "export the same corpus the
numbers come from", but the only exporter is scripts/backtest-corpus-export.ts,
which shells out to `wrangler d1 execute --remote` and needs that deployment's
own Cloudflare credentials. Step 1 was never runnable by a third party, which
made the page's "nothing needs an API key" claim false. #9636 fixed the claim by
marking the step operator-only; this fixes the gap.

GET /v1/public/eval-corpus?ruleId=<id> serves one rule's labeled corpus over the
same window the published per-rule precision covers, unauthenticated.

REDACTION IS THE DESIGN, and it costs nothing that replay needs:

  - `targetKey` (literally `owner/repo#number`) is DROPPED, not hashed.
    scoreBacktest never reads it, and a hash would still be a stable per-PR
    identifier -- correlatable, for no replay benefit.
  - metadata is narrowed to `confidence`, kept NESTED where
    buildConfidenceThresholdClassifier actually reads it
    (backtest-threshold.ts:21). Flattening it to a top-level field would make
    every replay silently hit the `?? 1` fallback and label every case
    "confirmed" -- a wrong answer that looks like a working one.
  - timestamps are truncated to the UTC day. Nothing in the replay path reads
    them; full-precision pairs were the one remaining way to line a case up
    against a private repo's PR timeline.

The checksum commits to THIS artifact, not to the internal manifest. A reader
can only re-derive what they can download, and a checksum over a preimage nobody
can obtain verifies nothing -- exactly the failure #9636 fixed on the eval-score
records. It deliberately uses canonicalJson + Web Crypto, the same pair every
other digest here uses, so a consumer learns one serialization rule.

Counterfactual-replay overrides are excluded, matching the per-rule precision
this corpus explains -- otherwise the corpus and the number would disagree.

Docs: step 1 is now a credential-free curl, and step 2's verification snippet
imports NOTHING from LoopOver -- canonical JSON is eight lines, and running our
code to check our numbers is not much of a check. The snippet was executed
against real output before being written down. A callout records that the
operator CLI's older canonicalization produces a different, deliberately
non-comparable checksum, since each commits to the artifact it ships with.

what-you-can-verify.mdx's "private repositories are the exception" callout is
corrected rather than left flattering: a private repo's cases DO appear here,
because the published precision counts them and a corpus omitting them would not
explain those numbers. They appear stripped of identity. What is still not
published is any identifiable per-tenant history.

Closes #9636
@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-29 09:37:50 UTC

11 files · 1 AI reviewer · 2 blockers · CI green · clean

⏸️ Suggested Action - Manual Review

  • Required AI review was skipped by a submitter-reputation downgrade: This repository requires blocking AI review, and the submitter's recent-submission signal downgraded this PR to deterministic-only checks. Those checks do not read code semantics, so the gate is held for human review instead of passing automatically.

Review summary
This PR adds an unauthenticated GET /v1/public/eval-corpus endpoint that serves a redacted, checksummed corpus of one rule's backtest cases (targetKey dropped, metadata narrowed to confidence, timestamps truncated to day), fully wired through routes.ts, route-auth.ts, openapi.json, and openapi/spec.ts, plus docs updates and comprehensive unit/integration tests. The design rationale (why targetKey is dropped not hashed, why metadata.confidence stays nested for buildConfidenceThresholdClassifier, why the checksum commits to the published artifact not the internal manifest) is well-reasoned and the redaction logic in redactBacktestCase/sortPublicEvalCorpusCases/applyPublicEvalCorpusCap is pure and well-tested including boundary cases. One correctness concern: NON_ATTRIBUTABLE_OVERRIDE_PROVENANCES is exported from public-rule-precision.ts and reused here, coupling the two modules' filtering logic by reference rather than duplicating it, which is good, but worth confirming the load-failure fallback (empty arrays) doesn't silently mask a real outage on this new route the way it does for its sibling.

Nits — 7 non-blocking
  • src/review/public-eval-corpus.ts:124 — the window math (`24 * 60 * 60 * 1000`) duplicates a day-in-ms literal instead of reusing a shared constant if one exists elsewhere in the codebase.
  • The external review brief flags that issue Public verifiability: the published freeze point commits to an empty corpus, and the walkthrough's stats link 404s #9636's own coverage is 'partial' (published freeze point still commits to an empty corpus, stats link 404s) — worth confirming that claim against the actual issue before merging, since it isn't visible in this diff.
  • apps/loopover-ui/content/docs/verify-this-review.mdx's step-2 checksum snippet reimplements canonicalJson inline in a bash/node one-liner rather than importing the shared canonicalJson used everywhere else — intentional per the PR description ('imports nothing from LoopOver'), but worth double-checking the inline implementation stays byte-for-byte identical to src/review/decision-record.ts's canonicalJson if that function ever changes.
  • src/review/public-rule-precision.ts:73 — widening `NON_ATTRIBUTABLE_OVERRIDE_PROVENANCES` from module-private `const` to `export const` is a small API-surface change; confirm no other consumer should instead get its own copy to avoid tight coupling between the precision and corpus modules.
  • Add a day-in-ms shared constant (or reuse PUBLIC_PRECISION_WINDOW_DAYS-adjacent helpers) instead of the inline `24 * 60 * 60 * 1000` literal in public-eval-corpus.ts:124.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
  • Required AI review was skipped by a submitter-reputation downgrade — Review this PR manually, or run AI review with a trusted override, before merging.

Concerns raised — review before merging

  • No linked issue detected: The PR cites an issue number, but it could not be verified as a currently open issue. — If this PR is intended to solve an issue, link it explicitly in the PR body.
  • Linked issue does not appear to be satisfied: AI assessment: this PR does not appear to satisfy its linked issue's scope. This PR is a different, later change (Public verifiability: the published freeze point commits to an empty corpus, and the walkthrough's stats link 404s #9636: publishing an anonymous eval corpus) that the issue itself explicitly lists as out-of-scope for this ticket, and it does not touch the issue's actual asks: it neither fixes the empty-corpus `corpusChecksum` published in `/v1/public/stats`'s `latestBacktestRun` (still driven by the gated `linkedIssueSatisfactionGateMode`), nor changes the relative `/v1/p — Confirm this PR actually addresses the linked issue's scope, or link the correct issue.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. No linked issue detected: The PR cites an issue number, but it could not be verified as a currently open issue. — If this PR is intended to solve an issue, link it explicitly in the PR body.

2. Linked issue does not appear to be satisfied: AI assessment: this PR does not appear to satisfy its linked issue's scope. This PR is a different, later change \(\#9636: publishing an anonymous eval corpus\) that the issue itself explicitly lists as out-of-scope for this ticket, and it does not touch the issue's actual asks: it neither fixes the empty-corpus \`corpusChecksum\` published in \`/v1/public/stats\`'s \`latestBacktestRun\` \(still driven by the gated \`linkedIssueSatisfactionGateMode\`\), nor changes the relative \`/v1/p — Confirm this PR actually addresses the linked issue's scope, or link the correct issue.

Decision drivers

  • ❌ Code review — 2 blockers (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9636
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 14 registered-repo PR(s), 13 merged, 370 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 14 PR(s), 370 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Linked issue satisfaction

Not yet addressed
This PR is a different, later change (#9636: publishing an anonymous eval corpus) that the issue itself explicitly lists as out-of-scope for this ticket, and it does not touch the issue's actual asks: it neither fixes the empty-corpus `corpusChecksum` published in `/v1/public/stats`'s `latestBacktestRun` (still driven by the gated `linkedIssueSatisfactionGateMode`), nor changes the relative `/v1/p

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is registered but has no active allocation in the current snapshot.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 14 PR(s), 370 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 2 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Decision record
  • action: hold · clause: missing_linked_issue
  • config: a31ddfd24cf149f238339cb53fd31c2d4cd4fdd9a80a126df8e4643802058606 · pack: oss-anti-slop · ci: passed
  • record: e443109bcbcbb11877241f29262b6bfe4165cfd70898402412ca6818c0e41109 (schema v5, head aa5fbb1)
Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before /
before /
after /
after /
/ mobile before / (mobile)
before / (mobile)
after / (mobile)
after / (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

Scroll preview
Route Before (production) After (this PR's preview)
/ before / (scroll)
before / (scroll)
after / (scroll)
after / (scroll)

A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 29, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
loopover-ui aa5fbb1 Commit Preview URL

Branch Preview URL
Jul 29 2026, 09:19 AM

@JSONbored JSONbored self-assigned this Jul 29, 2026
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 9.27kB (0.12%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
loopover-ui 7.89MB 9.27kB (0.12%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: loopover-ui

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/add-scalar-classes-Co4bxscz.js (New) 2.16MB 2.16MB 100.0% 🚀
assets/tanstack-vendor-BrLkyrp7.js (New) 928.35kB 928.35kB 100.0% 🚀
openapi.json 1.31kB 746.13kB 0.18%
assets/docs.fumadocs-spike-api-reference-DfTn6R6t.js (New) 443.45kB 443.45kB 100.0% 🚀
assets/AgentScalarChatInterface.vue-NOan_aMG.js (New) 201.7kB 201.7kB 100.0% 🚀
assets/modal-WOXR3gUX.js (New) 184.5kB 184.5kB 100.0% 🚀
assets/client-DuA7DV3N.js (New) 151.47kB 151.47kB 100.0% 🚀
assets/maintainer-panel-D2txyoLr.js (New) 78.99kB 78.99kB 100.0% 🚀
assets/what-you-can-verify-Cj9CcDTI.js (New) 61.2kB 61.2kB 100.0% 🚀
assets/verify-this-review-D8G2EFth.js (New) 46.41kB 46.41kB 100.0% 🚀
assets/routes-BUD43Duw.js (New) 35.96kB 35.96kB 100.0% 🚀
assets/owner-panel-D1grqkVY.js (New) 27.97kB 27.97kB 100.0% 🚀
assets/app-BUEzAAxm.js (New) 25.78kB 25.78kB 100.0% 🚀
assets/ui-vendor-C5Zk7cdo.js (New) 24.57kB 24.57kB 100.0% 🚀
assets/miner-panel-B9ZOgJfW.js (New) 20.24kB 20.24kB 100.0% 🚀
assets/app.runs-Ekyd81-a.js (New) 20.22kB 20.22kB 100.0% 🚀
assets/api._op-B9v07T4F.js (New) 17.57kB 17.57kB 100.0% 🚀
assets/self-hosting-docs-audit-Dl24X7Sh.js (New) 16.6kB 16.6kB 100.0% 🚀
assets/docs._slug-Laux4Rro.js (New) 15.52kB 15.52kB 100.0% 🚀
assets/playground-panel-DclhOVAD.js (New) 14.42kB 14.42kB 100.0% 🚀
assets/fairness-Biy4-HRq.js (New) 13.98kB 13.98kB 100.0% 🚀
assets/app.audit-_RqbGU90.js (New) 10.08kB 10.08kB 100.0% 🚀
assets/app.config-generator-iDSNNebO.js (New) 10.06kB 10.06kB 100.0% 🚀
assets/maintainers-C3GJwuNu.js (New) 8.06kB 8.06kB 100.0% 🚀
assets/miners-D1zyYrMj.js (New) 7.91kB 7.91kB 100.0% 🚀
assets/agents-DmTYsj0e.js (New) 7.74kB 7.74kB 100.0% 🚀
assets/commands-panel-YM6uCe0t.js (New) 6.65kB 6.65kB 100.0% 🚀
assets/maintainer-workflow-HKB2HzUv.js (New) 6.52kB 6.52kB 100.0% 🚀
assets/digest-panel-IfWFF3ds.js (New) 6.15kB 6.15kB 100.0% 🚀
assets/repos._owner._repo.quality-C2P3mODQ.js (New) 6.14kB 6.14kB 100.0% 🚀
assets/docs-nav-BZW4wpMx.js (New) 6.01kB 6.01kB 100.0% 🚀
assets/docs.index-Rcc5TwxR.js (New) 5.95kB 5.95kB 100.0% 🚀
assets/api.index-DJCuwmYz.js (New) 4.7kB 4.7kB 100.0% 🚀
assets/docs-D3CkX6Y3.js (New) 2.7kB 2.7kB 100.0% 🚀
assets/api-DGUNEAEd.js (New) 2.69kB 2.69kB 100.0% 🚀
assets/docs-page-jawKODwl.js (New) 2.1kB 2.1kB 100.0% 🚀
assets/table-BOvRRjKc.js (New) 1.75kB 1.75kB 100.0% 🚀
assets/app.workbench-BQ61iCDh.js (New) 1.58kB 1.58kB 100.0% 🚀
assets/tabs-Cr7FkTc-.js (New) 1.39kB 1.39kB 100.0% 🚀
assets/app.repos-Bb4hCDDr.js (New) 1.07kB 1.07kB 100.0% 🚀
assets/input-BeAeWi4a.js (New) 796 bytes 796 bytes 100.0% 🚀
assets/file-cog-CxWOBttH.js (New) 758 bytes 758 bytes 100.0% 🚀
assets/app.maintainer-SV2QZgE-.js (New) 502 bytes 502 bytes 100.0% 🚀
assets/app.owner-BZcFkBha.js (New) 474 bytes 474 bytes 100.0% 🚀
assets/app.commands-Cf7Jgc82.js (New) 455 bytes 455 bytes 100.0% 🚀
assets/app.playground-BtOEQUHd.js (New) 442 bytes 442 bytes 100.0% 🚀
assets/index-BzAArDB0.js (New) 438 bytes 438 bytes 100.0% 🚀
assets/app.digest-DYxtqglb.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/eye-off-BFKMYgZr.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/app.miner-OJ6QJjbG.js (New) 422 bytes 422 bytes 100.0% 🚀
assets/key-round-hI5MoUun.js (New) 355 bytes 355 bytes 100.0% 🚀
assets/bot-DbcCDqdg.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/trash-2-Cfk4PTpD.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/save-COPHD__w.js (New) 327 bytes 327 bytes 100.0% 🚀
assets/git-pull-request-arrow-BIq6V7ox.js (New) 321 bytes 321 bytes 100.0% 🚀
assets/list-checks-DKhy3zDq.js (New) 279 bytes 279 bytes 100.0% 🚀
assets/compass-D1D2dVCC.js (New) 251 bytes 251 bytes 100.0% 🚀
assets/history-C7_c8eS9.js (New) 237 bytes 237 bytes 100.0% 🚀
assets/message-square-pqmOfA5s.js (New) 233 bytes 233 bytes 100.0% 🚀
assets/lock-DYpBx3vw.js (New) 206 bytes 206 bytes 100.0% 🚀
assets/rotate-cw-BNWX5pjV.js (New) 201 bytes 201 bytes 100.0% 🚀
assets/play-UKVcci2r.js (New) 190 bytes 190 bytes 100.0% 🚀
assets/circle-check-D8Bv-iR2.js (New) 178 bytes 178 bytes 100.0% 🚀
assets/search-C71-2cOv.js (New) 174 bytes 174 bytes 100.0% 🚀
assets/add-scalar-classes-BmHAjn_k.js (Deleted) -2.16MB 0 bytes -100.0% 🗑️
assets/tanstack-vendor-DC-uRsTm.js (Deleted) -927.37kB 0 bytes -100.0% 🗑️
assets/docs.fumadocs-spike-api-reference-B_QNXsxj.js (Deleted) -443.45kB 0 bytes -100.0% 🗑️
assets/AgentScalarChatInterface.vue-oXEm16qx.js (Deleted) -201.7kB 0 bytes -100.0% 🗑️
assets/modal-BldXDdI2.js (Deleted) -184.5kB 0 bytes -100.0% 🗑️
assets/client-DHsm1fQ2.js (Deleted) -151.47kB 0 bytes -100.0% 🗑️
assets/maintainer-panel-CVjOD9Ov.js (Deleted) -78.99kB 0 bytes -100.0% 🗑️
assets/what-you-can-verify-DRZe7pNw.js (Deleted) -59.84kB 0 bytes -100.0% 🗑️
assets/verify-this-review-NDb9HyS-.js (Deleted) -40.8kB 0 bytes -100.0% 🗑️
assets/routes-XPDYCnTc.js (Deleted) -35.96kB 0 bytes -100.0% 🗑️
assets/owner-panel-CCyCxzt8.js (Deleted) -27.97kB 0 bytes -100.0% 🗑️
assets/app-uIX8Y_x5.js (Deleted) -25.78kB 0 bytes -100.0% 🗑️
assets/ui-vendor-DSdgMFDw.js (Deleted) -24.57kB 0 bytes -100.0% 🗑️
assets/miner-panel-BHWxXAg9.js (Deleted) -20.24kB 0 bytes -100.0% 🗑️
assets/app.runs-a3_cokka.js (Deleted) -20.22kB 0 bytes -100.0% 🗑️
assets/api._op-RNveZlOG.js (Deleted) -17.57kB 0 bytes -100.0% 🗑️
assets/self-hosting-docs-audit-DvnZRPRR.js (Deleted) -16.6kB 0 bytes -100.0% 🗑️
assets/docs._slug-BAzVCSmk.js (Deleted) -15.52kB 0 bytes -100.0% 🗑️
assets/playground-panel-C148YE2m.js (Deleted) -14.42kB 0 bytes -100.0% 🗑️
assets/fairness-BUSOVCDO.js (Deleted) -13.98kB 0 bytes -100.0% 🗑️
assets/app.audit-B6DMFFfK.js (Deleted) -10.08kB 0 bytes -100.0% 🗑️
assets/app.config-generator-C0khjBtK.js (Deleted) -10.06kB 0 bytes -100.0% 🗑️
assets/maintainers-BWSs_WXY.js (Deleted) -8.06kB 0 bytes -100.0% 🗑️
assets/miners-DT4TMPBG.js (Deleted) -7.91kB 0 bytes -100.0% 🗑️
assets/agents-CBDcTbGx.js (Deleted) -7.74kB 0 bytes -100.0% 🗑️
assets/commands-panel-CfsF_9bj.js (Deleted) -6.65kB 0 bytes -100.0% 🗑️
assets/maintainer-workflow-gCAtxMSA.js (Deleted) -6.52kB 0 bytes -100.0% 🗑️
assets/digest-panel-DSb7_g9s.js (Deleted) -6.15kB 0 bytes -100.0% 🗑️
assets/repos._owner._repo.quality-DVZjKY52.js (Deleted) -6.14kB 0 bytes -100.0% 🗑️
assets/docs-nav-BRTGJ5Ma.js (Deleted) -6.01kB 0 bytes -100.0% 🗑️
assets/docs.index-C80oP19v.js (Deleted) -5.95kB 0 bytes -100.0% 🗑️
assets/api.index-Cg-ysTta.js (Deleted) -4.7kB 0 bytes -100.0% 🗑️
assets/docs-JGDbAt8G.js (Deleted) -2.7kB 0 bytes -100.0% 🗑️
assets/api-BBPzk0J7.js (Deleted) -2.69kB 0 bytes -100.0% 🗑️
assets/docs-page-DZm9vg5-.js (Deleted) -2.1kB 0 bytes -100.0% 🗑️
assets/table-DavZSEqD.js (Deleted) -1.75kB 0 bytes -100.0% 🗑️
assets/app.workbench-D4OQD3DX.js (Deleted) -1.58kB 0 bytes -100.0% 🗑️
assets/tabs-DbWTiXd-.js (Deleted) -1.39kB 0 bytes -100.0% 🗑️
assets/app.repos-CpfPLcxN.js (Deleted) -1.07kB 0 bytes -100.0% 🗑️
assets/input-CmGIjLLA.js (Deleted) -796 bytes 0 bytes -100.0% 🗑️
assets/file-cog-CxHItU_X.js (Deleted) -758 bytes 0 bytes -100.0% 🗑️
assets/app.maintainer-Dz1MCHY9.js (Deleted) -502 bytes 0 bytes -100.0% 🗑️
assets/app.owner-BlXQBqoW.js (Deleted) -474 bytes 0 bytes -100.0% 🗑️
assets/app.commands-U3ti8QFn.js (Deleted) -455 bytes 0 bytes -100.0% 🗑️
assets/app.playground-Cv0ax5XG.js (Deleted) -442 bytes 0 bytes -100.0% 🗑️
assets/index-y39TZUKo.js (Deleted) -438 bytes 0 bytes -100.0% 🗑️
assets/app.digest-BKPhK2Xg.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/eye-off-C-tw7RmD.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/app.miner-n0EPVY-J.js (Deleted) -422 bytes 0 bytes -100.0% 🗑️
assets/key-round-DQ8kQRdC.js (Deleted) -355 bytes 0 bytes -100.0% 🗑️
assets/bot-BgHPVlg-.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/trash-2-CfVjPyWT.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/save-a5SX6tDL.js (Deleted) -327 bytes 0 bytes -100.0% 🗑️
assets/git-pull-request-arrow-BAQajn3C.js (Deleted) -321 bytes 0 bytes -100.0% 🗑️
assets/list-checks-Drx098rT.js (Deleted) -279 bytes 0 bytes -100.0% 🗑️
assets/compass-mOmx77Kg.js (Deleted) -251 bytes 0 bytes -100.0% 🗑️
assets/history-D-sd6lQL.js (Deleted) -237 bytes 0 bytes -100.0% 🗑️
assets/message-square-CYOwk3tg.js (Deleted) -233 bytes 0 bytes -100.0% 🗑️
assets/lock-BGT11TkY.js (Deleted) -206 bytes 0 bytes -100.0% 🗑️
assets/rotate-cw-Igh7ghN4.js (Deleted) -201 bytes 0 bytes -100.0% 🗑️
assets/play-Ce2vJQAG.js (Deleted) -190 bytes 0 bytes -100.0% 🗑️
assets/circle-check-C_YrjHEA.js (Deleted) -178 bytes 0 bytes -100.0% 🗑️
assets/search-DzFi78oK.js (Deleted) -174 bytes 0 bytes -100.0% 🗑️

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.49%. Comparing base (7df6148) to head (aa5fbb1).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9764      +/-   ##
==========================================
- Coverage   90.33%   89.49%   -0.85%     
==========================================
  Files         917      917              
  Lines      113904   113643     -261     
  Branches    26966    26959       -7     
==========================================
- Hits       102894   101703    -1191     
- Misses       9681    10850    +1169     
+ Partials     1329     1090     -239     
Flag Coverage Δ
backend 94.09% <100.00%> (-1.48%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/api/routes.ts 95.60% <100.00%> (+0.01%) ⬆️
src/auth/route-auth.ts 100.00% <100.00%> (ø)
src/openapi/spec.ts 99.27% <100.00%> (+<0.01%) ⬆️
src/review/public-eval-corpus.ts 100.00% <100.00%> (ø)
src/review/public-rule-precision.ts 100.00% <100.00%> (ø)

... and 5 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 29, 2026
@JSONbored

Copy link
Copy Markdown
Owner Author

Not previously fixed — you were right to push, and it turned out to be worse than the reviewer framed it. Two defects, both now fixed in the latest push.

1. The fallback did mask an outage — and it was the exact bug this endpoint exists to close

listAuditEventsByType awaits its drizzle query directly and does not swallow, so my try/catch was live: a database failure returned { caseCount: 0, checksum: sha256("[]"), cases: [] } with a 200.

That is a checksummed empty corpus. It verifies perfectly and commits to nothing — precisely the defect #9636 was opened for, reintroduced by the endpoint built to close it. A reader downloading during an outage would verify the checksum, replay zero cases, and conclude the rule has no history.

The siblings' degrade-to-empty posture is right for them: each is one section of a larger payload. Here the whole response is the artifact and it carries a commitment, so the read now propagates and the route returns 503 eval_corpus_unavailable. "The database was down" can no longer be mistaken for "this rule has no history."

2. Worse, and not in the review: truncated could report false over a truncated corpus

queryRuleHistory inherits listAuditEventsByType's default limit = 500. Truncation therefore happened upstream, before pairing, invisible in cases.length — so applyPublicEvalCorpusCap saw a short array, and the response asserted truncated: false over a corpus SQL had already cut short. Production's ai_consensus_defect sits at 460 decided, so this is live at 501.

A checksummed artifact that silently omits rows while claiming completeness is a worse lie than the empty one.

Fixed with queryBoundedRuleHistory, which takes an explicit limit and returns a saturated flag. truncated is now capped || saturated. PUBLIC_EVAL_CORPUS_MAX_CASES also drops from an invented 5,000 to MAX_RULE_HISTORY_EVENTS (2,000) — listAuditEventsByType clamps at 2,000, so a cap above the retrieval ceiling was unreachable by construction and could never have fired.

saturated can false-positive when a rule has exactly limit events. Over-reporting truncation is the safe direction; the alternative asserts a completeness nobody checked.

The interface method is untouched — its read errors "deliberately propagate" for the decision-time callers, and the 500 default is fine for them; only a publishing consumer needs the bound made explicit.

Validation

File Changed lines Uncovered Partial branches
public-eval-corpus.ts 157 none none
signal-tracking-wire.ts 37 none none
routes.ts 26 none none
route-auth.ts 4 none none

54 tests green, including two new regressions: the loader now rejects.toThrow() on a broken store, and the route returns 503; plus a real-D1 test seeding past the event ceiling to prove truncated flips. Rebased onto current main; typecheck and ui:openapi:check clean. The 503 is registered in OpenAPI with the reason.

# Conflicts:
#	apps/loopover-ui/public/openapi.json
@JSONbored
JSONbored merged commit f5711a3 into main Jul 29, 2026
11 checks passed
@JSONbored
JSONbored deleted the feat/public-eval-corpus branch July 29, 2026 09:40
JSONbored added a commit that referenced this pull request Jul 29, 2026
…er claim a review was skipped when it ran (#9800)

Two defects found live on the ORB, both surfaced by the maintainer's own PRs:

1. The machine-paced cadence leg of shouldSkipAiForReputation downgraded the
   repo OWNER to deterministic-only on every PR: 50 submissions in 24h at a
   7.2-minute median gap trips isMachinePacedCadence (>=5 in 24h, median gap
   under 10 minutes), regardless of a 145-merge success record. The cadence
   check is a spend control against UNPROVEN accounts; "trusted" is this same
   module's own definition of proven (5+ recent merged successes at a low fail
   rate). A trusted submitter now short-circuits the cadence read entirely.
   The exemption cannot mask genuine abuse: any prompt-injection row in the
   window hard-locks the signal to "low" before success counting, pinned by an
   invariant test.

2. maybeAddReputationSkipHold pushed the "Required AI review was skipped by a
   submitter-reputation downgrade" finding whenever the skip WOULD fire --
   without checking that aiReviewAllAuthors or a forced re-run bypassed it, in
   which case the review genuinely ran. The published panel then asserted the
   review was skipped directly above that review's own summary, and held the
   gate for a review that succeeded (observed on #9764).
   The hold now describes what happened, not what the heuristic wanted.

Operationally: LOOPOVER_REVIEW_REPUTATION is commented out on the ORB until
this ships in an image; re-enabling is a one-line uncomment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Public verifiability: the published freeze point commits to an empty corpus, and the walkthrough's stats link 404s

1 participant