diff --git a/apps/loopover-extension/background.js b/apps/loopover-extension/background.js index 6266b1077f..070a794256 100644 --- a/apps/loopover-extension/background.js +++ b/apps/loopover-extension/background.js @@ -1,8 +1,8 @@ import { logoutExtensionSession, requestPullContext } from "./auth.js"; chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { - if (!message || !["gittensory:pull-context", "gittensory:logout"].includes(message.type)) return false; - const task = message.type === "gittensory:logout" ? logoutExtensionSession() : requestPullContext(message); + if (!message || !["loopover:pull-context", "loopover:logout"].includes(message.type)) return false; + const task = message.type === "loopover:logout" ? logoutExtensionSession() : requestPullContext(message); void task.then((payload) => sendResponse({ ok: true, payload })).catch((error) => sendResponse({ ok: false, error: error instanceof Error ? error.message : String(error) })); return true; }); diff --git a/apps/loopover-extension/content.js b/apps/loopover-extension/content.js index 001418500f..5cef4120a7 100644 --- a/apps/loopover-extension/content.js +++ b/apps/loopover-extension/content.js @@ -19,26 +19,26 @@ function matchPullRequestTarget(pathname) { } function mountOverlay(target) { - if (document.querySelector("[data-gittensory-pr-context]")) return; + if (document.querySelector("[data-loopover-pr-context]")) return; const container = document.createElement("aside"); const host = findPullRequestSidebar(); - container.className = `gittensory-overlay ${host ? "gittensory-overlay--sidebar" : "gittensory-overlay--floating"}`; + container.className = `loopover-overlay ${host ? "loopover-overlay--sidebar" : "loopover-overlay--floating"}`; container.dataset.loopoverPrContext = "true"; container.innerHTML = ` -
- G +
+ G LoopOver - Private - + Private +
-
Loading private context...
+
Loading private context...
`; if (host) { host.prepend(container); } else { document.body.appendChild(container); } - const refresh = container.querySelector(".gittensory-overlay__refresh"); + const refresh = container.querySelector(".loopover-overlay__refresh"); refresh?.addEventListener("click", () => load(container, target)); void load(container, target); } @@ -53,12 +53,12 @@ function findPullRequestSidebar() { } async function load(container, target) { - const body = container.querySelector(".gittensory-overlay__body"); + const body = container.querySelector(".loopover-overlay__body"); if (!body) return; body.textContent = "Loading private context..."; - const response = await chrome.runtime.sendMessage({ type: "gittensory:pull-context", ...target }); + const response = await chrome.runtime.sendMessage({ type: "loopover:pull-context", ...target }); if (!response?.ok) { - body.innerHTML = `
${escapeHtml(response?.error || "Context unavailable")}
`; + body.innerHTML = `
${escapeHtml(response?.error || "Context unavailable")}
`; return; } body.innerHTML = renderPullContext(response.payload); @@ -79,26 +79,26 @@ function renderSection(section) { const actions = Array.isArray(section?.actions) ? section.actions : []; const tone = ["good", "warn", "neutral", "private"].includes(section?.tone) ? section.tone : "neutral"; return ` -
-
+
+
${escapeHtml(section?.label || "Panel")} ${escapeHtml(section?.badge || "live")}
${rows.length > 0 ? `
${rows.map((row) => `
${escapeHtml(row.label || "")}
${escapeHtml(row.value || "")}
`).join("")}
` : ""} - ${items.length > 0 ? `
    ${items.map((item) => `
  • ${escapeHtml(item)}
  • `).join("")}
` : ""} - ${actions.length > 0 ? `
    ${actions.map((action) => `
  1. ${escapeHtml(action)}
  2. `).join("")}
` : ""} + ${items.length > 0 ? `
    ${items.map((item) => `
  • ${escapeHtml(item)}
  • `).join("")}
` : ""} + ${actions.length > 0 ? `
    ${actions.map((action) => `
  1. ${escapeHtml(action)}
  2. `).join("")}
` : ""}
`; } function renderLegacyPanels(payload) { const panels = Array.isArray(payload?.panels) ? payload.panels : []; - if (panels.length === 0) return `
No cached private context is available for this pull request.
`; + if (panels.length === 0) return `
No cached private context is available for this pull request.
`; return panels .map( (panel) => ` -
-
+
+
${escapeHtml(panel.label || "Panel")} ${escapeHtml(panel.badge || "live")}
@@ -134,15 +134,15 @@ function renderActions(body, actions) { const list = Array.isArray(actions) ? actions : []; if (list.length === 0) return; const container = document.createElement("section"); - container.className = "gittensory-overlay__panel gittensory-overlay__panel--private"; + container.className = "loopover-overlay__panel loopover-overlay__panel--private"; container.innerHTML = ` -
+
Actions extension
-
+
`; - const actionsNode = container.querySelector(".gittensory-overlay__action-buttons"); + const actionsNode = container.querySelector(".loopover-overlay__action-buttons"); if (!actionsNode) return; for (const action of list) { if (action?.id === "copy_public_safe_packet" && typeof action?.markdown === "string") { diff --git a/apps/loopover-extension/styles.css b/apps/loopover-extension/styles.css index 4070d136c5..b98bcb869f 100644 --- a/apps/loopover-extension/styles.css +++ b/apps/loopover-extension/styles.css @@ -1,4 +1,4 @@ -.gittensory-overlay { +.loopover-overlay { border: 1px solid rgba(126, 231, 188, 0.45); border-radius: 8px; background: #0f1117; @@ -6,13 +6,13 @@ font: 13px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } -.gittensory-overlay--sidebar { +.loopover-overlay--sidebar { width: 100%; margin-bottom: 16px; overflow: hidden; } -.gittensory-overlay--floating { +.loopover-overlay--floating { position: fixed; right: 16px; bottom: 16px; @@ -23,7 +23,7 @@ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45); } -.gittensory-overlay__header { +.loopover-overlay__header { display: flex; align-items: center; gap: 8px; @@ -32,7 +32,7 @@ font-weight: 650; } -.gittensory-overlay__privacy { +.loopover-overlay__privacy { border: 1px solid rgba(126, 231, 188, 0.35); border-radius: 999px; color: #7ee7bc; @@ -43,7 +43,7 @@ text-transform: uppercase; } -.gittensory-overlay__mark { +.loopover-overlay__mark { display: inline-flex; width: 22px; height: 22px; @@ -55,7 +55,7 @@ font-weight: 800; } -.gittensory-overlay__refresh { +.loopover-overlay__refresh { margin-left: auto; border: 1px solid rgba(255, 255, 255, 0.18); border-radius: 6px; @@ -66,33 +66,33 @@ padding: 3px 7px; } -.gittensory-overlay__body { +.loopover-overlay__body { padding: 12px; } -.gittensory-overlay__panel { +.loopover-overlay__panel { border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 7px; padding: 10px; } -.gittensory-overlay__panel--good { +.loopover-overlay__panel--good { border-color: rgba(126, 231, 188, 0.35); } -.gittensory-overlay__panel--warn { +.loopover-overlay__panel--warn { border-color: rgba(255, 189, 105, 0.45); } -.gittensory-overlay__panel--private { +.loopover-overlay__panel--private { border-color: rgba(145, 181, 255, 0.38); } -.gittensory-overlay__panel + .gittensory-overlay__panel { +.loopover-overlay__panel + .loopover-overlay__panel { margin-top: 8px; } -.gittensory-overlay__panel-head { +.loopover-overlay__panel-head { display: flex; align-items: center; justify-content: space-between; @@ -100,7 +100,7 @@ margin-bottom: 8px; } -.gittensory-overlay__panel-head span { +.loopover-overlay__panel-head span { border: 1px solid rgba(126, 231, 188, 0.4); border-radius: 999px; color: #7ee7bc; @@ -109,32 +109,32 @@ text-transform: uppercase; } -.gittensory-overlay__panel--warn .gittensory-overlay__panel-head span { +.loopover-overlay__panel--warn .loopover-overlay__panel-head span { border-color: rgba(255, 189, 105, 0.45); color: #ffbd69; } -.gittensory-overlay__panel--private .gittensory-overlay__panel-head span { +.loopover-overlay__panel--private .loopover-overlay__panel-head span { border-color: rgba(145, 181, 255, 0.45); color: #91b5ff; } -.gittensory-overlay dl { +.loopover-overlay dl { margin: 0; } -.gittensory-overlay dl div { +.loopover-overlay dl div { display: flex; justify-content: space-between; gap: 12px; } -.gittensory-overlay dt { +.loopover-overlay dt { color: rgba(244, 247, 245, 0.62); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; } -.gittensory-overlay dd { +.loopover-overlay dd { margin: 0; color: rgba(244, 247, 245, 0.9); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; @@ -142,29 +142,29 @@ overflow-wrap: anywhere; } -.gittensory-overlay__list, -.gittensory-overlay__actions { +.loopover-overlay__list, +.loopover-overlay__actions { margin: 8px 0 0; padding-left: 18px; } -.gittensory-overlay__list li, -.gittensory-overlay__actions li { +.loopover-overlay__list li, +.loopover-overlay__actions li { color: rgba(244, 247, 245, 0.78); margin-top: 4px; } -.gittensory-overlay__actions li { +.loopover-overlay__actions li { color: rgba(244, 247, 245, 0.9); } -.gittensory-overlay__action-buttons { +.loopover-overlay__action-buttons { display: grid; gap: 8px; } -.gittensory-overlay__action-buttons button, -.gittensory-overlay__action-buttons details { +.loopover-overlay__action-buttons button, +.loopover-overlay__action-buttons details { border: 1px solid rgba(145, 181, 255, 0.32); border-radius: 6px; background: rgba(145, 181, 255, 0.08); @@ -172,35 +172,35 @@ font: inherit; } -.gittensory-overlay__action-buttons button { +.loopover-overlay__action-buttons button { cursor: pointer; padding: 7px 9px; text-align: left; } -.gittensory-overlay__action-buttons details { +.loopover-overlay__action-buttons details { padding: 7px 9px; } -.gittensory-overlay__action-buttons summary { +.loopover-overlay__action-buttons summary { cursor: pointer; font-weight: 650; } -.gittensory-overlay__action-buttons ul { +.loopover-overlay__action-buttons ul { margin: 6px 0 0; padding-left: 18px; } -.gittensory-overlay__action-buttons li { +.loopover-overlay__action-buttons li { color: rgba(244, 247, 245, 0.82); margin-top: 4px; } -.gittensory-overlay__error { +.loopover-overlay__error { color: #ffb4a8; } -.gittensory-overlay__empty { +.loopover-overlay__empty { color: rgba(244, 247, 245, 0.72); } diff --git a/apps/loopover-miner-extension/background.js b/apps/loopover-miner-extension/background.js index ef7a6ffe05..0c29bf9f8d 100644 --- a/apps/loopover-miner-extension/background.js +++ b/apps/loopover-miner-extension/background.js @@ -4,9 +4,9 @@ import "./toolbar-badge.js"; const badgeApi = globalThis.__loopoverMinerOpportunityBadge; const toolbarBadgeApi = globalThis.__loopoverMinerToolbarBadge; -const PING_MESSAGE = "gittensory-miner:ping"; -const ISSUE_CONTEXT_MESSAGE = "gittensory-miner:issue-context"; -const SYNC_RANKED_CANDIDATES_MESSAGE = "gittensory-miner:sync-ranked-candidates"; +const PING_MESSAGE = "loopover-miner:ping"; +const ISSUE_CONTEXT_MESSAGE = "loopover-miner:issue-context"; +const SYNC_RANKED_CANDIDATES_MESSAGE = "loopover-miner:sync-ranked-candidates"; chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { if (!message || typeof message.type !== "string") return false; @@ -85,7 +85,7 @@ async function loadRankedCandidates() { } const DEFAULT_MINER_UI_URL = "http://localhost:5174"; -const SYNC_ALARM_NAME = "gittensory-miner:sync-ranked-candidates"; +const SYNC_ALARM_NAME = "loopover-miner:sync-ranked-candidates"; const SYNC_ALARM_PERIOD_MINUTES = 10; async function loadMinerUiUrl() { @@ -158,7 +158,7 @@ async function refreshToolbarBadge() { await chrome.action.setBadgeText({ text: badge.text }); await chrome.action.setBadgeBackgroundColor({ color: badge.backgroundColor }); } catch (error) { - console.warn("gittensory-miner: failed to refresh toolbar badge", error); + console.warn("loopover-miner: failed to refresh toolbar badge", error); } } diff --git a/apps/loopover-miner-extension/content.js b/apps/loopover-miner-extension/content.js index 1caea9b73a..27e40f4433 100644 --- a/apps/loopover-miner-extension/content.js +++ b/apps/loopover-miner-extension/content.js @@ -14,12 +14,12 @@ function matchGitHubIssueTarget(pathname) { } function mountOpportunityBadge(target) { - if (document.querySelector("[data-gittensory-miner-opportunity-badge]")) return; + if (document.querySelector("[data-loopover-miner-opportunity-badge]")) return; const host = findIssueSidebar(); const container = document.createElement("aside"); container.className = host - ? "gittensory-miner-opportunity-badge" - : "gittensory-miner-opportunity-badge gittensory-miner-opportunity-badge--floating"; + ? "loopover-miner-opportunity-badge" + : "loopover-miner-opportunity-badge loopover-miner-opportunity-badge--floating"; container.dataset.loopoverMinerOpportunityBadge = "true"; container.hidden = true; if (host) { @@ -41,7 +41,7 @@ function findIssueSidebar() { async function loadOpportunityBadge(container, target) { const response = await chrome.runtime.sendMessage({ - type: "gittensory-miner:issue-context", + type: "loopover-miner:issue-context", owner: target.owner, repo: target.repo, issueNumber: target.issueNumber, diff --git a/apps/loopover-miner-extension/opportunity-badge.js b/apps/loopover-miner-extension/opportunity-badge.js index 50a8cdb1a9..45a89d42ed 100644 --- a/apps/loopover-miner-extension/opportunity-badge.js +++ b/apps/loopover-miner-extension/opportunity-badge.js @@ -79,19 +79,19 @@ function escapeOpportunityHtml(value) { function renderOpportunityBadgeMarkup(badge, lastSyncedLabel) { if (!badge || typeof badge !== "object") return ""; return ` -
- G +
+ G LoopOver opportunity - Read-only + Read-only
-
+
${escapeOpportunityHtml(badge.tier)} ${escapeOpportunityHtml(badge.score)}
-

${escapeOpportunityHtml(badge.why)}

+

${escapeOpportunityHtml(badge.why)}

${ lastSyncedLabel - ? `

${escapeOpportunityHtml(lastSyncedLabel)}

` + ? `

${escapeOpportunityHtml(lastSyncedLabel)}

` : "" } `; diff --git a/apps/loopover-miner-extension/options.js b/apps/loopover-miner-extension/options.js index 8051fb37c5..b674b36169 100644 --- a/apps/loopover-miner-extension/options.js +++ b/apps/loopover-miner-extension/options.js @@ -43,7 +43,7 @@ async function removeLegacyDiscoveryIndexUrl() { // Mirrors background.js's own literal (#4859) -- these classic (non-ESM-importing) extension scripts share a // message-type "protocol" via matching string literals, the same convention content.js already uses for // ISSUE_CONTEXT_MESSAGE, not a cross-file import. -const SYNC_RANKED_CANDIDATES_MESSAGE = "gittensory-miner:sync-ranked-candidates"; +const SYNC_RANKED_CANDIDATES_MESSAGE = "loopover-miner:sync-ranked-candidates"; const DEFAULT_MINER_UI_URL = "http://localhost:5174"; function normalizeMinerUiUrl(text) { diff --git a/apps/loopover-miner-extension/styles.css b/apps/loopover-miner-extension/styles.css index d5e30515f4..5d34ec6baa 100644 --- a/apps/loopover-miner-extension/styles.css +++ b/apps/loopover-miner-extension/styles.css @@ -1,4 +1,4 @@ -.gittensory-miner-opportunity-badge { +.loopover-miner-opportunity-badge { border: 1px solid rgba(126, 231, 188, 0.35); border-radius: 8px; background: rgba(15, 17, 23, 0.96); @@ -8,7 +8,7 @@ padding: 12px; } -.gittensory-miner-opportunity-badge--floating { +.loopover-miner-opportunity-badge--floating { position: fixed; right: 16px; bottom: 16px; @@ -17,14 +17,14 @@ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); } -.gittensory-miner-opportunity-badge__header { +.loopover-miner-opportunity-badge__header { align-items: center; display: flex; gap: 8px; margin-bottom: 8px; } -.gittensory-miner-opportunity-badge__mark { +.loopover-miner-opportunity-badge__mark { align-items: center; background: #7ee7bc; border-radius: 999px; @@ -37,33 +37,33 @@ width: 20px; } -.gittensory-miner-opportunity-badge__read-only { +.loopover-miner-opportunity-badge__read-only { color: rgba(244, 247, 245, 0.55); font-size: 11px; margin-left: auto; } -.gittensory-miner-opportunity-badge__score { +.loopover-miner-opportunity-badge__score { align-items: baseline; display: flex; gap: 8px; margin-bottom: 6px; } -.gittensory-miner-opportunity-badge__score strong { +.loopover-miner-opportunity-badge__score strong { font-size: 15px; } -.gittensory-miner-opportunity-badge__score span { +.loopover-miner-opportunity-badge__score span { color: rgba(244, 247, 245, 0.72); } -.gittensory-miner-opportunity-badge__why { +.loopover-miner-opportunity-badge__why { color: rgba(244, 247, 245, 0.78); margin: 0; } -.gittensory-miner-opportunity-badge__synced { +.loopover-miner-opportunity-badge__synced { color: rgba(244, 247, 245, 0.55); font-size: 11px; margin: 6px 0 0; diff --git a/apps/loopover-miner-extension/test/background.test.ts b/apps/loopover-miner-extension/test/background.test.ts index 1c9d8b00af..c39ba309d6 100644 --- a/apps/loopover-miner-extension/test/background.test.ts +++ b/apps/loopover-miner-extension/test/background.test.ts @@ -253,10 +253,10 @@ describe("background service worker", () => { fetchImpl: jsonFetch(200, { candidates: [] }), }); - expect(mod.alarmCreateCalls[0]?.[0]).toBe("gittensory-miner:sync-ranked-candidates"); + expect(mod.alarmCreateCalls[0]?.[0]).toBe("loopover-miner:sync-ranked-candidates"); mod.dispatchStartup(); mod.dispatchInstalled(); - mod.dispatchAlarm("gittensory-miner:sync-ranked-candidates"); + mod.dispatchAlarm("loopover-miner:sync-ranked-candidates"); mod.dispatchAlarm("other-alarm"); await flush(); expect(mod.localSetCalls.length).toBeGreaterThan(0); diff --git a/apps/loopover-ui/public/openapi.json b/apps/loopover-ui/public/openapi.json index 8d1ffc2e0a..293bb3a837 100644 --- a/apps/loopover-ui/public/openapi.json +++ b/apps/loopover-ui/public/openapi.json @@ -17161,7 +17161,7 @@ "schema": { "type": "string", "minLength": 1, - "example": "gittensory" + "example": "loopover" }, "required": true, "description": "Repository name", diff --git a/apps/loopover-ui/src/lib/analytics-window.ts b/apps/loopover-ui/src/lib/analytics-window.ts index 9b4a275fd4..41176da577 100644 --- a/apps/loopover-ui/src/lib/analytics-window.ts +++ b/apps/loopover-ui/src/lib/analytics-window.ts @@ -1,7 +1,7 @@ export const ANALYTICS_WINDOW_OPTIONS = [7, 30, 90] as const; export type AnalyticsWindowDays = (typeof ANALYTICS_WINDOW_OPTIONS)[number]; export const DEFAULT_ANALYTICS_WINDOW_DAYS: AnalyticsWindowDays = 7; -export const ANALYTICS_WINDOW_STORAGE_KEY = "gittensory.analytics.windowDays"; +export const ANALYTICS_WINDOW_STORAGE_KEY = "loopover.analytics.windowDays"; export function parseAnalyticsWindowDays(value: unknown): AnalyticsWindowDays { const numeric = Number(value); diff --git a/apps/loopover-ui/src/lib/api/session.ts b/apps/loopover-ui/src/lib/api/session.ts index 85452a0fca..9704ec3c16 100644 --- a/apps/loopover-ui/src/lib/api/session.ts +++ b/apps/loopover-ui/src/lib/api/session.ts @@ -45,7 +45,7 @@ type AuthState = type SessionResponse = (AppSession & { status: "authenticated" }) | { status: "signed_out" }; -const SESSION_CHANGED_EVENT = "gittensory.session.changed"; +const SESSION_CHANGED_EVENT = "loopover.session.changed"; async function fetchBrowserSession(): Promise { const origin = getApiOrigin().replace(/\/$/, ""); diff --git a/apps/loopover-ui/src/routeTree.gen.ts b/apps/loopover-ui/src/routeTree.gen.ts index 5cf0eca531..737dfd2c8b 100644 --- a/apps/loopover-ui/src/routeTree.gen.ts +++ b/apps/loopover-ui/src/routeTree.gen.ts @@ -50,8 +50,8 @@ import { Route as DocsMcpClientsRouteImport } from './routes/docs.mcp-clients' import { Route as DocsMaintainerWorkflowRouteImport } from './routes/docs.maintainer-workflow' import { Route as DocsMaintainerSelfHostingRouteImport } from './routes/docs.maintainer-self-hosting' import { Route as DocsMaintainerInstallTrustRouteImport } from './routes/docs.maintainer-install-trust' +import { Route as DocsLoopoverCommandsRouteImport } from './routes/docs.loopover-commands' import { Route as DocsHowReviewsWorkRouteImport } from './routes/docs.how-reviews-work' -import { Route as DocsGittensoryCommandsRouteImport } from './routes/docs.gittensory-commands' import { Route as DocsGithubAppRouteImport } from './routes/docs.github-app' import { Route as DocsBranchAnalysisRouteImport } from './routes/docs.branch-analysis' import { Route as DocsBetaOnboardingRouteImport } from './routes/docs.beta-onboarding' @@ -289,16 +289,16 @@ const DocsMaintainerInstallTrustRoute = path: '/maintainer-install-trust', getParentRoute: () => DocsRoute, } as any) +const DocsLoopoverCommandsRoute = DocsLoopoverCommandsRouteImport.update({ + id: '/loopover-commands', + path: '/loopover-commands', + getParentRoute: () => DocsRoute, +} as any) const DocsHowReviewsWorkRoute = DocsHowReviewsWorkRouteImport.update({ id: '/how-reviews-work', path: '/how-reviews-work', getParentRoute: () => DocsRoute, } as any) -const DocsGittensoryCommandsRoute = DocsGittensoryCommandsRouteImport.update({ - id: '/gittensory-commands', - path: '/gittensory-commands', - getParentRoute: () => DocsRoute, -} as any) const DocsGithubAppRoute = DocsGithubAppRouteImport.update({ id: '/github-app', path: '/github-app', @@ -424,8 +424,8 @@ export interface FileRoutesByFullPath { '/docs/beta-onboarding': typeof DocsBetaOnboardingRoute '/docs/branch-analysis': typeof DocsBranchAnalysisRoute '/docs/github-app': typeof DocsGithubAppRoute - '/docs/gittensory-commands': typeof DocsGittensoryCommandsRoute '/docs/how-reviews-work': typeof DocsHowReviewsWorkRoute + '/docs/loopover-commands': typeof DocsLoopoverCommandsRoute '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-self-hosting': typeof DocsMaintainerSelfHostingRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute @@ -485,8 +485,8 @@ export interface FileRoutesByTo { '/docs/beta-onboarding': typeof DocsBetaOnboardingRoute '/docs/branch-analysis': typeof DocsBranchAnalysisRoute '/docs/github-app': typeof DocsGithubAppRoute - '/docs/gittensory-commands': typeof DocsGittensoryCommandsRoute '/docs/how-reviews-work': typeof DocsHowReviewsWorkRoute + '/docs/loopover-commands': typeof DocsLoopoverCommandsRoute '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-self-hosting': typeof DocsMaintainerSelfHostingRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute @@ -550,8 +550,8 @@ export interface FileRoutesById { '/docs/beta-onboarding': typeof DocsBetaOnboardingRoute '/docs/branch-analysis': typeof DocsBranchAnalysisRoute '/docs/github-app': typeof DocsGithubAppRoute - '/docs/gittensory-commands': typeof DocsGittensoryCommandsRoute '/docs/how-reviews-work': typeof DocsHowReviewsWorkRoute + '/docs/loopover-commands': typeof DocsLoopoverCommandsRoute '/docs/maintainer-install-trust': typeof DocsMaintainerInstallTrustRoute '/docs/maintainer-self-hosting': typeof DocsMaintainerSelfHostingRoute '/docs/maintainer-workflow': typeof DocsMaintainerWorkflowRoute @@ -616,8 +616,8 @@ export interface FileRouteTypes { | '/docs/beta-onboarding' | '/docs/branch-analysis' | '/docs/github-app' - | '/docs/gittensory-commands' | '/docs/how-reviews-work' + | '/docs/loopover-commands' | '/docs/maintainer-install-trust' | '/docs/maintainer-self-hosting' | '/docs/maintainer-workflow' @@ -677,8 +677,8 @@ export interface FileRouteTypes { | '/docs/beta-onboarding' | '/docs/branch-analysis' | '/docs/github-app' - | '/docs/gittensory-commands' | '/docs/how-reviews-work' + | '/docs/loopover-commands' | '/docs/maintainer-install-trust' | '/docs/maintainer-self-hosting' | '/docs/maintainer-workflow' @@ -741,8 +741,8 @@ export interface FileRouteTypes { | '/docs/beta-onboarding' | '/docs/branch-analysis' | '/docs/github-app' - | '/docs/gittensory-commands' | '/docs/how-reviews-work' + | '/docs/loopover-commands' | '/docs/maintainer-install-trust' | '/docs/maintainer-self-hosting' | '/docs/maintainer-workflow' @@ -1080,6 +1080,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DocsMaintainerInstallTrustRouteImport parentRoute: typeof DocsRoute } + '/docs/loopover-commands': { + id: '/docs/loopover-commands' + path: '/loopover-commands' + fullPath: '/docs/loopover-commands' + preLoaderRoute: typeof DocsLoopoverCommandsRouteImport + parentRoute: typeof DocsRoute + } '/docs/how-reviews-work': { id: '/docs/how-reviews-work' path: '/how-reviews-work' @@ -1087,13 +1094,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DocsHowReviewsWorkRouteImport parentRoute: typeof DocsRoute } - '/docs/gittensory-commands': { - id: '/docs/gittensory-commands' - path: '/gittensory-commands' - fullPath: '/docs/gittensory-commands' - preLoaderRoute: typeof DocsGittensoryCommandsRouteImport - parentRoute: typeof DocsRoute - } '/docs/github-app': { id: '/docs/github-app' path: '/github-app' @@ -1283,8 +1283,8 @@ interface DocsRouteChildren { DocsBetaOnboardingRoute: typeof DocsBetaOnboardingRoute DocsBranchAnalysisRoute: typeof DocsBranchAnalysisRoute DocsGithubAppRoute: typeof DocsGithubAppRoute - DocsGittensoryCommandsRoute: typeof DocsGittensoryCommandsRoute DocsHowReviewsWorkRoute: typeof DocsHowReviewsWorkRoute + DocsLoopoverCommandsRoute: typeof DocsLoopoverCommandsRoute DocsMaintainerInstallTrustRoute: typeof DocsMaintainerInstallTrustRoute DocsMaintainerSelfHostingRoute: typeof DocsMaintainerSelfHostingRoute DocsMaintainerWorkflowRoute: typeof DocsMaintainerWorkflowRoute @@ -1321,8 +1321,8 @@ const DocsRouteChildren: DocsRouteChildren = { DocsBetaOnboardingRoute: DocsBetaOnboardingRoute, DocsBranchAnalysisRoute: DocsBranchAnalysisRoute, DocsGithubAppRoute: DocsGithubAppRoute, - DocsGittensoryCommandsRoute: DocsGittensoryCommandsRoute, DocsHowReviewsWorkRoute: DocsHowReviewsWorkRoute, + DocsLoopoverCommandsRoute: DocsLoopoverCommandsRoute, DocsMaintainerInstallTrustRoute: DocsMaintainerInstallTrustRoute, DocsMaintainerSelfHostingRoute: DocsMaintainerSelfHostingRoute, DocsMaintainerWorkflowRoute: DocsMaintainerWorkflowRoute, diff --git a/apps/loopover-ui/src/routes/docs.index.tsx b/apps/loopover-ui/src/routes/docs.index.tsx index b2711c2075..1ba6b3192d 100644 --- a/apps/loopover-ui/src/routes/docs.index.tsx +++ b/apps/loopover-ui/src/routes/docs.index.tsx @@ -76,7 +76,7 @@ const AUDIENCES: Audience[] = [ { to: "/docs/maintainer-install-trust", label: "Install & trust guide" }, { to: "/docs/github-app", label: "GitHub App configuration" }, { to: "/docs/maintainer-workflow", label: "Maintainer workflow" }, - { to: "/docs/gittensory-commands", label: "@loopover commands" }, + { to: "/docs/loopover-commands", label: "@loopover commands" }, { to: "/docs/self-hosting-rees-analyzers", label: "REES analyzers" }, { to: "/docs/upstream-drift", label: "Upstream drift" }, { to: "/docs/ai-summaries", label: "AI summaries policy" }, diff --git a/apps/loopover-ui/src/routes/docs.gittensory-commands.tsx b/apps/loopover-ui/src/routes/docs.loopover-commands.tsx similarity index 96% rename from apps/loopover-ui/src/routes/docs.gittensory-commands.tsx rename to apps/loopover-ui/src/routes/docs.loopover-commands.tsx index 067db74a58..1b509a191a 100644 --- a/apps/loopover-ui/src/routes/docs.gittensory-commands.tsx +++ b/apps/loopover-ui/src/routes/docs.loopover-commands.tsx @@ -8,7 +8,7 @@ import { PUBLIC_COMMAND_ENTRIES, } from "@/lib/command-reference"; -export const Route = createFileRoute("/docs/gittensory-commands")({ +export const Route = createFileRoute("/docs/loopover-commands")({ head: () => ({ meta: [ { title: "@loopover command reference — LoopOver docs" }, @@ -23,9 +23,9 @@ export const Route = createFileRoute("/docs/gittensory-commands")({ content: "Every @loopover PR and issue comment command: syntax, default authorization roles, and the hard boundary between auto-review and the one-shot gate.", }, - { property: "og:url", content: "/docs/gittensory-commands" }, + { property: "og:url", content: "/docs/loopover-commands" }, ], - links: [{ rel: "canonical", href: "/docs/gittensory-commands" }], + links: [{ rel: "canonical", href: "/docs/loopover-commands" }], }), component: LoopOverCommandsReference, }); diff --git a/apps/loopover-ui/src/routes/docs.maintainer-workflow.tsx b/apps/loopover-ui/src/routes/docs.maintainer-workflow.tsx index 1d7fe44b26..328c4f912e 100644 --- a/apps/loopover-ui/src/routes/docs.maintainer-workflow.tsx +++ b/apps/loopover-ui/src/routes/docs.maintainer-workflow.tsx @@ -160,7 +160,7 @@ GET /v1/repos/:owner/:repo/registration-readiness`}

For syntax, default roles, PR action verbs, and the gate vs auto-review boundary, see the{" "} - @loopover command reference. + @loopover command reference.

diff --git a/packages/loopover-engine/src/miner/worktree-plan.ts b/packages/loopover-engine/src/miner/worktree-plan.ts index 0d29fe1b14..e052ad074c 100644 --- a/packages/loopover-engine/src/miner/worktree-plan.ts +++ b/packages/loopover-engine/src/miner/worktree-plan.ts @@ -30,8 +30,8 @@ export type WorktreePlan = { }; /** Worktrees live under this dir inside the repo; the branch carries this prefix. */ -export const WORKTREE_SUBDIR = ".gittensory-worktrees"; -export const WORKTREE_BRANCH_PREFIX = "gittensory/attempt/"; +export const WORKTREE_SUBDIR = ".loopover-worktrees"; +export const WORKTREE_BRANCH_PREFIX = "loopover/attempt/"; const MAX_SLUG_LENGTH = 64; /** Deterministically slugify an attempt id into a filesystem- and git-ref-safe token (same id → same slug). */ diff --git a/scripts/check-docs-drift.mjs b/scripts/check-docs-drift.mjs index ad77016942..5a20df76a7 100644 --- a/scripts/check-docs-drift.mjs +++ b/scripts/check-docs-drift.mjs @@ -297,7 +297,7 @@ export function checkDocsDrift({ root, readFile = defaultReadFile }) { if (allCommandIds.length < 15) { failures.push(`src/github/commands.ts: extraction found only ${allCommandIds.length} unique @loopover command ids -- expected 15+; the extraction regex may be broken`); } else { - const commandDocsPages = ["docs.maintainer-workflow.tsx", "docs.maintainer-install-trust.tsx", "docs.gittensory-commands.tsx"]; + const commandDocsPages = ["docs.maintainer-workflow.tsx", "docs.maintainer-install-trust.tsx", "docs.loopover-commands.tsx"]; for (const page of commandDocsPages) { const pageText = read(`${DOCS_ROUTES_DIR}/${page}`); if (pageText.includes("@/lib/command-reference")) continue; diff --git a/scripts/mcp-release-core.mjs b/scripts/mcp-release-core.mjs index f7809b798d..b9f8a6c76d 100644 --- a/scripts/mcp-release-core.mjs +++ b/scripts/mcp-release-core.mjs @@ -1,4 +1,4 @@ -export const MCP_RELEASE_DUE_MARKER = ""; +export const MCP_RELEASE_DUE_MARKER = ""; const DIRECT_MCP_PATHS = [ "packages/loopover-mcp/", diff --git a/src/db/repositories.ts b/src/db/repositories.ts index 4c101417c6..a8e7d4a0e2 100644 --- a/src/db/repositories.ts +++ b/src/db/repositories.ts @@ -4006,7 +4006,7 @@ async function listRepoFullNamesForInstallation(env: Env, installationId: number if (rows.length === INSTALLATION_REPO_LIST_LIMIT) { await recordAuditEvent(env, { eventType: "agent.global_open_item_cap.repo_list_truncated", - actor: "gittensory", + actor: "loopover", targetKey: `installation:${installationId}`, outcome: "error", detail: `installation has >= ${INSTALLATION_REPO_LIST_LIMIT} repos; the global contributor-cap check may undercount repos not included here`, @@ -4055,7 +4055,7 @@ export async function listOpenItemsForAuthorAcrossInstall(env: Env, installation if (prRows.length === AUTHOR_OPEN_ITEM_LIST_LIMIT) { await recordAuditEvent(env, { eventType: "agent.global_open_item_cap.author_items_truncated", - actor: "gittensory", + actor: "loopover", targetKey: `${authorLogin}@installation:${installationId}`, outcome: "error", detail: `author has >= ${AUTHOR_OPEN_ITEM_LIST_LIMIT} open pull requests across the install; the global contributor-cap check may undercount`, @@ -4069,7 +4069,7 @@ export async function listOpenItemsForAuthorAcrossInstall(env: Env, installation if (issueRows.length === AUTHOR_OPEN_ITEM_LIST_LIMIT) { await recordAuditEvent(env, { eventType: "agent.global_open_item_cap.author_items_truncated", - actor: "gittensory", + actor: "loopover", targetKey: `${authorLogin}@installation:${installationId}`, outcome: "error", detail: `author has >= ${AUTHOR_OPEN_ITEM_LIST_LIMIT} open issues across the install; the global contributor-cap check may undercount`, @@ -6743,7 +6743,7 @@ async function hashProductUsageIdentifier(env: Env, kind: "actor" | "session", v if (!normalized) return null; const salt = env.PRODUCT_USAGE_HASH_SALT; if (!salt) return null; - return sha256Hex(`gittensory:product-usage:v1:${kind}:${salt}:${normalized}`); + return sha256Hex(`loopover:product-usage:v1:${kind}:${salt}:${normalized}`); } function boundedProductUsageField(value: unknown, maxLength: number): string | null { diff --git a/src/github/client.ts b/src/github/client.ts index 7f76a416ef..295f534270 100644 --- a/src/github/client.ts +++ b/src/github/client.ts @@ -703,7 +703,7 @@ export function makeInstallationOctokit(env: Env, token: string, mode: AgentActi const url = options.url; await recordAuditEvent(env, { eventType: "github.write.suppressed", - actor: "gittensory", + actor: "loopover", targetKey: url, outcome: effectiveMode === "dry_run" ? "completed" : "denied", detail: `${effectiveMode}: suppressed ${method} ${url}`, diff --git a/src/github/e2e-test-commit.ts b/src/github/e2e-test-commit.ts index ecd7383a45..e9b392e0d6 100644 --- a/src/github/e2e-test-commit.ts +++ b/src/github/e2e-test-commit.ts @@ -57,7 +57,7 @@ export async function commitE2eTestToPrBranch( if (args.mode !== "live") return { status: "declined", reason: `commit not pushed: action mode is "${args.mode}"` }; const { owner, name: repo } = repoParts(args.repoFullName); const path = args.testFilePath?.trim() || defaultE2eTestFilePath(args.prNumber); - const message = `test: add AI-generated E2E test\n\nGenerated-by: gittensory (invoked by @${args.actor})`; + const message = `test: add AI-generated E2E test\n\nGenerated-by: loopover (invoked by @${args.actor})`; try { return await withInstallationTokenRetry(env, args.installationId, async (token) => { const octokit = makeInstallationOctokit(env, token, args.mode, githubRateLimitAdmissionKeyForInstallation(args.installationId)); diff --git a/src/github/footer.ts b/src/github/footer.ts index 47737aee62..9fa89816d6 100644 --- a/src/github/footer.ts +++ b/src/github/footer.ts @@ -44,9 +44,9 @@ export function maintainerControlPanelUrl(env: { PUBLIC_SITE_ORIGIN?: string | u export function commandReferenceUrl(env: LoopOverFooterEnv): string { const origin = env.PUBLIC_SITE_ORIGIN ?? LOOPOVER_SITE_URL; try { - return new URL("/docs/gittensory-commands", origin).toString(); + return new URL("/docs/loopover-commands", origin).toString(); } catch { - return `${LOOPOVER_SITE_URL}/docs/gittensory-commands`; + return `${LOOPOVER_SITE_URL}/docs/loopover-commands`; } } diff --git a/src/github/repo-doc-pr.ts b/src/github/repo-doc-pr.ts index 75251998a1..f9381f6ab9 100644 --- a/src/github/repo-doc-pr.ts +++ b/src/github/repo-doc-pr.ts @@ -39,7 +39,7 @@ import type { AgentActionMode } from "../settings/agent-execution"; /** Stable across runs (not per-run unique) so a repeat invocation targets the SAME branch/PR instead of piling up * duplicates -- #3004's diff-aware refresh is expected to update commits on this same branch rather than open a * second PR. #3000 itself only needs the "already an open PR on this branch" short-circuit below. */ -const REPO_DOC_BRANCH_NAME = "gittensory/repo-docs"; +const REPO_DOC_BRANCH_NAME = "loopover/repo-docs"; const AGENTS_FILE_PATH = "AGENTS.md"; const CLAUDE_FILE_PATH = "CLAUDE.md"; const PR_TITLE = "docs: generate AGENTS.md and CLAUDE.md from repo profile"; diff --git a/src/openapi/spec.ts b/src/openapi/spec.ts index 48ea37f095..23e4dcfb91 100644 --- a/src/openapi/spec.ts +++ b/src/openapi/spec.ts @@ -961,7 +961,7 @@ export function buildOpenApiSpec() { request: { query: z.object({ owner: z.string().min(1).openapi({ param: { description: "Repository owner" }, example: "JSONbored" }), - repo: z.string().min(1).openapi({ param: { description: "Repository name" }, example: "gittensory" }), + repo: z.string().min(1).openapi({ param: { description: "Repository name" }, example: "loopover" }), pullNumber: z.string().min(1).openapi({ param: { description: "Pull request number" }, example: "120" }), }), }, diff --git a/src/queue/dlq.ts b/src/queue/dlq.ts index bf0e7eff33..cf5a23aebc 100644 --- a/src/queue/dlq.ts +++ b/src/queue/dlq.ts @@ -39,7 +39,7 @@ export async function processDlqBatch(batch: MessageBatch, env: Env, // Best-effort audit record — never block the ack on a write failure. await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: `dlq:${jobType}:${message.id}`, outcome: "error", detail: `Job of type '${jobType}' exhausted all retries and was dead-lettered.`, diff --git a/src/queue/processors.ts b/src/queue/processors.ts index b1c1fbd8bf..e5999a0f93 100644 --- a/src/queue/processors.ts +++ b/src/queue/processors.ts @@ -1089,7 +1089,7 @@ async function surfaceRepairPriorityPullNumbers( const targetKey = regateRepairTargetKey(repoFullName, pr.number, pr.headSha); const attempts = await countRecentAuditEventsForActorAndTarget( env, - "gittensory", + "loopover", REGATE_REPAIR_ATTEMPT_EVENT_TYPE, targetKey, sinceIso, @@ -1098,7 +1098,7 @@ async function surfaceRepairPriorityPullNumbers( priorityPullNumbers.delete(prNumber); const alreadyFlagged = await countRecentAuditEventsForActorAndTarget( env, - "gittensory", + "loopover", REGATE_REPAIR_EXHAUSTED_EVENT_TYPE, targetKey, sinceIso, @@ -1106,7 +1106,7 @@ async function surfaceRepairPriorityPullNumbers( if (alreadyFlagged > 0) return; await recordAuditEvent(env, { eventType: REGATE_REPAIR_EXHAUSTED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: `re-gate repair exhausted after ${attempts} attempt(s) for the same head SHA; falling back to ordinary staleness cadence`, @@ -1339,7 +1339,7 @@ export async function sweepRepoRegate( if (mode === "paused") { await recordAuditEvent(env, { eventType: "agent.sweep.regate", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "denied", detail: "agent actions paused — re-gate sweep skipped", @@ -1366,7 +1366,7 @@ export async function sweepRepoRegate( if (regateBacklog > 0 && priorityPullNumbers.length === 0) { await recordAuditEvent(env, { eventType: "agent.sweep.regate", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "queued", detail: @@ -1418,7 +1418,7 @@ export async function sweepRepoRegate( ); await recordAuditEvent(env, { eventType: "agent.sweep.regate", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "queued", detail: `re-gate sweep deferred: shared GitHub REST budget below the maintenance headroom floor; re-queued after ${sweepRateResetAt}`, @@ -1521,7 +1521,7 @@ export async function sweepRepoRegate( } await recordAuditEvent(env, { eventType: "agent.sweep.regate", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "completed", detail: `scheduled re-gate recomputed ${candidates.length} stale open PR verdict(s); ${flaggedPulls.length} flagged; fanned out per-PR re-review`, @@ -1712,7 +1712,7 @@ export async function sweepRepoBacklogConvergence( if (mode === "paused") { await recordAuditEvent(env, { eventType: "agent.sweep.backlog_convergence", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "denied", detail: "agent actions paused — backlog-convergence sweep skipped", @@ -1762,7 +1762,7 @@ export async function sweepRepoBacklogConvergence( ); await recordAuditEvent(env, { eventType: "agent.sweep.backlog_convergence", - actor: "gittensory", + actor: "loopover", targetKey: repoFullName, outcome: "completed", detail: `backlog-convergence sweep found ${candidates.length} open PR(s) with a stale/missing public surface`, @@ -1890,7 +1890,7 @@ export async function regatePullRequest( if (repairHeadSha && reachedReadiness) { await recordAuditEvent(env, { eventType: REGATE_REPAIR_ATTEMPT_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey: regateRepairTargetKey(repoFullName, prNumber, repairHeadSha), outcome: "completed", detail: `outage-repair re-review executing for ${repoFullName}#${prNumber}`, @@ -2489,7 +2489,7 @@ async function runAgentMaintenancePlanAndExecute( const ciCompletenessHeadSha = pr.headSha ?? null; await recordAuditEvent(env, { eventType: "github_app.ci_completeness_unverified", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "completed", detail: ciAggregate.ciCompletenessWarning, @@ -2941,7 +2941,7 @@ async function runAgentMaintenancePlanAndExecute( }); await recordAuditEvent(env, { eventType: "agent.action.hold", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "completed", detail: holdDetail, @@ -3417,7 +3417,7 @@ async function prReadyForReview( ) { await recordAuditEvent(env, { eventType: "github_app.review_deferred_ci_pending", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "queued", detail: "CI still running — review deferred until all checks finish", @@ -3428,7 +3428,7 @@ async function prReadyForReview( if (ci.hasMissingRequiredContext) { await recordAuditEvent(env, { eventType: "github_app.review_deferred_ci_pending", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "queued", detail: @@ -3449,7 +3449,7 @@ async function prReadyForReview( const guardTargetKey = `${repoFullName}#${pr.number}#${pr.headSha}`; const alreadyFinalizedForSha = await countRecentAuditEventsForActorAndTarget( env, - "gittensory", + "loopover", CI_STUCK_FINALIZE_GUARD_EVENT_TYPE, guardTargetKey, new Date(Date.now() - CI_STUCK_FINALIZE_GUARD_LOOKBACK_MS).toISOString(), @@ -3457,7 +3457,7 @@ async function prReadyForReview( if (alreadyFinalizedForSha >= CI_STUCK_FINALIZE_MAX_PER_SHA) { await recordAuditEvent(env, { eventType: "github_app.review_deferred_ci_pending", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "queued", detail: "CI still stuck pending, but already finalized once for this head SHA — deferring again instead of re-spending a review", @@ -3486,7 +3486,7 @@ async function prReadyForReview( } await recordAuditEvent(env, { eventType: "github_app.review_finalized_ci_stuck", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "completed", detail: @@ -3495,7 +3495,7 @@ async function prReadyForReview( }).catch(() => undefined); await recordAuditEvent(env, { eventType: CI_STUCK_FINALIZE_GUARD_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey: guardTargetKey, outcome: "completed", detail: "recorded so a repeat evaluation of the SAME head SHA does not pay for another review", @@ -3657,7 +3657,7 @@ async function maybeForceFreshRebase( if (attempt >= MAX_FRESH_REBASE_FORCES) { await recordAuditEvent(env, { eventType: "agent.action.fresh_rebase_window_cap_exceeded", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "completed", detail: `base advanced within the ${windowMinutes}m freshness window, but the ${MAX_FRESH_REBASE_FORCES}-attempt forced-rebase cap was already reached for this PR — falling through to a normal merge decision`, @@ -3700,7 +3700,7 @@ async function maybeForceFreshRebase( await putTransientKey(env, countKey, String(nextAttempt), 24 * 3600); await recordAuditEvent(env, { eventType: "agent.action.forced_rebase_freshness", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "completed", detail: `forced update_branch (attempt ${nextAttempt}/${MAX_FRESH_REBASE_FORCES}) — base advanced within the ${windowMinutes}m freshness window`, @@ -4026,7 +4026,7 @@ async function maybeReReviewOnCiCompletion( if (viaHeadShaFallback && prNumbers.length > 0) { await recordAuditEvent(env, { eventType: "github_app.ci_completion_fork_resume", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${prNumbers.join(",")}`, outcome: "queued", detail: @@ -12061,7 +12061,7 @@ async function maybeThrottleReviewNagPing( } await recordAuditEvent(env, { eventType: "github_app.review_nag_cooldown_applied", - actor: "gittensory", + actor: "loopover", targetKey, outcome: mode === "live" ? "completed" : "denied", detail: `hold applied: ${commenter} pinged ${pingCount} times (limit ${maxPings})`, @@ -12098,7 +12098,7 @@ async function maybeThrottleReviewNagPing( // Autonomy is not currently acting for label/close — nothing to execute, but the policy still engaged. await recordAuditEvent(env, { eventType: "github_app.review_nag_cooldown_applied", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: `close policy engaged but autonomy is not acting for label/close: ${commenter} pinged ${pingCount} times (limit ${maxPings})`, @@ -12252,7 +12252,7 @@ async function maybeThrottleMonitoredMentions( } await recordAuditEvent(env, { eventType: "github_app.review_nag_cooldown_applied", - actor: "gittensory", + actor: "loopover", targetKey, outcome: mode === "live" ? "completed" : "denied", detail: `hold applied: ${commenter} pinged @${mentionedLogin} ${pingCount} times (limit ${maxPings})`, @@ -12284,7 +12284,7 @@ async function maybeThrottleMonitoredMentions( if (planned.length === 0) { await recordAuditEvent(env, { eventType: "github_app.review_nag_cooldown_applied", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: `close policy engaged but autonomy is not acting for label/close: ${commenter} pinged @${mentionedLogin} ${pingCount} times (limit ${maxPings})`, @@ -12418,7 +12418,7 @@ async function maybeThrottleLoopOverCommand( } await recordAuditEvent(env, { eventType: "github_app.command_rate_limit_applied", - actor: "gittensory", + actor: "loopover", targetKey, outcome: args.mode === "live" ? "completed" : "denied", detail: `hold applied: ${args.commenter} invoked ${args.command} ${invocationCount} times (limit ${maxPerWindow})`, diff --git a/src/queue/review-evasion.ts b/src/queue/review-evasion.ts index e58fd5e2b4..3d4c3fe300 100644 --- a/src/queue/review-evasion.ts +++ b/src/queue/review-evasion.ts @@ -117,7 +117,7 @@ async function evaluateCloseEnforcementGate(args: { if (closeAutonomy !== "auto") { await recordAuditEvent(env, { eventType, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: @@ -134,7 +134,7 @@ async function evaluateCloseEnforcementGate(args: { if (mode === "dry_run") { await recordAuditEvent(env, { eventType, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "completed", detail: args.dryRun.detail, @@ -149,7 +149,7 @@ async function evaluateCloseEnforcementGate(args: { if (args.paused) { await recordAuditEvent(env, { eventType, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: args.paused.detail, @@ -168,7 +168,7 @@ async function evaluateCloseEnforcementGate(args: { if (readiness !== "ready") { await recordAuditEvent(env, { eventType, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: args.permissionReadiness.detail, @@ -191,7 +191,7 @@ async function evaluateCloseEnforcementGate(args: { if (stale) { await recordAuditEvent(env, { eventType, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: `${pullRequestFreshnessDetail(freshness)}${args.freshness.detailSuffix}`, @@ -309,7 +309,7 @@ async function closeDraftDodgeAttemptIfBlocked( ).catch(() => undefined); await recordAuditEvent(env, { eventType: "github_app.draft_dodge_closed", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "completed", detail: `closed draft-dodge attempt by ${pr.authorLogin ?? "unknown"} — prior gate failure on headSha ${pr.headSha} stands`, @@ -444,7 +444,7 @@ async function recloseDisallowedReopenIfNeeded( if (await hasMaintainerPermission(reopener)) { await recordAuditEvent(env, { eventType: "github_app.reopen_reclosed", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "denied", detail: `${reopener} now holds maintainer permission — reopen re-close not executed`, @@ -472,7 +472,7 @@ async function recloseDisallowedReopenIfNeeded( if (reopenerSuperseded) { await recordAuditEvent(env, { eventType: "github_app.reopen_reclosed", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: "denied", detail: latestReopener.errored @@ -501,7 +501,7 @@ async function recloseDisallowedReopenIfNeeded( /* v8 ignore next -- fail-safe: an audit write failure never blocks the handler. */ await recordAuditEvent(env, { eventType: "github_app.reopen_reclosed", - actor: "gittensory", + actor: "loopover", targetKey: `${repoFullName}#${pr.number}`, outcome: closeError === null ? "completed" : "error", detail: @@ -627,7 +627,7 @@ async function closeReviewEvasionSelfCloseIfActive( if (reopenError !== null) { await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "error", detail: `FAILED to reopen ${pr.authorLogin}'s self-close for review-evasion enforcement -- the reopen API call did not succeed`, @@ -644,7 +644,7 @@ async function closeReviewEvasionSelfCloseIfActive( if (closeError !== null) { await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "error", detail: `FAILED to re-close review-evasion self-close by ${pr.authorLogin} -- the reopen already succeeded, so the PR is live on GitHub as OPEN; retrying via the queue rather than leaving it that way`, @@ -695,7 +695,7 @@ async function closeReviewEvasionSelfCloseIfActive( } await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "completed", detail: `re-closed a review-evasion self-close by ${pr.authorLogin} -- active review on headSha ${pr.headSha} was in progress`, @@ -814,7 +814,7 @@ async function closeReviewEvasionDraftConversionIfActive( if (closeError !== null) { await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "error", detail: `FAILED to close review-evasion draft-conversion by ${pr.authorLogin} -- the close API call did not succeed; the PR may still be open`, @@ -846,7 +846,7 @@ async function closeReviewEvasionDraftConversionIfActive( } await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "completed", detail: `closed a review-evasion draft-conversion by ${pr.authorLogin} -- active review on headSha ${pr.headSha} was in progress`, @@ -980,7 +980,7 @@ async function closeRepeatedDraftCyclingIfDetected( if (closeError !== null) { await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "error", detail: `FAILED to close repeated draft-cycling by ${pr.authorLogin} -- the close API call did not succeed; the PR may still be open`, @@ -1012,7 +1012,7 @@ async function closeRepeatedDraftCyclingIfDetected( } await recordAuditEvent(env, { eventType: REVIEW_EVASION_CLOSED_EVENT_TYPE, - actor: "gittensory", + actor: "loopover", targetKey, outcome: "completed", detail: `closed repeated draft-cycling by ${pr.authorLogin} -- conversion #${draftConversionCount} on this PR`, diff --git a/src/review/fix-handoff-render.ts b/src/review/fix-handoff-render.ts index 5d8c933454..155a4a485c 100644 --- a/src/review/fix-handoff-render.ts +++ b/src/review/fix-handoff-render.ts @@ -31,7 +31,7 @@ export type FixHandoffBlock = { /** The HTML comment marker prefixing every rendered block, so a contributor's own agent can reliably locate and * parse fix-handoff blocks in a comment body without depending on markdown structure alone. */ -const FIX_HANDOFF_MARKER = ""; +const FIX_HANDOFF_MARKER = ""; /** Public-safe inline-code escaping for a finding path/location. GitHub comments still render markdown inside * collapsibles, so neutralize delimiters that can break out of the `...` span or table-like contexts before diff --git a/src/review/maintainer-recap-wire.ts b/src/review/maintainer-recap-wire.ts index c562a02fda..51dba98cab 100644 --- a/src/review/maintainer-recap-wire.ts +++ b/src/review/maintainer-recap-wire.ts @@ -202,7 +202,7 @@ export async function runMaintainerRecapJob( if (!result.skipped) { await recordAuditEvent(env, { eventType: "maintainer_recap_generated", - actor: "gittensory", + actor: "loopover", route: "scheduled", targetKey: `maintainer-recap:${periodKey}`, outcome: "success", diff --git a/src/review/parity.ts b/src/review/parity.ts index e240a61d4f..bb91e748d9 100644 --- a/src/review/parity.ts +++ b/src/review/parity.ts @@ -251,7 +251,7 @@ export async function computeGateParity( opts: { days: number; nowMs: number; project?: string; authoritative?: string; shadow?: string }, ): Promise { const authoritative = opts.authoritative ?? "reviewbot"; - const shadow = opts.shadow ?? "gittensory"; + const shadow = opts.shadow ?? "loopover"; const days = Number.isFinite(opts.days) && opts.days > 0 ? Math.min(opts.days, 730) : 90; const fromIso = new Date(opts.nowMs - days * 86_400_000).toISOString().slice(0, 10); diff --git a/src/review/stats.ts b/src/review/stats.ts index 6928184e3a..02446158f0 100644 --- a/src/review/stats.ts +++ b/src/review/stats.ts @@ -109,7 +109,7 @@ export interface StatsEvalDeps { } const EMPTY_EVAL: GateEvalReport = { rows: [], hasSignal: false }; -const emptyParity = (authoritative = "reviewbot", shadow = "gittensory"): GateParityReport => ({ authoritative, shadow, rows: [], hasSignal: false }); +const emptyParity = (authoritative = "reviewbot", shadow = "loopover"): GateParityReport => ({ authoritative, shadow, rows: [], hasSignal: false }); /** Default deps: no-signal eval, no recommendations, empty parity. Keeps the payload shape with no engine. */ export const defaultStatsEvalDeps: StatsEvalDeps = { diff --git a/src/review/unified-comment-bridge.ts b/src/review/unified-comment-bridge.ts index 53e0220dd4..14eaf1e89e 100644 --- a/src/review/unified-comment-bridge.ts +++ b/src/review/unified-comment-bridge.ts @@ -145,7 +145,7 @@ const BOILERPLATE_NIT_CODES = new Set([ "no_linked_issue_without_rationale", ]); const BOILERPLATE_NIT_TITLE = - /local gittensory cache|registration is not available|config was not parsed|not registered/i; + /local loopover cache|registration is not available|config was not parsed|not registered/i; const MANUAL_HOLD_WARNING_CODES = new Set([ "guardrail_hold", "oversized_pr", diff --git a/src/selfhost/otel.ts b/src/selfhost/otel.ts index f9d051ae69..9d89af9488 100644 --- a/src/selfhost/otel.ts +++ b/src/selfhost/otel.ts @@ -56,7 +56,7 @@ export function openTelemetryTraceExportEnabled(env: NodeJS.ProcessEnv): boolean function serviceAttributes(env: NodeJS.ProcessEnv): Attributes { const attrs: Attributes = { - "service.name": nonBlank(env.OTEL_SERVICE_NAME) ?? "gittensory-selfhost", + "service.name": nonBlank(env.OTEL_SERVICE_NAME) ?? "loopover-selfhost", "deployment.environment.name": nonBlank(env.OTEL_SERVICE_ENVIRONMENT) ?? nonBlank(env.SENTRY_ENVIRONMENT) ?? "selfhost", }; const version = nonBlank(env.LOOPOVER_VERSION) ?? nonBlank(env.SENTRY_RELEASE); @@ -292,7 +292,7 @@ export async function initOpenTelemetry( bridge?.validate?.(); provider = nextProvider; Otel = api; - tracer = nextProvider.getTracer("gittensory-selfhost"); + tracer = nextProvider.getTracer("loopover-selfhost"); active = true; return true; } diff --git a/src/selfhost/qdrant-vectorize.ts b/src/selfhost/qdrant-vectorize.ts index d1d93fa9c1..3849f53a68 100644 --- a/src/selfhost/qdrant-vectorize.ts +++ b/src/selfhost/qdrant-vectorize.ts @@ -26,7 +26,7 @@ import type { SelfHostVectorize, } from "./backend-contracts"; -const DEFAULT_COLLECTION = "gittensory"; +const DEFAULT_COLLECTION = "loopover"; const DEFAULT_DIM = 1024; // bge-m3 / mxbai-embed-large (1024-d); set QDRANT_DIM to override interface QdrantSearchResult { diff --git a/src/selfhost/review-tracing.ts b/src/selfhost/review-tracing.ts index cd6c74c45c..aff6d15b0c 100644 --- a/src/selfhost/review-tracing.ts +++ b/src/selfhost/review-tracing.ts @@ -43,9 +43,9 @@ export async function reviewTraceAttributes( attrs["github.pull_request.number"] = input.pullNumber; const installationHash = await hashedInstallationId(input.installationId); if (installationHash) attrs["github.installation_id_hash"] = installationHash; - if (input.operation) attrs["gittensory.operation"] = input.operation; - if (input.agent) attrs["gittensory.agent"] = input.agent; - if (input.decisionOutcome) attrs["gittensory.decision_outcome"] = input.decisionOutcome; + if (input.operation) attrs["loopover.operation"] = input.operation; + if (input.agent) attrs["loopover.agent"] = input.agent; + if (input.decisionOutcome) attrs["loopover.decision_outcome"] = input.decisionOutcome; return attrs; } diff --git a/src/selfhost/sentry.ts b/src/selfhost/sentry.ts index d6ad9984e9..bda9ff91d9 100644 --- a/src/selfhost/sentry.ts +++ b/src/selfhost/sentry.ts @@ -62,7 +62,7 @@ const PRIVATE_TEXT = /\b(raw[-_\s]?score|scoring context|private rubric|gate prompt|review prompt|guardrail paths?|pull request body|pr body|pr title|raw diff)\b/gi; const PUBLIC_UNSAFE_SCRUB = new RegExp(String.raw`\b(${PUBLIC_UNSAFE_TERMS})\b`, "gi"); const ALLOWED_CONTEXTS = new Set([ - "gittensory", + "loopover", "review", "log", "sentry_monitor", @@ -158,7 +158,7 @@ export function resolveSentryMonitorSlug( name: SentryMonitorName, environment = sentryEnvironment, ): string { - return `gittensory-selfhost-${slugPart(environment)}-${SENTRY_MONITORS[name].slug}`; + return `loopover-selfhost-${slugPart(environment)}-${SENTRY_MONITORS[name].slug}`; } function safeMonitorContext( @@ -409,7 +409,7 @@ export async function initSentry(env: NodeJS.ProcessEnv): Promise { : {}), ...(useCustomOpenTelemetry ? { skipOpenTelemetrySetup: true } : {}), // Identify this instance by a CLEAN, configurable name, not the public-origin URL. An operator sets - // SENTRY_SERVER_NAME (e.g. "gittensory-us-east"); unset falls back to the OS hostname. + // SENTRY_SERVER_NAME (e.g. "loopover-us-east"); unset falls back to the OS hostname. serverName: nonBlank(env.SENTRY_SERVER_NAME) ?? hostname(), beforeSend: (e) => scrubEvent(e), beforeSendTransaction: (e) => scrubEvent(e), @@ -492,7 +492,7 @@ function namedCaptureError(error: unknown, eventName?: string): Error { * Sentry's default stack-trace-based grouping fragments the SAME logical failure into separate issues whenever * it is captured from more than one call site (e.g. two different functions each constructing the identical * `new Error("...")` message), which is exactly what happened to GITTENSORY-5/10 and GITTENSORY-C/W before this. - * Mirrors forwardStructuredLogToSentry's identical `scope.setFingerprint(["gittensory-log", event])` discipline. */ + * Mirrors forwardStructuredLogToSentry's identical `scope.setFingerprint(["loopover-log", event])` discipline. */ export function captureError( error: unknown, context?: Record, @@ -502,8 +502,8 @@ export function captureError( if (!meetsSeverityThreshold("error", resolveSentryMinSeverity(contextRepoFullName(context)))) return; Sentry.withScope((scope) => { setOtelTraceScope(scope); - if (context) { const safeContext = hashedInstallationContext(context); scope.setContext("gittensory", safeContext); applyOperationalTags(scope, safeContext); } - if (eventName) scope.setFingerprint(["gittensory-error", eventName]); + if (context) { const safeContext = hashedInstallationContext(context); scope.setContext("loopover", safeContext); applyOperationalTags(scope, safeContext); } + if (eventName) scope.setFingerprint(["loopover-error", eventName]); Sentry!.captureException(namedCaptureError(error, eventName)); }); } @@ -528,7 +528,7 @@ export function captureReviewFailure( scope.setContext("review", safeContext); applyOperationalTags(scope, safeContext); } - if (eventName) scope.setFingerprint(["gittensory-review-failure", eventName]); + if (eventName) scope.setFingerprint(["loopover-review-failure", eventName]); Sentry!.captureException(namedCaptureError(error, eventName)); }); } @@ -661,7 +661,7 @@ export function forwardStructuredLogToSentry(line: unknown, fromErrorSink = fals if (event) safeObj.event = event; applyOperationalTags(scope, safeObj); // Group recurrences of ONE failure into a single issue (by event, not the variable detail in the value). - if (event) scope.setFingerprint(["gittensory-log", event]); + if (event) scope.setFingerprint(["loopover-log", event]); // Sentry uses event.transaction as the issue culprit fallback when the stack has no frames; point it at the // operational event slug rather than the forwarding helper. if (event) @@ -707,7 +707,7 @@ export async function withSentryMonitor( const monitorContext = safeMonitorContext(name, monitorSlug, context); scope.setContext("sentry_monitor", monitorContext); applyOperationalTags(scope, { ...monitorContext, monitor: monitorSlug, kind: `sentry_monitor_${name}`, subsystem: "scheduled" }); - scope.setFingerprint(["gittensory-sentry-monitor", name]); + scope.setFingerprint(["loopover-sentry-monitor", name]); Sentry!.captureException(error instanceof Error ? error : new Error(String(error))); }); throw error; diff --git a/src/services/agent-action-executor.ts b/src/services/agent-action-executor.ts index 15a3342ed4..7889078a3c 100644 --- a/src/services/agent-action-executor.ts +++ b/src/services/agent-action-executor.ts @@ -42,7 +42,7 @@ import { captureError } from "../selfhost/sentry"; // The agent actor name on every audit record — the App acts on the maintainer's behalf per their configured // autonomy (the config IS the authorization; there is no human commenter to authorize, unlike #824). -const AGENT_ACTOR = "gittensory"; +const AGENT_ACTOR = "loopover"; // Bound on audit_events.detail / the reason embedded in buildAgentActionAudit (#terminal-outcome-audit). A // heuristic close/hold reason is built by joining every blocker's title (agent-actions.ts), so an unbounded PR @@ -520,7 +520,7 @@ export async function executeAgentMaintenanceActions(env: Env, ctx: AgentActionE // unaffected below. await recordAuditEvent(env, { eventType: "agent.action.merge_train_would_wait", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "denied", detail: `merge train (audit mode): would wait for older mergeable sibling #${decision.blockingPr}`, diff --git a/src/services/operator-dashboard.ts b/src/services/operator-dashboard.ts index 6e3b91ce94..6907979add 100644 --- a/src/services/operator-dashboard.ts +++ b/src/services/operator-dashboard.ts @@ -283,7 +283,7 @@ function operatorAgentConfig(env: Env): { slug: string; secrets: Record /^(status|state|source|bot|codex|gittensory|reward|score|miner|verified|risk)([:/-]|$)/i.test(label)); + const suspiciousConfiguredLabels = configuredLabels.filter((label) => /^(status|state|source|bot|codex|loopover|reward|score|miner|verified|risk)([:/-]|$)/i.test(label)); const findings: SignalFinding[] = []; if (repo?.registryConfig?.trustedLabelPipeline && missingConfiguredLabels.length > 0) { findings.push({ diff --git a/src/upstream/unmodeled-scoring-drift.ts b/src/upstream/unmodeled-scoring-drift.ts index b9c52f7576..29563972c5 100644 --- a/src/upstream/unmodeled-scoring-drift.ts +++ b/src/upstream/unmodeled-scoring-drift.ts @@ -7,7 +7,7 @@ import type { UpstreamDriftArea, UpstreamDriftReportRecord, UpstreamDriftSeverit import { sha256Hex } from "../utils/crypto"; import { nowIso } from "../utils/json"; -const UNMODELED_SCORING_CONSTANTS_FINGERPRINT_SEED = "gittensory:upstream:unmodeled_scoring_constants:v1"; +const UNMODELED_SCORING_CONSTANTS_FINGERPRINT_SEED = "loopover:upstream:unmodeled_scoring_constants:v1"; const SCORING_MODEL_FOLLOW_UP = ["src/scoring/model.ts", "src/upstream/ruleset.ts", "test/unit/upstream-ruleset.test.ts"]; export async function unmodeledScoringConstantsFingerprint(): Promise { diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index 13ac20b153..fbf7c7d004 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -129,7 +129,7 @@ async function deriveDraftTokenAesKey(secret: string, salt: Uint8Array): Promise // salt is always a plain (never shared) ArrayBuffer view — the cast only narrows the TYPE for the UI // workspace's stricter DOM-lib HkdfParams, which excludes SharedArrayBuffer from ArrayBufferLike. return crypto.subtle.deriveKey( - { name: "HKDF", hash: "SHA-256", salt: salt as Uint8Array, info: new TextEncoder().encode("gittensory:draft-user-token:v1") }, + { name: "HKDF", hash: "SHA-256", salt: salt as Uint8Array, info: new TextEncoder().encode("loopover:draft-user-token:v1") }, keyMaterial, { name: "AES-GCM", length: 256 }, false, diff --git a/test/unit/agent-execution.test.ts b/test/unit/agent-execution.test.ts index 99c13092c1..159831a012 100644 --- a/test/unit/agent-execution.test.ts +++ b/test/unit/agent-execution.test.ts @@ -56,12 +56,12 @@ describe("buildAgentActionAudit", () => { outcome: "completed", repoFullName: "owner/repo", targetKey: "owner/repo#7", - actor: "gittensory", + actor: "loopover", reason: "merge-readiness met", }); expect(audit).toMatchObject({ eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: "merge-readiness met", diff --git a/test/unit/check-docs-drift-script.test.ts b/test/unit/check-docs-drift-script.test.ts index b0d1d09fc7..54fe851c46 100644 --- a/test/unit/check-docs-drift-script.test.ts +++ b/test/unit/check-docs-drift-script.test.ts @@ -306,7 +306,7 @@ describe("check-docs-drift script", () => { "apps/loopover-ui/src/routes/docs.privacy-security.tsx": buildFlagsPageText(baseFlagNames), "apps/loopover-ui/src/routes/docs.maintainer-workflow.tsx": buildDocsPageText(allBaseCommandIds), "apps/loopover-ui/src/routes/docs.maintainer-install-trust.tsx": buildDocsPageText(allBaseCommandIds), - "apps/loopover-ui/src/routes/docs.gittensory-commands.tsx": + "apps/loopover-ui/src/routes/docs.loopover-commands.tsx": 'import { PUBLIC_COMMAND_ENTRIES, MAINTAINER_COMMAND_ENTRIES, ACTION_COMMAND_ENTRIES } from "@/lib/command-reference";', "apps/loopover-ui/src/routes/docs.how-reviews-work.tsx": buildGateModePageText(), "apps/loopover-ui/src/routes/docs.github-app.tsx": buildGateModePageText(), diff --git a/test/unit/db-parsers.test.ts b/test/unit/db-parsers.test.ts index 052ea0419c..5752ec39d0 100644 --- a/test/unit/db-parsers.test.ts +++ b/test/unit/db-parsers.test.ts @@ -514,10 +514,10 @@ describe("database row parser hardening", () => { it("countRecentDeadLetters counts github_app.dlq_dead_lettered audits since a cutoff, independent of any ops flag (#1276)", async () => { const env = createTestEnv(); - await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", actor: "gittensory", targetKey: "dlq:github-webhook:a", outcome: "error", createdAt: "2026-06-24T10:00:00.000Z" }); - await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", actor: "gittensory", targetKey: "dlq:backfill-repo-segment:b", outcome: "error", createdAt: "2026-06-24T12:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", actor: "loopover", targetKey: "dlq:github-webhook:a", outcome: "error", createdAt: "2026-06-24T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", actor: "loopover", targetKey: "dlq:backfill-repo-segment:b", outcome: "error", createdAt: "2026-06-24T12:00:00.000Z" }); // An unrelated audit event must NOT be counted (the event-type filter). - await recordAuditEvent(env, { eventType: "agent.sweep.regate", actor: "gittensory", targetKey: "owner/repo", outcome: "completed", createdAt: "2026-06-24T12:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "agent.sweep.regate", actor: "loopover", targetKey: "owner/repo", outcome: "completed", createdAt: "2026-06-24T12:00:00.000Z" }); expect(await countRecentDeadLetters(env, "2026-06-24T09:00:00.000Z")).toBe(2); // both dead-letters in window expect(await countRecentDeadLetters(env, "2026-06-24T11:00:00.000Z")).toBe(1); // only the 12:00 one @@ -528,7 +528,7 @@ describe("database row parser hardening", () => { const env = createTestEnv(); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:github-webhook:a", outcome: "error", createdAt: "2026-06-24T12:00:00.000Z", @@ -536,7 +536,7 @@ describe("database row parser hardening", () => { }); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:backfill-repo-segment:b", outcome: "error", createdAt: "2026-06-24T10:00:00.000Z", @@ -544,7 +544,7 @@ describe("database row parser hardening", () => { }); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:github-webhook:c", outcome: "error", createdAt: "2026-06-24T14:00:00.000Z", @@ -563,7 +563,7 @@ describe("database row parser hardening", () => { const env = createTestEnv(); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:refresh-registry:a", outcome: "error", createdAt: "2026-06-24T10:00:00.000Z", @@ -571,7 +571,7 @@ describe("database row parser hardening", () => { }); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:refresh-registry:b", outcome: "error", createdAt: "2026-06-24T11:00:00.000Z", @@ -587,7 +587,7 @@ describe("database row parser hardening", () => { const env = createTestEnv(); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:github-webhook:stale", outcome: "error", createdAt: "2026-06-24T08:59:59.000Z", @@ -595,7 +595,7 @@ describe("database row parser hardening", () => { }); await recordAuditEvent(env, { eventType: "agent.sweep.regate", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo", outcome: "completed", createdAt: "2026-06-24T12:00:00.000Z", @@ -608,14 +608,14 @@ describe("database row parser hardening", () => { const env = createTestEnv(); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:unknown:a", outcome: "error", createdAt: "2026-06-24T10:00:00.000Z", }); await recordAuditEvent(env, { eventType: "github_app.dlq_dead_lettered", - actor: "gittensory", + actor: "loopover", targetKey: "dlq:unknown:b", outcome: "error", createdAt: "2026-06-24T11:00:00.000Z", diff --git a/test/unit/e2e-test-commit.test.ts b/test/unit/e2e-test-commit.test.ts index 40107d4465..b5dd57bbf3 100644 --- a/test/unit/e2e-test-commit.test.ts +++ b/test/unit/e2e-test-commit.test.ts @@ -72,7 +72,7 @@ describe("commitE2eTestToPrBranch (#4197)", () => { const commitCall = calls.find((c) => c.url.endsWith("/git/commits") && c.method === "POST"); expect(commitCall?.body).toMatchObject({ tree: "new-tree-sha", parents: ["head-commit-sha"] }); - expect(commitCall?.body.message as string).toContain("Generated-by: gittensory (invoked by @maintainer)"); + expect(commitCall?.body.message as string).toContain("Generated-by: loopover (invoked by @maintainer)"); // octokit percent-encodes the whole "heads/feature/my-branch" ref value into one path segment. const refCall = calls.find((c) => c.method === "PATCH"); diff --git a/test/unit/fix-handoff-collapsible.test.ts b/test/unit/fix-handoff-collapsible.test.ts index cde24a403c..7314959dc9 100644 --- a/test/unit/fix-handoff-collapsible.test.ts +++ b/test/unit/fix-handoff-collapsible.test.ts @@ -36,7 +36,7 @@ describe("buildFixHandoffCollapsible (#1962)", () => { const c = buildFixHandoffCollapsible(blocks); expect(c).not.toBeNull(); expect(c?.title).toBe("Fix handoff"); - expect(c?.body).toContain(""); + expect(c?.body).toContain(""); expect(c?.body).toContain("`src/a.ts:10`"); expect(c?.body).toContain("Possible null dereference on the fetched record."); expect(c?.body).toContain("Suggested change:"); diff --git a/test/unit/fix-handoff-render.test.ts b/test/unit/fix-handoff-render.test.ts index 5a2b37cc15..69eb966cef 100644 --- a/test/unit/fix-handoff-render.test.ts +++ b/test/unit/fix-handoff-render.test.ts @@ -60,7 +60,7 @@ describe("buildFixHandoffBlock (#2175)", () => { it("includes the fix-handoff HTML comment marker so a harness can locate the block", () => { const block = buildFixHandoffBlock(finding()); - expect(block.body).toContain(""); + expect(block.body).toContain(""); }); it("carries the finding's body as the instruction verbatim (already public-safe upstream)", () => { diff --git a/test/unit/gate-outcome-audit-rollups.test.ts b/test/unit/gate-outcome-audit-rollups.test.ts index d1ad4d082c..c77e4ed9b0 100644 --- a/test/unit/gate-outcome-audit-rollups.test.ts +++ b/test/unit/gate-outcome-audit-rollups.test.ts @@ -7,28 +7,28 @@ describe("listGateOutcomeAuditEventRollups (#2203)", () => { const env = createTestEnv(); await recordAuditEvent(env, { eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "octo/demo#1", outcome: "completed", createdAt: "2026-07-10T12:00:00.000Z", }); await recordAuditEvent(env, { eventType: "agent.action.close", - actor: "gittensory", + actor: "loopover", targetKey: "octo/demo#2", outcome: "success", createdAt: "2026-07-10T13:00:00.000Z", }); await recordAuditEvent(env, { eventType: "agent.action.hold", - actor: "gittensory", + actor: "loopover", targetKey: "octo/demo#3", outcome: "completed", createdAt: "2026-07-10T14:00:00.000Z", }); await recordAuditEvent(env, { eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "other/repo#9", outcome: "completed", createdAt: "2026-07-10T15:00:00.000Z", diff --git a/test/unit/github-commands.test.ts b/test/unit/github-commands.test.ts index 835e358406..64d3671e86 100644 --- a/test/unit/github-commands.test.ts +++ b/test/unit/github-commands.test.ts @@ -229,19 +229,19 @@ describe("GitHub mention commands", () => { it("helpSections links to the public command reference doc (#2171)", () => { const body = githubCommandsInternals.helpSections({}).join("\n"); - expect(body).toContain("https://loopover.ai/docs/gittensory-commands"); + expect(body).toContain("https://loopover.ai/docs/loopover-commands"); expect(body).toContain("Full command reference"); }); it("helpSections' command reference link follows a self-hoster's PUBLIC_SITE_ORIGIN, trailing slash and all (#4670)", () => { const body = githubCommandsInternals.helpSections({ PUBLIC_SITE_ORIGIN: "https://my-instance.example.com/" }).join("\n"); - expect(body).toContain("https://my-instance.example.com/docs/gittensory-commands"); + expect(body).toContain("https://my-instance.example.com/docs/loopover-commands"); expect(body).not.toContain("gittensory.aethereal.dev"); }); it("commandReferenceUrl falls back to the default site when PUBLIC_SITE_ORIGIN is malformed", () => { expect(githubCommandsInternals.commandReferenceUrl({ PUBLIC_SITE_ORIGIN: "not a url" })).toBe( - "https://loopover.ai/docs/gittensory-commands", + "https://loopover.ai/docs/loopover-commands", ); }); diff --git a/test/unit/local-write-tools.test.ts b/test/unit/local-write-tools.test.ts index ea2f6170c9..a78ca3270e 100644 --- a/test/unit/local-write-tools.test.ts +++ b/test/unit/local-write-tools.test.ts @@ -154,7 +154,7 @@ describe("buildFollowUpIssueSpec (#2177)", () => { }); it("strips an embedded HTML-comment marker and fenced block before composing the body (public-safe)", () => { - const finding = "\n**Fix handoff — Blocker at `src/a.ts:42`**\nNull check missing.\n\n```suggestion\nif (!x) return null;\n```"; + const finding = "\n**Fix handoff — Blocker at `src/a.ts:42`**\nNull check missing.\n\n```suggestion\nif (!x) return null;\n```"; const s = buildFollowUpIssueSpec({ repoFullName: "o/r", path: "src/a.ts", line: 42, finding }); expect(s.command).not.toContain(""); + expect(issue.body).toContain(""); expect(issue.body).toContain("- [ ] Run `npm run test:release:mcp`"); expect(issue.body).toContain("- [ ] Tag `mcp-v0.4.0`"); }); @@ -103,7 +103,7 @@ describe("MCP release changelog detection", () => { expect( isReleaseWatchIssue({ title: "MCP release due: 0.4.0", - body: "", + body: "", user: { login: "github-actions[bot]" }, }), ).toBe(true); @@ -111,7 +111,7 @@ describe("MCP release changelog detection", () => { expect( isReleaseWatchIssue({ title: "MCP release due: 0.4.0", - body: "", + body: "", user: { login: "public-contributor" }, }), ).toBe(false); diff --git a/test/unit/miner-attempt-cli.test.ts b/test/unit/miner-attempt-cli.test.ts index 97e9541e03..0fde987c47 100644 --- a/test/unit/miner-attempt-cli.test.ts +++ b/test/unit/miner-attempt-cli.test.ts @@ -28,7 +28,7 @@ const closeables: Array<{ close(): void }> = []; /** A stubbed successful prepareAttemptWorktree, for tests exercising code paths past worktree preparation * that don't themselves care about real git plumbing (covered separately by miner-attempt-worktree.test.ts). */ function fakeWorktreeResult(): Extract { - return { ok: true, worktreePath: "/fake/repo/.gittensory-worktrees/fake", repoPath: "/fake/repo", branchName: "gittensory/attempt/fake" }; + return { ok: true, worktreePath: "/fake/repo/.loopover-worktrees/fake", repoPath: "/fake/repo", branchName: "loopover/attempt/fake" }; } function fakeReviewContext() { @@ -46,7 +46,7 @@ function fakeCodingTaskSpec() { ready: true as const, verdict: "go" as const, feasibility: { verdict: "go" as const, avoidReasons: [], raiseReasons: [], summary: "ready" }, - acceptanceCriteriaPath: "/fake/repo/.gittensory-worktrees/fake/acceptance-criteria.json", + acceptanceCriteriaPath: "/fake/repo/.loopover-worktrees/fake/acceptance-criteria.json", instructions: "Resolve issue #7", title: "Uploads should retry on 5xx", body: "Uploads fail silently.", @@ -1294,7 +1294,7 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { ...readyPipelineOptions({ resolveMinerGoalSpec: undefined, // use the real, non-injected resolver against the real repoRoot below checkMinerKillSwitch: undefined, // use the real resolver too, so it actually reacts to repoPaused - prepareAttemptWorktree: async () => ({ ok: true, worktreePath: repoRoot, repoPath: repoRoot, branchName: "gittensory/attempt/real" }), + prepareAttemptWorktree: async () => ({ ok: true, worktreePath: repoRoot, repoPath: repoRoot, branchName: "loopover/attempt/real" }), runMinerAttempt: runMinerAttemptSpy, }), }); @@ -1321,7 +1321,7 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { ...readyPipelineOptions({ resolveMinerGoalSpec: undefined, checkMinerKillSwitch: undefined, - prepareAttemptWorktree: async () => ({ ok: true, worktreePath: repoRoot, repoPath: repoRoot, branchName: "gittensory/attempt/real" }), + prepareAttemptWorktree: async () => ({ ok: true, worktreePath: repoRoot, repoPath: repoRoot, branchName: "loopover/attempt/real" }), runMinerAttempt: runMinerAttemptSpy, }), }); diff --git a/test/unit/miner-attempt-input-builder.test.ts b/test/unit/miner-attempt-input-builder.test.ts index 447e8d5163..2c906a23a2 100644 --- a/test/unit/miner-attempt-input-builder.test.ts +++ b/test/unit/miner-attempt-input-builder.test.ts @@ -12,7 +12,7 @@ function codingTaskSpec(overrides: Record = {}) { ready: true as const, verdict: "go" as const, feasibility: { verdict: "go" as const, avoidReasons: [], raiseReasons: [], summary: "ready" }, - acceptanceCriteriaPath: "/fake/repo/.gittensory-worktrees/fake/acceptance-criteria.json", + acceptanceCriteriaPath: "/fake/repo/.loopover-worktrees/fake/acceptance-criteria.json", instructions: "Resolve issue #7", title: "Uploads should retry on 5xx", body: "Uploads fail silently.", @@ -114,7 +114,7 @@ describe("buildAttemptLoopInput (#5132)", () => { const loopInput = buildAttemptLoopInput({ codingTaskSpec: codingTaskSpec(), reviewContext: reviewContext(), - worktreePath: "/fake/repo/.gittensory-worktrees/fake", + worktreePath: "/fake/repo/.loopover-worktrees/fake", attemptId: "acme_widgets-7-12345", mode: "dry_run", repoFullName: "acme/widgets", @@ -125,8 +125,8 @@ describe("buildAttemptLoopInput (#5132)", () => { expect(loopInput).toEqual({ attemptId: "acme_widgets-7-12345", - workingDirectory: "/fake/repo/.gittensory-worktrees/fake", - acceptanceCriteriaPath: "/fake/repo/.gittensory-worktrees/fake/acceptance-criteria.json", + workingDirectory: "/fake/repo/.loopover-worktrees/fake", + acceptanceCriteriaPath: "/fake/repo/.loopover-worktrees/fake/acceptance-criteria.json", instructions: "Resolve issue #7", mode: "dry_run", maxIterations: DEFAULT_AMS_POLICY_SPEC.maxIterations, @@ -206,9 +206,9 @@ describe("buildAttemptLoopInput (#5132)", () => { minerLogin: "alice", rejectionSignaled: false, amsPolicySpec: DEFAULT_AMS_POLICY_SPEC, - branchRef: "gittensory/attempt/a1", + branchRef: "loopover/attempt/a1", }); - expect(loopInput.branchRef).toBe("gittensory/attempt/a1"); + expect(loopInput.branchRef).toBe("loopover/attempt/a1"); }); it("omits body/labels/linkedIssues when the coding-task-spec itself omits them", () => { diff --git a/test/unit/miner-attempt-worktree.test.ts b/test/unit/miner-attempt-worktree.test.ts index b281c6f1a4..665ad30ad9 100644 --- a/test/unit/miner-attempt-worktree.test.ts +++ b/test/unit/miner-attempt-worktree.test.ts @@ -65,13 +65,13 @@ describe("prepareAttemptWorktree / cleanupAttemptWorktree (#5132)", () => { expect(result.ok).toBe(true); if (!result.ok) throw new Error("expected ok"); - expect(result.branchName).toBe("gittensory/attempt/attempt-1"); + expect(result.branchName).toBe("loopover/attempt/attempt-1"); expect(existsSync(result.worktreePath)).toBe(true); // The critical assertion: real repo content is actually present, not an empty directory. expect(readFileSync(join(result.worktreePath, "README.md"), "utf8")).toBe("hello\n"); // And it's a real, distinct branch -- not just a copy of main. const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: result.worktreePath, encoding: "utf8" }).trim(); - expect(branch).toBe("gittensory/attempt/attempt-1"); + expect(branch).toBe("loopover/attempt/attempt-1"); }); it("removes a succeeded attempt's worktree but retains a failed one's, per the engine's own retention policy", async () => { diff --git a/test/unit/miner-extension-live-fetch.test.ts b/test/unit/miner-extension-live-fetch.test.ts index 9aec97b78e..4202ec28e5 100644 --- a/test/unit/miner-extension-live-fetch.test.ts +++ b/test/unit/miner-extension-live-fetch.test.ts @@ -194,7 +194,7 @@ describe("syncRankedCandidatesFromMinerUi (#4859)", () => { }); expect(alarmCreateCalls).toHaveLength(1); const [name, info] = alarmCreateCalls[0]!; - expect(name).toBe("gittensory-miner:sync-ranked-candidates"); + expect(name).toBe("loopover-miner:sync-ranked-candidates"); expect(info).toEqual({ periodInMinutes: 10 }); dispatchAlarm("some-other-extensions-alarm"); @@ -298,7 +298,7 @@ describe("options.js miner-UI URL field + Sync now button (#4859)", () => { syncResponse: { ok: true, payload: { ok: true, count: 3, minerUiUrl: "http://localhost:5174" } }, }); await (elements["#syncNow"] as ReturnType).dispatchClick(); - expect(sentMessages).toEqual([{ type: "gittensory-miner:sync-ranked-candidates" }]); + expect(sentMessages).toEqual([{ type: "loopover-miner:sync-ranked-candidates" }]); expect((elements["#status"] as { textContent: string }).textContent).toMatch(/Synced 3 ranked candidate/); }); diff --git a/test/unit/miner-worktree-pool.test.ts b/test/unit/miner-worktree-pool.test.ts index 651a071b9f..d67829d18b 100644 --- a/test/unit/miner-worktree-pool.test.ts +++ b/test/unit/miner-worktree-pool.test.ts @@ -24,8 +24,8 @@ describe("worktree pool allocator (#4297)", () => { expect(r.ok).toBe(true); if (!r.ok) return; expect(r.allocation.attemptId).toBe("attempt-1"); - expect(r.allocation.plan.worktreePath).toContain(".gittensory-worktrees"); - expect(r.allocation.plan.branchName).toContain("gittensory/attempt/"); + expect(r.allocation.plan.worktreePath).toContain(".loopover-worktrees"); + expect(r.allocation.plan.branchName).toContain("loopover/attempt/"); expect(r.state.allocations).toHaveLength(1); expect(isWorktreeAllocated(r.state, "attempt-1")).toBe(true); expect(availableWorktreeSlots(r.state, config)).toBe(1); diff --git a/test/unit/notify-pagerduty.test.ts b/test/unit/notify-pagerduty.test.ts index 0838d284be..e3c40364ad 100644 --- a/test/unit/notify-pagerduty.test.ts +++ b/test/unit/notify-pagerduty.test.ts @@ -235,7 +235,7 @@ describe("triggerPagerDutyIncident — cooldown gate (alert fatigue control #2)" const tenMinutesAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString(); await recordAuditEvent(env, { eventType: "external_notification.pagerduty", - actor: "gittensory", + actor: "loopover", targetKey: "ops_anomaly:acme/widgets", outcome: "completed", detail: "triggered", diff --git a/test/unit/operator-dashboard.test.ts b/test/unit/operator-dashboard.test.ts index 1f1cb94244..5fbe96e03e 100644 --- a/test/unit/operator-dashboard.test.ts +++ b/test/unit/operator-dashboard.test.ts @@ -109,9 +109,9 @@ describe("operator dashboard payload", () => { }); const unset = createTestEnv(); delete (unset as Partial).GITHUB_APP_SLUG; - expect(operatorAgentConfig(unset)).toEqual({ slug: "gittensory", secrets: {} }); + expect(operatorAgentConfig(unset)).toEqual({ slug: "loopover", secrets: {} }); expect(operatorAgentConfig(createTestEnv({ GITHUB_APP_SLUG: "" }))).toEqual({ - slug: "gittensory", + slug: "loopover", secrets: {}, }); }); diff --git a/test/unit/parity.test.ts b/test/unit/parity.test.ts index 8249dbbaa9..375b234e24 100644 --- a/test/unit/parity.test.ts +++ b/test/unit/parity.test.ts @@ -43,17 +43,17 @@ describe("computeGateParity — cross-system gate-decision agreement (#preconv-p it("folds the paired matrix into agreement / disagree counts + rate", async () => { const out = await computeGateParity( parityEnv([ - { project: "gittensory", auth_act: "merge", shadow_act: "merge", reason: "dual_review_approved", n: 40 }, - { project: "gittensory", auth_act: "close", shadow_act: "close", reason: "consensus_close", n: 10 }, - { project: "gittensory", auth_act: "hold", shadow_act: "hold", reason: "split", n: 5 }, - { project: "gittensory", auth_act: "hold", shadow_act: "close", reason: "split", n: 2 }, // benign disagree + { project: "loopover", auth_act: "merge", shadow_act: "merge", reason: "dual_review_approved", n: 40 }, + { project: "loopover", auth_act: "close", shadow_act: "close", reason: "consensus_close", n: 10 }, + { project: "loopover", auth_act: "hold", shadow_act: "hold", reason: "split", n: 5 }, + { project: "loopover", auth_act: "hold", shadow_act: "close", reason: "split", n: 2 }, // benign disagree ]), { days: 90, nowMs: NOW }, ); const g = out.rows[0]; expect(g).toBeDefined(); if (!g) return; - expect(g.project).toBe("gittensory"); + expect(g.project).toBe("loopover"); expect(g.pairedSamples).toBe(57); expect(g.bothMerge).toBe(40); expect(g.bothClose).toBe(10); @@ -62,7 +62,7 @@ describe("computeGateParity — cross-system gate-decision agreement (#preconv-p expect(g.agreementRate).toBeCloseTo(55 / 57); expect(g.unsafeDisagreements).toBe(0); // hold→close is the SAFE direction expect(out.authoritative).toBe("reviewbot"); - expect(out.shadow).toBe("gittensory"); + expect(out.shadow).toBe("loopover"); }); it("counts ONLY the dangerous direction (shadow MERGES where authoritative HOLDs/CLOSEs) as unsafe", async () => { @@ -102,10 +102,10 @@ describe("computeGateParity — cross-system gate-decision agreement (#preconv-p it("binds BOTH source filters (authoritative + shadow) so two distinct writers are compared", async () => { const cap: { sql?: string; binds?: unknown[] } = {}; - await computeGateParity(parityEnv([], cap), { days: 90, nowMs: NOW, authoritative: "reviewbot", shadow: "gittensory" }); + await computeGateParity(parityEnv([], cap), { days: 90, nowMs: NOW, authoritative: "reviewbot", shadow: "loopover" }); // binds order: auth-source, fromIso, shadow-source, fromIso (no project filter). expect(cap.binds?.[0]).toBe("reviewbot"); - expect(cap.binds?.[2]).toBe("gittensory"); + expect(cap.binds?.[2]).toBe("loopover"); // The per-commit join key requires a non-null head_sha on BOTH sides. expect(cap.sql).toContain("head_sha IS NOT NULL"); expect(cap.sql).toContain("auth.head_sha = shad.head_sha"); @@ -113,11 +113,11 @@ describe("computeGateParity — cross-system gate-decision agreement (#preconv-p it("passes the project filter through to both CTE binds when scoped", async () => { const cap: { sql?: string; binds?: unknown[] } = {}; - await computeGateParity(parityEnv([], cap), { days: 90, nowMs: NOW, project: "gittensory" }); + await computeGateParity(parityEnv([], cap), { days: 90, nowMs: NOW, project: "loopover" }); // binds: auth, fromIso, project, shadow, fromIso, project expect(cap.binds).toHaveLength(6); - expect(cap.binds?.[2]).toBe("gittensory"); - expect(cap.binds?.[5]).toBe("gittensory"); + expect(cap.binds?.[2]).toBe("loopover"); + expect(cap.binds?.[5]).toBe("loopover"); }); it("excludes pairs whose action isn't a comparable merge/close/hold", async () => { @@ -301,9 +301,9 @@ describe("computeGateEval — source scoping for per-system standalone accuracy }, }, } as unknown as Env; - await computeGateEval(env, { days: 90, nowMs: NOW, source: "gittensory" }); + await computeGateEval(env, { days: 90, nowMs: NOW, source: "loopover" }); expect(boundSql).toContain("AND source = ?"); - expect(bound).toContain("gittensory"); + expect(bound).toContain("loopover"); }); it("omits the source filter (scores ALL writers) when no source is given — behavior-preserving", async () => { diff --git a/test/unit/queue-2.test.ts b/test/unit/queue-2.test.ts index 2ec6cb3f22..6306762608 100644 --- a/test/unit/queue-2.test.ts +++ b/test/unit/queue-2.test.ts @@ -1800,7 +1800,7 @@ describe("queue processors", () => { for (let i = 0; i < 5; i += 1) { await repositoriesModule.recordAuditEvent(env, { eventType: "agent.sweep.regate.repair_attempt", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "queued", detail: "prior attempt", @@ -1865,7 +1865,7 @@ describe("queue processors", () => { for (let i = 0; i < 4; i += 1) { await repositoriesModule.recordAuditEvent(env, { eventType: "agent.sweep.regate.repair_attempt", - actor: "gittensory", + actor: "loopover", targetKey, outcome: "queued", detail: "prior attempt", diff --git a/test/unit/repo-doc-pr.test.ts b/test/unit/repo-doc-pr.test.ts index 109a026ffe..cc56023ea2 100644 --- a/test/unit/repo-doc-pr.test.ts +++ b/test/unit/repo-doc-pr.test.ts @@ -186,7 +186,7 @@ describe("openRepoDocPullRequest (#3000)", () => { if (url.endsWith("/branches/main")) return Response.json({ commit: { sha: "base-commit-sha", commit: { tree: { sha: "base-tree-sha" } } } }); if (url.endsWith("/git/trees") && method === "POST") return Response.json({ sha: "new-tree-sha" }); if (url.endsWith("/git/commits") && method === "POST") return Response.json({ sha: "new-commit-sha" }); - if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/gittensory/repo-docs" }); + if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/loopover/repo-docs" }); if (url.endsWith("/repos/owner/widgets/pulls") && method === "POST") return Response.json({ number: 42, html_url: "https://github.com/owner/widgets/pull/42" }); return new Response("unexpected", { status: 500 }); }); @@ -205,10 +205,10 @@ describe("openRepoDocPullRequest (#3000)", () => { expect(commitCall?.body).toMatchObject({ tree: "new-tree-sha", parents: ["base-commit-sha"] }); const refCall = calls.find((c) => c.url.endsWith("/git/refs")); - expect(refCall?.body).toMatchObject({ ref: "refs/heads/gittensory/repo-docs", sha: "new-commit-sha" }); + expect(refCall?.body).toMatchObject({ ref: "refs/heads/loopover/repo-docs", sha: "new-commit-sha" }); const prCall = calls.find((c) => c.url.endsWith("/repos/owner/widgets/pulls") && c.method === "POST"); - expect(prCall?.body).toMatchObject({ head: "gittensory/repo-docs", base: "main", title: "docs: generate AGENTS.md and CLAUDE.md from repo profile" }); + expect(prCall?.body).toMatchObject({ head: "loopover/repo-docs", base: "main", title: "docs: generate AGENTS.md and CLAUDE.md from repo profile" }); expect(prCall?.body.body as string).toContain("LoopOver opened this pull request"); }); @@ -233,7 +233,7 @@ describe("openRepoDocPullRequest (#3000)", () => { if (url.endsWith("/branches/main")) return Response.json({ commit: { sha: "base-commit-sha", commit: { tree: { sha: "base-tree-sha" } } } }); if (url.endsWith("/git/trees") && method === "POST") return Response.json({ sha: "new-tree-sha" }); if (url.endsWith("/git/commits") && method === "POST") return Response.json({ sha: "new-commit-sha" }); - if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/gittensory/repo-docs" }); + if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/loopover/repo-docs" }); if (url.endsWith("/repos/owner/widgets/pulls") && method === "POST") return Response.json({ number: 43, html_url: "https://github.com/owner/widgets/pull/43" }); return new Response("unexpected", { status: 500 }); }); @@ -268,7 +268,7 @@ describe("openRepoDocPullRequest (#3000)", () => { if (url.endsWith("/branches/main")) return Response.json({ commit: { sha: "base-commit-sha", commit: { tree: { sha: "base-tree-sha" } } } }); if (url.endsWith("/git/trees") && method === "POST") return Response.json({ sha: "new-tree-sha" }); if (url.endsWith("/git/commits") && method === "POST") return Response.json({ sha: "new-commit-sha" }); - if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/gittensory/repo-docs" }); + if (url.endsWith("/git/refs") && method === "POST") return Response.json({ ref: "refs/heads/loopover/repo-docs" }); if (url.endsWith("/repos/owner/widgets/pulls") && method === "POST") return Response.json({ number: 44, html_url: "https://github.com/owner/widgets/pull/44" }); return new Response("unexpected", { status: 500 }); }); diff --git a/test/unit/routes-agent-approval.test.ts b/test/unit/routes-agent-approval.test.ts index 4059068923..f86471f070 100644 --- a/test/unit/routes-agent-approval.test.ts +++ b/test/unit/routes-agent-approval.test.ts @@ -191,11 +191,11 @@ describe("agent approval-queue routes (#779)", () => { describe("agent audit-feed route (#784)", () => { async function seedAudit(env: Env) { - await recordAuditEvent(env, { eventType: "agent.action.merge", actor: "gittensory", targetKey: "owner/repo#7", outcome: "completed", detail: "merged", createdAt: "2026-06-18T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "agent.action.merge", actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: "merged", createdAt: "2026-06-18T10:00:00.000Z" }); await recordAuditEvent(env, { eventType: "agent.pending_action.rejected", actor: "owner", targetKey: "owner/repo#8", outcome: "completed", detail: "rejected merge", createdAt: "2026-06-18T11:00:00.000Z" }); // excluded: a non-agent event on this repo, and an agent event on a different repo. await recordAuditEvent(env, { eventType: "github_app.pr_visibility_skipped", actor: "x", targetKey: "owner/repo#9", outcome: "completed", createdAt: "2026-06-18T12:00:00.000Z" }); - await recordAuditEvent(env, { eventType: "agent.action.label", actor: "gittensory", targetKey: "other/repo#1", outcome: "completed", createdAt: "2026-06-18T13:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "agent.action.label", actor: "loopover", targetKey: "other/repo#1", outcome: "completed", createdAt: "2026-06-18T13:00:00.000Z" }); } it("returns this repo's agent action + decision events newest-first, excluding non-agent and other-repo events", async () => { @@ -262,7 +262,7 @@ describe("agent audit-feed route (#784)", () => { it("reports a null pullNumber for an agent event whose targetKey has no numeric PR", async () => { const env = createTestEnv(); - await recordAuditEvent(env, { eventType: "agent.action.label", actor: "gittensory", targetKey: "owner/repo#manual", outcome: "completed", createdAt: "2026-06-18T09:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "agent.action.label", actor: "loopover", targetKey: "owner/repo#manual", outcome: "completed", createdAt: "2026-06-18T09:00:00.000Z" }); const res = await app.request("/v1/repos/owner/repo/agent/audit-feed", { headers: headers(env) }, env); const body = (await res.json()) as { events: Array<{ pullNumber: number | null }> }; expect(body.events).toHaveLength(1); @@ -286,7 +286,7 @@ describe("agent audit-feed route (#784)", () => { it("scrubs forbidden terms from the free-form detail before returning", async () => { const env = createTestEnv(); - await recordAuditEvent(env, { eventType: "agent.action.merge", actor: "gittensory", targetKey: "owner/repo#7", outcome: "completed", detail: "reward estimate leaked", createdAt: "2026-06-18T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "agent.action.merge", actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: "reward estimate leaked", createdAt: "2026-06-18T10:00:00.000Z" }); const res = await app.request("/v1/repos/owner/repo/agent/audit-feed", { headers: headers(env) }, env); const body = (await res.json()) as { events: Array<{ detail: string | null }> }; expect(body.events[0]?.detail).not.toMatch(/reward/i); @@ -297,11 +297,11 @@ describe("agent audit-feed route (#784)", () => { async function seedUnfilteredAudit(env: Env) { // Unlike seedAudit above, none of these are agent.action.%/agent.pending_action.% -- proving the // ?pull= branch carries NO eventType restriction (the whole point of listAuditEventsForTarget). - await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "gittensory", targetKey: "owner/repo#7", outcome: "completed", detail: "applied labels: gittensor:bug", createdAt: "2026-06-18T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: "applied labels: gittensor:bug", createdAt: "2026-06-18T10:00:00.000Z" }); await recordAuditEvent(env, { eventType: "github_app.pr_visibility_skipped", actor: "x", targetKey: "owner/repo#7", outcome: "completed", detail: "not_official_gittensor_miner", createdAt: "2026-06-18T11:00:00.000Z" }); // excluded: a different PR on the same repo, and a same-number PR on a different repo. - await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "gittensory", targetKey: "owner/repo#8", outcome: "completed", createdAt: "2026-06-18T12:00:00.000Z" }); - await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "gittensory", targetKey: "other/repo#7", outcome: "completed", createdAt: "2026-06-18T13:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "loopover", targetKey: "owner/repo#8", outcome: "completed", createdAt: "2026-06-18T12:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "loopover", targetKey: "other/repo#7", outcome: "completed", createdAt: "2026-06-18T13:00:00.000Z" }); } it("returns every event type for the single PR's targetKey, newest-first, excluding other targets", async () => { @@ -345,7 +345,7 @@ describe("agent audit-feed route (#784)", () => { it("scrubs forbidden terms from detail on the ?pull= branch too", async () => { const env = createTestEnv(); - await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "gittensory", targetKey: "owner/repo#7", outcome: "completed", detail: "reward estimate leaked", createdAt: "2026-06-18T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: "reward estimate leaked", createdAt: "2026-06-18T10:00:00.000Z" }); const res = await app.request("/v1/repos/owner/repo/agent/audit-feed?pull=7", { headers: headers(env) }, env); const body = (await res.json()) as { events: Array<{ detail: string | null }> }; expect(body.events[0]?.detail).not.toMatch(/reward/i); @@ -354,7 +354,7 @@ describe("agent audit-feed route (#784)", () => { it("passes through a null detail on the ?pull= branch unchanged (no sanitizer call on a null)", async () => { const env = createTestEnv(); - await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "gittensory", targetKey: "owner/repo#7", outcome: "completed", detail: null, createdAt: "2026-06-18T10:00:00.000Z" }); + await recordAuditEvent(env, { eventType: "github_app.type_label_decision", actor: "loopover", targetKey: "owner/repo#7", outcome: "completed", detail: null, createdAt: "2026-06-18T10:00:00.000Z" }); const res = await app.request("/v1/repos/owner/repo/agent/audit-feed?pull=7", { headers: headers(env) }, env); const body = (await res.json()) as { events: Array<{ detail: string | null }> }; expect(body.events[0]?.detail).toBeNull(); diff --git a/test/unit/routes-gate-outcome-breakdown.test.ts b/test/unit/routes-gate-outcome-breakdown.test.ts index 1e41622e06..210705e93a 100644 --- a/test/unit/routes-gate-outcome-breakdown.test.ts +++ b/test/unit/routes-gate-outcome-breakdown.test.ts @@ -37,21 +37,21 @@ describe("GET /v1/app/maintainer-dashboard gateOutcomeBreakdown (#2203)", () => const now = "2026-07-11T12:00:00.000Z"; await recordAuditEvent(env, { eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#1", outcome: "completed", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.close", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#2", outcome: "success", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.hold", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#3", outcome: "completed", createdAt: now, @@ -93,35 +93,35 @@ describe("GET /v1/app/maintainer-dashboard gateOutcomeBreakdown (#2203)", () => const now = "2026-07-11T12:00:00.000Z"; await recordAuditEvent(env, { eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#1", outcome: "queued", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.close", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#2", outcome: "denied", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.hold", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#3", outcome: "denied", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.approve", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#4", outcome: "completed", createdAt: now, }); await recordAuditEvent(env, { eventType: "agent.action.merge", - actor: "gittensory", + actor: "loopover", targetKey: "owner/repo#5", outcome: "success", createdAt: now, diff --git a/test/unit/selfhost-otel.test.ts b/test/unit/selfhost-otel.test.ts index 6562e5c1bc..4e04e76b8a 100644 --- a/test/unit/selfhost-otel.test.ts +++ b/test/unit/selfhost-otel.test.ts @@ -315,7 +315,7 @@ describe("self-host OpenTelemetry", () => { const span = otelMocks.exportedSpans.find((entry) => entry.name === "plain-failure"); expect(span.status.message).toBe("plain boom"); expect(span.resource.attributes).toMatchObject({ - "service.name": "gittensory-selfhost", + "service.name": "loopover-selfhost", "service.version": "custom-release", "deployment.environment.name": "selfhost", }); @@ -382,7 +382,7 @@ describe("self-host OpenTelemetry", () => { contextManager, validate, })).toBe(true); - await withOtelSpan("selfhost.review.gate", { "gittensory.operation": "gate_decision" }, () => undefined); + await withOtelSpan("selfhost.review.gate", { "loopover.operation": "gate_decision" }, () => undefined); await flushOpenTelemetry(); expect(otelMocks.OTLPTraceExporter).not.toHaveBeenCalled(); @@ -391,7 +391,7 @@ describe("self-host OpenTelemetry", () => { expect(sentryProcessor.onEnd).toHaveBeenCalledTimes(1); expect(sentryEndedSpans[0].name).toBe("selfhost.review.gate"); expect(sentryEndedSpans[0].attributes).toMatchObject({ - "gittensory.operation": "gate_decision", + "loopover.operation": "gate_decision", }); await resetOpenTelemetryForTest(); @@ -610,9 +610,9 @@ describe("self-host OpenTelemetry", () => { "github.repository": "JSONbored/gittensory", "github.pull_request.number": 1001, "github.installation_id_hash": "68b9c2136087c5ca", - "gittensory.operation": "gate_decision", - "gittensory.agent": "dual-ai", - "gittensory.decision_outcome": "success", + "loopover.operation": "gate_decision", + "loopover.agent": "dual-ai", + "loopover.decision_outcome": "success", }); await expect(reviewTraceAttributes({})).resolves.toEqual({}); }); diff --git a/test/unit/selfhost-qdrant-vectorize.test.ts b/test/unit/selfhost-qdrant-vectorize.test.ts index ce8fe6d51c..aff81ef2f8 100644 --- a/test/unit/selfhost-qdrant-vectorize.test.ts +++ b/test/unit/selfhost-qdrant-vectorize.test.ts @@ -48,7 +48,7 @@ describe("initQdrantCollection (#1217)", () => { await initQdrantCollection(BASE); expect(fake).toHaveBeenCalledOnce(); const [url, init] = fake.mock.calls[0] as unknown as [string, RequestInit]; - expect(url).toBe(`${BASE}/collections/gittensory`); + expect(url).toBe(`${BASE}/collections/loopover`); const body = JSON.parse(init.body as string) as { vectors: { size: number; distance: string } }; expect(body.vectors.distance).toBe("Cosine"); expect(body.vectors.size).toBe(1024); @@ -62,7 +62,7 @@ describe("initQdrantCollection (#1217)", () => { vi.stubGlobal("fetch", fake); await expect(initQdrantCollection(BASE)).resolves.not.toThrow(); expect(fake).toHaveBeenCalledTimes(2); - expect(fake.mock.calls[1]?.[0]).toBe(`${BASE}/collections/gittensory`); + expect(fake.mock.calls[1]?.[0]).toBe(`${BASE}/collections/loopover`); }); it("throws on a 409 when the existing collection dimension is wrong", async () => { @@ -71,7 +71,7 @@ describe("initQdrantCollection (#1217)", () => { .mockResolvedValueOnce(new Response(JSON.stringify({ error: "exists" }), { status: 409 })) .mockResolvedValueOnce(new Response(JSON.stringify(collectionInfo(1024)), { status: 200 })); vi.stubGlobal("fetch", fake); - await expect(initQdrantCollection(BASE, "gittensory", 768)).rejects.toThrow(/existing 1024, configured 768/); + await expect(initQdrantCollection(BASE, "loopover", 768)).rejects.toThrow(/existing 1024, configured 768/); }); it("throws when an existing collection cannot be inspected after a 409", async () => { diff --git a/test/unit/selfhost-sentry.test.ts b/test/unit/selfhost-sentry.test.ts index 9f0bd3d09f..670e3ce00b 100644 --- a/test/unit/selfhost-sentry.test.ts +++ b/test/unit/selfhost-sentry.test.ts @@ -105,7 +105,7 @@ describe("scrubEvent — redact secrets before an event leaves the box", () => { const ev = scrubbedEvent({ request: { headers: { authorization: "Bearer abc", "x-trace": "ok" } }, contexts: { - gittensory: { + loopover: { jobId: "j1", apiKey: "shh", nested: { secretToken: "deep" }, @@ -115,9 +115,9 @@ describe("scrubEvent — redact secrets before an event leaves the box", () => { }) as any; expect(ev.request.headers.authorization).toBe("[redacted]"); expect(ev.request.headers["x-trace"]).toBe("ok"); - expect(ev.contexts.gittensory.apiKey).toBe("[redacted]"); - expect(ev.contexts.gittensory.jobId).toBe("j1"); - expect(ev.contexts.gittensory.nested.secretToken).toBe("[redacted]"); + expect(ev.contexts.loopover.apiKey).toBe("[redacted]"); + expect(ev.contexts.loopover.jobId).toBe("j1"); + expect(ev.contexts.loopover.nested.secretToken).toBe("[redacted]"); expect(ev.extra.note).toBe("fine"); }); @@ -153,7 +153,7 @@ describe("scrubEvent — redact secrets before an event leaves the box", () => { cookies: { session: "abc" }, }, contexts: { - gittensory: { + loopover: { safeReason: "provider unavailable", pullRequestTitle: "PR title with private rubric", reviewText: "raw review body", @@ -180,10 +180,10 @@ describe("scrubEvent — redact secrets before an event leaves the box", () => { expect(ev.request.headers["x-trace"]).toBe("ok"); expect(ev.contexts.mystery).toBeUndefined(); expect(ev.contexts.runtime.name).toBe("node"); - expect(ev.contexts.gittensory.pullRequestTitle).toBe("[redacted]"); - expect(ev.contexts.gittensory.reviewText).toBe("[redacted]"); - expect(ev.contexts.gittensory.repoConfig).toBe("[redacted]"); - expect(ev.contexts.gittensory.nested.apiKey).toBe("[redacted]"); + expect(ev.contexts.loopover.pullRequestTitle).toBe("[redacted]"); + expect(ev.contexts.loopover.reviewText).toBe("[redacted]"); + expect(ev.contexts.loopover.repoConfig).toBe("[redacted]"); + expect(ev.contexts.loopover.nested.apiKey).toBe("[redacted]"); expect(ev.extra.diff).toBe("[redacted]"); expect(ev.extra.note).not.toContain(fakeToken); expect(ev.extra.note).not.toMatch(/wallet|raw score|\/home\/alice/i); @@ -525,7 +525,7 @@ describe("enabled when SENTRY_DSN is set", () => { it("captureError sends with context, tags operational fields, and without context skips setContext", async () => { await initSentry({ SENTRY_DSN: "d" } as unknown as NodeJS.ProcessEnv); captureError(new Error("boom"), { kind: "job_dead" }); - expect(mocks.scope.setContext).toHaveBeenCalledWith("gittensory", { + expect(mocks.scope.setContext).toHaveBeenCalledWith("loopover", { kind: "job_dead", }); expect(mocks.scope.setTag).toHaveBeenCalledWith("kind", "job_dead"); @@ -536,7 +536,7 @@ describe("enabled when SENTRY_DSN is set", () => { kind: "job_dead", installation_id: "not-an-installation", }); - expect(mocks.scope.setContext).toHaveBeenCalledWith("gittensory", { + expect(mocks.scope.setContext).toHaveBeenCalledWith("loopover", { kind: "job_dead", }); expect(mocks.scope.setTag).toHaveBeenCalledWith("kind", "job_dead"); @@ -583,7 +583,7 @@ describe("enabled when SENTRY_DSN is set", () => { captureError(new Error("self-host queue processing lease expired"), { kind: "job_dead" }, "processing_timeout"); expect(lastCapturedError().name).toBe("processing_timeout"); expect(lastCapturedError().message).toBe("self-host queue processing lease expired"); - expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["gittensory-error", "processing_timeout"]); + expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["loopover-error", "processing_timeout"]); }); it("captureError without an eventName leaves a caught exception's own name untouched, and never overrides Sentry's default grouping", async () => { @@ -603,7 +603,7 @@ describe("enabled when SENTRY_DSN is set", () => { await initSentry({ SENTRY_DSN: "d" } as unknown as NodeJS.ProcessEnv); captureReviewFailure(new Error("AI review inconclusive — no usable verdict for the PR head"), { repo: "o/r" }, "ai_review_inconclusive"); expect(lastCapturedError().name).toBe("ai_review_inconclusive"); - expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["gittensory-review-failure", "ai_review_inconclusive"]); + expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["loopover-review-failure", "ai_review_inconclusive"]); }); it("captureReviewFailure without an eventName never overrides Sentry's default grouping", async () => { @@ -683,16 +683,16 @@ describe("enabled when SENTRY_DSN is set", () => { it("builds stable environment-aware monitor slugs", () => { expect(resolveSentryMonitorSlug("scheduled-loop", "Prod East/1")).toBe( - "gittensory-selfhost-prod-east-1-scheduled-loop", + "loopover-selfhost-prod-east-1-scheduled-loop", ); expect(resolveSentryMonitorSlug("orb-export", " !!! ")).toBe( - "gittensory-selfhost-production-orb-export", + "loopover-selfhost-production-orb-export", ); expect(resolveSentryMonitorSlug("orb-relay-drain", "x".repeat(60))).toBe( - `gittensory-selfhost-${"x".repeat(48)}-orb-relay-drain`, + `loopover-selfhost-${"x".repeat(48)}-orb-relay-drain`, ); expect(resolveSentryMonitorSlug("queue-dead-letter-revive", "prod")).toBe( - "gittensory-selfhost-prod-queue-dead-letter-revive", + "loopover-selfhost-prod-queue-dead-letter-revive", ); }); @@ -712,7 +712,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 1, - { monitorSlug: "gittensory-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, + { monitorSlug: "loopover-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, expect.objectContaining({ schedule: { type: "interval", value: 30, unit: "minute" }, checkinMargin: 10, @@ -724,7 +724,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 2, expect.objectContaining({ - monitorSlug: "gittensory-selfhost-prod-queue-dead-letter-revive", + monitorSlug: "loopover-selfhost-prod-queue-dead-letter-revive", status: "ok", checkInId: "check-in-id", duration: expect.any(Number), @@ -745,7 +745,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 1, - { monitorSlug: "gittensory-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, + { monitorSlug: "loopover-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, expect.objectContaining({ schedule: { type: "interval", value: 90, unit: "minute" }, checkinMargin: 30, @@ -768,7 +768,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 1, - { monitorSlug: "gittensory-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, + { monitorSlug: "loopover-selfhost-prod-queue-dead-letter-revive", status: "in_progress" }, expect.objectContaining({ schedule: { type: "interval", value: 1, unit: "minute" }, checkinMargin: 5, @@ -795,7 +795,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 1, - { monitorSlug: "gittensory-selfhost-self-host-scheduled-loop", status: "in_progress" }, + { monitorSlug: "loopover-selfhost-self-host-scheduled-loop", status: "in_progress" }, expect.objectContaining({ schedule: { type: "interval", value: 2, unit: "minute" }, checkinMargin: 3, @@ -807,7 +807,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 2, expect.objectContaining({ - monitorSlug: "gittensory-selfhost-self-host-scheduled-loop", + monitorSlug: "loopover-selfhost-self-host-scheduled-loop", status: "ok", checkInId: "check-in-id", duration: expect.any(Number), @@ -848,7 +848,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.captureCheckIn).toHaveBeenNthCalledWith( 2, expect.objectContaining({ - monitorSlug: "gittensory-selfhost-prod-orb-export", + monitorSlug: "loopover-selfhost-prod-orb-export", status: "error", checkInId: "check-in-id", duration: expect.any(Number), @@ -857,7 +857,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.scope.setLevel).toHaveBeenCalledWith("error"); expect(mocks.scope.setTag).toHaveBeenCalledWith( "monitor", - "gittensory-selfhost-prod-orb-export", + "loopover-selfhost-prod-orb-export", ); expect(mocks.scope.setTag).toHaveBeenCalledWith("jobType", "orb-export"); expect(mocks.scope.setTag).toHaveBeenCalledWith( @@ -866,12 +866,12 @@ describe("enabled when SENTRY_DSN is set", () => { ); expect(mocks.scope.setTag).toHaveBeenCalledWith("subsystem", "scheduled"); expect(mocks.scope.setFingerprint).toHaveBeenCalledWith([ - "gittensory-sentry-monitor", + "loopover-sentry-monitor", "orb-export", ]); expect(mocks.scope.setContext).toHaveBeenCalledWith("sentry_monitor", { monitor: "orb-export", - monitorSlug: "gittensory-selfhost-prod-orb-export", + monitorSlug: "loopover-selfhost-prod-orb-export", jobType: "orb-export", repo: "JSONbored/gittensory", exported: 7, @@ -894,7 +894,7 @@ describe("enabled when SENTRY_DSN is set", () => { expect(mocks.scope.setContext).toHaveBeenCalledWith("sentry_monitor", { monitor: "orb-relay-drain", - monitorSlug: "gittensory-selfhost-production-orb-relay-drain", + monitorSlug: "loopover-selfhost-production-orb-relay-drain", }); expect((mocks.captureException.mock.calls.at(-1)?.[0] as Error).message).toBe( "relay failed", @@ -978,7 +978,7 @@ describe("forwardStructuredLogToSentry — central console.log → Sentry error installationId: 143010787, })); // Recurrences of one failure group into a single issue by event. - expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["gittensory-log", "orb_broker_unavailable"]); + expect(mocks.scope.setFingerprint).toHaveBeenCalledWith(["loopover-log", "orb_broker_unavailable"]); }); it("strips the synthetic wrapper stack so the issue culprit is not forwardStructuredLogToSentry", async () => { diff --git a/test/unit/unified-comment-parity.test.ts b/test/unit/unified-comment-parity.test.ts index b8adb31e4a..f8e0f02681 100644 --- a/test/unit/unified-comment-parity.test.ts +++ b/test/unit/unified-comment-parity.test.ts @@ -241,7 +241,7 @@ describe("converged comment ↔ legacy panel parity (#unified-comment)", () => { const beta = collapsibles.find((section) => section.title === "[BETA] Chat with LoopOver"); expect(beta?.body).toContain("`@loopover ask `"); expect(beta?.body).toContain("`@loopover chat `"); - expect(beta?.body).toContain("https://example-selfhost.test/docs/gittensory-commands"); + expect(beta?.body).toContain("https://example-selfhost.test/docs/loopover-commands"); // Intent routing is off in this fixture, so its plain-language line must not appear. expect(beta?.body).not.toContain("Plain-language"); });