Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude/skills/contributing-to-loopover/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ minor-version deprecation cycle.
with `loopover_check_before_start` + `loopover_validate_linked_issue`.
- **A linked, currently-open, unassigned, eligible issue is always required before opening a PR** —
there is no "small enough to skip it" exemption, no matter how self-evident the fix looks. This
holds regardless of what the committed root `.gittensory.yml`'s `linkedIssuePolicy` says: that
holds regardless of what the committed root `.loopover.yml`'s `linkedIssuePolicy` says: that
file is a non-representative **example** checked into the repo, not the live enforced rule. If no
suitable open issue exists, open one yourself first, then link it from the PR.
- **Run the pre-start checks** via MCP: `loopover_check_before_start` (is it claimed / a duplicate
Expand All @@ -146,7 +146,7 @@ minor-version deprecation cycle.
- Comments: sparse but dense; explain *why*, anchor non-obvious logic to an issue number
(`(#1234)`). Don't narrate the obvious.
- **Config-as-code parity:** a new per-repo gate/setting field must be wired in *every* site
(DB migration + Drizzle/types + the settings resolver + OpenAPI + the `.gittensory.yml` schema)
(DB migration + Drizzle/types + the settings resolver + OpenAPI + the `.loopover.yml` schema)
in the **same** PR — partial wiring fails review. (See the per-repo-setting checklist in
`reference.md`.)
- UI: use design tokens (`text-token-*`, `rounded-token`, `border-hairline`, …) in
Expand Down Expand Up @@ -250,7 +250,7 @@ Run the MCP predictor with your actual PR shape:
- `loopover_lint_pr_text` — your commit + PR body must read as **strong**: Conventional Commit
subject, traceability (a linked, currently-open, eligible issue — no no-issue rationale accepted),
and a body that says what changed, why, and how it was validated.
- `gittensory_predict_gate` — simulate the repo's public `.gittensory.yml` gate. Resolve any
- `gittensory_predict_gate` — simulate the repo's public `.loopover.yml` gate. Resolve any
predicted blocker (the duplicate-PR blocker is the one that hard-fails here) before opening.

Resolve **every** finding before you push. The engine MERGES only a clean + green + gate-passing PR
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/contributing-to-loopover/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Implications for you:
- Owner / automation-bot PRs are exempt from auto-close, and crucial guarded-path PRs are held — but
**assume you are a contributor** and that adverse = close.

`.gittensory.yml` (the public config you can predict against) sets the gate *modes* (`linkedIssue:
`.loopover.yml` (the public config you can predict against) sets the gate *modes* (`linkedIssue:
advisory`, `duplicates: block`, `readiness: advisory/60`, AI review off) and the focus manifest
(`wantedPaths`: `src/ packages/ test/ migrations/ scripts/ review-enrichment/ .github/workflows/
wrangler.jsonc apps/gittensory-ui/`; `blockedPaths`: `site/ CNAME **/lovable/**`; `linkedIssuePolicy: preferred`;
Expand Down Expand Up @@ -260,9 +260,9 @@ absence of forbidden terms.
Wire it in **every** site in the **same** PR, or review fails:
1. DB migration (`migrations/NNNN_*.sql`) for the new column/table.
2. Drizzle schema + types (`src/db/schema.ts`, `src/types.ts`).
3. The settings resolver / focus-manifest loader (so `.gittensory.yml` > DB > defaults still holds).
3. The settings resolver / focus-manifest loader (so `.loopover.yml` > DB > defaults still holds).
4. OpenAPI (`npm run ui:openapi`) for any new request/response field.
5. The `.gittensory.yml` schema + docs so contributors can set it.
5. The `.loopover.yml` schema + docs so contributors can set it.
6. Tests covering the new field's resolution precedence + the gate behavior it drives.

---
Expand Down
6 changes: 3 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# code path is fully inert — the review behaves as if the feature did not exist.
#
# See https://gittensory.aethereal.dev/docs/tuning for the full reference
# (flags, per-repo `.gittensory.yml` settings, and secret descriptions).
# (flags, per-repo `.loopover.yml` settings, and secret descriptions).

# =============================================================================
# 1. Review feature flags (GITTENSORY_REVIEW_*)
Expand Down Expand Up @@ -163,7 +163,7 @@ GITTENSORY_REVIEW_DRAFT=false
# --- Optional (capability-gated; degrade safely when absent) -----------------
# GITHUB_OAUTH_CLIENT_ID= # GitHub OAuth (dashboard sign-in, draft flow)
# GITHUB_OAUTH_CLIENT_SECRET= # GitHub OAuth; also required by the draft flow
# GITHUB_PUBLIC_TOKEN= # unauthenticated public-GitHub reads (.gittensory.yml fetch)
# GITHUB_PUBLIC_TOKEN= # unauthenticated public-GitHub reads (.loopover.yml fetch)
# TOKEN_ENCRYPTION_SECRET= # AES-256-GCM master secret for maintainer BYOK keys at rest
# DRAFT_TOKEN_ENCRYPTION_SECRET= # AES-256-GCM secret for the contributor OAuth token (draft flow)
# GITTENSORY_REVIEW_STATS_TOKEN= # bearer token guarding the stats data endpoint
Expand Down Expand Up @@ -706,7 +706,7 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# # shared frontier claude-code/codex chain. Unset = every advisory
# # capability stays on the shared chain. Even when set, a
# # capability only actually routes through it once the repo's
# # .gittensory.yml settings.advisoryAiRouting also opts it in
# # .loopover.yml settings.advisoryAiRouting also opts it in
# # (global default + per-repo override) -- this binding alone
# # changes nothing.
# AI_ADVISORY_API_KEY= # bearer credential for AI_ADVISORY_BASE_URL, if it requires one.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/visual-capture-fallback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ name: LoopOver Visual Capture Fallback
# preview-deploy pipeline): copy this file, unmodified, into the target repo's `.github/workflows/` at this
# EXACT path and name (`visual-capture-fallback.yml` / "LoopOver Visual Capture Fallback") -- gittensory's
# dispatch call and workflow_run listener both key off this fixed name. Then set `review.visual.actions_fallback:
# true` in that repo's `.gittensory.yml` (see .gittensory.yml.example) to opt in; it activates ONLY when the
# true` in that repo's `.loopover.yml` (see .loopover.yml.example) to opt in; it activates ONLY when the
# existing discovery chain finds no preview at all, so a repo with its own CI-produced preview is unaffected.

on:
Expand Down
6 changes: 3 additions & 3 deletions .gittensory.minimal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# .gittensory.minimal.yml — smallest safe starter config for a new repo
# ============================================================================
#
# Copy this file to your repo root as `.gittensory.yml` and customize from here.
# (This filename is not read directly — only `.gittensory.yml` / `.github/gittensory.yml` are.)
# Copy this file to your repo root as `.loopover.yml` and customize from here.
# (This filename is not read directly — only `.loopover.yml` / `.github/loopover.yml` are.)
# Also shipped at config/examples/gittensory.minimal.yml for self-host operators.
# For every supported field, defaults, and examples see `.gittensory.yml.example` or
# For every supported field, defaults, and examples see `.loopover.yml.example` or
# config/examples/gittensory.full.yml.
#
# Safe by default:
Expand Down
2 changes: 1 addition & 1 deletion .gittensory.yml → .loopover.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ testExpectations:
issueDiscoveryPolicy: discouraged

# Authoritative gate config, config-as-code (layered OVER dashboard repository settings:
# .gittensory.yml > DB settings > safe defaults). ONLY confirmed Gittensor contributors are ever
# .loopover.yml > DB settings > safe defaults). ONLY confirmed Gittensor contributors are ever
# hard-blocked (see PR #644); these fields only choose what the gate does, not who it applies to.
gate:
# enabled: false # set false to disable the gate from config (turning it on is a dashboard setting)
Expand Down
14 changes: 7 additions & 7 deletions .gittensory.yml.example → .loopover.yml.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ============================================================================
# .gittensory.yml — per-repo configuration for gittensory CI & gittensory review
# .loopover.yml — per-repo configuration for gittensory CI & gittensory review
# ============================================================================
#
# Drop this file at the root of any repo gittensory watches to tune how the
Expand All @@ -10,10 +10,10 @@
# config/examples/gittensory.minimal.yml — smallest safe starter (gate off, observe-only autonomy)
# config/examples/gittensory.full.yml — exhaustive reference (body synced with this file)
# .gittensory.minimal.yml — same minimal starter at repo root
# .gittensory.yml.example — this file
# .loopover.yml.example — this file
#
# WHERE IT LIVES (first match wins):
# .gittensory.yml → .github/gittensory.yml → .gittensory.json → .github/gittensory.json
# .loopover.yml → .github/loopover.yml → .loopover.json → .github/loopover.json
#
# PRECEDENCE (most specific wins):
# this file > per-repo dashboard/API settings > built-in safe defaults
Expand Down Expand Up @@ -404,7 +404,7 @@ gate:
# defaults.
#
# SELF-HOST ONLY (`review.shared_config`, #2046): when `GITTENSORY_REPO_CONFIG_DIR` is mounted,
# place a shared review base at `${GITTENSORY_REPO_CONFIG_DIR}/_shared/.gittensory.yml` (see
# place a shared review base at `${GITTENSORY_REPO_CONFIG_DIR}/_shared/.loopover.yml` (see
# `config/examples/shared.gittensory.yml`). Per-repo `review:` keys overlay it field-by-field —
# repo value wins when set, shared fills gaps, defaults stay byte-identical. Absent shared base is
# the common case and changes nothing. A malformed shared base warns and is ignored (never blocks a
Expand Down Expand Up @@ -635,7 +635,7 @@ settings:
# rarely formally assigned to a specific contributor), the reward label needs this flag to ever reach them.
# Disabled by default (no mappings) -- a self-hoster opts in per repo. If your labels carry reward or
# moderation weight, configure this in PRIVATE per-repo/global config (see `config/examples/README.md`)
# rather than the public `.gittensory.yml`, so contributors cannot see the exact mapping rules. A per-repo
# rather than the public `.loopover.yml`, so contributors cannot see the exact mapping rules. A per-repo
# `mappings` override in the private-config layer REPLACES the global default list wholesale -- it does
# not merge with it.
# linkedIssueLabelPropagation:
Expand Down Expand Up @@ -918,7 +918,7 @@ settings:
# chatQaFrontierFallback: false # Opt-in only: falls back to the frontier env.AI chain if env.AI_ADVISORY is unconfigured, instead of declining. Meaningless unless chatQa is also true. Default: false.
# intentRouting: false # Closed-set intent classifier for unrecognized @gittensory mentions -> existing Q&A commands only. Ollama-ONLY, same as chatQa (never uses chatQaFrontierFallback). Co-requisite: commandRateLimitPolicy: hold. Default: false.

# Maintainer AI review tuning (`.gittensory.yml` top-level `review:` block). These knobs shape the advisory AI
# Maintainer AI review tuning (`.loopover.yml` top-level `review:` block). These knobs shape the advisory AI
# review prompt and file selection only — gate/slop/secret-scan are unaffected.
# review:
# # Globs whose matching files are dropped from the AI review (lockfiles, generated output, etc.).
Expand Down Expand Up @@ -1073,7 +1073,7 @@ settings:
# # Config-as-code enable/disable for this repo, layered ON TOP OF (never a replacement for) the
# # GITTENSORY_REVIEW_SCREENSHOTS + per-repo cutover-allowlist env-var gate above (#4083). Bool or null.
# # Default: null (unset) ⇒ defers entirely to that env-var gate's own decision -- byte-identical to today.
# # Explicit `false` (set once at the global-default `.gittensory.yml`, or overridden per-repo here) forces
# # Explicit `false` (set once at the global-default `.loopover.yml`, or overridden per-repo here) forces
# # capture off for this repo even when the env-var gate would otherwise allow it. Explicit `true` opts this
# # repo back in at a layer where a broader default disabled it -- it does NOT bypass the env-var gate
# # itself, so the env vars remain the outer infra-availability switch.
Expand Down
5 changes: 2 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ Public GitHub surfaces:
app/infra state) resolves to a neutral, non-blocking gate. Adding a blocker must keep it
confirmed-contributor-gated through `evaluateGateCheck`.

Config as code (`.loopover.yml`; the legacy `.gittensory.yml` filename is dual-read indefinitely, #4773) — every repository setting is controllable from the config file:
Config as code (`.loopover.yml`) — every repository setting is controllable from the config file:

- **`settings:`** is a partial of the repository settings: any behaviour a maintainer can toggle in the
dashboard can be set here as code — `commentMode`, `publicAudienceMode`, `publicSurface`, `checkRunMode`,
Expand All @@ -303,8 +303,7 @@ Config as code (`.loopover.yml`; the legacy `.gittensory.yml` filename is dual-r
a hand-maintained AGENTS.md/CLAUDE.md — absent it, an existing hand-written file is left alone and
generation is skipped.
- Precedence: `.loopover.yml` `gate:` > `.loopover.yml` `settings:` > dashboard repository settings >
safe defaults; unset fields fall back to the next layer (the legacy `.gittensory.yml` filename works
identically wherever `.loopover.yml` does, #4773). The committed root `.gittensory.yml` is the
safe defaults; unset fields fall back to the next layer. The committed root `.loopover.yml` is the
worked example. Resolved once in `resolveRepositorySettings`, so the whole app honours the file.
- The config chooses **what** LoopOver does (gate on/off, blockers, comments, labels, surface, panel
content); it never changes **who** can be blocked — only confirmed Gittensor contributors are ever
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ LoopOver CI and LoopOver review score, gate, and comment on pull requests. The r
- **CI + full-file grounding** — grounds the AI reviewer with the PR's finished CI status and the full post-change content of the changed files, so claims are verified against reality instead of predicted.
- **Codebase RAG** — retrieval-augmented context that queries the codebase vector index for related callers, modules, and conventions and appends them to the reviewer prompt (additive only; inert until an index exists).
- **Submitter-reputation gating** — an internal-only spend control that downgrades new / burst / low-reputation submitters to a deterministic-only review, never surfaced on any public comment, label, or check.
- **Unified review comment** — renders the public PR feedback as one in-place comment instead of multiple panels. With `.loopover.yml`'s `review.changed_files_summary` also on (off by default; legacy `.gittensory.yml` name also still works, indefinitely), it gains a deterministic, no-AI "Changed files" collapsible: one row per file category (source/test/docs/config/generated), with file counts and +/- totals.
- **Unified review comment** — renders the public PR feedback as one in-place comment instead of multiple panels. With `.loopover.yml`'s `review.changed_files_summary` also on (off by default), it gains a deterministic, no-AI "Changed files" collapsible: one row per file category (source/test/docs/config/generated), with file counts and +/- totals.
- **Per-repo activation** — capabilities roll forward (and back) one flag and one repo at a time via the `GITTENSORY_REVIEW_REPOS` allowlist.

**Check-run and comment surfaces, disambiguated** (a common point of confusion — these are three independent, separately-configured things, not layers of the same feature):
Expand All @@ -46,7 +46,7 @@ LoopOver CI and LoopOver review score, gate, and comment on pull requests. The r
- **`LoopOver Context`** (`settings.checkRunMode` / `settings.checkRunDetailLevel`, off by default) — a separate, purely advisory Check Run. At its default `checkRunDetailLevel: minimal` it publishes no findings at all; even at `standard`/`deep` it only re-renders content already shown elsewhere. Never make this one required.
- **Inline review comments** (`GITTENSORY_REVIEW_INLINE_COMMENTS` + `.loopover.yml`'s `review.inline_comments`, off by both by default) — real, reply-able line-anchored PR review comment threads (CodeRabbit-style). This is the ONLY one of the three that posts an interactive per-line thread; the two check runs above never do. With `.loopover.yml`'s `review.suggestions` also on, a precise line-anchored fix is additionally rendered as a one-click, committable GitHub suggested-change block. With `review.finding_categories` also on (off by default), each finding is additionally tagged with a category — security/correctness/performance/maintainability/tests/style — in both the inline comment label and the unified comment's "Finding categories" collapsible; a deterministic path/keyword fallback covers whatever the model omits.

See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the full flag, setting, and `.loopover.yml` reference (the legacy `.gittensory.yml` filename is dual-read indefinitely — #4773 — so an existing repo's committed file keeps working unchanged).
See [Tuning your reviews](https://gittensory.aethereal.dev/docs/tuning) for the full flag, setting, and `.loopover.yml` reference.

## Start Here

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ describe("ConfigGeneratorYamlPreview", () => {
expect(screen.getByText("Preview")).toBeTruthy();
// The filename appears both in the descriptive copy and the CodeBlock's own filename label.
expect(screen.getAllByText(".loopover.yml").length).toBeGreaterThanOrEqual(2);
// The legacy filename is still mentioned as also-supported (#4773), not silently dropped.
expect(screen.getAllByText(".gittensory.yml").length).toBeGreaterThanOrEqual(1);
expect(screen.getByText(/combine: consensus/)).toBeTruthy();
expect(screen.getByText(/provider: anthropic/)).toBeTruthy();
expect(screen.getByRole("button", { name: "Copy code" })).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import { formStateToYaml, type GeneratorFormState } from "@/lib/config-generator
* Read-only `.loopover.yml` preview for the config generator (#2210, part of #1683): renders the
* current GeneratorFormState as text via CodeBlock (built-in copy-to-clipboard) so the output is
* explicit and reviewable before a self-hoster saves or copies it. Purely presentational — field-group
* panels own collecting the form state. The legacy `.gittensory.yml` filename works identically if a
* self-hoster already has one committed (#4773) — this preview just names the new canonical filename.
* panels own collecting the form state.
*/
export function ConfigGeneratorYamlPreview({ formState }: { formState: GeneratorFormState }) {
return (
<section className="rounded-token border-hairline bg-card p-5">
<h2 className="font-display text-token-lg font-semibold">Preview</h2>
<p className="mt-1 text-token-xs text-muted-foreground">
The exact <code className="font-mono">.loopover.yml</code> this configuration would produce
(the legacy <code className="font-mono">.gittensory.yml</code> name also still works).
The exact <code className="font-mono">.loopover.yml</code> this configuration would produce.
Nothing is saved until you copy it into your repo.
</p>
<div className="mt-4">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,7 @@ type FocusManifestResponse = { manifest: unknown };

/**
* Edit the repo's focus manifest as JSON. The manifest is repo-public config-as-code (it mirrors
* `.loopover.yml`, or the legacy `.gittensory.yml`, #4773); this surface lets a maintainer edit the
* API-record copy without committing a file.
* `.loopover.yml`); this surface lets a maintainer edit the API-record copy without committing a file.
*/
function FocusManifestEditor({ base }: { base: string | null }) {
const [text, setText] = useState("");
Expand Down
Loading
Loading