feat(api): maintainer quality-dashboard service + endpoint - #635
Conversation
|
Note Gittensory Gate skippedPR closed before full evaluation. No late first comment was created.
💰 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. |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
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 · Suggestions
Worth double-checking
Reviewer B · Suggestions
Worth double-checking
|
JSONbored
left a comment
There was a problem hiding this comment.
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
- Block only confirmed contributors. Rebase onto
main; fold the slop blocker into the post-#644blockersarray inevaluateGateCheck(src/rules/advisory.ts) above thepolicy.confirmedContributor === false → neutralearly-return. Add tests assertingconfirmedContributor: false+ slopRisk>max → neutral, andconfirmedContributor: true→ failure. gateCheckPolicysignature. #644 made it(settings, readinessScore, confirmedContributor). Extend to also carryslopRisk(prefer an options object) and thread both at thesrc/queue/processors.tscall sites.- De-dupe the fetch.
computeSlopRiskForGateadds a 2ndlistPullRequestFilescall;processors.tsalready fetches PR files for annotations — hoist one fetch and share it. - Tighten the guard to
slopGateMode === "block" && slopGateMaxRisk != nullso 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.
3d9e679 to
dc6a746
Compare
…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.
dc6a746 to
d60b5cc
Compare
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>
27a51d2 to
c7092b8
Compare
c7092b8 to
b980395
Compare
b980395 to
df38014
Compare
|
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 |
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>
df38014 to
8736440
Compare
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
src/services/maintainer-quality-dashboard.ts—buildMaintainerQualityDashboard(...)shapes ALREADY-cached repo data (issues + PRs) into:buildCollisionReport)GET /v1/app/maintainer-dashboardwithqualityDashboard, scoped to the maintainer's repos, withgeneratedAt+ astaleflag (isMaintainerQualityDataStale, derived from repo sync freshness — reads cache, no heavy recompute).Public/private boundary
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 newqualityDashboardshape, access scope, bands-not-numbers, and redaction.npm run test:cigreen; 97%+ branch & function coverage.🤖 Generated with Claude Code