Skip to content

feat(api): maintainer quality-dashboard service + endpoint - #635

Merged
JSONbored merged 3 commits into
JSONbored:mainfrom
oktofeesh1:feat/issue-571-slop-gate
Jun 14, 2026
Merged

feat(api): maintainer quality-dashboard service + endpoint#635
JSONbored merged 3 commits into
JSONbored:mainfrom
oktofeesh1:feat/issue-571-slop-gate

Conversation

@oktofeesh1

@oktofeesh1 oktofeesh1 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #557. (This PR was repurposed from the now-superseded slop-gate work — #530/#531/#532 were implemented upstream in #716 — onto a fresh, unbuilt contributor-delegated issue.)

Carves out the non-visual data service behind the maintainer quality dashboard so #539 can focus on rendering. No UI.

What this adds

  • New src/services/maintainer-quality-dashboard.tsbuildMaintainerQualityDashboard(...) shapes ALREADY-cached repo data (issues + PRs) into:
    • per-repo queue-health band (low/medium/high/critical) + open-PR count
    • duplicate/collision trends (cluster + high-risk counts, via buildCollisionReport)
    • aggregate quality signals (open PRs, in high-risk duplicate cluster, missing linked issue)
    • top contributors by quality band (strong/developing/early) — deterministic from the share of an author's open PRs that are clean (linked + not in a high-risk duplicate cluster)
  • Enriches GET /v1/app/maintainer-dashboard with qualityDashboard, scoped to the maintainer's repos, with generatedAt + a stale flag (isMaintainerQualityDataStale, derived from repo sync freshness — reads cache, no heavy recompute).

Public/private boundary

  • Maintainer/owner/operator-authenticated; scoped to the caller's repos.
  • Bands, never raw numbers — the queue burden score and contributor credibility are never exposed; only bands + observable counts. Output is forbidden-term-clean.

Tests

  • test/unit/maintainer-quality-dashboard.test.ts — shaping, bands, ranking, stale-helper branches, redaction.
  • test/integration/api.test.ts — the enriched endpoint asserts the new qualityDashboard shape, access scope, bands-not-numbers, and redaction.
  • npm run test:ci green; 97%+ branch & function coverage.

🤖 Generated with Claude Code

@ghost

ghost commented Jun 12, 2026

Copy link
Copy Markdown

Note

Gittensory Gate skipped

PR closed before full evaluation. No late first comment was created.

Signal Result Evidence Action
Gate result ⚠️ Skipped #635 is no longer open. No action.

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

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

@ghost ghost added the gittensory:reviewed label Jun 12, 2026
@oktofeesh1
oktofeesh1 marked this pull request as ready for review June 12, 2026 20:03
@oktofeesh1
oktofeesh1 requested a review from JSONbored as a code owner June 12, 2026 20:03
@superagent-security

Copy link
Copy Markdown
Contributor

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

@ghost

ghost commented Jun 12, 2026

Copy link
Copy Markdown

gittensory · advisory review

Reviewed 4 changed file(s) — two independent AI reviewers.

Suggested action:Safe to merge — both reviewers found no blocking issues.

Reviewer A · gpt-oss-120b — recommends ✅ merge
This PR adds a new maintainer quality‑dashboard service that aggregates cached repo data into public‑safe quality signals and exposes it via the maintainer‑dashboard API endpoint, with comprehensive unit and integration tests. The implementation respects the public/private boundary and appears type‑correct.

Suggestions

  • Add a test case covering the repo‑cap truncation logic to verify the truncated flag is set when more repos exist than are shaped.
  • Consider documenting the new qualityDashboard field in the API spec or response type definitions for downstream consumers.
  • Review the added DB queries for performance impact when the cap is increased; a comment clarifying the expected load would help future maintainers.

Worth double-checking

  • Potential increase in DB load due to per‑repo issue and PR fetches, though capped at 12 repos.
  • If listRepoSyncStates ever returns unexpected shapes, the stale calculation could misbehave; ensure its contract remains stable.

Reviewer B · nemotron-3-120b-a12b — recommends ✅ merge
This PR adds a maintainer quality dashboard service and API endpoint that processes cached repo data into public-safe quality bands and signals. The implementation correctly avoids exposing private metrics (using bands only), includes comprehensive unit and integration tests, and follows project conventions. The API endpoint is scoped to a repo cap and properly handles staleness/truncation.

Suggestions

  • Consider adding a comment in src/api/routes.ts explaining why QUALITY_DASHBOARD_REPO_CAP is set to 12 (matches the existing open PR fetch limit for consistency).
  • In the unit test, the variable 'gamed' could be renamed to 'gamedDashboard' for clarity.
  • In the integration test, the type assertion for qualityDashboard could be split into multiple lines for readability.
  • Ensure the service handles the case where repo.authorLogin is undefined (currently handled via 'unknown' fallback, but verify this aligns with Prisma/GitHub types).

