From a42f0cb0b8ae0f7c3132090bd232a37889d8cb63 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:44:09 -0700 Subject: [PATCH 1/3] docs(core): rename gittensory prose to loopover in signals/selfhost/services Rebrand cutover cleanup: update brand-name prose in comments across 31 files in src/signals, src/selfhost, and src/services, plus the matching test/unit/selfhost-ai.test.ts assertions for a tmpdir prefix rename in src/selfhost/ai.ts. Comment-only (plus the tmpdir prefix), no behavior change. Includes the matching engine-twin fix for src/signals/change-guardrail.ts (packages/loopover-engine/src/signals/change-guardrail.ts) to keep scripts/check-engine-parity.ts passing. Deliberate legacy references left untouched: the 'gittensory-native' review_audit source discriminator, GITTENSORY-[A-Z0-9]+ Sentry issue slugs, and the gittensory-app.env self-host default path (a separate functional follow-up, out of scope for this prose-only sweep). --- .../src/signals/change-guardrail.ts | 4 ++-- src/selfhost/ai.ts | 8 ++++---- src/selfhost/audit.ts | 2 +- src/selfhost/d1-adapter.ts | 4 ++-- src/selfhost/d1-size-probe.ts | 4 ++-- src/selfhost/health.ts | 2 +- src/selfhost/load-file-secrets.ts | 2 +- src/selfhost/migrate.ts | 2 +- src/selfhost/orb-collector.ts | 6 +++--- src/selfhost/pg-dialect.ts | 2 +- src/selfhost/private-config.ts | 8 ++++---- src/selfhost/queue-common.ts | 2 +- src/selfhost/vectorize.ts | 2 +- src/services/ai-review.ts | 2 +- src/services/draft.ts | 4 ++-- src/services/maintainer-recap.ts | 2 +- src/services/notify-discord.ts | 2 +- src/services/outcome-calibration.ts | 4 ++-- src/services/plan-dag.ts | 2 +- src/signals/boundary-test-generation.ts | 10 +++++----- src/signals/change-guardrail.ts | 4 ++-- src/signals/check-summary.ts | 2 +- src/signals/focus-manifest.ts | 2 +- src/signals/local-branch.ts | 2 +- src/signals/local-scorer.ts | 2 +- src/signals/path-matchers.ts | 2 +- src/signals/reward-risk.ts | 2 +- src/signals/slop.ts | 2 +- src/signals/test-evidence.ts | 2 +- src/signals/unlinked-issue-candidates.ts | 2 +- test/unit/selfhost-ai.test.ts | 14 +++++++------- 31 files changed, 55 insertions(+), 55 deletions(-) diff --git a/packages/loopover-engine/src/signals/change-guardrail.ts b/packages/loopover-engine/src/signals/change-guardrail.ts index 2bbabbb0f0..dadac82942 100644 --- a/packages/loopover-engine/src/signals/change-guardrail.ts +++ b/packages/loopover-engine/src/signals/change-guardrail.ts @@ -1,5 +1,5 @@ // Convergence safety: the hard-guardrail path check for the auto-maintain layer (#778). Changed paths that -// match a repo's configured hardGuardrailGlobs force MANUAL review — gittensory must never auto-merge OR +// match a repo's configured hardGuardrailGlobs force MANUAL review — loopover must never auto-merge OR // auto-close a PR that touches a guarded path. Ported verbatim from // reviewbot core/change-classifier.ts — the mechanism that prevents the awesome-claude #4196 incident class // (a weakened policy script auto-merging because its path wasn't guarded). Pure + dependency-free. @@ -118,7 +118,7 @@ export function matchesAny(path: string, globs: string[]): boolean { /** * The changed paths (if any) that trip a hard guardrail. A non-empty result means the PR touches a guarded - * path and MUST fall through to a human — gittensory may neither auto-merge nor auto-close it. Pure. + * path and MUST fall through to a human — loopover may neither auto-merge nor auto-close it. Pure. */ export function changedPathsHittingGuardrail(changedPaths: string[], hardGuardrailGlobs: string[]): string[] { if (hardGuardrailGlobs.length === 0) return []; diff --git a/src/selfhost/ai.ts b/src/selfhost/ai.ts index c0bb008f68..e1a0ea983a 100644 --- a/src/selfhost/ai.ts +++ b/src/selfhost/ai.ts @@ -1,8 +1,8 @@ -// Self-host AI provider (#979). gittensory calls `env.AI.run(model, { messages, max_tokens, temperature })` +// Self-host AI provider (#979). loopover calls `env.AI.run(model, { messages, max_tokens, temperature })` // and reads `{ response }`. On self-host we provide an Ai-shaped adapter selected by AI_PROVIDER: // • ollama / openai-compatible / openai — any OpenAI-compatible /chat/completions endpoint (BYO key) // • claude-code / codex — a locally-authenticated CLI SUBSCRIPTION, run as a subprocess -// Absent (no AI_PROVIDER) → env.AI is undefined → gittensory's AI summary degrades to "unavailable" and the +// Absent (no AI_PROVIDER) → env.AI is undefined → loopover's AI summary degrades to "unavailable" and the // review proceeds deterministically. Every path returns `{ response: string }` (or throws → the caller // records an error and degrades — never a silent wrong answer). @@ -410,7 +410,7 @@ export function createAnthropicAi(opts: { apiKey: string; model?: string | undef // // NOTE (#4284): the reusable half of this pattern — a parameterized allowlist builder + secret redaction — now also // lives in `@loopover/engine` (`SUBPROCESS_CLI_ENV_ALLOWLIST`, `buildAllowlistedEnv`, `SECRET_PATTERNS`, -// `redactSecrets`) so the coming gittensory-miner coding-agent drivers can depend on one source of truth. This copy +// `redactSecrets`) so the coming loopover-miner coding-agent drivers can depend on one source of truth. This copy // is deliberately kept parallel for now (the review path's `subscriptionCliEnv` also folds in CLI-specific PATH // resolution); keep the two in sync, or shim this onto the engine copy (like `src/rules/predicted-gate.ts` does) in // a follow-up if it drifts. @@ -520,7 +520,7 @@ async function isolatedCliCwd(): Promise { const { mkdtemp } = await import("node:fs/promises"); const { tmpdir } = await import("node:os"); const { join } = await import("node:path"); - return mkdtemp(join(tmpdir(), "gittensory-ai-")); + return mkdtemp(join(tmpdir(), "loopover-ai-")); } /** Write `systemAppend` into `cwd` (the SAME per-call isolated temp dir already used for the subprocess's diff --git a/src/selfhost/audit.ts b/src/selfhost/audit.ts index a369292ccf..3d44101b54 100644 --- a/src/selfhost/audit.ts +++ b/src/selfhost/audit.ts @@ -1,7 +1,7 @@ // Structured audit log for the self-host runtime (#980). Emits one JSON line per job lifecycle event so // operators can grep / pipe to their log aggregator (Loki, CloudWatch, Datadog, etc.) without any extra // setup. Written to process.stdout so it is captured by Docker's default json-file log driver and is -// accessible via `docker compose logs gittensory`. +// accessible via `docker compose logs loopover`. // // NOT the durable audit_events DB table (#2908): this module is a stdout-only logger for exactly the 4 queue- // lifecycle events below, called only from sqlite-queue.ts/pg-queue.ts. For the actual queryable audit trail of diff --git a/src/selfhost/d1-adapter.ts b/src/selfhost/d1-adapter.ts index 4f0d9d2caa..394bac1af4 100644 --- a/src/selfhost/d1-adapter.ts +++ b/src/selfhost/d1-adapter.ts @@ -1,5 +1,5 @@ // Self-host D1 adapter (#980). A FAITHFUL D1Database implementation over a synchronous SQLite driver, so -// EVERY data-access path in gittensory runs UNCHANGED on a local file: +// EVERY data-access path in loopover runs UNCHANGED on a local file: // • drizzle-orm/d1 (getDb → the ~171 repository call sites) — calls bind/all/run/raw/batch + reads .results // • the raw `env.DB.prepare(sql).bind(...).all()/.first()/.run()/.batch()` sites // • the test suite, which uses the same D1 surface @@ -93,7 +93,7 @@ export function createD1Adapter(driver: SqliteDriver): D1Database { return { count: (sql.match(/;/g) ?? []).length || 1, duration: 0 }; }, async dump() { - return new ArrayBuffer(0); // unused by gittensory; present for D1 surface completeness + return new ArrayBuffer(0); // unused by loopover; present for D1 surface completeness }, }; return adapter as unknown as D1Database; diff --git a/src/selfhost/d1-size-probe.ts b/src/selfhost/d1-size-probe.ts index 68e9e06e5b..3fb70b549d 100644 --- a/src/selfhost/d1-size-probe.ts +++ b/src/selfhost/d1-size-probe.ts @@ -1,5 +1,5 @@ // Cloudflare D1 size + row-count observability probe (central-cloud storage, #3810). The Cloudflare D1 -// database backing gittensory's shared cloud gittensory-api/Orb deployment hit its ~10GB account storage +// database backing loopover's shared cloud loopover-api/Orb deployment hit its ~10GB account storage // cap on 2026-07-06 -- see src/db/retention.ts's dedupeSignalSnapshots for the write-side root-cause fix // (signal_snapshots was accumulating hundreds of superseded rows per key). D1's own query surface has no way // to report the database's FILE size as a metric from inside a query -- that figure only exists via the @@ -15,7 +15,7 @@ // CLOUDFLARE_D1_MONITOR_* env vars IS the enablement switch, the same convention as isOrbBrokerMode's // ORB_ENROLLMENT_SECRET-presence check (src/orb/broker-client.ts) -- most self-host operators run their own // SQLite/Postgres backend and have nothing to monitor here; this exists for whichever deployment owns a real -// Cloudflare D1 worth watching (including gittensory's own central cloud database). Wired into the self-host +// Cloudflare D1 worth watching (including loopover's own central cloud database). Wired into the self-host // process's OWN boot-time interval registrations in server.ts (mirroring the Orb relay registration retry // timer), NOT the Cloudflare Worker `scheduled()` cron: that cron's job registry is shared with the hosted // cloud Worker's ephemeral, multi-isolate request lifecycle, which cannot reliably carry an in-memory sample diff --git a/src/selfhost/health.ts b/src/selfhost/health.ts index f1d89e935f..9f495f6a48 100644 --- a/src/selfhost/health.ts +++ b/src/selfhost/health.ts @@ -195,7 +195,7 @@ function looksNonPublic(origin: string): boolean { } } -/** Boot-time advisory (JSONbored/gittensory PR #4180's live bug): `PUBLIC_API_ORIGIN`/`PUBLIC_SITE_ORIGIN` get +/** Boot-time advisory (JSONbored/loopover PR #4180's live bug): `PUBLIC_API_ORIGIN`/`PUBLIC_SITE_ORIGIN` get * embedded VERBATIM as `` in the public "Visual preview" PR comment table (see * `src/review/visual/capture.ts`) — a value GitHub's own servers, not this instance, must be able to fetch. * `PUBLIC_API_ORIGIN`'s existing preflight check (see `isBareHttpsOrigin` above) only confirms it's a diff --git a/src/selfhost/load-file-secrets.ts b/src/selfhost/load-file-secrets.ts index 93093acd23..f622ebe387 100644 --- a/src/selfhost/load-file-secrets.ts +++ b/src/selfhost/load-file-secrets.ts @@ -3,7 +3,7 @@ // app on import and is Codecov-ignored, so it has no runtime test coverage of its own. import { readFileSync } from "node:fs"; -// Docker Compose's OWN reserved `_FILE`-suffixed environment variables -- never gittensory's secret-file +// Docker Compose's OWN reserved `_FILE`-suffixed environment variables -- never loopover's secret-file // convention, so they must never be dereferenced below. `COMPOSE_FILE` is a colon-delimited list of // compose file paths (never a single readable file itself, so readFileSync always throws), and // `COMPOSE_ENV_FILE` (less commonly set, but equally reserved by Compose) points at an operator's custom diff --git a/src/selfhost/migrate.ts b/src/selfhost/migrate.ts index a711f6a7d6..7efdb1f7ae 100644 --- a/src/selfhost/migrate.ts +++ b/src/selfhost/migrate.ts @@ -1,4 +1,4 @@ -// Apply gittensory's D1 migrations to the self-host SQLite database at startup. The same `migrations/*.sql` +// Apply loopover's D1 migrations to the self-host SQLite database at startup. The same `migrations/*.sql` // files Cloudflare applies via `wrangler d1 migrations apply` — they're plain SQLite DDL, so they run as-is // through the D1 adapter's exec(). Tracked in a `_selfhost_migrations` table so a restart re-applies only the // new ones (idempotent), mirroring wrangler's migration ledger. diff --git a/src/selfhost/orb-collector.ts b/src/selfhost/orb-collector.ts index 2108924d68..55facbdeb9 100644 --- a/src/selfhost/orb-collector.ts +++ b/src/selfhost/orb-collector.ts @@ -1,13 +1,13 @@ // LoopOver Orb (#1255) — fleet calibration EXPORTER. Each self-hosted instance already records de-noised // ground truth in review_audit (gate_decision + pr_outcome + reversal_reopened/reversal_reverted) via the -// engine's outcomes-wire. This ships an anonymized, reversal-aware signal UP to gittensory's central +// engine's outcomes-wire. This ships an anonymized, reversal-aware signal UP to loopover's central // collector so the gate can be calibrated across the whole self-host fleet. // // Export is ALWAYS ON once the GitHub App is configured (the fleet-telemetry contract of self-hosting) — // there is no opt-out flag. It self-gates on a configured App private key (no App → no review data to // export anyway) and anonymizes with a DEDICATED, per-instance secret generated once and persisted in // system_flags (never the App private key or the webhook-verification secret — key separation). -// ORB_COLLECTOR_URL= — endpoint (default: gittensory's hosted collector) +// ORB_COLLECTOR_URL= — endpoint (default: loopover's hosted collector) // ORB_AIR_GAP=true — air-gapped/offline deployments only: compute locally, never send // ORB_ANONYMIZE=true — HMAC-hash repo/PR before export (default: true) // ORB_COLLECTOR_TOKEN= — bearer credential for the hosted collector @@ -161,7 +161,7 @@ export async function exportOrbBatch(db: D1Database, batchSize = 200, fetchFn: t const brokered = Boolean((process.env.ORB_ENROLLMENT_SECRET ?? "").trim()); if (!brokered && !(process.env.GITHUB_APP_PRIVATE_KEY ?? "")) return 0; - // gittensory's hosted collector. No shared secret is sent: repo/PR identifiers are HMAC'd with this + // loopover's hosted collector. No shared secret is sent: repo/PR identifiers are HMAC'd with this // instance's DEDICATED anonymization secret (a 256-bit random key generated once and persisted in // system_flags — see getOrCreateAnonSecret), single-purpose and never the App key, so the collector // (which never holds it) can never de-anonymize them. diff --git a/src/selfhost/pg-dialect.ts b/src/selfhost/pg-dialect.ts index 39bff6dbad..eecd0e6e42 100644 --- a/src/selfhost/pg-dialect.ts +++ b/src/selfhost/pg-dialect.ts @@ -1,4 +1,4 @@ -// SQLite → Postgres SQL dialect translation for the self-host Postgres backend (#977). gittensory's core and +// SQLite → Postgres SQL dialect translation for the self-host Postgres backend (#977). loopover's core and // drizzle-orm/d1 emit SQLite-dialect SQL; this translates the bounded set of SQLite-isms the codebase uses // (placeholders + a handful of scalar functions + INSERT OR REPLACE/IGNORE + the rowid pseudo-column) so // the SAME queries run on Postgres. The timestamp columns are TEXT (ISO strings written by the app), so the diff --git a/src/selfhost/private-config.ts b/src/selfhost/private-config.ts index e3c261ec65..98478a8d50 100644 --- a/src/selfhost/private-config.ts +++ b/src/selfhost/private-config.ts @@ -6,10 +6,10 @@ // import never reaches the Cloudflare bundle. // // Layout (CodeRabbit-style: per-repo override, layered over a global default, layered over a cross-repo shared -// base — #1959). For a repo `JSONbored/gittensory` the reader tries, in priority order: -// 1. `jsonbored__gittensory/.loopover.yml` — owner-qualified folder (robust to repo-name collisions across owners) -// 2. `gittensory/.loopover.yml` — bare repo-name folder (the clean, human-readable layout) -// 3. `jsonbored__gittensory.yml` — flat owner__repo file (the original #1390 layout; back-compat) +// base — #1959). For a repo `JSONbored/loopover` the reader tries, in priority order: +// 1. `jsonbored__loopover/.loopover.yml` — owner-qualified folder (robust to repo-name collisions across owners) +// 2. `loopover/.loopover.yml` — bare repo-name folder (the clean, human-readable layout) +// 3. `jsonbored__loopover.yml` — flat owner__repo file (the original #1390 layout; back-compat) // 4. `.loopover.yml` — GLOBAL default at the dir root, shared by every repo. // 5. `_shared/.loopover.yml` — SHARED BASE (#1959), the lowest-priority layer: one house policy // an operator running many repos writes once instead of copy-pasting into every repo's private config. diff --git a/src/selfhost/queue-common.ts b/src/selfhost/queue-common.ts index d554c2eab3..45583acebb 100644 --- a/src/selfhost/queue-common.ts +++ b/src/selfhost/queue-common.ts @@ -97,7 +97,7 @@ const GITHUB_BUDGET_BACKGROUND_TYPES = new Set([ "rag-index-repo", // #4505: found via a systematic audit of every MAINTENANCE_JOB_TYPES member against this set (prompted by // reconcile-open-prs below) -- each of these five genuinely makes real GitHub REST calls (directly, or - // transitively via resolveRepositorySettings -> loadRepoFocusManifest's cache-miss fetch of .gittensory.json) + // transitively via resolveRepositorySettings -> loadRepoFocusManifest's cache-miss fetch of .loopover.json) // but was missing from this set, contradicting this module's own header comment. // // runOpenPrReconciliation makes real, potentially large paginated GitHub REST calls per watched repo (up to diff --git a/src/selfhost/vectorize.ts b/src/selfhost/vectorize.ts index ccc43eb5d5..dafb7b1ed7 100644 --- a/src/selfhost/vectorize.ts +++ b/src/selfhost/vectorize.ts @@ -1,5 +1,5 @@ // SQLite-backed Vectorize adapter for self-host RAG (#979). Implements the Cloudflare `Vectorize` binding -// surface (upsert / query / deleteByIds) that gittensory's RAG (reviewVectorAdapter) wraps, backed by a +// surface (upsert / query / deleteByIds) that loopover's RAG (reviewVectorAdapter) wraps, backed by a // SQLite table with brute-force cosine similarity. For a repo's worth of chunks (hundreds–few-thousand // vectors per namespace) this is fast enough; namespaces (one per repo) keep each query's candidate set // small. Embeddings come from the OpenAI-compatible AI adapter's /embeddings path (e.g. Ollama bge-m3, 1024-d). diff --git a/src/services/ai-review.ts b/src/services/ai-review.ts index bdff9467d1..3fd56fcb28 100644 --- a/src/services/ai-review.ts +++ b/src/services/ai-review.ts @@ -1,7 +1,7 @@ // LoopOver AI maintainer review (the `aiReview` capability). // // Two layers, both opt-in and both fail-safe (no AI / errors / over-budget / unsafe output → no public -// text and no gate finding; gittensory NEVER blocks because the model spoke): +// text and no gate finding; loopover NEVER blocks because the model spoke): // // • Advisory notes — a concise maintainer-style write-up (assessment + suggestions + risks). When the // repo has BYOK configured, the maintainer's own frontier model (Anthropic/OpenAI) writes it; diff --git a/src/services/draft.ts b/src/services/draft.ts index 5e9612b06e..014fdee58f 100644 --- a/src/services/draft.ts +++ b/src/services/draft.ts @@ -6,7 +6,7 @@ // GET /v1/drafts/auth/callback -> exchange code, encrypt+store the user token, queue submit-draft // queue submit-draft -> fork the upstream repo with the user's token + open the content PR // -// Single-tenant (gittensory is one worker): the per-project `slug`/`AgentConfig` partitioning from +// Single-tenant (loopover is one worker): the per-project `slug`/`AgentConfig` partitioning from // reviewbot is collapsed into module constants + env vars. The flow is gated by LOOPOVER_REVIEW_DRAFT; when // the flag is off the router never mounts these handlers (callers see 404). import { decryptDraftToken, encryptDraftToken, newDraftId, randomDraftToken, sha256Hex, timingSafeEqualHex } from "../utils/crypto"; @@ -703,7 +703,7 @@ export async function processSubmitDraft(env: Env, draftId: string): Promise = { - "jsonbored/gittensory": "LOOPOVER_DISCORD_WEBHOOK", + "jsonbored/loopover": "LOOPOVER_DISCORD_WEBHOOK", "jsonbored/metagraphed": "METAGRAPHED_DISCORD_WEBHOOK", "jsonbored/awesome-claude": "AWESOME_DISCORD_WEBHOOK", }; diff --git a/src/services/outcome-calibration.ts b/src/services/outcome-calibration.ts index 11760cbfa8..87bff559a4 100644 --- a/src/services/outcome-calibration.ts +++ b/src/services/outcome-calibration.ts @@ -1,10 +1,10 @@ -// #543 outcome-learning loop: calibrate gittensory's predictions against real merge/close outcomes. +// #543 outcome-learning loop: calibrate loopover's predictions against real merge/close outcomes. // // MEASUREMENT only — it never auto-adjusts a score (that would move live rankings; like time-decay it would // need owner review). It answers two questions a maintainer/operator can act on: // • Is the deterministic slop score PREDICTIVE? For resolved PRs that carry a persisted slop band, do // higher-slop bands actually merge less often? (`discriminates`). -// • Are gittensory's recommendations panning out? The positive vs negative outcome split from the agent +// • Are loopover's recommendations panning out? The positive vs negative outcome split from the agent // recommendation-outcome ledger. // All inputs already exist: slop_band persists on the PR row (#726) + closed PRs are retained, and the // agent_recommendation_outcomes ledger (#543's recommendation half) is populated by evaluateRecommendationOutcomes. diff --git a/src/services/plan-dag.ts b/src/services/plan-dag.ts index aa6f85e079..55fbcbb61a 100644 --- a/src/services/plan-dag.ts +++ b/src/services/plan-dag.ts @@ -1,5 +1,5 @@ // #783 multi-step action DAG. A miner plan is a set of steps with dependencies ("close 1 stale PR → land 2 → -// open a new direct PR"); gittensory tracks per-step state + retries so the plan survives across MCP tool +// open a new direct PR"); loopover tracks per-step state + retries so the plan survives across MCP tool // calls and resumes where it left off. PURE + deterministic — the harness performs each step's real work and // reports the result back; this module only advances the state machine. diff --git a/src/signals/boundary-test-generation.ts b/src/signals/boundary-test-generation.ts index 9958d92b35..9369b4dfd4 100644 --- a/src/signals/boundary-test-generation.ts +++ b/src/signals/boundary-test-generation.ts @@ -9,7 +9,7 @@ import { isTestPath, hasLocalTestEvidence } from "./test-evidence"; // test-code generation is deliberately OUT of scope (server-side generated test code would need a human to // verify it is even correct, which risks false confidence) — this only builds a LOCAL-execution action spec // (mirrors `local-write-tools.ts`'s pattern) that hands the contributor's OWN agent the criteria to scaffold -// tests with, so gittensory never writes code and the boundary between review and execution stays intact. +// tests with, so loopover never writes code and the boundary between review and execution stays intact. /** A changed source file's path plus its unified-diff patch text (added/removed lines only — no full file * content). Deliberately narrower than `PullRequestFileRecord` so callers (MCP tools, tests) can supply just @@ -121,15 +121,15 @@ export type BoundaryTestGenerationSpec = { /** The boundary touches this spec was generated from — path + pattern kind only, never source text. */ touches: BoundaryTouch[]; /** Natural-language hints the contributor's own agent uses to scaffold tests in the repo's own framework and - * conventions — content supplied by gittensory, execution stays on the contributor's machine. */ + * conventions — content supplied by loopover, execution stays on the contributor's machine. */ hints: string[]; boundary: string; }; // Reuses the exact boundary-disclosure string local-write-tools.ts uses for every other local-execution spec, -// so the no-cloud-write guarantee reads identically across every action gittensory ever proposes. +// so the no-cloud-write guarantee reads identically across every action loopover ever proposes. const BOUNDARY_TEST_GENERATION_BOUNDARY = - "This is a suggestion, not a generated test file. Run it locally with your OWN agent/toolchain and the repo's own test framework — gittensory supplies the criteria but never writes or executes test code."; + "This is a suggestion, not a generated test file. Run it locally with your OWN agent/toolchain and the repo's own test framework — loopover supplies the criteria but never writes or executes test code."; const KIND_HINTS: Record = { array_index_bounds: "Add a case at the first/last valid index and one just past each bound (index -1, index === length).", @@ -139,7 +139,7 @@ const KIND_HINTS: Record = { /** * Build the boundary-safe test-generation action spec: criteria + framework/convention hints for the - * contributor's OWN agent to scaffold tests from — never test code itself, and never executed by gittensory. + * contributor's OWN agent to scaffold tests from — never test code itself, and never executed by loopover. * Returns null when there are no boundary touches (nothing to generate hints for). */ export function buildBoundaryTestGenerationSpec(touches: BoundaryTouch[]): BoundaryTestGenerationSpec | null { diff --git a/src/signals/change-guardrail.ts b/src/signals/change-guardrail.ts index 2bbabbb0f0..dadac82942 100644 --- a/src/signals/change-guardrail.ts +++ b/src/signals/change-guardrail.ts @@ -1,5 +1,5 @@ // Convergence safety: the hard-guardrail path check for the auto-maintain layer (#778). Changed paths that -// match a repo's configured hardGuardrailGlobs force MANUAL review — gittensory must never auto-merge OR +// match a repo's configured hardGuardrailGlobs force MANUAL review — loopover must never auto-merge OR // auto-close a PR that touches a guarded path. Ported verbatim from // reviewbot core/change-classifier.ts — the mechanism that prevents the awesome-claude #4196 incident class // (a weakened policy script auto-merging because its path wasn't guarded). Pure + dependency-free. @@ -118,7 +118,7 @@ export function matchesAny(path: string, globs: string[]): boolean { /** * The changed paths (if any) that trip a hard guardrail. A non-empty result means the PR touches a guarded - * path and MUST fall through to a human — gittensory may neither auto-merge nor auto-close it. Pure. + * path and MUST fall through to a human — loopover may neither auto-merge nor auto-close it. Pure. */ export function changedPathsHittingGuardrail(changedPaths: string[], hardGuardrailGlobs: string[]): string[] { if (hardGuardrailGlobs.length === 0) return []; diff --git a/src/signals/check-summary.ts b/src/signals/check-summary.ts index 987c85f6c3..7a577ea31c 100644 --- a/src/signals/check-summary.ts +++ b/src/signals/check-summary.ts @@ -1,5 +1,5 @@ // Check-summary classifiers, extracted to `@loopover/engine` (#4256) so reward-risk and the -// published gittensory-mcp/gittensory-miner CLIs can depend on the same source instead of reaching into +// published loopover-mcp/loopover-miner CLIs can depend on the same source instead of reaching into // `local-branch.ts` (which pulls in the whole review-scoring/Gittensor-API subsystem). This file is a thin // re-export shim; the implementation lives at packages/loopover-engine/src/signals/check-summary.ts // (imported via relative source path, not the published package, to match this repo's existing diff --git a/src/signals/focus-manifest.ts b/src/signals/focus-manifest.ts index 8b648145a0..46d4a6523e 100644 --- a/src/signals/focus-manifest.ts +++ b/src/signals/focus-manifest.ts @@ -509,7 +509,7 @@ function applyGateConfigOverrides(effective: RepositorySettings, gate: FocusMani /** * Resolve the EFFECTIVE repository settings a webhook should act on: `.loopover.yml` > DB settings > * safe defaults. The generic `settings:` override applies first; the friendly `gate:` alias then wins - * for its fields. This single resolver makes the whole gittensory configuration — gate on/off, blocker + * for its fields. This single resolver makes the whole loopover configuration — gate on/off, blocker * modes, comments, labels, surface, audience — controllable from the repo's `.loopover.yml`. */ export function resolveEffectiveSettings( diff --git a/src/signals/local-branch.ts b/src/signals/local-branch.ts index 6195c1e575..1da0fc0ed5 100644 --- a/src/signals/local-branch.ts +++ b/src/signals/local-branch.ts @@ -807,7 +807,7 @@ function buildLocalFindings( title: "Source upload disabled", detail: "Local MCP branch analysis used structured git metadata only; source contents were not uploaded.", }, - ...(input.repoFullName.toLowerCase() === "jsonbored/gittensory" + ...(input.repoFullName.toLowerCase() === "jsonbored/loopover" ? [ { code: "loopover_not_registered", diff --git a/src/signals/local-scorer.ts b/src/signals/local-scorer.ts index 368b6fbf2b..9785244232 100644 --- a/src/signals/local-scorer.ts +++ b/src/signals/local-scorer.ts @@ -1,5 +1,5 @@ // #782 deterministic local scorer — extracted to `@loopover/engine` (#4253) so the published -// gittensory-mcp / gittensory-miner CLIs and the hosted Worker import the identical, versioned scoring logic +// loopover-mcp / loopover-miner CLIs and the hosted Worker import the identical, versioned scoring logic // instead of drifting. The Vectorize/Node-coupled local-branch.ts is intentionally NOT moved; this shim only // re-exports the pure scorer. packages/loopover-engine/src/local-scorer.ts (imported via relative source // path, matching the #2278/#2282/#4254 extraction shims) is the source of truth. diff --git a/src/signals/path-matchers.ts b/src/signals/path-matchers.ts index 122e22c291..3554f89b73 100644 --- a/src/signals/path-matchers.ts +++ b/src/signals/path-matchers.ts @@ -1,5 +1,5 @@ // Pure, deterministic path matchers for slop classification (#561), extracted to -// `@loopover/engine` (#4252) so the published gittensory-mcp/gittensory-miner CLIs can depend on +// `@loopover/engine` (#4252) so the published loopover-mcp/loopover-miner CLIs can depend on // the same source instead of hand-porting it. This file is a thin re-export shim; the implementation lives at // packages/loopover-engine/src/signals/path-matchers.ts (imported via relative source path, not the // published package, to match this repo's existing engine-consumption convention — see e.g. diff --git a/src/signals/reward-risk.ts b/src/signals/reward-risk.ts index db5af3ee7a..105f03caea 100644 --- a/src/signals/reward-risk.ts +++ b/src/signals/reward-risk.ts @@ -1,4 +1,4 @@ -// Reward/risk reasoning signals, extracted to `@loopover/engine` (#2281) so the gittensory-miner +// Reward/risk reasoning signals, extracted to `@loopover/engine` (#2281) so the loopover-miner // can rank candidate work locally with the same logic the maintainer-side gate computes. The implementation // lives at `packages/loopover-engine/src/reward-risk.ts`, imported via its RELATIVE SOURCE PATH (matching // the merged #2276/#2278/#2282 shims) — not the published `@loopover/engine` specifier, so no diff --git a/src/signals/slop.ts b/src/signals/slop.ts index efb68a6f63..55903dbbb7 100644 --- a/src/signals/slop.ts +++ b/src/signals/slop.ts @@ -1,5 +1,5 @@ // PR-side slop-assessment shim (#5133). The canonical implementation now lives at -// packages/loopover-engine/src/signals/slop.ts, extracted so the published gittensory-mcp/gittensory-miner +// packages/loopover-engine/src/signals/slop.ts, extracted so the published loopover-mcp/loopover-miner // CLIs can run the SAME deterministic self-review scorer the live gate uses (imported via relative source // path, not the published package, to match this repo's existing engine-consumption convention — see e.g. // src/signals/test-evidence.ts — and to avoid depending on the engine package's built dist/ output, which is diff --git a/src/signals/test-evidence.ts b/src/signals/test-evidence.ts index 53302e786c..a8d63e3570 100644 --- a/src/signals/test-evidence.ts +++ b/src/signals/test-evidence.ts @@ -1,5 +1,5 @@ // Test/code-path classifiers, extracted to `@loopover/engine` so the published -// gittensory-mcp/gittensory-miner CLIs can depend on the same source instead of hand-porting it +// loopover-mcp/loopover-miner CLIs can depend on the same source instead of hand-porting it // (previously drifted three times independently — see commit history titled "re-sync isTestFile // with the server"). This file is a thin re-export shim; the implementation lives at // packages/loopover-engine/src/signals/test-evidence.ts (imported via relative source path, not diff --git a/src/signals/unlinked-issue-candidates.ts b/src/signals/unlinked-issue-candidates.ts index b72ed74a32..6dc7cbfcf1 100644 --- a/src/signals/unlinked-issue-candidates.ts +++ b/src/signals/unlinked-issue-candidates.ts @@ -1,5 +1,5 @@ // Unlinked-issue candidate pre-filter, extracted to `@loopover/engine` (#4883) so the published -// gittensory-mcp/gittensory-miner CLIs can run the SAME deterministic recall pass the maintainer gate uses to +// loopover-mcp/loopover-miner CLIs can run the SAME deterministic recall pass the maintainer gate uses to // surface a PR's likely-but-unlinked issue, instead of reaching into this backend's src/ tree. This file is a // thin re-export shim; the implementation lives at packages/loopover-engine/src/signals/unlinked-issue-candidates.ts // (imported via relative source path, not the published package, to match this repo's existing diff --git a/test/unit/selfhost-ai.test.ts b/test/unit/selfhost-ai.test.ts index 8cd79bd90c..6e6dabc612 100644 --- a/test/unit/selfhost-ai.test.ts +++ b/test/unit/selfhost-ai.test.ts @@ -485,7 +485,7 @@ describe("createChainAi (fallback)", () => { const result = await chain.run("m", { prompt: "review this diff", jobId: "delivery-123", - repoFullName: "JSONbored/gittensory", + repoFullName: "JSONbored/loopover", pullNumber: 42, attempt: 0, }); @@ -498,8 +498,8 @@ describe("createChainAi (fallback)", () => { const chainFailure = logged.find((entry) => entry.event === "selfhost_ai_provider_failed_in_chain" && entry.provider === "codex"); // (b) both the provider-level and chain-level failure logs carry the new correlation fields. - expect(codexFailure).toMatchObject({ jobId: "delivery-123", repoFullName: "JSONbored/gittensory", pullNumber: 42, attempt: 0 }); - expect(chainFailure).toMatchObject({ jobId: "delivery-123", repoFullName: "JSONbored/gittensory", pullNumber: 42, attempt: 0 }); + expect(codexFailure).toMatchObject({ jobId: "delivery-123", repoFullName: "JSONbored/loopover", pullNumber: 42, attempt: 0 }); + expect(chainFailure).toMatchObject({ jobId: "delivery-123", repoFullName: "JSONbored/loopover", pullNumber: 42, attempt: 0 }); // (c) the Codex timeout detail is present but no secret value ever appears in the logged error text. expect(codexFailure.error).toContain("codex_timeout"); @@ -1415,7 +1415,7 @@ describe("subscription CLI helpers + fail-safe", () => { expect(seen).not.toContain("x"); expect(capturedInput).toBe("x"); expect(capturedEnv).toEqual({ PATH: resolveSubscriptionCliPath({ PATH: "/bin" }) }); - expect(capturedCwd).toContain("gittensory-ai-"); + expect(capturedCwd).toContain("loopover-ai-"); expect(timeout).toBe(300_000); // Provider-specific model/effort are passed through. await createCodexAi({ CODEX_AI_MODEL: "gpt-5.5", CODEX_AI_EFFORT: "high", LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER: "1" }, ok, noAuthCheck).run("", { prompt: "x" }); @@ -2003,7 +2003,7 @@ describe("subscription CLI helpers + fail-safe", () => { it("defaultSpawn rejects when the CLI binary is missing (error handler)", async () => { const origPath = process.env.PATH; - process.env.PATH = "/nonexistent-gittensory-empty"; + process.env.PATH = "/nonexistent-loopover-empty"; try { await expect(createCodexAi({ ...process.env, LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER: "1" }).run("gpt-5", { prompt: "x" })).rejects.toThrow(); } finally { @@ -2016,7 +2016,7 @@ describe("subscription CLI helpers + fail-safe", () => { // shell) so this reaches the REAL ENOENT spawn error deterministically, rather than short-circuiting on the // credential-isolation guard the way an ambient CODEX_HOME would. await expect( - createCodexAi({ PATH: "/nonexistent-gittensory-empty", LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER: "1" }, undefined, noAuthCheck).run( + createCodexAi({ PATH: "/nonexistent-loopover-empty", LOOPOVER_ENABLE_UNSAFE_CODEX_REVIEWER: "1" }, undefined, noAuthCheck).run( "gpt-5", { prompt: "x" }, ), @@ -2025,7 +2025,7 @@ describe("subscription CLI helpers + fail-safe", () => { // firstOutputTimer-PRESENT branch for claude too, proving the error handler clears it cleanly (no leaked // timer, no unhandled rejection) rather than only ever having been exercised via codex. await expect( - createClaudeCodeAi({ PATH: "/nonexistent-gittensory-empty", CLAUDE_CODE_OAUTH_TOKEN: "t" }).run("sonnet", { prompt: "x" }), + createClaudeCodeAi({ PATH: "/nonexistent-loopover-empty", CLAUDE_CODE_OAUTH_TOKEN: "t" }).run("sonnet", { prompt: "x" }), ).rejects.toThrow(/ENOENT/); }); From 01e67ef2b98ef921007cd9bdef71802531f1aaaa Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 14 Jul 2026 15:14:50 -0700 Subject: [PATCH 2/3] fix(core): update test fixtures for renamed self-repo/webhook-map keys src/signals/local-branch.ts's self-repo detection and src/services/notify-discord.ts's per-repo webhook map both compare against the literal 'jsonbored/loopover' string now (this batch's own rename, matching the real renamed GitHub repo). Five tests across local-branch.test.ts, notify-discord.test.ts, queue.test.ts, and review-recap.test.ts still passed the pre-rename 'JSONbored/gittensory' as their input/fixture and so no longer matched -- updated to match current reality. --- test/unit/local-branch.test.ts | 2 +- test/unit/notify-discord.test.ts | 4 ++-- test/unit/queue.test.ts | 8 ++++---- test/unit/review-recap.test.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/unit/local-branch.test.ts b/test/unit/local-branch.test.ts index fe55a3abf4..68ef2c6c8e 100644 --- a/test/unit/local-branch.test.ts +++ b/test/unit/local-branch.test.ts @@ -1465,7 +1465,7 @@ describe("local branch analysis", () => { const analysis = buildLocalBranchAnalysis({ input: { login: "jsonbored", - repoFullName: "JSONbored/gittensory", + repoFullName: "JSONbored/loopover", branchName: "miner-mcp-upgrade", changedFiles: [{ path: "src/api/routes.ts", additions: 90, deletions: 2, status: "modified" }], validation: [{ command: "npm run test:ci", status: "not_run" }], diff --git a/test/unit/notify-discord.test.ts b/test/unit/notify-discord.test.ts index 957552393a..7010e8e202 100644 --- a/test/unit/notify-discord.test.ts +++ b/test/unit/notify-discord.test.ts @@ -63,7 +63,7 @@ describe("notify-discord resolveWebhook (modular self-host fallback)", () => { it("a mapped repo uses its own per-channel secret", async () => { const calls = stubFetch(); - await notify(withEnv({ LOOPOVER_DISCORD_WEBHOOK: HOOK }), "JSONbored/gittensory"); + await notify(withEnv({ LOOPOVER_DISCORD_WEBHOOK: HOOK }), "JSONbored/loopover"); expect(calls).toEqual([HOOK]); }); @@ -116,7 +116,7 @@ describe("notify-discord resolveWebhook (modular self-host fallback)", () => { it("an invalid mapped repo secret suppresses instead of falling back to the global channel", async () => { const calls = stubFetch(); const env = withEnv({ LOOPOVER_DISCORD_WEBHOOK: "https://example.com/not-discord", DISCORD_WEBHOOK_URL: FALLBACK }); - await notify(env, "JSONbored/gittensory"); + await notify(env, "JSONbored/loopover"); expect(calls).toEqual([]); expect(await externalNotificationAudit(env, "discord")).toEqual([expect.objectContaining({ outcome: "denied", detail: "invalid_repo_webhook" })]); }); diff --git a/test/unit/queue.test.ts b/test/unit/queue.test.ts index 07556e400b..34965f1c4d 100644 --- a/test/unit/queue.test.ts +++ b/test/unit/queue.test.ts @@ -576,10 +576,10 @@ describe("queue processors", () => { it("runs the review recap job through the queue processor when reviewRecap.enabled is true (#1963)", async () => { const env = Object.assign(createTestEnv(), { LOOPOVER_DISCORD_WEBHOOK: "https://discord.com/api/webhooks/123/abc" }) as Env; - await upsertRepoFocusManifest(env, "JSONbored/gittensory", { reviewRecap: { enabled: true, cadenceDays: 3 } }); + await upsertRepoFocusManifest(env, "JSONbored/loopover", { reviewRecap: { enabled: true, cadenceDays: 3 } }); vi.stubGlobal("fetch", async () => new Response(null, { status: 204 })); - await processJob(env, { type: "generate-review-recap", requestedBy: "test", repoFullName: "JSONbored/gittensory" }); + await processJob(env, { type: "generate-review-recap", requestedBy: "test", repoFullName: "JSONbored/loopover" }); const row = await env.DB.prepare("select outcome, detail from audit_events where event_type = ? order by created_at desc limit 1").bind("review_recap_notification.discord").first(); expect(row).toMatchObject({ outcome: "completed", detail: "sent" }); @@ -588,14 +588,14 @@ describe("queue processors", () => { it("uses the job message's explicit windowDays over the manifest's cadenceDays default (#1963, nullish fallback present side)", async () => { const env = Object.assign(createTestEnv(), { LOOPOVER_DISCORD_WEBHOOK: "https://discord.com/api/webhooks/123/abc" }) as Env; - await upsertRepoFocusManifest(env, "JSONbored/gittensory", { reviewRecap: { enabled: true, cadenceDays: 3 } }); + await upsertRepoFocusManifest(env, "JSONbored/loopover", { reviewRecap: { enabled: true, cadenceDays: 3 } }); let capturedBody: string | undefined; vi.stubGlobal("fetch", async (_url: RequestInfo | URL, init?: RequestInit) => { capturedBody = String(init?.body ?? ""); return new Response(null, { status: 204 }); }); - await processJob(env, { type: "generate-review-recap", requestedBy: "test", repoFullName: "JSONbored/gittensory", windowDays: 21 }); + await processJob(env, { type: "generate-review-recap", requestedBy: "test", repoFullName: "JSONbored/loopover", windowDays: 21 }); expect(capturedBody).toContain("(21d)"); vi.unstubAllGlobals(); diff --git a/test/unit/review-recap.test.ts b/test/unit/review-recap.test.ts index 30be37f1e9..fd29ac8102 100644 --- a/test/unit/review-recap.test.ts +++ b/test/unit/review-recap.test.ts @@ -238,7 +238,7 @@ async function auditRows(env: Env): Promise { const recap = buildReviewRecap({ - repoFullName: "JSONbored/gittensory", + repoFullName: "JSONbored/loopover", generatedAt: NOW, windowDays: 7, pullRequests: [], @@ -257,7 +257,7 @@ describe("sendReviewRecapToDiscord (#1963, reuses resolveDiscordWebhook)", () => expect(result.sent).toBe(true); expect(calls).toHaveLength(1); expect(calls[0]?.url).toBe(HOOK); - expect(JSON.parse(calls[0]?.body ?? "{}").embeds[0].title).toContain("JSONbored/gittensory"); + expect(JSON.parse(calls[0]?.body ?? "{}").embeds[0].title).toContain("JSONbored/loopover"); const rows = await auditRows(env); expect(rows.some((r) => r.outcome === "completed")).toBe(true); }); From 2ace57f8926d49c7f875b5851c08b28b4d0bb7bd Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 14 Jul 2026 16:35:56 -0700 Subject: [PATCH 3/3] fix(core): fix second stale repo-name fixture in review-recap.test.ts generateAndSendReviewRecap's manual-trigger test also passed the pre-rename 'JSONbored/gittensory' repo, missed by the earlier fix to this file's sendReviewRecapToDiscord describe block. --- test/unit/review-recap.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/review-recap.test.ts b/test/unit/review-recap.test.ts index fd29ac8102..c3283e8ff4 100644 --- a/test/unit/review-recap.test.ts +++ b/test/unit/review-recap.test.ts @@ -397,8 +397,8 @@ describe("generateAndSendReviewRecap (#1963, manual-trigger entry point)", () => it("builds the recap and returns both the recap and the delivery result together", async () => { vi.stubGlobal("fetch", async () => new Response(null, { status: 204 })); const env = envWithWebhook(); - const { recap, delivery } = await generateAndSendReviewRecap(env, "JSONbored/gittensory", { windowDays: 7, nowIso: NOW }); - expect(recap.repoFullName).toBe("JSONbored/gittensory"); + const { recap, delivery } = await generateAndSendReviewRecap(env, "JSONbored/loopover", { windowDays: 7, nowIso: NOW }); + expect(recap.repoFullName).toBe("JSONbored/loopover"); expect(delivery.sent).toBe(true); });