diff --git a/apps/gittensory-miner-ui/src/auth.test.ts b/apps/gittensory-miner-ui/src/auth.test.ts index 35fdcf67a2..f704ea80f3 100644 --- a/apps/gittensory-miner-ui/src/auth.test.ts +++ b/apps/gittensory-miner-ui/src/auth.test.ts @@ -14,19 +14,19 @@ describe("isAuthenticatedRequest (#4858)", () => { }); it("skips a malformed cookie pair with no '=' separator, without throwing", () => { - expect(isAuthenticatedRequest(`malformed; gittensory_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); + expect(isAuthenticatedRequest(`malformed; loopover_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); }); it("skips a cookie pair with an empty name (leading '=')", () => { - expect(isAuthenticatedRequest(`=novalue; gittensory_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); + expect(isAuthenticatedRequest(`=novalue; loopover_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); }); it("rejects the auth cookie when its value doesn't match the server's token", () => { - expect(isAuthenticatedRequest("gittensory_miner_ui_token=wrong-value", TOKEN)).toBe(false); + expect(isAuthenticatedRequest("loopover_miner_ui_token=wrong-value", TOKEN)).toBe(false); }); it("accepts the auth cookie when its value matches the server's token exactly", () => { - expect(isAuthenticatedRequest(`gittensory_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); + expect(isAuthenticatedRequest(`loopover_miner_ui_token=${TOKEN}`, TOKEN)).toBe(true); }); }); @@ -41,7 +41,7 @@ describe("handleAuthRequest (#4858)", () => { }); it("falls through (null) for an authenticated /api/* request", () => { - expect(handleAuthRequest("/api/portfolio-queue", `gittensory_miner_ui_token=${TOKEN}`, TOKEN)).toBeNull(); + expect(handleAuthRequest("/api/portfolio-queue", `loopover_miner_ui_token=${TOKEN}`, TOKEN)).toBeNull(); }); it("returns a 401 JSON body for an unauthenticated /api/* request", () => { @@ -101,7 +101,7 @@ describe("authPlugin (#4858)", () => { middleware({ url: "/", headers: {} }, res, () => { calledNext = true; }); - expect(headers["Set-Cookie"]).toBe(`gittensory_miner_ui_token=${TOKEN}; HttpOnly; SameSite=Strict; Path=/`); + expect(headers["Set-Cookie"]).toBe(`loopover_miner_ui_token=${TOKEN}; HttpOnly; SameSite=Strict; Path=/`); expect(calledNext).toBe(true); }); @@ -128,18 +128,18 @@ describe("authPlugin (#4858)", () => { const middleware = captureMiddleware(); const { res, headers } = fakeResponse(); let calledNext = false; - middleware({ url: "/api/portfolio-queue", headers: { cookie: `gittensory_miner_ui_token=${TOKEN}` } }, res, () => { + middleware({ url: "/api/portfolio-queue", headers: { cookie: `loopover_miner_ui_token=${TOKEN}` } }, res, () => { calledNext = true; }); expect(calledNext).toBe(true); - expect(headers["Set-Cookie"]).toBe(`gittensory_miner_ui_token=${TOKEN}; HttpOnly; SameSite=Strict; Path=/`); + expect(headers["Set-Cookie"]).toBe(`loopover_miner_ui_token=${TOKEN}; HttpOnly; SameSite=Strict; Path=/`); }); it("uses deps.generateToken so a fixed test token is deterministic across requests", () => { const middleware = captureMiddleware({ generateToken: () => "fixed-token-123" }); const { res } = fakeResponse(); let calledNext = false; - middleware({ url: "/api/ledgers", headers: { cookie: "gittensory_miner_ui_token=fixed-token-123" } }, res, () => { + middleware({ url: "/api/ledgers", headers: { cookie: "loopover_miner_ui_token=fixed-token-123" } }, res, () => { calledNext = true; }); expect(calledNext).toBe(true); diff --git a/apps/gittensory-miner-ui/vite-auth.ts b/apps/gittensory-miner-ui/vite-auth.ts index b885d4548e..d2532d0037 100644 --- a/apps/gittensory-miner-ui/vite-auth.ts +++ b/apps/gittensory-miner-ui/vite-auth.ts @@ -24,7 +24,7 @@ import type { Plugin } from "vite"; // request never reaches any of them. This also means any FUTURE /api/* endpoint (e.g. a write action) is // covered automatically, with no per-endpoint auth wiring required. -const COOKIE_NAME = "gittensory_miner_ui_token"; +const COOKIE_NAME = "loopover_miner_ui_token"; export type AuthDeps = { /** Injectable so tests get a deterministic token instead of a real random one. */ diff --git a/packages/gittensory-engine/src/miner-prediction-metrics.ts b/packages/gittensory-engine/src/miner-prediction-metrics.ts index 0973bfdd77..d475c3fc9b 100644 --- a/packages/gittensory-engine/src/miner-prediction-metrics.ts +++ b/packages/gittensory-engine/src/miner-prediction-metrics.ts @@ -6,20 +6,20 @@ // Scoped as an on-demand RENDERER, not a live HTTP registry: gittensory-miner is a local CLI, not a daemon, so a // caller renders this to stdout for its own scrape/cron setup and reads the ledger itself (no data collection of // its own lives here — this stays a pure, side-effect-free function like the rest of gittensory-engine). It mirrors -// the metric-naming (`gittensory_miner_*_total`) and HELP/TYPE/label conventions of src/selfhost/metrics.ts rather +// the metric-naming (`loopover_miner_*_total`) and HELP/TYPE/label conventions of src/selfhost/metrics.ts rather // than importing across the package boundary. // // Counters emitted: -// - `gittensory_miner_predictions_total{conclusion="..."}` — predictions recorded, one series per predicted +// - `loopover_miner_predictions_total{conclusion="..."}` — predictions recorded, one series per predicted // conclusion (e.g. merge/close/hold). -// - `gittensory_miner_prediction_correct_total` — predictions whose realized outcome matched the prediction. -// - `gittensory_miner_prediction_incorrect_total` — predictions whose realized outcome differed. +// - `loopover_miner_prediction_correct_total` — predictions whose realized outcome matched the prediction. +// - `loopover_miner_prediction_incorrect_total` — predictions whose realized outcome differed. // The correct/incorrect counters only move for rows carrying a resolved outcome; unresolved rows count toward // `predictions_total` only, so the surface is meaningful before outcome-pairing exists and grows once it does. -export const MINER_PREDICTIONS_TOTAL = "gittensory_miner_predictions_total"; -export const MINER_PREDICTION_CORRECT_TOTAL = "gittensory_miner_prediction_correct_total"; -export const MINER_PREDICTION_INCORRECT_TOTAL = "gittensory_miner_prediction_incorrect_total"; +export const MINER_PREDICTIONS_TOTAL = "loopover_miner_predictions_total"; +export const MINER_PREDICTION_CORRECT_TOTAL = "loopover_miner_prediction_correct_total"; +export const MINER_PREDICTION_INCORRECT_TOTAL = "loopover_miner_prediction_incorrect_total"; /** One prediction-ledger row for metrics: its predicted `conclusion`, plus an optional realized-outcome pairing * (`correct`: true = matched, false = differed, null/undefined = not yet resolved). */ diff --git a/packages/gittensory-miner/lib/deny-hook-synthesis.js b/packages/gittensory-miner/lib/deny-hook-synthesis.js index f041659871..2c8ac5d75e 100644 --- a/packages/gittensory-miner/lib/deny-hook-synthesis.js +++ b/packages/gittensory-miner/lib/deny-hook-synthesis.js @@ -72,7 +72,7 @@ export function resolveDenyHookSynthesisDbPath(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/event-ledger-cli.js b/packages/gittensory-miner/lib/event-ledger-cli.js index 493d68375c..f82aa52834 100644 --- a/packages/gittensory-miner/lib/event-ledger-cli.js +++ b/packages/gittensory-miner/lib/event-ledger-cli.js @@ -167,10 +167,10 @@ export function renderLedgerTable(events) { const EVENT_LEDGER_METRICS_USAGE = "Usage: gittensory-miner ledger metrics"; -// Prometheus metric name for the per-type event-ledger counter. Mirrors the `gittensory_miner_*_total` naming and +// Prometheus metric name for the per-type event-ledger counter. Mirrors the `loopover_miner_*_total` naming and // the HELP/TYPE/label conventions of the engine's renderMinerPredictionMetrics // (packages/gittensory-engine/src/miner-prediction-metrics.ts) rather than importing across the package boundary. -const MINER_EVENTS_TOTAL = "gittensory_miner_events_total"; +const MINER_EVENTS_TOTAL = "loopover_miner_events_total"; /** HELP-text escaping — backslash + newline (mirrors miner-prediction-metrics.ts's escapeHelpText). */ function escapeHelpText(help) { @@ -184,7 +184,7 @@ function escapeLabelValue(value) { } /** - * Render event-ledger activity as Prometheus text-exposition counters: one `gittensory_miner_events_total{type}` + * Render event-ledger activity as Prometheus text-exposition counters: one `loopover_miner_events_total{type}` * series per event type, so a self-hoster's own Grafana/alerting can scrape ledger activity instead of polling * `ledger list --json` (#4841). Pure + side-effect-free — the caller supplies the rows and prints the result; * deterministic (series emitted in sorted type order); always emits HELP/TYPE so an empty ledger is still a diff --git a/packages/gittensory-miner/lib/governor-ledger.js b/packages/gittensory-miner/lib/governor-ledger.js index 7e09473b41..7620121acd 100644 --- a/packages/gittensory-miner/lib/governor-ledger.js +++ b/packages/gittensory-miner/lib/governor-ledger.js @@ -36,7 +36,7 @@ export function resolveGovernorLedgerDbPath(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/governor-metrics-cli.js b/packages/gittensory-miner/lib/governor-metrics-cli.js index 9d36df6d18..77eeacefa3 100644 --- a/packages/gittensory-miner/lib/governor-metrics-cli.js +++ b/packages/gittensory-miner/lib/governor-metrics-cli.js @@ -26,8 +26,8 @@ import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js const GOVERNOR_METRICS_USAGE = "Usage: gittensory-miner governor metrics"; -export const GOVERNOR_RATE_LIMIT_REMAINING_RATIO = "gittensory_miner_governor_rate_limit_remaining_ratio"; -export const GOVERNOR_CAP_USAGE_RATIO = "gittensory_miner_governor_cap_usage_ratio"; +export const GOVERNOR_RATE_LIMIT_REMAINING_RATIO = "loopover_miner_governor_rate_limit_remaining_ratio"; +export const GOVERNOR_CAP_USAGE_RATIO = "loopover_miner_governor_cap_usage_ratio"; /** HELP-text escaping — backslash + newline (mirrors miner-prediction-metrics.ts's escapeHelpText). */ function escapeMetricsHelpText(help) { diff --git a/packages/gittensory-miner/lib/laptop-init.js b/packages/gittensory-miner/lib/laptop-init.js index a557582846..ccef1caadd 100644 --- a/packages/gittensory-miner/lib/laptop-init.js +++ b/packages/gittensory-miner/lib/laptop-init.js @@ -20,7 +20,7 @@ function resolveMinerStateDir(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner"); + return join(configHome, "loopover-miner"); } /** Path to the laptop-mode SQLite bootstrap file inside the miner state directory. */ diff --git a/packages/gittensory-miner/lib/local-store.js b/packages/gittensory-miner/lib/local-store.js index c9640ccb3c..da802b6f5b 100644 --- a/packages/gittensory-miner/lib/local-store.js +++ b/packages/gittensory-miner/lib/local-store.js @@ -25,7 +25,7 @@ export function resolveLocalStoreDbPath(defaultDbFileName, explicitEnvVarName, e const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } /** Trim and validate a caller-supplied (or resolved-default) DB path, throwing `invalidPathError` if it is empty. */ diff --git a/packages/gittensory-miner/lib/orb-export.js b/packages/gittensory-miner/lib/orb-export.js index f20a0c7a43..9bb7d662d6 100644 --- a/packages/gittensory-miner/lib/orb-export.js +++ b/packages/gittensory-miner/lib/orb-export.js @@ -38,7 +38,7 @@ export function resolveOrbExportDbPath(env = process.env) { typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/plan-store.js b/packages/gittensory-miner/lib/plan-store.js index c548275745..593661cfef 100644 --- a/packages/gittensory-miner/lib/plan-store.js +++ b/packages/gittensory-miner/lib/plan-store.js @@ -34,7 +34,7 @@ export function resolvePlanStoreDbPath(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/portfolio-queue-cli.js b/packages/gittensory-miner/lib/portfolio-queue-cli.js index f7cbedf125..115d1dbdaa 100644 --- a/packages/gittensory-miner/lib/portfolio-queue-cli.js +++ b/packages/gittensory-miner/lib/portfolio-queue-cli.js @@ -499,11 +499,11 @@ export function runQueueClaimBatch(args, options = {}) { const QUEUE_METRICS_USAGE = "Usage: gittensory-miner queue metrics"; -// Prometheus metric names for the portfolio-queue gauges (#5186). Mirrors the `gittensory_miner_*` naming and +// Prometheus metric names for the portfolio-queue gauges (#5186). Mirrors the `loopover_miner_*` naming and // HELP/TYPE/label conventions of event-ledger-cli.js's renderEventLedgerMetrics / the engine's // renderMinerPredictionMetrics, rather than importing across the package boundary. -export const QUEUE_ITEMS = "gittensory_miner_portfolio_queue_items"; -export const QUEUE_OLDEST_IN_PROGRESS_LEASE_AGE_SECONDS = "gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds"; +export const QUEUE_ITEMS = "loopover_miner_portfolio_queue_items"; +export const QUEUE_OLDEST_IN_PROGRESS_LEASE_AGE_SECONDS = "loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds"; /** HELP-text escaping — backslash + newline (mirrors miner-prediction-metrics.ts's escapeHelpText). */ function escapeMetricsHelpText(help) { diff --git a/packages/gittensory-miner/lib/prediction-ledger.js b/packages/gittensory-miner/lib/prediction-ledger.js index 83bf68ca7c..ce576af2ab 100644 --- a/packages/gittensory-miner/lib/prediction-ledger.js +++ b/packages/gittensory-miner/lib/prediction-ledger.js @@ -37,7 +37,7 @@ export function resolvePredictionLedgerDbPath(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/repo-clone.js b/packages/gittensory-miner/lib/repo-clone.js index 848ff8308a..30f5cedc2f 100644 --- a/packages/gittensory-miner/lib/repo-clone.js +++ b/packages/gittensory-miner/lib/repo-clone.js @@ -25,7 +25,7 @@ export function resolveRepoCloneBaseDir(env = process.env) { if (explicitConfigDir) return join(explicitConfigDir, DEFAULT_CLONE_DIR_NAME); const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", DEFAULT_CLONE_DIR_NAME); + return join(configHome, "loopover-miner", DEFAULT_CLONE_DIR_NAME); } // GitHub owner/repo names are restricted to alphanumerics, hyphens, underscores, and periods, and are never diff --git a/packages/gittensory-miner/lib/status.js b/packages/gittensory-miner/lib/status.js index 760e16cf9d..04357824c4 100644 --- a/packages/gittensory-miner/lib/status.js +++ b/packages/gittensory-miner/lib/status.js @@ -58,7 +58,7 @@ export function resolveMinerStateDir(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner"); + return join(configHome, "loopover-miner"); } /** diff --git a/packages/gittensory-miner/lib/worktree-allocator.js b/packages/gittensory-miner/lib/worktree-allocator.js index c50c83abfd..ade02d63cd 100644 --- a/packages/gittensory-miner/lib/worktree-allocator.js +++ b/packages/gittensory-miner/lib/worktree-allocator.js @@ -26,7 +26,7 @@ export function resolveWorktreeAllocatorDbPath(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultDbFileName); + return join(configHome, "loopover-miner", defaultDbFileName); } export function resolveWorktreeBaseDir(env = process.env) { @@ -43,7 +43,7 @@ export function resolveWorktreeBaseDir(env = process.env) { const configHome = typeof env.XDG_CONFIG_HOME === "string" && env.XDG_CONFIG_HOME.trim() ? env.XDG_CONFIG_HOME.trim() : join(homedir(), ".config"); - return join(configHome, "gittensory-miner", defaultWorktreeDirName); + return join(configHome, "loopover-miner", defaultWorktreeDirName); } function normalizeDbPath(dbPath) { diff --git a/prometheus/rules/alerts.yml b/prometheus/rules/alerts.yml index 2b816568a1..66b865d251 100644 --- a/prometheus/rules/alerts.yml +++ b/prometheus/rules/alerts.yml @@ -626,7 +626,7 @@ groups: # renderMinerPredictionMetrics (packages/gittensory-engine/src/miner-prediction-metrics.ts, #4264, wired # into a command in #4838 over the calibration-report join built in #4849) to a file/pushgateway their # Prometheus scrapes. The rule is therefore DORMANT until such a target exists: an absent - # gittensory_miner_prediction_* series simply yields no result (and the `> 0` denominator guard also makes + # loopover_miner_prediction_* series simply yields no result (and the `> 0` denominator guard also makes # the 0/0 case undefined), so it loads cleanly via `selfhost:validate-observability` and never false-fires # on an install that has no miner scrape configured yet -- exactly like loopover-d1-storage stays silent # without the D1 probe. @@ -636,7 +636,7 @@ groups: # Calibration = how often the miner's predicted gate conclusion matched the realized outcome. This is # the miner counterpart of loopover-jobs' LoopoverHighJobFailureRatio and uses the identical # bad/(bad+good) shape: the fraction of RESOLVED predictions that came back INCORRECT over the window. - # gittensory_miner_prediction_{correct,incorrect}_total only move for rows carrying a resolved outcome + # loopover_miner_prediction_{correct,incorrect}_total only move for rows carrying a resolved outcome # (renderMinerPredictionMetrics), so still-unresolved predictions never dilute the ratio. The trailing # `> 0` on the denominator guards the 0/0 = NaN case (no resolved predictions in the window -> the rule # stays inactive rather than firing on garbage), which is also what makes it degrade to silent when the @@ -649,11 +649,11 @@ groups: # inline-documented-threshold convention (there are no recording rules here to hang a named constant on). expr: | ( - sum(rate(gittensory_miner_prediction_incorrect_total[6h])) + sum(rate(loopover_miner_prediction_incorrect_total[6h])) / ( - sum(rate(gittensory_miner_prediction_correct_total[6h])) - + sum(rate(gittensory_miner_prediction_incorrect_total[6h])) + sum(rate(loopover_miner_prediction_correct_total[6h])) + + sum(rate(loopover_miner_prediction_incorrect_total[6h])) > 0 ) ) > 0.5 @@ -663,13 +663,13 @@ groups: annotations: summary: "gittensory miner prediction calibration has drifted" description: "{{ $value | humanizePercentage }} of the miner's recently resolved gate predictions were incorrect over the last 6h (sustained 30m). Predicted-gate accuracy has drifted out of tolerance." - runbook: "Compare gittensory_miner_prediction_correct_total vs gittensory_miner_prediction_incorrect_total and review the miner's own calibration report (`gittensory-miner calibration`). Sustained drift usually means the predicted-gate heuristics need recalibration against the repo(s) the miner now targets, or a recent upstream gate-behavior change the predictor hasn't caught up to." + runbook: "Compare loopover_miner_prediction_correct_total vs loopover_miner_prediction_incorrect_total and review the miner's own calibration report (`gittensory-miner calibration`). Sustained drift usually means the predicted-gate heuristics need recalibration against the repo(s) the miner now targets, or a recent upstream gate-behavior change the predictor hasn't caught up to." # ── Miner portfolio-queue backlog health (#5186) ────────────────────────── # Same DORMANT-until-a-scrape-target-exists posture as gittensory-miner-prediction above: an operator runs # `gittensory-miner queue metrics` (packages/gittensory-miner/lib/portfolio-queue-cli.js's # renderPortfolioQueueMetrics) to a file/pushgateway their Prometheus scrapes. Absent - # gittensory_miner_portfolio_queue_* series simply yield no result, so this loads cleanly via + # loopover_miner_portfolio_queue_* series simply yield no result, so this loads cleanly via # `selfhost:validate-observability` and never false-fires on an install with no miner scrape configured. - name: gittensory-miner-portfolio-queue rules: @@ -681,7 +681,7 @@ groups: # stuck, so a lease sits well past its own 30m default with nothing automatically reclaiming it. # 3600s (1h) is a generous multiple of DEFAULT_MAX_LEASE_MS so a healthy install's own reclaim sweep # always clears this long before the alert would fire; tune down if your reclaim cadence is tighter. - expr: gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds > 3600 + expr: loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds > 3600 for: 15m labels: severity: warning @@ -695,7 +695,7 @@ groups: # LoopoverQueueBacklogHigh above -- a sustained high queued count means discovery is outpacing # claiming, mirroring the main product's own "queue > threshold for N minutes" shape. 200 is a # generous default for a single-host laptop-mode install; tune to your normal steady-state depth. - expr: gittensory_miner_portfolio_queue_items{status="queued"} > 200 + expr: loopover_miner_portfolio_queue_items{status="queued"} > 200 for: 30m labels: severity: warning @@ -707,7 +707,7 @@ groups: # ── Governor rate-limit/budget threshold pressure (#5187) ───────────────── # Same DORMANT-until-a-scrape-target-exists posture as the two miner groups above: an operator runs # `gittensory-miner governor metrics` (packages/gittensory-miner/lib/governor-metrics-cli.js's - # renderGovernorMetrics) to a file/pushgateway their Prometheus scrapes. Absent gittensory_miner_governor_* + # renderGovernorMetrics) to a file/pushgateway their Prometheus scrapes. Absent loopover_miner_governor_* # series simply yield no result. Read-only: these rules alert on the governor's already-persisted rate-limit # (#5134/write-rate-limit.ts) and cap-usage (#5134/budget-cap.ts) state; they do not gate, retry, or modify # governor decision logic in any way (governor-chokepoint.js/governor-chokepoint-persisted.js are untouched). @@ -719,7 +719,7 @@ groups: # 60s (the default policy's windowMs), so staying under 0.1 for a full 10m means the bucket has been # refilled to >90% capacity across at least ten separate windows in a row -- sustained heavy write # pressure, not one spike. - expr: gittensory_miner_governor_rate_limit_remaining_ratio < 0.1 + expr: loopover_miner_governor_rate_limit_remaining_ratio < 0.1 for: 10m labels: severity: warning @@ -733,7 +733,7 @@ groups: # elapsed session ms) against DEFAULT_AMS_POLICY_SPEC.capLimits, the same fleet-wide default loop-cli.js # itself falls back to when a repo has no `.gittensory-ams.yml` override. 0.9 gives an operator a # heads-up before evaluateGovernorCaps' own exceeded/kill_switch verdict actually halts the run. - expr: gittensory_miner_governor_cap_usage_ratio > 0.9 + expr: loopover_miner_governor_cap_usage_ratio > 0.9 for: 10m labels: severity: warning diff --git a/test/unit/alerts-miner-governor-rate-limit-budget-pressure.test.ts b/test/unit/alerts-miner-governor-rate-limit-budget-pressure.test.ts index 37de72195c..4bd64986d4 100644 --- a/test/unit/alerts-miner-governor-rate-limit-budget-pressure.test.ts +++ b/test/unit/alerts-miner-governor-rate-limit-budget-pressure.test.ts @@ -52,7 +52,7 @@ describe("GittensoryMinerGovernorRateLimitPressureHigh alert (#5187)", () => { }); it("keys off the real renderer's rate-limit-remaining gauge, not an invented metric name", () => { - expect(GOVERNOR_RATE_LIMIT_REMAINING_RATIO).toBe("gittensory_miner_governor_rate_limit_remaining_ratio"); + expect(GOVERNOR_RATE_LIMIT_REMAINING_RATIO).toBe("loopover_miner_governor_rate_limit_remaining_ratio"); expect(flat).toBe(`${GOVERNOR_RATE_LIMIT_REMAINING_RATIO} < 0.1`); }); @@ -61,7 +61,7 @@ describe("GittensoryMinerGovernorRateLimitPressureHigh alert (#5187)", () => { }); it("never references any loopover_* server metric (a miner rule must not fire on server data)", () => { - expect(flat).not.toMatch(/loopover_/); + expect(flat).not.toMatch(/loopover_(?!miner_)/); }); it("has warning severity and human-readable annotations", () => { @@ -88,7 +88,7 @@ describe("GittensoryMinerGovernorCapUsageHigh alert (#5187)", () => { }); it("keys off the real renderer's cap-usage gauge, thresholded at 90%", () => { - expect(GOVERNOR_CAP_USAGE_RATIO).toBe("gittensory_miner_governor_cap_usage_ratio"); + expect(GOVERNOR_CAP_USAGE_RATIO).toBe("loopover_miner_governor_cap_usage_ratio"); expect(flat).toBe(`${GOVERNOR_CAP_USAGE_RATIO} > 0.9`); }); @@ -98,7 +98,7 @@ describe("GittensoryMinerGovernorCapUsageHigh alert (#5187)", () => { }); it("never references any loopover_* server metric (a miner rule must not fire on server data)", () => { - expect(flat).not.toMatch(/loopover_/); + expect(flat).not.toMatch(/loopover_(?!miner_)/); }); it("only reads governor state -- the runbook never instructs a governor decision-logic change", () => { diff --git a/test/unit/alerts-miner-portfolio-queue-backlog.test.ts b/test/unit/alerts-miner-portfolio-queue-backlog.test.ts index d92acf1a53..61cebe9309 100644 --- a/test/unit/alerts-miner-portfolio-queue-backlog.test.ts +++ b/test/unit/alerts-miner-portfolio-queue-backlog.test.ts @@ -52,7 +52,7 @@ describe("GittensoryMinerPortfolioQueueItemStuck alert (#5186)", () => { it("keys off the real renderer's oldest-lease-age gauge, not an invented metric name", () => { expect(QUEUE_OLDEST_IN_PROGRESS_LEASE_AGE_SECONDS).toBe( - "gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds", + "loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds", ); expect(flat).toContain(QUEUE_OLDEST_IN_PROGRESS_LEASE_AGE_SECONDS); }); @@ -63,7 +63,7 @@ describe("GittensoryMinerPortfolioQueueItemStuck alert (#5186)", () => { }); it("never references any loopover_* server metric (a miner rule must not fire on server data)", () => { - expect(flat).not.toMatch(/loopover_/); + expect(flat).not.toMatch(/loopover_(?!miner_)/); }); it("has warning severity and human-readable annotations", () => { @@ -84,7 +84,7 @@ describe("GittensoryMinerPortfolioQueueBacklogHigh alert (#5186)", () => { }); it("keys off the real renderer's items gauge, scoped to the queued status label", () => { - expect(QUEUE_ITEMS).toBe("gittensory_miner_portfolio_queue_items"); + expect(QUEUE_ITEMS).toBe("loopover_miner_portfolio_queue_items"); expect(flat).toBe(`${QUEUE_ITEMS}{status="queued"} > 200`); }); @@ -94,6 +94,6 @@ describe("GittensoryMinerPortfolioQueueBacklogHigh alert (#5186)", () => { }); it("never references any loopover_* server metric (a miner rule must not fire on server data)", () => { - expect(flat).not.toMatch(/loopover_/); + expect(flat).not.toMatch(/loopover_(?!miner_)/); }); }); diff --git a/test/unit/alerts-miner-prediction-calibration-drift.test.ts b/test/unit/alerts-miner-prediction-calibration-drift.test.ts index 6696a73217..e2b8939251 100644 --- a/test/unit/alerts-miner-prediction-calibration-drift.test.ts +++ b/test/unit/alerts-miner-prediction-calibration-drift.test.ts @@ -51,15 +51,15 @@ describe("GittensoryMinerPredictionCalibrationDrift alert (#5188)", () => { }); it("keys off the miner renderer's real correct/incorrect counters, not invented metric names", () => { - expect(MINER_PREDICTION_CORRECT_TOTAL).toBe("gittensory_miner_prediction_correct_total"); - expect(MINER_PREDICTION_INCORRECT_TOTAL).toBe("gittensory_miner_prediction_incorrect_total"); + expect(MINER_PREDICTION_CORRECT_TOTAL).toBe("loopover_miner_prediction_correct_total"); + expect(MINER_PREDICTION_INCORRECT_TOTAL).toBe("loopover_miner_prediction_incorrect_total"); expect(flat).toContain(MINER_PREDICTION_CORRECT_TOTAL); expect(flat).toContain(MINER_PREDICTION_INCORRECT_TOTAL); }); it("uses the incorrect/(correct+incorrect) drift ratio shape over a 6h window", () => { expect(flat).toMatch( - /sum\(rate\(gittensory_miner_prediction_incorrect_total\[6h\]\)\) \/ \( sum\(rate\(gittensory_miner_prediction_correct_total\[6h\]\)\) \+ sum\(rate\(gittensory_miner_prediction_incorrect_total\[6h\]\)\)/, + /sum\(rate\(loopover_miner_prediction_incorrect_total\[6h\]\)\) \/ \( sum\(rate\(loopover_miner_prediction_correct_total\[6h\]\)\) \+ sum\(rate\(loopover_miner_prediction_incorrect_total\[6h\]\)\)/, ); }); @@ -70,7 +70,7 @@ describe("GittensoryMinerPredictionCalibrationDrift alert (#5188)", () => { }); it("never references any loopover_* server metric (a miner rule must not fire on server data)", () => { - expect(flat).not.toMatch(/loopover_/); + expect(flat).not.toMatch(/loopover_(?!miner_)/); }); it("has a sustain window, warning severity, and human-readable annotations", () => { diff --git a/test/unit/miner-attempt-log.test.ts b/test/unit/miner-attempt-log.test.ts index 7255f74837..2729921843 100644 --- a/test/unit/miner-attempt-log.test.ts +++ b/test/unit/miner-attempt-log.test.ts @@ -50,9 +50,9 @@ describe("gittensory-miner attempt log (#4294)", () => { "/custom/config/attempt-log.sqlite3", ); expect(resolveAttemptLogDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/attempt-log.sqlite3", + "/xdg/loopover-miner/attempt-log.sqlite3", ); - expect(resolveAttemptLogDbPath({})).toMatch(/\/\.config\/gittensory-miner\/attempt-log\.sqlite3$/); + expect(resolveAttemptLogDbPath({})).toMatch(/\/\.config\/loopover-miner\/attempt-log\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and reads empty before any append", () => { diff --git a/test/unit/miner-claim-ledger.test.ts b/test/unit/miner-claim-ledger.test.ts index c2a4dbfdb1..378b4d69d3 100644 --- a/test/unit/miner-claim-ledger.test.ts +++ b/test/unit/miner-claim-ledger.test.ts @@ -51,9 +51,9 @@ describe("gittensory-miner claim ledger (#2314)", () => { "/custom/config/claim-ledger.sqlite3", ); expect(resolveClaimLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/claim-ledger.sqlite3", + "/xdg/loopover-miner/claim-ledger.sqlite3", ); - expect(resolveClaimLedgerDbPath({})).toMatch(/\/\.config\/gittensory-miner\/claim-ledger\.sqlite3$/); + expect(resolveClaimLedgerDbPath({})).toMatch(/\/\.config\/loopover-miner\/claim-ledger\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and lists empty before any claim", () => { diff --git a/test/unit/miner-deny-hook-synthesis.test.ts b/test/unit/miner-deny-hook-synthesis.test.ts index a809cf59e9..2293961f3d 100644 --- a/test/unit/miner-deny-hook-synthesis.test.ts +++ b/test/unit/miner-deny-hook-synthesis.test.ts @@ -12,6 +12,7 @@ import { changedPathToDenyGlob, initDenyHookSynthesisStore, normalizeBlockerHistory, + resolveDenyHookSynthesisDbPath, resolveEffectiveDenyRules, setProposalStatuses, synthesizeDenyRuleProposals, @@ -33,6 +34,21 @@ function tempStore() { return store; } +describe("resolveDenyHookSynthesisDbPath() (#4522)", () => { + it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { + expect(resolveDenyHookSynthesisDbPath({ LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB: "/custom/d.sqlite3" })).toBe( + "/custom/d.sqlite3", + ); + expect(resolveDenyHookSynthesisDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( + "/custom/config/deny-hook-synthesis.sqlite3", + ); + expect(resolveDenyHookSynthesisDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( + "/xdg/loopover-miner/deny-hook-synthesis.sqlite3", + ); + expect(resolveDenyHookSynthesisDbPath({})).toMatch(/\/\.config\/loopover-miner\/deny-hook-synthesis\.sqlite3$/); + }); +}); + describe("synthesizeDenyRuleProposals() (#4522)", () => { it("returns no proposals and empty history aggregates cleanly", () => { expect(synthesizeDenyRuleProposals([])).toEqual([]); diff --git a/test/unit/miner-event-ledger-cli.test.ts b/test/unit/miner-event-ledger-cli.test.ts index f6bab5499c..ffcbd53d4e 100644 --- a/test/unit/miner-event-ledger-cli.test.ts +++ b/test/unit/miner-event-ledger-cli.test.ts @@ -155,33 +155,33 @@ describe("gittensory-miner event ledger CLI (#2290)", () => { }); describe("gittensory-miner ledger metrics CLI (#4841)", () => { - it("renderEventLedgerMetrics emits one sorted gittensory_miner_events_total series per type", () => { + it("renderEventLedgerMetrics emits one sorted loopover_miner_events_total series per type", () => { const text = renderEventLedgerMetrics([ metricEntry(1, "manage_pr_update"), metricEntry(2, "discovered_issue"), metricEntry(3, "manage_pr_update"), ]); expect(text).toContain( - "# HELP gittensory_miner_events_total Event-ledger entries the miner has recorded, by event type.", + "# HELP loopover_miner_events_total Event-ledger entries the miner has recorded, by event type.", ); - expect(text).toContain("# TYPE gittensory_miner_events_total counter"); + expect(text).toContain("# TYPE loopover_miner_events_total counter"); // Series are emitted in sorted type order, so "discovered_issue" precedes "manage_pr_update". - expect(text).toContain('gittensory_miner_events_total{type="discovered_issue"} 1'); - expect(text).toContain('gittensory_miner_events_total{type="manage_pr_update"} 2'); + expect(text).toContain('loopover_miner_events_total{type="discovered_issue"} 1'); + expect(text).toContain('loopover_miner_events_total{type="manage_pr_update"} 2'); expect(text.indexOf("discovered_issue")).toBeLessThan(text.indexOf("manage_pr_update")); expect(text.endsWith("\n")).toBe(true); }); it("renderEventLedgerMetrics still emits a well-formed document for an empty ledger", () => { expect(renderEventLedgerMetrics([])).toBe( - "# HELP gittensory_miner_events_total Event-ledger entries the miner has recorded, by event type.\n" + - "# TYPE gittensory_miner_events_total counter\n", + "# HELP loopover_miner_events_total Event-ledger entries the miner has recorded, by event type.\n" + + "# TYPE loopover_miner_events_total counter\n", ); }); it("renderEventLedgerMetrics escapes label-breaking characters in the event type", () => { expect(renderEventLedgerMetrics([metricEntry(1, 'weird"type')])).toContain( - 'gittensory_miner_events_total{type="weird\\"type"} 1', + 'loopover_miner_events_total{type="weird\\"type"} 1', ); }); @@ -195,9 +195,9 @@ describe("gittensory-miner ledger metrics CLI (#4841)", () => { expect(runLedgerMetrics([], { initEventLedger: () => eventLedger })).toBe(0); const text = String(log.mock.calls[0]?.[0]); - expect(text).toContain("# TYPE gittensory_miner_events_total counter"); - expect(text).toContain('gittensory_miner_events_total{type="discovered_issue"} 1'); - expect(text).toContain('gittensory_miner_events_total{type="manage_pr_update"} 2'); + expect(text).toContain("# TYPE loopover_miner_events_total counter"); + expect(text).toContain('loopover_miner_events_total{type="discovered_issue"} 1'); + expect(text).toContain('loopover_miner_events_total{type="manage_pr_update"} 2'); // The output is a single, once-terminated document (no doubled trailing blank line). expect(text.endsWith("\n")).toBe(false); }); @@ -217,7 +217,7 @@ describe("gittensory-miner ledger metrics CLI (#4841)", () => { if (prev === undefined) delete process.env.LOOPOVER_MINER_EVENT_LEDGER_DB; else process.env.LOOPOVER_MINER_EVENT_LEDGER_DB = prev; } - expect(String(log.mock.calls[0]?.[0])).toContain('gittensory_miner_events_total{type="plan_built"} 1'); + expect(String(log.mock.calls[0]?.[0])).toContain('loopover_miner_events_total{type="plan_built"} 1'); }); it("runLedgerMetrics rejects unexpected arguments with a usage error", () => { @@ -265,6 +265,6 @@ describe("gittensory-miner ledger metrics CLI (#4841)", () => { eventLedger.appendEvent({ type: "plan_built", payload: { steps: 1 } }); const log = vi.spyOn(console, "log").mockImplementation(() => undefined); expect(runLedgerCli("metrics", [], { initEventLedger: () => eventLedger })).toBe(0); - expect(String(log.mock.calls[0]?.[0])).toContain('gittensory_miner_events_total{type="plan_built"} 1'); + expect(String(log.mock.calls[0]?.[0])).toContain('loopover_miner_events_total{type="plan_built"} 1'); }); }); diff --git a/test/unit/miner-event-ledger.test.ts b/test/unit/miner-event-ledger.test.ts index a9c874f9f5..b5633c0045 100644 --- a/test/unit/miner-event-ledger.test.ts +++ b/test/unit/miner-event-ledger.test.ts @@ -34,9 +34,9 @@ describe("gittensory-miner event ledger (#2290)", () => { "/custom/config/event-ledger.sqlite3", ); expect(resolveEventLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/event-ledger.sqlite3", + "/xdg/loopover-miner/event-ledger.sqlite3", ); - expect(resolveEventLedgerDbPath({})).toMatch(/\/\.config\/gittensory-miner\/event-ledger\.sqlite3$/); + expect(resolveEventLedgerDbPath({})).toMatch(/\/\.config\/loopover-miner\/event-ledger\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and reads empty before any append", () => { diff --git a/test/unit/miner-governor-ledger.test.ts b/test/unit/miner-governor-ledger.test.ts index 8631b7e38f..af3d35685e 100644 --- a/test/unit/miner-governor-ledger.test.ts +++ b/test/unit/miner-governor-ledger.test.ts @@ -42,9 +42,9 @@ describe("gittensory-miner governor ledger (#2328)", () => { "/custom/config/governor-ledger.sqlite3", ); expect(resolveGovernorLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/governor-ledger.sqlite3", + "/xdg/loopover-miner/governor-ledger.sqlite3", ); - expect(resolveGovernorLedgerDbPath({})).toMatch(/\/\.config\/gittensory-miner\/governor-ledger\.sqlite3$/); + expect(resolveGovernorLedgerDbPath({})).toMatch(/\/\.config\/loopover-miner\/governor-ledger\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and reads empty before any append", () => { diff --git a/test/unit/miner-laptop-init.test.ts b/test/unit/miner-laptop-init.test.ts index 1cd2ca5965..da1b98f439 100644 --- a/test/unit/miner-laptop-init.test.ts +++ b/test/unit/miner-laptop-init.test.ts @@ -37,7 +37,7 @@ describe("gittensory-miner laptop init (#2329)", () => { expect(resolveLaptopStateDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/state" })) .toBe("/custom/state/laptop-state.sqlite3"); expect(resolveLaptopStateDbPath({ XDG_CONFIG_HOME: "/xdg" })) - .toBe("/xdg/gittensory-miner/laptop-state.sqlite3"); + .toBe("/xdg/loopover-miner/laptop-state.sqlite3"); }); it("fresh init creates the state dir and SQLite file", () => { diff --git a/test/unit/miner-local-store.test.ts b/test/unit/miner-local-store.test.ts index 181e4b288b..8be3ab7420 100644 --- a/test/unit/miner-local-store.test.ts +++ b/test/unit/miner-local-store.test.ts @@ -54,9 +54,9 @@ describe("gittensory-miner shared local-store helper (#4272)", () => { ).toBe("/custom/config/thing.sqlite3"); expect( resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", { XDG_CONFIG_HOME: "/xdg" }), - ).toBe("/xdg/gittensory-miner/thing.sqlite3"); + ).toBe("/xdg/loopover-miner/thing.sqlite3"); expect(resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", {})).toMatch( - /\/\.config\/gittensory-miner\/thing\.sqlite3$/, + /\/\.config\/loopover-miner\/thing\.sqlite3$/, ); }); diff --git a/test/unit/miner-metrics-cli.test.ts b/test/unit/miner-metrics-cli.test.ts index 705e6bb567..1fa20ea414 100644 --- a/test/unit/miner-metrics-cli.test.ts +++ b/test/unit/miner-metrics-cli.test.ts @@ -54,13 +54,13 @@ describe("gittensory-miner metrics CLI (#4838)", () => { expect(runMetrics([], { initPredictionLedger: () => ledger })).toBe(0); const text = String(log.mock.calls[0]?.[0]); - expect(text).toContain("# TYPE gittensory_miner_predictions_total counter"); + expect(text).toContain("# TYPE loopover_miner_predictions_total counter"); // Series are emitted in sorted conclusion order, so "close" precedes "merge". - expect(text).toContain('gittensory_miner_predictions_total{conclusion="close"} 1'); - expect(text).toContain('gittensory_miner_predictions_total{conclusion="merge"} 2'); + expect(text).toContain('loopover_miner_predictions_total{conclusion="close"} 1'); + expect(text).toContain('loopover_miner_predictions_total{conclusion="merge"} 2'); // No outcome-join exists yet, so both the correct and incorrect counters stay zero. - expect(text).toContain("gittensory_miner_prediction_correct_total 0"); - expect(text).toContain("gittensory_miner_prediction_incorrect_total 0"); + expect(text).toContain("loopover_miner_prediction_correct_total 0"); + expect(text).toContain("loopover_miner_prediction_incorrect_total 0"); // The output is a single, once-terminated document (no doubled trailing blank line). expect(text.endsWith("\n")).toBe(false); }); @@ -80,7 +80,7 @@ describe("gittensory-miner metrics CLI (#4838)", () => { if (prev === undefined) delete process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB; else process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB = prev; } - expect(String(log.mock.calls[0]?.[0])).toContain('gittensory_miner_predictions_total{conclusion="hold"} 1'); + expect(String(log.mock.calls[0]?.[0])).toContain('loopover_miner_predictions_total{conclusion="hold"} 1'); }); it("runMetrics rejects unexpected arguments with a usage error", () => { diff --git a/test/unit/miner-plan-store.test.ts b/test/unit/miner-plan-store.test.ts index eab53fde5c..a52da066ff 100644 --- a/test/unit/miner-plan-store.test.ts +++ b/test/unit/miner-plan-store.test.ts @@ -46,8 +46,8 @@ describe("gittensory-miner plan store (#2318)", () => { expect(resolvePlanStoreDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/plan-store.sqlite3", ); - expect(resolvePlanStoreDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe("/xdg/gittensory-miner/plan-store.sqlite3"); - expect(resolvePlanStoreDbPath({})).toMatch(/\/\.config\/gittensory-miner\/plan-store\.sqlite3$/); + expect(resolvePlanStoreDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe("/xdg/loopover-miner/plan-store.sqlite3"); + expect(resolvePlanStoreDbPath({})).toMatch(/\/\.config\/loopover-miner\/plan-store\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and loads null before any save", () => { diff --git a/test/unit/miner-policy-doc-cache.test.ts b/test/unit/miner-policy-doc-cache.test.ts index 8277532a2d..f82cde5f07 100644 --- a/test/unit/miner-policy-doc-cache.test.ts +++ b/test/unit/miner-policy-doc-cache.test.ts @@ -39,7 +39,7 @@ describe("resolvePolicyDocCacheDbPath (#4842)", () => { join("/cfg", "policy-doc-cache.sqlite3"), ); expect(resolvePolicyDocCacheDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - join("/xdg", "gittensory-miner", "policy-doc-cache.sqlite3"), + join("/xdg", "loopover-miner", "policy-doc-cache.sqlite3"), ); }); }); diff --git a/test/unit/miner-policy-verdict-cache.test.ts b/test/unit/miner-policy-verdict-cache.test.ts index b647748647..a4d972ff0d 100644 --- a/test/unit/miner-policy-verdict-cache.test.ts +++ b/test/unit/miner-policy-verdict-cache.test.ts @@ -41,7 +41,7 @@ describe("resolvePolicyVerdictCacheDbPath (#4843)", () => { join("/cfg", "policy-verdict-cache.sqlite3"), ); expect(resolvePolicyVerdictCacheDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - join("/xdg", "gittensory-miner", "policy-verdict-cache.sqlite3"), + join("/xdg", "loopover-miner", "policy-verdict-cache.sqlite3"), ); }); }); diff --git a/test/unit/miner-portfolio-queue-cli.test.ts b/test/unit/miner-portfolio-queue-cli.test.ts index 1b5a03d2d7..d0e712a414 100644 --- a/test/unit/miner-portfolio-queue-cli.test.ts +++ b/test/unit/miner-portfolio-queue-cli.test.ts @@ -393,21 +393,21 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { ], now, ); - expect(output).toContain('gittensory_miner_portfolio_queue_items{status="queued"} 2'); - expect(output).toContain('gittensory_miner_portfolio_queue_items{status="in_progress"} 1'); - expect(output).toContain('gittensory_miner_portfolio_queue_items{status="done"} 1'); - expect(output).toContain("gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 600"); - expect(output).toContain("# HELP gittensory_miner_portfolio_queue_items"); - expect(output).toContain("# TYPE gittensory_miner_portfolio_queue_items gauge"); + expect(output).toContain('loopover_miner_portfolio_queue_items{status="queued"} 2'); + expect(output).toContain('loopover_miner_portfolio_queue_items{status="in_progress"} 1'); + expect(output).toContain('loopover_miner_portfolio_queue_items{status="done"} 1'); + expect(output).toContain("loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 600"); + expect(output).toContain("# HELP loopover_miner_portfolio_queue_items"); + expect(output).toContain("# TYPE loopover_miner_portfolio_queue_items gauge"); expect(output.endsWith("\n")).toBe(true); expect(output.endsWith("\n\n")).toBe(false); }); it("is well-formed (HELP/TYPE always present, lease age 0) for an empty queue", () => { const output = renderPortfolioQueueMetrics([], [], Date.parse("2026-07-13T12:00:00.000Z")); - expect(output).toContain("# TYPE gittensory_miner_portfolio_queue_items gauge"); - expect(output).toContain("gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); - expect(output).not.toContain('gittensory_miner_portfolio_queue_items{status='); + expect(output).toContain("# TYPE loopover_miner_portfolio_queue_items gauge"); + expect(output).toContain("loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); + expect(output).not.toContain('loopover_miner_portfolio_queue_items{status='); }); it("ignores a lease row with an unparseable leasedAt rather than corrupting the max", () => { @@ -416,7 +416,7 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { [{ leasedAt: null }, { leasedAt: "not-a-date" }], Date.parse("2026-07-13T12:00:00.000Z"), ); - expect(output).toContain("gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); + expect(output).toContain("loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); }); it("runQueueMetrics prints the rendered document from the real store", () => { @@ -429,7 +429,7 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { runQueueMetrics([], { initPortfolioQueue: () => portfolioQueue, nowMs: Date.parse("2026-07-13T12:00:00.000Z") }), ).toBe(0); const output = String(log.mock.calls[0]?.[0]); - expect(output).toContain('gittensory_miner_portfolio_queue_items{status="in_progress"} 1'); + expect(output).toContain('loopover_miner_portfolio_queue_items{status="in_progress"} 1'); expect(output.endsWith("\n")).toBe(false); // console.log adds its own trailing newline }); @@ -437,7 +437,7 @@ describe("gittensory-miner portfolio queue CLI (#2292)", () => { const portfolioQueue = tempQueueStore(); const log = vi.spyOn(console, "log").mockImplementation(() => undefined); expect(runQueueMetrics([], { initPortfolioQueue: () => portfolioQueue })).toBe(0); - expect(String(log.mock.calls[0]?.[0])).toContain("gittensory_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); + expect(String(log.mock.calls[0]?.[0])).toContain("loopover_miner_portfolio_queue_oldest_in_progress_lease_age_seconds 0"); }); it("rejects unexpected positional args and surfaces a store failure", () => { diff --git a/test/unit/miner-portfolio-queue.test.ts b/test/unit/miner-portfolio-queue.test.ts index 9b6a330c26..86322a7cae 100644 --- a/test/unit/miner-portfolio-queue.test.ts +++ b/test/unit/miner-portfolio-queue.test.ts @@ -54,9 +54,9 @@ describe("gittensory-miner portfolio/queue store (#2292)", () => { "/custom/config/portfolio-queue.sqlite3", ); expect(resolvePortfolioQueueDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/portfolio-queue.sqlite3", + "/xdg/loopover-miner/portfolio-queue.sqlite3", ); - expect(resolvePortfolioQueueDbPath({})).toMatch(/\/\.config\/gittensory-miner\/portfolio-queue\.sqlite3$/); + expect(resolvePortfolioQueueDbPath({})).toMatch(/\/\.config\/loopover-miner\/portfolio-queue\.sqlite3$/); }); it("creates the SQLite file with owner-only permissions and reads empty before any write", () => { diff --git a/test/unit/miner-prediction-ledger.test.ts b/test/unit/miner-prediction-ledger.test.ts index 910ca37fcd..ab1c12f5ed 100644 --- a/test/unit/miner-prediction-ledger.test.ts +++ b/test/unit/miner-prediction-ledger.test.ts @@ -34,8 +34,8 @@ describe("miner prediction ledger (#4263)", () => { it("resolvePredictionLedgerDbPath honors the explicit DB, config-dir, XDG, then home default", () => { expect(resolvePredictionLedgerDbPath({ LOOPOVER_MINER_PREDICTION_LEDGER_DB: "/custom/pred.sqlite3" })).toBe("/custom/pred.sqlite3"); expect(resolvePredictionLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/state" })).toBe(join("/state", "prediction-ledger.sqlite3")); - expect(resolvePredictionLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe(join("/xdg", "gittensory-miner", "prediction-ledger.sqlite3")); - expect(resolvePredictionLedgerDbPath({})).toMatch(/gittensory-miner[\\/]prediction-ledger\.sqlite3$/); + expect(resolvePredictionLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe(join("/xdg", "loopover-miner", "prediction-ledger.sqlite3")); + expect(resolvePredictionLedgerDbPath({})).toMatch(/loopover-miner[\\/]prediction-ledger\.sqlite3$/); }); it("appends a verdict and reads it back with codes + engine version intact", () => { diff --git a/test/unit/miner-prediction-metrics.test.ts b/test/unit/miner-prediction-metrics.test.ts index 0b80ed75ea..910112252c 100644 --- a/test/unit/miner-prediction-metrics.test.ts +++ b/test/unit/miner-prediction-metrics.test.ts @@ -20,9 +20,9 @@ function dataLines(text: string): Record { describe("miner prediction-calibration metrics (#4264)", () => { it("re-exports the renderer and metric-name constants from the engine barrel", () => { expect(typeof renderMinerPredictionMetrics).toBe("function"); - expect(MINER_PREDICTIONS_TOTAL).toBe("gittensory_miner_predictions_total"); - expect(MINER_PREDICTION_CORRECT_TOTAL).toBe("gittensory_miner_prediction_correct_total"); - expect(MINER_PREDICTION_INCORRECT_TOTAL).toBe("gittensory_miner_prediction_incorrect_total"); + expect(MINER_PREDICTIONS_TOTAL).toBe("loopover_miner_predictions_total"); + expect(MINER_PREDICTION_CORRECT_TOTAL).toBe("loopover_miner_prediction_correct_total"); + expect(MINER_PREDICTION_INCORRECT_TOTAL).toBe("loopover_miner_prediction_incorrect_total"); }); it("emits well-formed HELP/TYPE and zeroed counters for an empty ledger", () => { diff --git a/test/unit/miner-ranked-candidates.test.ts b/test/unit/miner-ranked-candidates.test.ts index bed7234486..2eb81f1d63 100644 --- a/test/unit/miner-ranked-candidates.test.ts +++ b/test/unit/miner-ranked-candidates.test.ts @@ -49,9 +49,9 @@ describe("gittensory-miner ranked-candidates store (#4859 prerequisite)", () => "/custom/config/ranked-candidates.sqlite3", ); expect(resolveRankedCandidatesDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/ranked-candidates.sqlite3", + "/xdg/loopover-miner/ranked-candidates.sqlite3", ); - expect(resolveRankedCandidatesDbPath({})).toMatch(/\/\.config\/gittensory-miner\/ranked-candidates\.sqlite3$/); + expect(resolveRankedCandidatesDbPath({})).toMatch(/\/\.config\/loopover-miner\/ranked-candidates\.sqlite3$/); }); it("creates the SQLite table on first use, with owner-only file permissions, and reads [] before any save", () => { diff --git a/test/unit/miner-run-state.test.ts b/test/unit/miner-run-state.test.ts index 07fd4c5a44..68a4c31d4a 100644 --- a/test/unit/miner-run-state.test.ts +++ b/test/unit/miner-run-state.test.ts @@ -46,9 +46,9 @@ describe("gittensory-miner run-state store (#2289)", () => { "/custom/config/run-state.sqlite3", ); expect(resolveRunStateDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( - "/xdg/gittensory-miner/run-state.sqlite3", + "/xdg/loopover-miner/run-state.sqlite3", ); - expect(resolveRunStateDbPath({})).toMatch(/\/\.config\/gittensory-miner\/run-state\.sqlite3$/); + expect(resolveRunStateDbPath({})).toMatch(/\/\.config\/loopover-miner\/run-state\.sqlite3$/); }); it("creates the SQLite table on first use and reads null before any write", () => { diff --git a/test/unit/miner-status.test.ts b/test/unit/miner-status.test.ts index 3bcfcfe00a..03141d1322 100644 --- a/test/unit/miner-status.test.ts +++ b/test/unit/miner-status.test.ts @@ -45,8 +45,8 @@ function fakeBinDir(name: string): string { describe("gittensory-miner status/doctor (#2288)", () => { it("resolves the state dir from the config-dir override, XDG, then the home default", () => { expect(resolveMinerStateDir({ LOOPOVER_MINER_CONFIG_DIR: "/custom/state" })).toBe("/custom/state"); - expect(resolveMinerStateDir({ XDG_CONFIG_HOME: "/xdg" })).toBe("/xdg/gittensory-miner"); - expect(resolveMinerStateDir({})).toMatch(/\/\.config\/gittensory-miner$/); + expect(resolveMinerStateDir({ XDG_CONFIG_HOME: "/xdg" })).toBe("/xdg/loopover-miner"); + expect(resolveMinerStateDir({})).toMatch(/\/\.config\/loopover-miner$/); }); it("collectStatus reports the installed versions, state dir, and config-file discovery", () => {