Worth double-checking

  • The dashboard computation involves looping through all PRs/issues for up to 12 repos per request - verify this doesn't cause performance issues under high load (though capped).
  • The staleness check uses scoped repos only (first 12) but reports truncation against total repo count - ensure this matches product expectations.
  • Double-check that buildCollisionReport/buildQueueHealth don't inadvertently leak private signals through their outputs (they're existing functions, but their usage here assumes public-safety).

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for this — the deterministic slop design (weighted missing_test_evidence + trivial_whitespace_churn, no LLM, 0–100 clamp) is exactly the right shape, and the migration/settings plumbing is clean. Holding for one rework: this was authored before #644 (the confirmed-contributor gate) and must integrate with it.

Required changes

  1. Block only confirmed contributors. Rebase onto main; fold the slop blocker into the post-#644 blockers array in evaluateGateCheck (src/rules/advisory.ts) above the policy.confirmedContributor === false → neutral early-return. Add tests asserting confirmedContributor: false + slopRisk>max → neutral, and confirmedContributor: truefailure.
  2. gateCheckPolicy signature. #644 made it (settings, readinessScore, confirmedContributor). Extend to also carry slopRisk (prefer an options object) and thread both at the src/queue/processors.ts call sites.
  3. De-dupe the fetch. computeSlopRiskForGate adds a 2nd listPullRequestFiles call; processors.ts already fetches PR files for annotations — hoist one fetch and share it.
  4. Tighten the guard to slopGateMode === "block" && slopGateMaxRisk != null so advisory mode does no wasted work.

Privacy is clean. Note: max achievable risk today is 55, so a maxRisk above that can never block — worth documenting.

