Skip to content

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

Merged
JSONbored merged 5 commits into
mainfrom
feat/gittensory-yml-gate-config
Jun 13, 2026
Merged

feat(github): authoritative .gittensory.yml gate config (config-as-code)#647
JSONbored merged 5 commits into
mainfrom
feat/gittensory-yml-gate-config

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Phase B (foundation): config-as-code gate policy

Lets maintainers declare the Gittensory Gate's blocker policy in .gittensory.yml under gate:, 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.

gate:
  duplicates: block            # block | advisory | off
  readiness:
    mode: advisory             # block | advisory | off
    minScore: 60
  # linkedIssue: advisory      # optional; falls back to the dashboard setting when unset

What it does

  • Extends the existing repo focus-manifest loader (src/signals/focus-manifest.ts / -loader.ts) with a gate: section — linkedIssue, duplicates, readiness: { mode, minScore }, each off | advisory | block. Reuses the loader's fetch + 6h cache + graceful-fallback (a broken/missing manifest degrades to deterministic signals, never throws). Unset fields stay null.
  • Precedence: .gittensory.yml > DB RepositorySettings > safe defaults, resolved in gateCheckPolicy (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.
  • Single evaluation path preserved. It only chooses which deterministic blockers are active — turning the gate on/off stays a repository setting (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).
  • Dogfood: the repo's own .gittensory.yml (+ bundled mirror, kept byte-aligned) now declare a gate: 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)

  • parseFocusManifest gate config: valid / invalid (warns, never throws) / partial / readiness block / clamping / non-mapping / gateConfigToJson cache round-trip / YAML.
  • gateCheckPolicy precedence: manifest overrides each mode; per-field fallback to DB; end-to-end evaluateGateCheck proving a manifest linkedIssue: block blocks 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 typecheck clean · full vitest green · npm run test:coverage97.02% branches (≥97% gate) · git diff --check clean.

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.

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.
@ghost

ghost commented Jun 13, 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 #647 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 13, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

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

@ghost

ghost commented Jun 13, 2026

Copy link
Copy Markdown

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 · gpt-oss-120b — recommends ✅ merge
This PR adds full config‑as‑code support for .gittensory.yml, including gate, settings, and review overrides, and integrates them throughout the pipeline with new parsing, resolution, and comment generation logic. The changes are comprehensive, well‑tested, and respect the public‑safe sanitization constraints.

Suggestions

  • Verify that the function sanitizePanelText used in buildPublicPrIntelligenceComment exists and applies the same public‑safe checks as sanitizePublicComment.
  • Add a unit test that confirms a non‑public‑safe footer or note is dropped and logged as a warning.
  • Run the full test suite to ensure no other callers of buildPublicPrIntelligenceComment need the new review argument (the default is safe).

Worth double-checking

  • If sanitizePanelText is missing or behaves incorrectly, public‑unsafe content could be emitted.
  • Any existing code that constructs a FocusManifest manually must now include the new fields; missed updates could cause undefined behavior.

Reviewer B · nemotron-3-120b-a12b — recommends ✅ merge
This PR introduces config-as-code via .gittensory.yml to authoritative override repository settings (gate behavior, review panel customization, etc.) while preserving the confirmed-contributor-only blocking invariant. Changes are extensive but cohesive, with proper layering (.gittensory.yml > DB > defaults), thorough tests, and maintained public/private safety boundaries. The implementation correctly handles manifest parsing, caching, and effective settings resolution.

Suggestions

  • Consider adding a comment in resolveRepositorySettings clarifying that the manifest is loaded per-webhook (with caching) to avoid confusion about freshness.
  • In src/signals/focus-manifest.ts, the parsePublicSafeText function could use a constant for MAX_ITEM_LENGTH instead of a magic number (though it's imported, verifying consistency is good).
  • The gateCheckPolicy function export in queue/processors.ts might benefit from a JSDoc comment explaining its role in the gate evaluation pipeline.

Worth double-checking

  • Ensure the TTL for cached manifests is appropriate so newly added .gittensory.yml files are picked up promptly (currently relies on persistRepoFocusManifest TTL).
  • Verify that all public-facing text from manifest (footerText, note) runs through sanitizePublicComment/isFocusManifestPublicSafe - the code shows this is done.
  • Confirm that the review.fields show/hide functionality doesn't accidentally hide critical gate/security information (it's cosmetic only per comments).

@ghost ghost added the gittensory-review label Jun 13, 2026
@JSONbored JSONbored self-assigned this Jun 13, 2026
…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.
@JSONbored
JSONbored merged commit 6e5757b into main Jun 13, 2026
10 checks passed
@JSONbored
JSONbored deleted the feat/gittensory-yml-gate-config branch June 13, 2026 11:26
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jun 13, 2026
@github-actions github-actions Bot mentioned this pull request Jun 13, 2026
12 tasks
JSONbored added a commit that referenced this pull request Jun 14, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant