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
4 changes: 2 additions & 2 deletions packages/loopover-engine/src/signals/change-guardrail.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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 [];
Expand Down
8 changes: 4 additions & 4 deletions src/selfhost/ai.ts
Original file line number Diff line number Diff line change
@@ -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).

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -520,7 +520,7 @@ async function isolatedCliCwd(): Promise<string> {
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
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/audit.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/selfhost/d1-adapter.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/selfhost/d1-size-probe.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<img src>` 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
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/load-file-secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/migrate.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/selfhost/orb-collector.ts
Original file line number Diff line number Diff line change
@@ -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=<url> — endpoint (default: gittensory's hosted collector)
// ORB_COLLECTOR_URL=<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=<secret> — bearer credential for the hosted collector
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/pg-dialect.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/selfhost/private-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/queue-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const GITHUB_BUDGET_BACKGROUND_TYPES = new Set<string>([
"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
Expand Down
2 changes: 1 addition & 1 deletion src/selfhost/vectorize.ts
Original file line number Diff line number Diff line change
@@ -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).
Expand Down
2 changes: 1 addition & 1 deletion src/services/ai-review.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/services/draft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -703,7 +703,7 @@ export async function processSubmitDraft(env: Env, draftId: string): Promise<voi
targetPath: row.target_path,
content,
title,
body: "PR-first submission created via gittensory. The submission gate will review category fit, sources, duplicates, safety, and scope.",
body: "PR-first submission created via loopover. The submission gate will review category fit, sources, duplicates, safety, and scope.",
});
await env.DB.prepare(
`UPDATE submission_drafts SET status = 'pr_open', github_login = ?, fork_full_name = ?, pull_request_url = ?, pull_request_number = ?, updated_at = ? WHERE id = ?`,
Expand Down
2 changes: 1 addition & 1 deletion src/services/maintainer-recap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Maintainer-recap BUILDER (#2239, foundation for the #1963 recap digest).
//
// A PURE data-shaping seam: fold a window of gittensory's own review-outcome data across repos into a single
// A PURE data-shaping seam: fold a window of loopover's own review-outcome data across repos into a single
// serializable RecapReport. No delivery, no scheduling, no I/O, no model call — exactly the shape
// weekly-value-report.ts's buildWeeklyValueReport uses (inputs injected, report returned). The caller supplies
// each repo's two already-computed aggregators (services/gate-precision.ts buildGatePrecisionReport +
Expand Down
2 changes: 1 addition & 1 deletion src/services/notify-discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function isValidDiscordWebhook(url: string): boolean {
// self-hosters should prefer DISCORD_REPO_WEBHOOKS for per-repo routing, or DISCORD_WEBHOOK_URL for one shared
// channel across unmapped repos.
const WEBHOOK_SECRET_BY_REPO: Record<string, string> = {
"jsonbored/gittensory": "LOOPOVER_DISCORD_WEBHOOK",
"jsonbored/loopover": "LOOPOVER_DISCORD_WEBHOOK",
"jsonbored/metagraphed": "METAGRAPHED_DISCORD_WEBHOOK",
"jsonbored/awesome-claude": "AWESOME_DISCORD_WEBHOOK",
};
Expand Down
4 changes: 2 additions & 2 deletions src/services/outcome-calibration.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/services/plan-dag.ts
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
Loading
Loading