Skip to content

feat(miner-ui): expose the attempt-log + PR-outcome stores via a read-only /attempts dashboard - #7718

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
xfodev:fix/miner-ui-attempt-log-api-7656
Jul 21, 2026
Merged

feat(miner-ui): expose the attempt-log + PR-outcome stores via a read-only /attempts dashboard#7718
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
xfodev:fix/miner-ui-attempt-log-api-7656

Conversation

@xfodev

@xfodev xfodev commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

packages/loopover-miner/lib/attempt-log.ts (per-attempt event log: attemptId, actionClass, provider, costUsd, tokensUsed) and pr-outcome.ts (merged/closed records with rejection reason) hold real, already-written data with no API exposure — run-history.tsx only shows current per-repo run state, not a log of past attempts (#7656).

This adds a read-only API + dashboard view exposing both, extending the existing local-store-API pattern exactly:

  • vite-attempt-log-api.ts — mirrors vite-ledgers-api.ts (types → emptyAttemptLogSummary() → pure summarize*() helpers → injectable AttemptLogApiDepshandleAttemptLogRequestattemptLogApiPlugin). GET /api/attempt-log aggregates both stores server-side to counts + a capped feed of SAFE columns. The attempt log's free-form payload never crosses the wire — only fixed columns are projected — the same invariant the sibling ledgers endpoint enforces. Each store's DB path is probed before reading, so a fresh install returns empty without creating the SQLite file; fail-soft try/catch → 500. PR-outcomes are read via readPrOutcomes over a reader built from the event ledger's readEvents.
  • /attempts route (attempts.tsx, mirroring ledgers.tsx) — per-attempt history: totals, action-class / event-type breakdowns, a recent-attempts feed (action, provider, cost, tokens), and the miner's own PR outcomes (merged/closed + close-reason). Distinct from run-history.tsx's current-state view. Nav entry added after Ledgers.

Entirely within apps/loopover-miner-ui/**; reads the existing miner-lib exports without modifying them.

Tests

New attempt-log-api.test.ts (handler: populated / fresh-install-no-DB / non-matching-url / 500, plus a raw-payload-leak canary) and attempts.test.tsx (route: render / empty / error / loading / pagination / live-refresh), mirroring the sibling *-api.test.ts conventions. Full miner-ui suite: 368 pass.

UI Evidence

The /attempts view rendered with VITE_DEMO_MODE sample data (DEMO_ATTEMPT_LOG_SUMMARY), dark theme (loopover-miner-ui defaults to dark).

Note: the full app shell can't boot in this sandbox — the client bundle pulls in packages/loopover-engine/dist/miner/deny-hook-synthesis.js, which calls node:crypto.createHash at module load, and Vite's browser externalization throws before React mounts. This is pre-existing and reproduces identically on unmodified routes like /run-history and /ledgers (same crash flagged in #7706), so it is not caused by this change. These shots therefore show the route component itself rendering the demo summary (no top nav chrome).

Viewport × Theme /attempts view
Desktop · Dark Desktop · Dark — /attempts view
Tablet · Dark Tablet · Dark — /attempts view
Mobile · Dark Mobile · Dark — /attempts view

Validation

  • @loopover/ui-miner typecheck, lint (0 errors), test (368 pass incl. the 2 new suites), build, prettier — all green; rebased onto latest main. No src/**/packages/** changes (miner-ui is outside Codecov's include set).

Closes #7656

…-only /attempts dashboard

The per-attempt event log (packages/loopover-miner/lib/attempt-log.ts) and the
local PR-outcome records (pr-outcome.ts, reduced from the event ledger) are real,
already-written data with no API exposure — run-history.tsx only shows current
per-repo state, not a log of past attempts. Add a vite-attempt-log-api.ts plugin
mirroring vite-ledgers-api.ts exactly (server-side aggregation to counts + a
capped feed of SAFE columns; raw payload never crosses the wire; each store's DB
path probed before read so a fresh install stays empty) and an /attempts route
consuming it, showing per-attempt actionClass/provider/cost/tokens and PR outcomes.

Closes JSONbored#7656
@xfodev
xfodev requested a review from JSONbored as a code owner July 21, 2026 10:55
@superagent-security

Copy link
Copy Markdown
Contributor

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

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 21, 2026
@loopover-orb

loopover-orb Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-21 11:00:44 UTC

9 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR adds a read-only /attempts dashboard by faithfully mirroring the existing vite-ledgers-api.ts pattern: server-side aggregation of attempt-log + PR-outcome stores into counts and a safe-column feed, with the raw payload never crossing the wire (verified by a leak-canary test). The fresh-install guard (file-existence probe before calling the lazy-init `read*` exports) matches the sibling endpoints' documented invariant, and the demo-data/route-tree/nav wiring is mechanical and consistent with prior additions (e.g. #7675). No issue-number is referenced in the description beyond #7656 context comments, and I can't verify from this diff alone whether #7656 is an open, maintainer-authorized issue this PR is closing.

Nits — 5 non-blocking
  • apps/loopover-miner-ui/routeTree.gen.ts is an auto-generated file; verify it was regenerated via the router codegen and not hand-edited (the `as any` casts are pre-existing codegen convention, not new risk).
  • apps/loopover-miner-ui/vite-attempt-log-api.ts:183 nests fileExists→reader-build→summarize at depth 5; consider extracting the PR-outcome branch into a small helper for readability, mirroring summarizeAttempts's flat shape.
  • apps/loopover-miner-ui/src/routes/attempts.tsx: AttemptLogSummaryContent is a single ~74-line function covering six sections; consider splitting per-section components (as CountTable/RecentAttemptsTable already are) to keep it under the file's own size convention.
  • The 500-response error message in vite-attempt-log-api.ts:197 forwards `error.message` directly to the client (e.g. 'sqlite locked'); confirm this matches the sibling ledgers endpoint's existing practice of surfacing raw driver messages, since it's a pre-existing pattern rather than new exposure here.
  • If Add API + dashboard exposure for attempt-log.ts / pr-outcome.ts (real per-attempt data, currently unexposed) #7656 isn't yet a maintainer-tagged/open issue this PR closes, link it explicitly in the PR description per the repo's contribution requirement.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #7656
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: 70 registered-repo PR(s), 41 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor xfodev; Gittensor profile; 70 PR(s), 0 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Addressed
The PR adds vite-attempt-log-api.ts closely mirroring vite-ledgers-api.ts's structure (types, emptySummary, summarize* helpers, injectable deps, handler, plugin) and aggregates both attempt-log.ts and pr-outcome.ts server-side into safe counts/feed, plus a new /attempts route distinct from run-history.tsx showing per-attempt history and PR outcomes, satisfying both deliverables.

Review context
  • Author: xfodev
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: JavaScript, TypeScript
  • Official Gittensor activity: 70 PR(s), 0 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
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 <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> 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.

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/attempts desktop before /attempts
before /attempts
after /attempts
after /attempts
/attempts mobile before /attempts (mobile)
before /attempts (mobile)
after /attempts (mobile)
after /attempts (mobile)
/ 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)
/attempts before /attempts (scroll)
before /attempts (scroll)
after /attempts (scroll)
after /attempts (scroll)
/ 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

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 95b6384 into JSONbored:main Jul 21, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add API + dashboard exposure for attempt-log.ts / pr-outcome.ts (real per-attempt data, currently unexposed)

1 participant