feat(github): authoritative .gittensory.yml gate config (config-as-code) - #647
Conversation
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.
|
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 13 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
|
…edIssue 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.
…sory.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.
… (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.
…amp (#701) (#708) Make the maintainer payoff self-evident at install: a repo-specific demo of what Gittensory would surface, plus a one-click advisory ramp. - `src/services/maintainer-activation.ts`: `buildMaintainerActivationPreview` runs the deterministic advisory engine (buildPullRequestAdvisory) over the repo's most recent PRs and returns "here's what Gittensory would have surfaced on N of your last M PRs" — per-PR findings + distinct finding-code counts + the current gate mode + whether AI review is configured + the single recommended next action. Pure over already-loaded data; NEVER runs AI (no surprise cost) — it only reports whether AI review is already on. - `recommendedAdvisoryActivationSettings()`: the one-click patch — enables the gate + deterministic rules in ADVISORY (non-blocking) mode, advisory-first per the #525 cross-cutting AC. AI review stays opt-in (separate ai-review route). - Routes (maintainer-scoped via requireRepoMaintainer; new `isRepoActivationPath` in canSessionAccessPath): GET `/v1/repos/:owner/:repo/activation-preview` and POST `/v1/repos/:owner/:repo/activation` (merges the advisory patch onto current settings, preserving unrelated fields). Reuses the existing gate engine + repo-settings infra (#647/#648); does not duplicate settings-preview (which previews ONE hypothetical PR — this previews the repo's REAL recent PRs). The dashboard rendering of this preview stays owner-led (visual). Email/AI live-preview remain out of scope. Tests: service unit (finding summary, recommended-action logic, AI-config flag, empty repo, sample-size clamp + recency fallback, code-count tie-break) + integration (maintainer preview + one-click flip persists; non-maintainer 403; server-to-server allowed). 97% coverage gate green; workers tests pass.
Phase B (foundation): config-as-code gate policy
Lets maintainers declare the Gittensory Gate's blocker policy in
.gittensory.ymlundergate:, layered over the dashboard repository settings — the CodeRabbit-style config-as-code model none of the in-flight gate PRs cover. Builds directly on the confirmed-contributor model from #644.What it does
src/signals/focus-manifest.ts/-loader.ts) with agate:section —linkedIssue,duplicates,readiness: { mode, minScore }, eachoff | advisory | block. Reuses the loader's fetch + 6h cache + graceful-fallback (a broken/missing manifest degrades to deterministic signals, never throws). Unset fields staynull..gittensory.yml> DBRepositorySettings> safe defaults, resolved ingateCheckPolicy(src/queue/processors.ts). The manifest is loaded only on the enabled-gate path (cached), so the ~all gate-off repos pay no fetch cost.gateCheckMode), and the fix(github): block only confirmed Gittensor contributors in the PR Gate #644 invariant holds: only confirmed Gittensor contributors are ever hard-blocked, regardless of the manifest (verified by test)..gittensory.yml(+ bundled mirror, kept byte-aligned) now declare agate:block; CONTRIBUTING documents the schema + precedence. The chosen values match current effective behavior, so this repo's gate is unchanged.Tests / validation (from repo root)
parseFocusManifestgate config: valid / invalid (warns, never throws) / partial / readiness block / clamping / non-mapping /gateConfigToJsoncache round-trip / YAML.gateCheckPolicyprecedence: manifest overrides each mode; per-field fallback to DB; end-to-endevaluateGateCheckproving a manifestlinkedIssue: blockblocks a confirmed author's no-issue PR even when DB is advisory, the inverse relief, and that a non-confirmed author still resolves to neutral.npm run typecheckclean · fullvitestgreen ·npm run test:coverage— 97.02% branches (≥97% gate) ·git diff --checkclean.Scope note
This is the config-as-code foundation. The deterministic slop-risk blocker stays tracked in #635 (contributor PR) — once it's rebased onto #644's single path, it plugs straight into this config (
gate.slop). Enabling the gate purely via yml (vs. the dashboard) is deferred to avoid a manifest fetch on every gate-off repo.