@JSONbored JSONbored added the gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier. label Jun 13, 2026
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch 2 times, most recently from 3d9e679 to dc6a746 Compare June 13, 2026 10:13
JSONbored added a commit that referenced this pull request Jun 13, 2026
…de) (#647)

* feat(github): authoritative .gittensory.yml gate config (config-as-code)

Phase B (config-as-code foundation): let maintainers declare the Gittensory Gate's
blocker policy in `.gittensory.yml` under `gate:`, layered over dashboard settings.

- Extend the existing repo focus-manifest loader (fetch + 6h cache, graceful fallback)
  with a `gate:` section: `linkedIssue`, `duplicates`, and `readiness: { mode, minScore }`
  (each off|advisory|block). Unset fields stay null so the resolver falls back per-field.
- Precedence: `.gittensory.yml` > DB RepositorySettings > safe defaults, resolved in
  `gateCheckPolicy`. The manifest is loaded only on the enabled-gate path (cached), so
  gate-off repos pay no fetch cost.
- Only selects which deterministic blockers are active; turning the gate on/off stays a
  repository setting (`gateCheckMode`), and the Phase A confirmed-contributor invariant is
  preserved — only confirmed Gittensor contributors are ever hard-blocked.
- Dogfood: the repo's own `.gittensory.yml` (and bundled mirror) declare a `gate:` block;
  CONTRIBUTING documents the schema + precedence.

Tests: parseGateConfig (valid/invalid/partial/readiness/round-trip/YAML), gateCheckPolicy
precedence (manifest > DB, per-field fallback), and end-to-end evaluateGateCheck precedence
incl. the confirmed-contributor invariant. Coverage holds the 97% gate.

The deterministic slop-risk blocker remains tracked in #635 (contributor PR); this PR is the
config-as-code layer it can plug into.

* feat(github): make the gate fully config-driven — gate.enabled + linkedIssue in .gittensory.yml

Completes config-as-code control of the Gittensory Gate (follow-up within this PR):
- `gate.enabled: false` disables the gate from `.gittensory.yml`. The manifest is loaded when the gate
  is enabled in settings (so dormant repos stay network-free); turning the gate on for the first time
  stays a one-click repository setting (gateCheckMode).
- This repo's own `.gittensory.yml` now sets `linkedIssue: advisory` (+ a documented `enabled` example),
  so missing-linked-issue no longer hard-blocks confirmed contributors here — the durable, version-
  controlled fix for the repeated "No linked issue detected" blocks.
- Precedence unchanged: `.gittensory.yml` > DB settings > safe defaults, all through the single
  confirmedContributor-gated evaluateGateCheck path. Only confirmed contributors are ever hard-blocked.

Tests: gate.enabled parse + an end-to-end disable (config turns the gate off despite gateCheckMode
enabled); the 4 self-repo gate tests now drive their blocker via a seeded `.gittensory.yml` manifest
(proving config control); gateConfigToJson round-trips enabled. typecheck + 97% coverage hold.

* feat(github): make EVERY repository setting controllable from .gittensory.yml

Turns `.gittensory.yml` into a full settings-override layer resolved once in
resolveRepositorySettings (`.gittensory.yml` > dashboard settings > safe defaults),
so the whole app — gate on/off + blocker modes, comments, labels, surface, audience
— honours the config file, with no dashboard dependency.

- `settings:` block: a partial of the repository settings (commentMode, publicSurface,
  gateCheckMode, the gate modes, autoLabelEnabled, gittensorLabel, requireLinkedIssue,
  backfillEnabled, ...), tolerantly parsed — invalid values dropped with warnings, never throws.
- `gate:` stays as the friendly gate alias and wins over `settings:` for its fields;
  `gate.enabled` now turns the gate on/off purely from config (no dashboard step).
- The overlay happens at the SINGLE settings-resolution point for webhooks, so the gate and
  every other consumer read effective settings (removed the per-gate manifestGate threading —
  simpler and uniform).
- The manifest is negative-cached (absent manifests persisted) so loading it on every webhook is
  a cached DB read after the first call, not a repeated raw-file fetch.
- Only confirmed Gittensor contributors are ever hard-blocked — unchanged.

Tests: settings: parse (full / invalid+warnings / non-mapping / round-trip), resolveEffectiveSettings
precedence (settings: over DB, gate: over settings:, gate.enabled), end-to-end gate config control +
the confirmed-contributor invariant, and a negative-cache test. typecheck + 97% coverage hold.

* feat(github): maintainer review-content overrides via .gittensory.yml (review:)

Adds a `review:` block so maintainers control the public review-panel CONTENT from config:
- `review.footer.text` — custom footer lead copy; the Gittensor register link + Gittensory
  attribution are ALWAYS appended (the growth surface is preserved).
- `review.note` — a custom intro line shown in the panel.
- `review.fields: { <row>: false }` — show/hide individual panel rows (linkedIssue, relatedWork,
  reviewLoad, validationEvidence, openPrQueue, contributorContext, gateResult).

Maintainer-supplied text (footer/note) is validated public-safe (forbidden reward/score/wallet/
hotkey terms + local paths) at parse time and dropped if unsafe — never published. Resolved and
threaded into the full panel + the minimal-invite comment; manifest is cached (a DB read after the
settings resolution already loaded it).

Tests: review parse (footer/fields/note, unsafe-rejected, invalid/non-mapping, round-trip) plus an
end-to-end panel render (custom footer + mandatory attribution kept, intro note shown, hidden row
absent). CONTRIBUTING documents the block. typecheck + 97% coverage hold.
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch from dc6a746 to d60b5cc Compare June 13, 2026 21:40
JSONbored added a commit that referenced this pull request Jun 13, 2026
The UI build emits a served static asset, client/downloads/gittensory-extension.zip
(generated by scripts/build-extension.mjs; linked from the extension route; asserted 200
by smoke-production.mjs). The "Validate downloaded artifact" step's extension allowlist
omitted `zip`, so it rejected the bundle and EVERY UI Preview Deploy failed at validation:

    ##[error]Artifact contains unexpected file types — refusing to deploy:
    ./client/downloads/gittensory-extension.zip

Because the deploy aborted before createDeployment, no preview Deployment/environment_url
was ever recorded, so Reviewbot's before/after table stayed stuck on "Rendering preview…"
for every UI PR (e.g. #635).

A .zip here is a passive download asset wrangler only uploads (never executes), so adding
it to the allowlist doesn't weaken the fork-PR defense — same risk class as the wasm/font
binaries already permitted.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch 2 times, most recently from 27a51d2 to c7092b8 Compare June 14, 2026 13:11
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch from c7092b8 to b980395 Compare June 14, 2026 15:29
@dosubot dosubot Bot added size:L and removed size:M labels Jun 14, 2026
@oktofeesh1 oktofeesh1 changed the title feat(github-app): deterministic slop gate (slopGateMode) feat(api): maintainer quality-dashboard service + endpoint Jun 14, 2026
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch from b980395 to df38014 Compare June 14, 2026 16:25
@oktofeesh1

Copy link
Copy Markdown
Contributor Author

Heads up — this PR was repurposed. The original slop-gate work (#532) was implemented upstream in #716, so I reset this branch and it now implements #557 (maintainer quality-dashboard service + endpoint) — see the updated title/description. The earlier changes requested review refers to the old slop content and no longer applies. It's conflict-free against current main and CI is green; ready for a fresh review whenever you have a moment. 🙏

Carves out the non-visual data service behind the maintainer quality dashboard
(JSONbored#557): new src/services/maintainer-quality-dashboard.ts shapes ALREADY-cached
repo data into per-repo queue-health bands, duplicate/collision trends, aggregate
quality signals, and top contributors by quality BAND. Enriches
GET /v1/app/maintainer-dashboard (scoped to the maintainer's repos, generatedAt +
stale flag, reads cache only). Public-safe: bands never raw credibility/reward
numbers; only observable counts exposed.

Fixes JSONbored#557

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@oktofeesh1
oktofeesh1 force-pushed the feat/issue-571-slop-gate branch from df38014 to 8736440 Compare June 14, 2026 16:46
@JSONbored
JSONbored self-requested a review June 14, 2026 17:33
@dosubot dosubot Bot added the lgtm label Jun 14, 2026
@JSONbored
JSONbored merged commit e64499a into JSONbored:main Jun 14, 2026
7 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jun 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:priority Maintainer-selected Gittensor priority — scores a 1.5x multiplier.

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

feat(api): maintainer quality-dashboard service + endpoint

2 participants