From 6ddf44ee158b51baeee608d9dc9fc068148e5005 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Mon, 13 Jul 2026 23:17:02 -0700 Subject: [PATCH] feat(miner)!: rename GITTENSORY_MINER_*/GITTENSORY_* env vars to LOOPOVER_MINER_*/LOOPOVER_* Phase 1 of the gittensory -> loopover rebrand epic (#5705). Full cutover, no dual-read: GITTENSORY_MINER_* (499 occurrences, 130 files -- the miner's entire env-var namespace, plus the self-host AMS-reporting family GITTENSORY_API_TOKEN_FILE/GITTENSORY_MCP_TOKEN_FILE/ GITTENSORY_MEM_LIMIT/GITTENSORY_REPORTING_*) all rename to their LOOPOVER_ equivalent. Regenerated packages/gittensory-miner/docs/env-reference.md last, per this repo's documented generator gotcha. BREAKING CHANGE: every GITTENSORY_MINER_*/GITTENSORY_API_TOKEN_FILE/ GITTENSORY_MCP_TOKEN_FILE/GITTENSORY_MEM_LIMIT/GITTENSORY_REPORTING_* env var an existing self-hosted AMS/miner deployment sets must be renamed to its LOOPOVER_ equivalent -- the old names are no longer read. Refs #5705 --- .env.example | 8 +-- .gittensory-miner.env.example | 40 +++++++------- .gittensory-miner.yml.example | 4 +- apps/gittensory-miner-extension/README.md | 2 +- apps/gittensory-miner-extension/background.js | 2 +- apps/gittensory-miner-extension/content.js | 2 +- .../opportunity-badge.js | 2 +- apps/gittensory-miner-extension/options.js | 2 +- .../test/helpers.ts | 2 +- docker-compose.yml | 26 ++++----- grafana/dashboards/miner-usage.json | 2 +- .../provisioning/datasources/ams-ledgers.yml | 2 +- k8s/README.md | 2 +- k8s/miner-deployment.yaml | 4 +- .../src/governor/action-mode.ts | 4 +- .../src/governor/kill-switch.ts | 2 +- .../gittensory-engine/src/miner-goal-spec.ts | 2 +- .../test/action-mode.test.ts | 6 +-- .../test/kill-switch.test.ts | 6 +-- packages/gittensory-miner/DEPLOYMENT.md | 18 +++---- packages/gittensory-miner/Dockerfile | 6 +-- packages/gittensory-miner/README.md | 40 +++++++------- .../gittensory-miner/docker-compose.miner.yml | 4 +- .../docs/config-precedence.md | 8 +-- .../docs/discovery-plane-operator-guide.md | 12 ++--- .../gittensory-miner/docs/env-reference.md | 54 +++++++++---------- .../gittensory-miner/docs/miner-goal-spec.md | 4 +- .../gittensory-miner/docs/observability.md | 20 +++---- .../docs/operations-runbook.md | 14 ++--- packages/gittensory-miner/docs/sizing.md | 6 +-- .../docs/unattended-scheduling.md | 6 +-- packages/gittensory-miner/lib/ams-policy.js | 4 +- packages/gittensory-miner/lib/attempt-log.js | 2 +- packages/gittensory-miner/lib/claim-ledger.js | 2 +- packages/gittensory-miner/lib/cli.js | 6 +-- .../gittensory-miner/lib/config-precedence.js | 2 +- .../lib/deny-hook-synthesis.js | 8 +-- .../lib/deployment-docs-audit.js | 8 +-- packages/gittensory-miner/lib/event-ledger.js | 2 +- .../gittensory-miner/lib/governor-ledger.js | 8 +-- .../gittensory-miner/lib/governor-state.js | 2 +- packages/gittensory-miner/lib/init-wizard.js | 4 +- packages/gittensory-miner/lib/laptop-init.js | 4 +- packages/gittensory-miner/lib/local-store.js | 6 +-- packages/gittensory-miner/lib/logger.js | 4 +- .../gittensory-miner/lib/oauth-device-flow.js | 2 +- packages/gittensory-miner/lib/orb-export.js | 8 +-- packages/gittensory-miner/lib/plan-store.js | 8 +-- .../gittensory-miner/lib/policy-doc-cache.js | 2 +- .../lib/policy-verdict-cache.js | 2 +- .../gittensory-miner/lib/portfolio-queue.js | 2 +- .../gittensory-miner/lib/prediction-ledger.js | 8 +-- .../gittensory-miner/lib/ranked-candidates.js | 2 +- .../gittensory-miner/lib/replay-snapshot.js | 2 +- packages/gittensory-miner/lib/repo-clone.js | 4 +- packages/gittensory-miner/lib/run-state.js | 2 +- packages/gittensory-miner/lib/status.js | 4 +- .../gittensory-miner/lib/store-maintenance.js | 4 +- packages/gittensory-miner/lib/update-check.js | 2 +- packages/gittensory-miner/lib/version.js | 4 +- .../lib/worktree-allocator.js | 16 +++--- .../schema/miner-goal-spec.schema.json | 2 +- .../scripts/generate-env-reference.mjs | 2 +- packages/gittensory-miner/terraform/README.md | 2 +- packages/gittensory-miner/terraform/main.tf | 2 +- .../gittensory-miner/terraform/outputs.tf | 2 +- scripts/backup-miner.sh | 10 ++-- scripts/export-ams-reporting-db.sh | 4 +- scripts/export-grafana-reporting-db.sh | 6 +-- scripts/export-miner-prometheus-textfile.sh | 4 +- scripts/restore-miner.sh | 6 +-- secrets/README.md | 4 +- systemd/gittensory-miner-ui.service.example | 4 +- systemd/gittensory-miner.service.example | 2 +- test/unit/mcp-feasibility-gate.test.ts | 4 +- test/unit/miner-ams-policy.test.ts | 16 +++--- test/unit/miner-attempt-cli.test.ts | 4 +- test/unit/miner-attempt-input-builder.test.ts | 4 +- test/unit/miner-attempt-log.test.ts | 12 ++--- test/unit/miner-attempt-runner.test.ts | 4 +- .../unit/miner-backup-restore-scripts.test.ts | 12 ++--- test/unit/miner-calibration-cli.test.ts | 2 +- test/unit/miner-claim-ledger.test.ts | 8 +-- test/unit/miner-cli-doctor-checks.test.ts | 8 +-- test/unit/miner-cli-e2e.test.ts | 4 +- test/unit/miner-cli.test.ts | 6 +-- test/unit/miner-config-precedence.test.ts | 2 +- test/unit/miner-deployment-doc.test.ts | 4 +- test/unit/miner-deployment-docs-audit.test.ts | 24 ++++----- test/unit/miner-discover-cli.test.ts | 32 +++++------ test/unit/miner-docker-compose.test.ts | 4 +- test/unit/miner-env-file-indirection.test.ts | 2 +- test/unit/miner-env-reference-script.test.ts | 24 ++++----- test/unit/miner-event-ledger-cli.test.ts | 8 +-- test/unit/miner-event-ledger.test.ts | 4 +- test/unit/miner-extension-content.test.ts | 14 ++--- test/unit/miner-extension-live-fetch.test.ts | 4 +- test/unit/miner-governor-action-mode.test.ts | 16 +++--- ...iner-governor-chokepoint-persisted.test.ts | 4 +- test/unit/miner-governor-kill-switch.test.ts | 12 ++--- test/unit/miner-governor-ledger.test.ts | 12 ++--- test/unit/miner-governor-metrics-cli.test.ts | 8 +-- test/unit/miner-governor-pause-cli.test.ts | 8 +-- test/unit/miner-governor-state.test.ts | 4 +- test/unit/miner-init-verify-token.test.ts | 2 +- test/unit/miner-init-wizard.test.ts | 14 ++--- test/unit/miner-k8s-manifests.test.ts | 2 +- test/unit/miner-laptop-init.test.ts | 16 +++--- test/unit/miner-local-store-readme.test.ts | 30 +++++------ test/unit/miner-local-store.test.ts | 20 +++---- test/unit/miner-logger.test.ts | 4 +- test/unit/miner-metrics-cli.test.ts | 8 +-- test/unit/miner-migrate-cli.test.ts | 2 +- test/unit/miner-oauth-device-flow.test.ts | 4 +- test/unit/miner-orb-export.test.ts | 4 +- test/unit/miner-package-skeleton.test.ts | 2 +- test/unit/miner-plan-store.test.ts | 4 +- test/unit/miner-policy-doc-cache.test.ts | 6 +-- test/unit/miner-policy-verdict-cache.test.ts | 6 +-- test/unit/miner-portfolio-queue.test.ts | 10 ++-- test/unit/miner-prediction-ledger.test.ts | 4 +- test/unit/miner-purge-cli.test.ts | 38 ++++++------- test/unit/miner-ranked-candidates.test.ts | 6 +-- test/unit/miner-replay-snapshot.test.ts | 2 +- test/unit/miner-repo-clone.test.ts | 6 +-- test/unit/miner-run-state.test.ts | 10 ++-- test/unit/miner-status.test.ts | 48 ++++++++--------- test/unit/miner-toolbar-badge.test.ts | 2 +- test/unit/miner-version.test.ts | 12 ++--- test/unit/miner-wire-cli-modules.test.ts | 4 +- test/unit/miner-worktree-allocator.test.ts | 8 +-- test/unit/selfhost-ams-reporting.test.ts | 4 +- .../selfhost-compose-resource-limits.test.ts | 4 +- test/unit/selfhost-grafana-reporting.test.ts | 6 +-- 134 files changed, 527 insertions(+), 527 deletions(-) diff --git a/.env.example b/.env.example index c62e9e0665..9d780549cb 100644 --- a/.env.example +++ b/.env.example @@ -344,7 +344,7 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review # Every service below gets a beginner-friendly default `deploy.resources.limits.memory` cap so one runaway # optional profile (e.g. Ollama loading a multi-GB model) can't OOM-kill or starve the core review pipeline. # Override any of these for a bigger/smaller host; values use Docker's byte-size shorthand (e.g. 512m, 4g). -# GITTENSORY_MEM_LIMIT=2g # core app (always runs) +# LOOPOVER_MEM_LIMIT=2g # core app (always runs) # REDIS_MEM_LIMIT=512m # core app (always runs) # POSTGRES_MEM_LIMIT=2g # --profile postgres / --profile pgbouncer # QDRANT_MEM_LIMIT=2g # --profile qdrant @@ -507,15 +507,15 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review # • "Claude usage (OTEL)" — cost/tokens/model/effort from the review CLI's OpenTelemetry export (see below). # • "Resource hub" — links to every integrated service. # GRAFANA_REPORTING_EXPORT_INTERVAL_SECONDS=30 # refresh cadence for the redacted reporting SQLite export -# GITTENSORY_REPORTING_SOURCE_DB=/appdb/gittensory.sqlite # if DATABASE_PATH=/data/custom.sqlite, set /appdb/custom.sqlite +# LOOPOVER_REPORTING_SOURCE_DB=/appdb/loopover.sqlite # if DATABASE_PATH=/data/custom.sqlite, set /appdb/custom.sqlite # # AMS (gittensory-miner) ledger dashboards — only useful when a miner ALSO runs on this same host (see # packages/gittensory-miner/docs/observability.md). Requires --profile ams-observability, separate from the # general observability profile above: an engine-only deployment has nothing for this exporter to read. # Grafana never mounts the live ledgers directly — this exporter reads them read-only and writes a redacted # snapshot (free-form attempt_log_events.reason/.payload_json dropped) into the same reporting volume. -# GITTENSORY_MINER_CONFIG_DIR=~/.config/gittensory-miner # host dir the exporter mounts read-only at /ams-ledgers -# GITTENSORY_AMS_REPORTING_EXPORT_INTERVAL_SECONDS=30 # refresh cadence for the redacted AMS ledger exports +# LOOPOVER_MINER_CONFIG_DIR=~/.config/gittensory-miner # host dir the exporter mounts read-only at /ams-ledgers +# LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS=30 # refresh cadence for the redacted AMS ledger exports # # Claude usage telemetry → OTEL collector → Prometheus → the Claude usage dashboard. OFF by default. # CLAUDE_CODE_ENABLE_TELEMETRY=1 # enable; needs --profile observability (starts the otel-collector) diff --git a/.gittensory-miner.env.example b/.gittensory-miner.env.example index b427c93955..94edc641f3 100644 --- a/.gittensory-miner.env.example +++ b/.gittensory-miner.env.example @@ -30,31 +30,31 @@ GITHUB_TOKEN=ghp_your_token_here # ============================================================================= # 3. Optional overrides — defaults are fine for a single-machine install # ============================================================================= -# By default all local state lives under GITTENSORY_MINER_CONFIG_DIR (else $XDG_CONFIG_HOME, else +# By default all local state lives under LOOPOVER_MINER_CONFIG_DIR (else $XDG_CONFIG_HOME, else # ~/.config), in a gittensory-miner/ subdirectory. Set the base dir, or any individual store path, # only to relocate state (e.g. onto a dedicated volume). -# GITTENSORY_MINER_CONFIG_DIR=/var/lib/gittensory-miner +# LOOPOVER_MINER_CONFIG_DIR=/var/lib/gittensory-miner # Repo clones and git worktrees created during attempts: -# GITTENSORY_MINER_REPO_CLONE_DIR=/var/lib/gittensory-miner/clones -# GITTENSORY_MINER_WORKTREE_DIR=/var/lib/gittensory-miner/worktrees +# LOOPOVER_MINER_REPO_CLONE_DIR=/var/lib/gittensory-miner/clones +# LOOPOVER_MINER_WORKTREE_DIR=/var/lib/gittensory-miner/worktrees # Per-store SQLite file overrides (each defaults to a file under the config dir above): -# GITTENSORY_MINER_CLAIM_LEDGER_DB= -# GITTENSORY_MINER_PORTFOLIO_QUEUE_DB= -# GITTENSORY_MINER_EVENT_LEDGER_DB= -# GITTENSORY_MINER_RUN_STATE_DB= -# GITTENSORY_MINER_PLAN_STORE_DB= -# GITTENSORY_MINER_PREDICTION_LEDGER_DB= -# GITTENSORY_MINER_GOVERNOR_LEDGER_DB= -# GITTENSORY_MINER_GOVERNOR_STATE_DB= -# GITTENSORY_MINER_ATTEMPT_LOG_DB= -# GITTENSORY_MINER_ORB_EXPORT_DB= -# GITTENSORY_MINER_REPLAY_SNAPSHOT_DB= -# GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB= -# GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB= +# LOOPOVER_MINER_CLAIM_LEDGER_DB= +# LOOPOVER_MINER_PORTFOLIO_QUEUE_DB= +# LOOPOVER_MINER_EVENT_LEDGER_DB= +# LOOPOVER_MINER_RUN_STATE_DB= +# LOOPOVER_MINER_PLAN_STORE_DB= +# LOOPOVER_MINER_PREDICTION_LEDGER_DB= +# LOOPOVER_MINER_GOVERNOR_LEDGER_DB= +# LOOPOVER_MINER_GOVERNOR_STATE_DB= +# LOOPOVER_MINER_ATTEMPT_LOG_DB= +# LOOPOVER_MINER_ORB_EXPORT_DB= +# LOOPOVER_MINER_REPLAY_SNAPSHOT_DB= +# LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB= +# LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB= # Misc: -# GITTENSORY_MINER_AMS_POLICY_PATH= # path to an AMS policy file -# GITTENSORY_MINER_NO_UPDATE_CHECK=1 # disable the startup npm-registry version nudge -# GITTENSORY_MINER_VERSION= # override the reported version (testing only) +# LOOPOVER_MINER_AMS_POLICY_PATH= # path to an AMS policy file +# LOOPOVER_MINER_NO_UPDATE_CHECK=1 # disable the startup npm-registry version nudge +# LOOPOVER_MINER_VERSION= # override the reported version (testing only) diff --git a/.gittensory-miner.yml.example b/.gittensory-miner.yml.example index 50e5a09ea2..e271c45e9e 100644 --- a/.gittensory-miner.yml.example +++ b/.gittensory-miner.yml.example @@ -69,14 +69,14 @@ selfPlagiarism: # Per-repo kill-switch (#2341) consulted by the Governor chokepoint before every write action. Distinct from # minerEnabled: pausing halts an already-in-flight queue without deregistering the repo from discovery, and # un-pausing resumes exactly where the queue left off. A separate GLOBAL kill-switch (env var -# GITTENSORY_MINER_KILL_SWITCH) halts every repo at once and always wins over this per-repo flag. +# LOOPOVER_MINER_KILL_SWITCH) halts every repo at once and always wins over this per-repo flag. # `paused` (boolean, default: false). killSwitch: paused: false # Per-repo dry-run/live execution opt-in (#2342). A freshly-configured miner always defaults to dry-run; this # field alone is NOT sufficient to go live -- the miner's own operator must also separately opt in globally -# (env var GITTENSORY_MINER_LIVE_MODE=live). `liveModeOptIn` must equal EXACTLY the string "live" (not a +# (env var LOOPOVER_MINER_LIVE_MODE=live). `liveModeOptIn` must equal EXACTLY the string "live" (not a # boolean, not "yes"/"on") -- any other value stays dry-run. Default: null. execution: liveModeOptIn: null diff --git a/apps/gittensory-miner-extension/README.md b/apps/gittensory-miner-extension/README.md index 624eb88cdf..23a5c79aeb 100644 --- a/apps/gittensory-miner-extension/README.md +++ b/apps/gittensory-miner-extension/README.md @@ -33,7 +33,7 @@ quota, instead of silently failing to save or leaving storage partially written. `npm test` runs with `--coverage` enabled (v8 provider) and enforces `vitest.config.ts`'s `coverage.thresholds` — a measured baseline (#4865), not an aspirational target. The suite imports `background.js`, `opportunity-badge.js`, and `toolbar-badge.js` directly (via the existing -`__GITTENSORY_MINER_EXTENSION_TEST__` hook) so v8 can attribute coverage; the root `test/unit/miner-*.test.ts` +`__LOOPOVER_MINER_EXTENSION_TEST__` hook) so v8 can attribute coverage; the root `test/unit/miner-*.test.ts` files remain as broader behavior tests through the `node:vm` harness. `content.js` and `options.js` are deliberately deferred — they need a jsdom mount harness before diff --git a/apps/gittensory-miner-extension/background.js b/apps/gittensory-miner-extension/background.js index 7005403392..aa7d030e37 100644 --- a/apps/gittensory-miner-extension/background.js +++ b/apps/gittensory-miner-extension/background.js @@ -171,7 +171,7 @@ if (chrome.action && chrome.storage.onChanged) { }); } -if (globalThis.__GITTENSORY_MINER_EXTENSION_TEST__) { +if (globalThis.__LOOPOVER_MINER_EXTENSION_TEST__) { globalThis.__gittensoryMinerBackgroundInternals = { PING_MESSAGE, ISSUE_CONTEXT_MESSAGE, diff --git a/apps/gittensory-miner-extension/content.js b/apps/gittensory-miner-extension/content.js index 4e2a8d7833..064bfbbf93 100644 --- a/apps/gittensory-miner-extension/content.js +++ b/apps/gittensory-miner-extension/content.js @@ -68,7 +68,7 @@ function renderOpportunityBadge(container, payload, nowMs = Date.now()) { container.innerHTML = markup; } -if (globalThis.__GITTENSORY_MINER_EXTENSION_TEST__) { +if (globalThis.__LOOPOVER_MINER_EXTENSION_TEST__) { globalThis.__gittensoryMinerContentInternals = { matchGitHubIssueTarget, findIssueSidebar, diff --git a/apps/gittensory-miner-extension/opportunity-badge.js b/apps/gittensory-miner-extension/opportunity-badge.js index 561f14dfb4..dc3b46fa29 100644 --- a/apps/gittensory-miner-extension/opportunity-badge.js +++ b/apps/gittensory-miner-extension/opportunity-badge.js @@ -110,6 +110,6 @@ const opportunityBadgeApi = { globalThis.__gittensoryMinerOpportunityBadge = opportunityBadgeApi; -if (globalThis.__GITTENSORY_MINER_EXTENSION_TEST__) { +if (globalThis.__LOOPOVER_MINER_EXTENSION_TEST__) { globalThis.__gittensoryMinerOpportunityBadgeTestExports = opportunityBadgeApi; } diff --git a/apps/gittensory-miner-extension/options.js b/apps/gittensory-miner-extension/options.js index a8efe40a2c..ff5e55f34a 100644 --- a/apps/gittensory-miner-extension/options.js +++ b/apps/gittensory-miner-extension/options.js @@ -51,7 +51,7 @@ function normalizeMinerUiUrl(text) { return trimmed || DEFAULT_MINER_UI_URL; } -if (globalThis.__GITTENSORY_MINER_EXTENSION_TEST__) { +if (globalThis.__LOOPOVER_MINER_EXTENSION_TEST__) { globalThis.__gittensoryMinerOptionsInternals = { parseWatchedRepos, parseRankedCandidatesJson, diff --git a/apps/gittensory-miner-extension/test/helpers.ts b/apps/gittensory-miner-extension/test/helpers.ts index 5681555bdc..9a5fa88cb0 100644 --- a/apps/gittensory-miner-extension/test/helpers.ts +++ b/apps/gittensory-miner-extension/test/helpers.ts @@ -177,7 +177,7 @@ export async function loadExtensionModules(options: ChromeMockOptions = {}) { const harness = buildChromeMock(options); vi.stubGlobal("chrome", harness.chrome); - vi.stubGlobal("__GITTENSORY_MINER_EXTENSION_TEST__", true); + vi.stubGlobal("__LOOPOVER_MINER_EXTENSION_TEST__", true); if (options.fetchImpl) vi.stubGlobal("fetch", options.fetchImpl); await import("../opportunity-badge.js"); diff --git a/docker-compose.yml b/docker-compose.yml index 063c1b85fc..4ed20e517b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -122,8 +122,8 @@ services: # additive, zero effect on an operator who has never touched secrets/. GITHUB_APP_PRIVATE_KEY_FILE: "${GITHUB_APP_PRIVATE_KEY_FILE:-/run/secrets/github_app_private_key}" GITHUB_WEBHOOK_SECRET_FILE: "${GITHUB_WEBHOOK_SECRET_FILE:-/run/secrets/github_webhook_secret}" - GITTENSORY_API_TOKEN_FILE: "${GITTENSORY_API_TOKEN_FILE:-/run/secrets/loopover_api_token}" - GITTENSORY_MCP_TOKEN_FILE: "${GITTENSORY_MCP_TOKEN_FILE:-/run/secrets/loopover_mcp_token}" + LOOPOVER_API_TOKEN_FILE: "${LOOPOVER_API_TOKEN_FILE:-/run/secrets/loopover_api_token}" + LOOPOVER_MCP_TOKEN_FILE: "${LOOPOVER_MCP_TOKEN_FILE:-/run/secrets/loopover_mcp_token}" INTERNAL_JOB_TOKEN_FILE: "${INTERNAL_JOB_TOKEN_FILE:-/run/secrets/internal_job_token}" SELFHOST_SETUP_TOKEN_FILE: "${SELFHOST_SETUP_TOKEN_FILE:-/run/secrets/selfhost_setup_token}" TOKEN_ENCRYPTION_SECRET_FILE: "${TOKEN_ENCRYPTION_SECRET_FILE:-/run/secrets/token_encryption_secret}" @@ -210,7 +210,7 @@ services: deploy: resources: limits: - memory: "${GITTENSORY_MEM_LIMIT:-2g}" + memory: "${LOOPOVER_MEM_LIMIT:-2g}" healthcheck: # Probe /ready (not /health): /health is a liveness stub that is 200 even when the DB is down, # whereas /ready returns 503 until the DB answers AND migrations are applied — so dependents that @@ -807,11 +807,11 @@ services: # If you override DATABASE_PATH, set this to the matching /appdb/ path. When DATABASE_URL points at # Postgres, the exporter reads Postgres with psql and still writes the same redacted SQLite reporting DB # for Grafana. Set GITTENSORY_REPORTING_SOURCE_DATABASE_URL only if the reporting reader uses a different URL. - GITTENSORY_REPORTING_SOURCE_DB: "${GITTENSORY_REPORTING_SOURCE_DB:-/appdb/loopover.sqlite}" + LOOPOVER_REPORTING_SOURCE_DB: "${LOOPOVER_REPORTING_SOURCE_DB:-/appdb/loopover.sqlite}" GITTENSORY_REPORTING_SOURCE_DATABASE_URL: "${GITTENSORY_REPORTING_SOURCE_DATABASE_URL:-}" DATABASE_URL: "${DATABASE_URL:-}" - GITTENSORY_REPORTING_DIR: /reporting - GITTENSORY_REPORTING_DB: "${GITTENSORY_REPORTING_DB:-/reporting/loopover-reporting.sqlite}" + LOOPOVER_REPORTING_DIR: /reporting + LOOPOVER_REPORTING_DB: "${LOOPOVER_REPORTING_DB:-/reporting/loopover-reporting.sqlite}" GRAFANA_REPORTING_EXPORT_INTERVAL_SECONDS: "${GRAFANA_REPORTING_EXPORT_INTERVAL_SECONDS:-30}" command: - /bin/sh @@ -828,7 +828,7 @@ services: test: [ "CMD-SHELL", - "db=\"$${GITTENSORY_REPORTING_DB:-/reporting/loopover-reporting.sqlite}\"; test -s \"$$db\" && sqlite3 \"$$db\" 'PRAGMA quick_check;' | grep -q '^ok$'", + "db=\"$${LOOPOVER_REPORTING_DB:-/reporting/loopover-reporting.sqlite}\"; test -s \"$$db\" && sqlite3 \"$$db\" 'PRAGMA quick_check;' | grep -q '^ok$'", ] interval: 30s timeout: 5s @@ -837,7 +837,7 @@ services: # Redacted AMS (gittensory-miner) ledger export -- a DEDICATED profile, not bundled into `observability`: unlike # the engine's own reporting-exporter above, this only does anything useful when a miner is ALSO running on this - # same host with its ledgers under GITTENSORY_MINER_CONFIG_DIR (an engine-only maintainer deployment has nothing + # same host with its ledgers under LOOPOVER_MINER_CONFIG_DIR (an engine-only maintainer deployment has nothing # for it to read). Grafana must never mount that directory directly -- attempt_log_events.reason/.payload_json # are free-form and can carry arbitrary internal detail (#5184 follow-up / PR #5471's flagged confidentiality # gap) -- so this exporter reads the live ledgers read-only and writes a redacted snapshot into the SAME shared @@ -850,8 +850,8 @@ services: profiles: ["ams-observability"] volumes: # Read-only live-ledger access for the exporter only -- Grafana does not get this mount (mirrors the - # /appdb:ro pattern above). Point this at the SAME host directory your miner uses as GITTENSORY_MINER_CONFIG_DIR. - - "${GITTENSORY_MINER_CONFIG_DIR:-~/.config/gittensory-miner}:/ams-ledgers:ro" + # /appdb:ro pattern above). Point this at the SAME host directory your miner uses as LOOPOVER_MINER_CONFIG_DIR. + - "${LOOPOVER_MINER_CONFIG_DIR:-~/.config/gittensory-miner}:/ams-ledgers:ro" - grafana-reporting-data:/reporting # Directory bind mount, not a single-file one -- see reporting-exporter's own comment above for why # (a single-file mount pins to the pre-`git pull` inode and silently never picks up a script update). @@ -859,10 +859,10 @@ services: environment: GITTENSORY_AMS_ATTEMPT_LOG_SOURCE_DB: "${GITTENSORY_AMS_ATTEMPT_LOG_SOURCE_DB:-/ams-ledgers/attempt-log.sqlite3}" GITTENSORY_AMS_PREDICTION_LEDGER_SOURCE_DB: "${GITTENSORY_AMS_PREDICTION_LEDGER_SOURCE_DB:-/ams-ledgers/prediction-ledger.sqlite3}" - GITTENSORY_REPORTING_DIR: /reporting + LOOPOVER_REPORTING_DIR: /reporting GITTENSORY_AMS_ATTEMPT_LOG_REPORTING_DB: "${GITTENSORY_AMS_ATTEMPT_LOG_REPORTING_DB:-/reporting/ams-attempt-log.sqlite}" GITTENSORY_AMS_PREDICTION_LEDGER_REPORTING_DB: "${GITTENSORY_AMS_PREDICTION_LEDGER_REPORTING_DB:-/reporting/ams-prediction-ledger.sqlite}" - GITTENSORY_AMS_REPORTING_EXPORT_INTERVAL_SECONDS: "${GITTENSORY_AMS_REPORTING_EXPORT_INTERVAL_SECONDS:-30}" + LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS: "${LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS:-30}" command: - /bin/sh - -c @@ -870,7 +870,7 @@ services: apk add --no-cache sqlite >/dev/null 2>&1 && while true; do sh /scripts/export-ams-reporting-db.sh || echo '[ams-reporting] export failed'; - interval="$${GITTENSORY_AMS_REPORTING_EXPORT_INTERVAL_SECONDS:-30}"; + interval="$${LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS:-30}"; case "$$interval" in ''|*[!0-9]*) interval=30;; esac; sleep "$$interval"; done diff --git a/grafana/dashboards/miner-usage.json b/grafana/dashboards/miner-usage.json index 34911efab9..d82ac82b1b 100644 --- a/grafana/dashboards/miner-usage.json +++ b/grafana/dashboards/miner-usage.json @@ -10,7 +10,7 @@ "from": "now-7d", "to": "now" }, - "description": "Per-provider coding-agent (claude-cli/codex-cli/agent-sdk) attempt outcomes, cost, and token usage for the Autonomous Miner System (AMS) -- a separate local CLI (gittensory-miner) from ORB, this dashboard's own AI usage. Reads the redacted attempt_outcome_summary rows exported from AMS's local attempt-log ledger (see packages/gittensory-miner/docs/observability.md) via the AMS Attempt Log SQLite datasource -- never the miner's live GITTENSORY_MINER_CONFIG_DIR ledgers, and never scraped from a Prometheus metrics path. All three coding-agent providers share one dashboard (a $provider template variable, not one dashboard per provider) since AMS's local ledger has far lower data volume than ORB's cloud reviewers. tokens_used is honestly 0/NULL until some future coding-agent driver reports real token usage (#5395) -- never fabricated.", + "description": "Per-provider coding-agent (claude-cli/codex-cli/agent-sdk) attempt outcomes, cost, and token usage for the Autonomous Miner System (AMS) -- a separate local CLI (gittensory-miner) from ORB, this dashboard's own AI usage. Reads the redacted attempt_outcome_summary rows exported from AMS's local attempt-log ledger (see packages/gittensory-miner/docs/observability.md) via the AMS Attempt Log SQLite datasource -- never the miner's live LOOPOVER_MINER_CONFIG_DIR ledgers, and never scraped from a Prometheus metrics path. All three coding-agent providers share one dashboard (a $provider template variable, not one dashboard per provider) since AMS's local ledger has far lower data volume than ORB's cloud reviewers. tokens_used is honestly 0/NULL until some future coding-agent driver reports real token usage (#5395) -- never fabricated.", "annotations": { "list": [] }, diff --git a/grafana/provisioning/datasources/ams-ledgers.yml b/grafana/provisioning/datasources/ams-ledgers.yml index 313c368941..59851d4dba 100644 --- a/grafana/provisioning/datasources/ams-ledgers.yml +++ b/grafana/provisioning/datasources/ams-ledgers.yml @@ -1,6 +1,6 @@ # AMS (gittensory-miner) redacted SQLite reporting datasources (#5184). # -# Grafana must not mount the miner's live GITTENSORY_MINER_CONFIG_DIR ledgers. The attempt log and prediction +# Grafana must not mount the miner's live LOOPOVER_MINER_CONFIG_DIR ledgers. The attempt log and prediction # ledger contain free-form reasons, payload JSON, repo/target identifiers, readiness scores, and blocker/warning # codes that are private AMS intelligence. Instead, expose only redacted reporting-export snapshots, mirroring the # maintainer LoopoverDB pattern in sqlite.yml. diff --git a/k8s/README.md b/k8s/README.md index fb5d8e4609..4087e756e3 100644 --- a/k8s/README.md +++ b/k8s/README.md @@ -9,7 +9,7 @@ points — review resource sizing, storage class, and your registry before apply ## Why a StatefulSet (not a Deployment) The miner keeps all state in **local SQLite ledgers** (`claim-ledger.sqlite3`, `plan-store.sqlite3`, …) under -`GITTENSORY_MINER_CONFIG_DIR` (`/data/miner`). Those stores are **not safe for concurrent multi-pod access**, so +`LOOPOVER_MINER_CONFIG_DIR` (`/data/miner`). Those stores are **not safe for concurrent multi-pod access**, so each worker needs its **own** volume. A Deployment can only mount a single shared PVC across every replica; a **StatefulSet's `volumeClaimTemplates`** give each replica its own PersistentVolumeClaim — so scaling to N replicas yields N workers with fully isolated state. That per-pod isolation is the whole reason these manifests diff --git a/k8s/miner-deployment.yaml b/k8s/miner-deployment.yaml index e1b33b6073..52eca6cd63 100644 --- a/k8s/miner-deployment.yaml +++ b/k8s/miner-deployment.yaml @@ -1,7 +1,7 @@ # Kubernetes workload for gittensory-miner (AMS) fleet mode (#5181). # # This is a StatefulSet, NOT a Deployment: the miner keeps all of its state in local SQLite ledgers -# (claim-ledger.sqlite3, plan-store.sqlite3, …) under GITTENSORY_MINER_CONFIG_DIR, and those stores are NOT +# (claim-ledger.sqlite3, plan-store.sqlite3, …) under LOOPOVER_MINER_CONFIG_DIR, and those stores are NOT # safe for concurrent multi-pod access. A Deployment can only mount one shared PVC across every replica; a # StatefulSet's volumeClaimTemplates give each replica its OWN PersistentVolumeClaim, so N workers run with # fully isolated state — the safety property this manifest exists to guarantee. See k8s/README.md. @@ -45,7 +45,7 @@ spec: # ENTRYPOINT is `gittensory-miner`; `run` is the continuous fleet-worker loop. args: ["run"] env: - - name: GITTENSORY_MINER_CONFIG_DIR + - name: LOOPOVER_MINER_CONFIG_DIR value: /data/miner - name: GITHUB_TOKEN valueFrom: diff --git a/packages/gittensory-engine/src/governor/action-mode.ts b/packages/gittensory-engine/src/governor/action-mode.ts index 0e31aefce2..e61646520f 100644 --- a/packages/gittensory-engine/src/governor/action-mode.ts +++ b/packages/gittensory-engine/src/governor/action-mode.ts @@ -16,7 +16,7 @@ export type MinerActionMode = "paused" | "dry_run" | "live"; /** * The ONLY value that opts a miner into LIVE write execution. Deliberately a specific string literal, not a - * boolean -- a fat-fingered `liveModeOptIn: true`, `"yes"`, `"on"`, or `GITTENSORY_MINER_LIVE_MODE=1` must never + * boolean -- a fat-fingered `liveModeOptIn: true`, `"yes"`, `"on"`, or `LOOPOVER_MINER_LIVE_MODE=1` must never * accidentally unlock writes the way a truthy-coerced flag could. Per the issue's explicit requirement: "not a * generic boolean flag that could be accidentally true." */ @@ -24,7 +24,7 @@ export const MINER_LIVE_MODE_OPT_IN = "live"; /** Env var an operator sets (to exactly {@link MINER_LIVE_MODE_OPT_IN}) to opt their own miner instance into * live write execution. Repo-side opt-in alone is never enough to execute writes. */ -export const MINER_LIVE_MODE_ENV_VAR = "GITTENSORY_MINER_LIVE_MODE"; +export const MINER_LIVE_MODE_ENV_VAR = "LOOPOVER_MINER_LIVE_MODE"; /** True only when `value` is EXACTLY the {@link MINER_LIVE_MODE_OPT_IN} string -- no truthy coercion, no case * folding, no alternate spellings. Everything else (including `true`, `"Live"`, `"1"`) reads as not opted in. */ diff --git a/packages/gittensory-engine/src/governor/kill-switch.ts b/packages/gittensory-engine/src/governor/kill-switch.ts index 3ffa22cc97..1889dbe22c 100644 --- a/packages/gittensory-engine/src/governor/kill-switch.ts +++ b/packages/gittensory-engine/src/governor/kill-switch.ts @@ -16,7 +16,7 @@ import type { GovernorLedgerEvent } from "../governor-ledger.js"; const TRUTHY_ENV_VALUE = /^(1|true|yes|on)$/i; /** Env var an operator sets to halt ALL miner write activity, across every repo, immediately. */ -export const MINER_KILL_SWITCH_ENV_VAR = "GITTENSORY_MINER_KILL_SWITCH"; +export const MINER_KILL_SWITCH_ENV_VAR = "LOOPOVER_MINER_KILL_SWITCH"; /** Which trigger (if any) is currently halting miner write activity for a given repo. */ export type MinerKillSwitchScope = "global" | "repo" | "none"; diff --git a/packages/gittensory-engine/src/miner-goal-spec.ts b/packages/gittensory-engine/src/miner-goal-spec.ts index 015ac16f2f..6c8a69b54d 100644 --- a/packages/gittensory-engine/src/miner-goal-spec.ts +++ b/packages/gittensory-engine/src/miner-goal-spec.ts @@ -51,7 +51,7 @@ export type MinerExecutionPolicy = { * Explicit opt-in to LIVE write execution for this repo. Must equal EXACTLY the literal string `"live"` — any * other value (a typo, `"yes"`, `"on"`, or a boolean `true` from a malformed file) is treated as not opted * in, so a fat-fingered config can never accidentally enable live writes. A miner also stays in dry-run - * unless its own operator separately opts in globally (`GITTENSORY_MINER_LIVE_MODE=live`) — this field alone + * unless its own operator separately opts in globally (`LOOPOVER_MINER_LIVE_MODE=live`) — this field alone * cannot force a stranger's miner instance live. Default: null (dry-run). */ liveModeOptIn: typeof MINER_LIVE_MODE_OPT_IN | null; diff --git a/packages/gittensory-engine/test/action-mode.test.ts b/packages/gittensory-engine/test/action-mode.test.ts index 94746f41b0..e34567e5a2 100644 --- a/packages/gittensory-engine/test/action-mode.test.ts +++ b/packages/gittensory-engine/test/action-mode.test.ts @@ -18,7 +18,7 @@ test("barrel: the public entrypoint re-exports the action-mode primitive (#2342) assert.equal(typeof isGlobalMinerLiveModeOptIn, "function"); assert.equal(typeof buildMinerDryRunGovernorLedgerEvent, "function"); assert.equal(MINER_LIVE_MODE_OPT_IN, "live"); - assert.equal(MINER_LIVE_MODE_ENV_VAR, "GITTENSORY_MINER_LIVE_MODE"); + assert.equal(MINER_LIVE_MODE_ENV_VAR, "LOOPOVER_MINER_LIVE_MODE"); }); test("isExplicitMinerLiveModeOptIn: only the exact literal opts in, no truthy coercion", () => { @@ -29,9 +29,9 @@ test("isExplicitMinerLiveModeOptIn: only the exact literal opts in, no truthy co }); test("isGlobalMinerLiveModeOptIn: only the exact env value opts in", () => { - assert.equal(isGlobalMinerLiveModeOptIn({ GITTENSORY_MINER_LIVE_MODE: "live" }), true); + assert.equal(isGlobalMinerLiveModeOptIn({ LOOPOVER_MINER_LIVE_MODE: "live" }), true); for (const value of [undefined, "", "1", "true", "Live", "on"]) { - assert.equal(isGlobalMinerLiveModeOptIn({ GITTENSORY_MINER_LIVE_MODE: value }), false); + assert.equal(isGlobalMinerLiveModeOptIn({ LOOPOVER_MINER_LIVE_MODE: value }), false); } }); diff --git a/packages/gittensory-engine/test/kill-switch.test.ts b/packages/gittensory-engine/test/kill-switch.test.ts index b34abe7a6b..b06e5a5c15 100644 --- a/packages/gittensory-engine/test/kill-switch.test.ts +++ b/packages/gittensory-engine/test/kill-switch.test.ts @@ -14,15 +14,15 @@ test("barrel: the public entrypoint re-exports the kill-switch primitive (#2341) assert.equal(typeof resolveMinerKillSwitch, "function"); assert.equal(typeof isMinerKillSwitchActive, "function"); assert.equal(typeof buildMinerKillSwitchTransitionGovernorLedgerEvent, "function"); - assert.equal(MINER_KILL_SWITCH_ENV_VAR, "GITTENSORY_MINER_KILL_SWITCH"); + assert.equal(MINER_KILL_SWITCH_ENV_VAR, "LOOPOVER_MINER_KILL_SWITCH"); }); test("isGlobalMinerKillSwitch: accepts the same truthy-string idiom as isGlobalAgentPause", () => { for (const value of ["1", "true", "TRUE", "yes", "on", "On"]) { - assert.equal(isGlobalMinerKillSwitch({ GITTENSORY_MINER_KILL_SWITCH: value }), true, `expected ${value} to be truthy`); + assert.equal(isGlobalMinerKillSwitch({ LOOPOVER_MINER_KILL_SWITCH: value }), true, `expected ${value} to be truthy`); } for (const value of [undefined, "", "0", "false", "no", "off", "banana"]) { - assert.equal(isGlobalMinerKillSwitch({ GITTENSORY_MINER_KILL_SWITCH: value }), false, `expected ${String(value)} to be falsy`); + assert.equal(isGlobalMinerKillSwitch({ LOOPOVER_MINER_KILL_SWITCH: value }), false, `expected ${String(value)} to be falsy`); } }); diff --git a/packages/gittensory-miner/DEPLOYMENT.md b/packages/gittensory-miner/DEPLOYMENT.md index 260d8db4f0..b26c603bea 100644 --- a/packages/gittensory-miner/DEPLOYMENT.md +++ b/packages/gittensory-miner/DEPLOYMENT.md @@ -6,7 +6,7 @@ Two form factors for running `@loopover/miner`: **laptop mode** (single machine, | ---------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | **Best for** | One contributor machine, local experimentation | Many parallel miner attempts on a host or small cluster | | **Dependencies** | Node.js `>=22.13.0` only | Docker (or compatible runtime) + Node image or custom image | -| **State** | SQLite files under `~/.config/gittensory-miner/` (override with `GITTENSORY_MINER_CONFIG_DIR`) | Same SQLite layout on a mounted `/data` (or `GITTENSORY_MINER_CONFIG_DIR`) volume | +| **State** | SQLite files under `~/.config/gittensory-miner/` (override with `LOOPOVER_MINER_CONFIG_DIR`) | Same SQLite layout on a mounted `/data` (or `LOOPOVER_MINER_CONFIG_DIR`) volume | | **Setup** | `npm install -g @loopover/miner` or workspace build | `docker build` + `docker run` with env + volume (see below) | | **Footprint** | One Node process, local disk for ledgers/queues | One container per worker; scale horizontally by adding containers | @@ -36,7 +36,7 @@ For provider selection and the CLI-specific model/timeout overrides, see ``` `init --interactive` offers "Authorize with GitHub" (device flow -- visit a URL, enter a short code, no - token to copy or paste) as its first option once `GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID` is configured for the + token to copy or paste) as its first option once `LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID` is configured for the centrally-held `loopover-ams` GitHub App; the original pasted-PAT prompt stays available as option 2, and is what the wizard falls back to automatically on any device-flow failure. Unconfigured, the wizard is byte-identical to the pasted-token-only prompt. Either way, the resulting `GITHUB_TOKEN` acts as your own @@ -67,10 +67,10 @@ For provider selection and the CLI-specific model/timeout overrides, see Not every file appears immediately: `laptop-state` is written by `init`, and each of the others is created the first time its subsystem actually runs (an attempt, a discovery pass, a replay, an Orb export, …), so a fresh install that has only run `status`/`doctor` will show a subset. All sixteen default into this one - directory. Override the directory for every store at once with `GITTENSORY_MINER_CONFIG_DIR` or + directory. Override the directory for every store at once with `LOOPOVER_MINER_CONFIG_DIR` or `XDG_CONFIG_HOME` (same resolution chain as `@loopover/mcp`); every store except `laptop-state.sqlite3` - (directory only) also honors its own `GITTENSORY_MINER__DB` path override — e.g. - `GITTENSORY_MINER_PORTFOLIO_QUEUE_DB` — to relocate an individual file. `doctor`'s `store-integrity:*` checks + (directory only) also honors its own `LOOPOVER_MINER__DB` path override — e.g. + `LOOPOVER_MINER_PORTFOLIO_QUEUE_DB` — to relocate an individual file. `doctor`'s `store-integrity:*` checks report the persistent stores, so it is the quickest way to confirm what exists and is readable on disk. 4. Optional per-repo miner goals: copy [`.gittensory-miner.yml.example`](../../.gittensory-miner.yml.example) to a target repo as `.gittensory-miner.yml`. See [`docs/miner-goal-spec.md`](docs/miner-goal-spec.md). @@ -87,7 +87,7 @@ Run a disposable worker with persistent SQLite state on a mounted volume. Inject ```sh docker run --rm -it \ - -e GITTENSORY_MINER_CONFIG_DIR=/data/miner \ + -e LOOPOVER_MINER_CONFIG_DIR=/data/miner \ -e GITHUB_TOKEN \ -v miner-data:/data/miner \ gittensory-miner:latest \ @@ -96,7 +96,7 @@ docker run --rm -it \ The image entrypoint is `gittensory-miner`; pass subcommands after the image name (`status`, `doctor`, `claim`, …). -- **`/data/miner` volume** — holds all SQLite state (`claim-ledger.sqlite3`, `plan-store.sqlite3`, etc.) so containers are disposable. Defaults to `GITTENSORY_MINER_CONFIG_DIR=/data/miner` in the image. +- **`/data/miner` volume** — holds all SQLite state (`claim-ledger.sqlite3`, `plan-store.sqlite3`, etc.) so containers are disposable. Defaults to `LOOPOVER_MINER_CONFIG_DIR=/data/miner` in the image. - **`GITHUB_TOKEN`** — supplied by the operator at run time; the image contains no credentials. - **Scale** — launch additional containers with the same volume (or partitioned config dirs) for parallel attempts. @@ -108,7 +108,7 @@ uses it exactly as if `GITHUB_TOKEN` had been set directly: ```sh docker run --rm -it \ - -e GITTENSORY_MINER_CONFIG_DIR=/data/miner \ + -e LOOPOVER_MINER_CONFIG_DIR=/data/miner \ -e GITHUB_TOKEN_FILE=/run/secrets/github_token \ -v miner-data:/data/miner \ -v /path/to/your/secret:/run/secrets/github_token:ro \ @@ -133,7 +133,7 @@ cp .gittensory-miner.env.example .gittensory-miner.env # fill in GITHUB_TOKEN docker compose -f docker-compose.miner.yml up -d --build ``` -**Scaling to N parallel workers.** `docker compose -f docker-compose.miner.yml up -d --scale miner=N` gives every replica the **same** `miner-data` volume — and the miner's SQLite ledgers are **not** safe for concurrent access, so N replicas on one volume will contend/corrupt. To run N **isolated** workers, give each its own state: run N separate compose projects (`docker compose -p miner-1 …`, `-p miner-2 …` — `-p` namespaces the volume) or point each at a distinct `GITTENSORY_MINER_CONFIG_DIR` on its own mount. For built-in isolated horizontal scaling, use the Kubernetes StatefulSet in [`k8s/`](../../k8s/) (per-pod volumes). +**Scaling to N parallel workers.** `docker compose -f docker-compose.miner.yml up -d --scale miner=N` gives every replica the **same** `miner-data` volume — and the miner's SQLite ledgers are **not** safe for concurrent access, so N replicas on one volume will contend/corrupt. To run N **isolated** workers, give each its own state: run N separate compose projects (`docker compose -p miner-1 …`, `-p miner-2 …` — `-p` namespaces the volume) or point each at a distinct `LOOPOVER_MINER_CONFIG_DIR` on its own mount. For built-in isolated horizontal scaling, use the Kubernetes StatefulSet in [`k8s/`](../../k8s/) (per-pod volumes). ## Bare-host (systemd, no Docker) diff --git a/packages/gittensory-miner/Dockerfile b/packages/gittensory-miner/Dockerfile index ab95eb90f4..d598684c72 100644 --- a/packages/gittensory-miner/Dockerfile +++ b/packages/gittensory-miner/Dockerfile @@ -1,7 +1,7 @@ # Fleet-mode image for @loopover/miner (#4295). Build context = monorepo root: # docker build -f packages/gittensory-miner/Dockerfile -t gittensory-miner:latest . # SECRETS ARE NEVER BAKED: supply operator credentials at `docker run` time only. -# Persistent SQLite ledgers live on a mounted volume (default GITTENSORY_MINER_CONFIG_DIR=/data/miner). +# Persistent SQLite ledgers live on a mounted volume (default LOOPOVER_MINER_CONFIG_DIR=/data/miner). ARG GITTENSORY_VERSION= @@ -22,8 +22,8 @@ FROM public.ecr.aws/docker/library/node:24-slim AS runtime WORKDIR /app ARG GITTENSORY_VERSION= ENV NODE_ENV=production \ - GITTENSORY_MINER_CONFIG_DIR=/data/miner \ - GITTENSORY_MINER_VERSION=${GITTENSORY_VERSION} \ + LOOPOVER_MINER_CONFIG_DIR=/data/miner \ + LOOPOVER_MINER_VERSION=${GITTENSORY_VERSION} \ PATH=/app/node_modules/.bin:$PATH COPY --from=build --chown=node:node /app/node_modules ./node_modules COPY --from=build --chown=node:node /app/packages/gittensory-miner ./packages/gittensory-miner diff --git a/packages/gittensory-miner/README.md b/packages/gittensory-miner/README.md index 21fe8ae1ff..218c4392bb 100644 --- a/packages/gittensory-miner/README.md +++ b/packages/gittensory-miner/README.md @@ -11,7 +11,7 @@ Current scope is intentionally small: - workspace package wiring - CLI entry point - `--help` and `version` commands -- startup npm version nudge (override with `--no-update-check` or `GITTENSORY_MINER_NO_UPDATE_CHECK=1`) +- startup npm version nudge (override with `--no-update-check` or `LOOPOVER_MINER_NO_UPDATE_CHECK=1`) Environment variables read by the miner are documented in [`docs/env-reference.md`](docs/env-reference.md). Regenerate that file with `npm run miner:env-reference` from the repo root after adding or removing env reads. @@ -101,26 +101,26 @@ Phase 6 of the same roadmap tracker and hasn't been scaffolded yet. (#4279) Independent local SQLite stores back the commands above. Each keeps its own file, its own table(s), and (for most stores) its own env-var override — this is a DRY pass over their shared path-resolution/open boilerplate (`local-store.js`), not a merge into one database. (#4272) -See [`docs/env-reference.md`](docs/env-reference.md) for the full `GITTENSORY_MINER_*` / `MINER_*` env-var list. +See [`docs/env-reference.md`](docs/env-reference.md) for the full `LOOPOVER_MINER_*` / `MINER_*` env-var list. | Store | File | Primary table(s) | Module | Env var override | | --- | --- | --- | --- | --- | -| Laptop bootstrap | `laptop-state.sqlite3` | `laptop_meta` | `laptop-init.js` | `GITTENSORY_MINER_CONFIG_DIR` (path only) | -| Run state | `run-state.sqlite3` | `miner_run_state` | `run-state.js` | `GITTENSORY_MINER_RUN_STATE_DB` | -| Claim ledger | `claim-ledger.sqlite3` | `miner_claims` | `claim-ledger.js` | `GITTENSORY_MINER_CLAIM_LEDGER_DB` | -| Portfolio queue | `portfolio-queue.sqlite3` | `miner_portfolio_queue` | `portfolio-queue.js` | `GITTENSORY_MINER_PORTFOLIO_QUEUE_DB` | -| Event ledger | `event-ledger.sqlite3` | `miner_event_ledger` | `event-ledger.js` | `GITTENSORY_MINER_EVENT_LEDGER_DB` | -| Plan store | `plan-store.sqlite3` | `miner_plans` | `plan-store.js` | `GITTENSORY_MINER_PLAN_STORE_DB` | -| Governor ledger | `governor-ledger.sqlite3` | `governor_events` | `governor-ledger.js` | `GITTENSORY_MINER_GOVERNOR_LEDGER_DB` | -| Governor state | `governor-state.sqlite3` | `governor_scalar_state`, `governor_reputation_history`, `governor_own_submissions` | `governor-state.js` | `GITTENSORY_MINER_GOVERNOR_STATE_DB` | -| Attempt log | `attempt-log.sqlite3` | `attempt_log_events` | `attempt-log.js` | `GITTENSORY_MINER_ATTEMPT_LOG_DB` | -| Prediction ledger | `prediction-ledger.sqlite3` | `predictions` | `prediction-ledger.js` | `GITTENSORY_MINER_PREDICTION_LEDGER_DB` | -| Replay snapshot | `replay-snapshot.sqlite3` | `replay_snapshots` | `replay-snapshot.js` | `GITTENSORY_MINER_REPLAY_SNAPSHOT_DB` | -| Deny-hook synthesis | `deny-hook-synthesis.sqlite3` | `deny_rule_proposals` | `deny-hook-synthesis.js` | `GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB` | -| Worktree allocator | `worktree-allocator.sqlite3` | `worktree_slots` | `worktree-allocator.js` | `GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB` | -| Orb export | `orb-export.sqlite3` | `orb_export_meta` | `orb-export.js` | `GITTENSORY_MINER_ORB_EXPORT_DB` | -| Policy-doc cache | `policy-doc-cache.sqlite3` | `policy_doc_cache` | `policy-doc-cache.js` | `GITTENSORY_MINER_POLICY_DOC_CACHE_DB` | -| Policy-verdict cache | `policy-verdict-cache.sqlite3` | `policy_verdict_cache` | `policy-verdict-cache.js` | `GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB` | +| Laptop bootstrap | `laptop-state.sqlite3` | `laptop_meta` | `laptop-init.js` | `LOOPOVER_MINER_CONFIG_DIR` (path only) | +| Run state | `run-state.sqlite3` | `miner_run_state` | `run-state.js` | `LOOPOVER_MINER_RUN_STATE_DB` | +| Claim ledger | `claim-ledger.sqlite3` | `miner_claims` | `claim-ledger.js` | `LOOPOVER_MINER_CLAIM_LEDGER_DB` | +| Portfolio queue | `portfolio-queue.sqlite3` | `miner_portfolio_queue` | `portfolio-queue.js` | `LOOPOVER_MINER_PORTFOLIO_QUEUE_DB` | +| Event ledger | `event-ledger.sqlite3` | `miner_event_ledger` | `event-ledger.js` | `LOOPOVER_MINER_EVENT_LEDGER_DB` | +| Plan store | `plan-store.sqlite3` | `miner_plans` | `plan-store.js` | `LOOPOVER_MINER_PLAN_STORE_DB` | +| Governor ledger | `governor-ledger.sqlite3` | `governor_events` | `governor-ledger.js` | `LOOPOVER_MINER_GOVERNOR_LEDGER_DB` | +| Governor state | `governor-state.sqlite3` | `governor_scalar_state`, `governor_reputation_history`, `governor_own_submissions` | `governor-state.js` | `LOOPOVER_MINER_GOVERNOR_STATE_DB` | +| Attempt log | `attempt-log.sqlite3` | `attempt_log_events` | `attempt-log.js` | `LOOPOVER_MINER_ATTEMPT_LOG_DB` | +| Prediction ledger | `prediction-ledger.sqlite3` | `predictions` | `prediction-ledger.js` | `LOOPOVER_MINER_PREDICTION_LEDGER_DB` | +| Replay snapshot | `replay-snapshot.sqlite3` | `replay_snapshots` | `replay-snapshot.js` | `LOOPOVER_MINER_REPLAY_SNAPSHOT_DB` | +| Deny-hook synthesis | `deny-hook-synthesis.sqlite3` | `deny_rule_proposals` | `deny-hook-synthesis.js` | `LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB` | +| Worktree allocator | `worktree-allocator.sqlite3` | `worktree_slots` | `worktree-allocator.js` | `LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB` | +| Orb export | `orb-export.sqlite3` | `orb_export_meta` | `orb-export.js` | `LOOPOVER_MINER_ORB_EXPORT_DB` | +| Policy-doc cache | `policy-doc-cache.sqlite3` | `policy_doc_cache` | `policy-doc-cache.js` | `LOOPOVER_MINER_POLICY_DOC_CACHE_DB` | +| Policy-verdict cache | `policy-verdict-cache.sqlite3` | `policy_verdict_cache` | `policy-verdict-cache.js` | `LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB` | The policy-doc and policy-verdict caches are the only stores above that hold no miner state of their own — both are pure optimization, and deleting either file only forces the next run to redo the work it would have skipped. The @@ -131,7 +131,7 @@ instead of re-downloading static content, spending no extra rate-limit budget wh confirmed unchanged, it reuses the already-resolved AI-usage-policy verdict instead of re-resolving it from the (identical) doc text (#4843). -Every store resolves its file the same way: the store-specific env var above, else `GITTENSORY_MINER_CONFIG_DIR`, +Every store resolves its file the same way: the store-specific env var above, else `LOOPOVER_MINER_CONFIG_DIR`, else `XDG_CONFIG_HOME` (falling back to `~/.config`), joined with `gittensory-miner/`. Every store also opens its file with `0700`/`0600` permissions and a shared `PRAGMA busy_timeout` so two instances on the same file serialize writes instead of racing. @@ -175,7 +175,7 @@ gittensory-miner doctor gittensory-miner status ``` -`init` creates `~/.config/gittensory-miner/` (or `GITTENSORY_MINER_CONFIG_DIR` / `XDG_CONFIG_HOME` overrides) and a local `laptop-state.sqlite3` bootstrap file. Re-running `init` is idempotent. Pass `--verify-token` to make one authenticated GitHub API call up front and fail fast if `GITHUB_TOKEN` is invalid or missing repository access scopes. `doctor` reports Node, the state directory, SQLite readiness, and whether Docker is installed (informational only). Every local store already applies its own pending schema migrations automatically the moment some other command first opens it, but `migrate` lets an operator proactively bring every EXISTING store file up to date in one pass (e.g. right after upgrading) instead of relying on whichever command happens to touch a given store first; a store file that hasn't been created yet is reported as skipped, not created. +`init` creates `~/.config/gittensory-miner/` (or `LOOPOVER_MINER_CONFIG_DIR` / `XDG_CONFIG_HOME` overrides) and a local `laptop-state.sqlite3` bootstrap file. Re-running `init` is idempotent. Pass `--verify-token` to make one authenticated GitHub API call up front and fail fast if `GITHUB_TOKEN` is invalid or missing repository access scopes. `doctor` reports Node, the state directory, SQLite readiness, and whether Docker is installed (informational only). Every local store already applies its own pending schema migrations automatically the moment some other command first opens it, but `migrate` lets an operator proactively bring every EXISTING store file up to date in one pass (e.g. right after upgrading) instead of relying on whichever command happens to touch a given store first; a store file that hasn't been created yet is reported as skipped, not created. First-time operators can instead run `gittensory-miner init --interactive` (#5176): a guided prompt for `GITHUB_TOKEN` (input hidden, never echoed or written to any log) and an optional coding-agent provider — plus that provider's model/timeout companion vars, each individually skippable with Enter — writes a starter `.env` to the state dir, then automatically reruns `doctor` against the collected values so setup problems surface immediately. `--interactive` makes no network calls of its own beyond what `doctor` already makes (none); non-interactive `init` invocations are unaffected. diff --git a/packages/gittensory-miner/docker-compose.miner.yml b/packages/gittensory-miner/docker-compose.miner.yml index 6b3c2f4be3..d42890e5b1 100644 --- a/packages/gittensory-miner/docker-compose.miner.yml +++ b/packages/gittensory-miner/docker-compose.miner.yml @@ -16,7 +16,7 @@ # • run N separate compose projects, each with its own volume: # docker compose -p miner-1 -f docker-compose.miner.yml up -d # docker compose -p miner-2 -f docker-compose.miner.yml up -d # …etc; -p namespaces the volume -# • or point each worker at a distinct GITTENSORY_MINER_CONFIG_DIR on its own mount. +# • or point each worker at a distinct LOOPOVER_MINER_CONFIG_DIR on its own mount. # (A single-shared-volume `--scale` is only safe for one active worker; Kubernetes StatefulSet per-pod PVCs, see # k8s/, are the built-in answer for isolated horizontal scaling.) services: @@ -32,7 +32,7 @@ services: # and NEVER commit the real file — env vars stay out of the compose file and out of `docker inspect` args. env_file: - .gittensory-miner.env - # The state dir is fixed at /data/miner — it is the Dockerfile's built-in GITTENSORY_MINER_CONFIG_DIR default + # The state dir is fixed at /data/miner — it is the Dockerfile's built-in LOOPOVER_MINER_CONFIG_DIR default # AND the volume mount below. It is deliberately NOT set here (and NOT offered as an env-file override): # Compose's `environment` would silently override an env-file value, and the mount is pinned to /data/miner, # so exposing it as a knob would be a silently-ignored footgun. To relocate state, change the volume mount. diff --git a/packages/gittensory-miner/docs/config-precedence.md b/packages/gittensory-miner/docs/config-precedence.md index 86e43b284e..d130d2afb1 100644 --- a/packages/gittensory-miner/docs/config-precedence.md +++ b/packages/gittensory-miner/docs/config-precedence.md @@ -7,7 +7,7 @@ AMS does **not** have a single `config.js` resolver. Configuration is layered by | Layer | Source | Scope | Typical modules | | --- | --- | --- | --- | | **Per-target-repo file** | `.gittensory-miner.yml` (or `.github/gittensory-miner.yml`, JSON variants) | One cloned target repo | `lib/miner-goal-spec.js`, engine `parseMinerGoalSpecContent` | -| **Operator env** | `GITTENSORY_MINER_*` / `MINER_*` | This miner process / fleet container | `lib/local-store.js`, `lib/governor-kill-switch.js`, `lib/attempt-cli.js`, … | +| **Operator env** | `LOOPOVER_MINER_*` / `MINER_*` | This miner process / fleet container | `lib/local-store.js`, `lib/governor-kill-switch.js`, `lib/attempt-cli.js`, … | | **CLI flags** | `gittensory-miner …` argv | One invocation | `lib/attempt-cli.js`, `lib/discover-cli.js`, `lib/loop-cli.js`, … | | **Operator file (not goal spec)** | `~/.config/gittensory-miner/.gittensory-ams.yml` | Operator execution policy | `lib/ams-policy.js` | @@ -26,7 +26,7 @@ First existing file wins (engine `MINER_GOAL_SPEC_FILENAMES`): ### Kill switch (halt miner writes) -**Sources:** `GITTENSORY_MINER_KILL_SWITCH` (operator env) and `.gittensory-miner.yml` → `killSwitch.paused`. +**Sources:** `LOOPOVER_MINER_KILL_SWITCH` (operator env) and `.gittensory-miner.yml` → `killSwitch.paused`. **Order (safest wins, engine `resolveMinerKillSwitch`):** @@ -38,7 +38,7 @@ There is **no CLI flag** for kill-switch today. `MINER_CODING_AGENT_PAUSED` is a ### Governor live write mode -**Sources:** `GITTENSORY_MINER_LIVE_MODE=live` (operator env) and `.gittensory-miner.yml` → `execution.liveModeOptIn: live`. +**Sources:** `LOOPOVER_MINER_LIVE_MODE=live` (operator env) and `.gittensory-miner.yml` → `execution.liveModeOptIn: live`. **Order (engine `resolveMinerActionMode`):** @@ -76,7 +76,7 @@ There is **no `.gittensory-miner.yml` forge block** today; `--api-base-url` foll ### Local SQLite store paths -**Sources:** per-store `GITTENSORY_MINER_*_DB` env var, then `GITTENSORY_MINER_CONFIG_DIR`, then XDG default (`lib/local-store.js`). +**Sources:** per-store `LOOPOVER_MINER_*_DB` env var, then `LOOPOVER_MINER_CONFIG_DIR`, then XDG default (`lib/local-store.js`). Explicit per-store env **wins** over config dir; config dir **wins** over XDG. No CLI or goal-spec override. diff --git a/packages/gittensory-miner/docs/discovery-plane-operator-guide.md b/packages/gittensory-miner/docs/discovery-plane-operator-guide.md index 1d7e42fa19..66dfa052a6 100644 --- a/packages/gittensory-miner/docs/discovery-plane-operator-guide.md +++ b/packages/gittensory-miner/docs/discovery-plane-operator-guide.md @@ -42,17 +42,17 @@ Until the contract issue lands, treat these as **documentation placeholders** fo | Variable (provisional) | Default | Purpose | |------------------------|---------|---------| -| `GITTENSORY_MINER_DISCOVERY_PLANE` | unset / `false` | Master opt-in. When not truthy (`1`, `true`, `yes`, `on`), the miner must not call the hosted index or emit discovery-plane telemetry. | -| `GITTENSORY_MINER_DISCOVERY_INDEX_URL` | unset | Hosted index base URL. Required when the plane is enabled; ignored when opt-in is off. | -| `GITTENSORY_MINER_DISCOVERY_TELEMETRY` | unset / `false` | Separate opt-in for anonymized operational telemetry ([#4301](https://github.com/JSONbored/gittensory/issues/4301)). Plane queries can stay on while telemetry stays off. | +| `LOOPOVER_MINER_DISCOVERY_PLANE` | unset / `false` | Master opt-in. When not truthy (`1`, `true`, `yes`, `on`), the miner must not call the hosted index or emit discovery-plane telemetry. | +| `LOOPOVER_MINER_DISCOVERY_INDEX_URL` | unset | Hosted index base URL. Required when the plane is enabled; ignored when opt-in is off. | +| `LOOPOVER_MINER_DISCOVERY_TELEMETRY` | unset / `false` | Separate opt-in for anonymized operational telemetry ([#4301](https://github.com/JSONbored/gittensory/issues/4301)). Plane queries can stay on while telemetry stays off. | **Truthy-string convention** (when implemented): `/^(1|true|yes|on)$/i`, matching other `GITTENSORY_*` flags in this repo. **Operator checklist (enabled plane):** -1. Set `GITTENSORY_MINER_DISCOVERY_PLANE=true` (exact name may change — see [#4300](https://github.com/JSONbored/gittensory/issues/4300)). -2. Set `GITTENSORY_MINER_DISCOVERY_INDEX_URL` to the operator-trusted index endpoint ([#4250](https://github.com/JSONbored/gittensory/issues/4250)). -3. Optionally set `GITTENSORY_MINER_DISCOVERY_TELEMETRY=true` if you want anonymized operational events for the hosted service — not required for index queries. +1. Set `LOOPOVER_MINER_DISCOVERY_PLANE=true` (exact name may change — see [#4300](https://github.com/JSONbored/gittensory/issues/4300)). +2. Set `LOOPOVER_MINER_DISCOVERY_INDEX_URL` to the operator-trusted index endpoint ([#4250](https://github.com/JSONbored/gittensory/issues/4250)). +3. Optionally set `LOOPOVER_MINER_DISCOVERY_TELEMETRY=true` if you want anonymized operational events for the hosted service — not required for index queries. 4. Keep `GITHUB_TOKEN` (or equivalent) on the instance only; never configure tokens intended for the hosted plane to receive. With opt-in off (default), behavior is byte-identical to today: local SQLite ledgers, local fan-out, no hosted calls. diff --git a/packages/gittensory-miner/docs/env-reference.md b/packages/gittensory-miner/docs/env-reference.md index d147b8658e..fd0a72a396 100644 --- a/packages/gittensory-miner/docs/env-reference.md +++ b/packages/gittensory-miner/docs/env-reference.md @@ -4,31 +4,31 @@ Generated by `npm run miner:env-reference`. Do not edit manually. | Name | First reference | Default | | --- | --- | --- | -| `GITTENSORY_MINER_AMS_COLLECTOR_TOKEN` | `lib/orb-export.js` | `""` | -| `GITTENSORY_MINER_AMS_COLLECTOR_URL` | `lib/orb-export.js` | `""` | -| `GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID` | `lib/oauth-device-flow.js` | `""` | -| `GITTENSORY_MINER_AMS_POLICY_PATH` | `lib/ams-policy.js` | (none) | -| `GITTENSORY_MINER_ATTEMPT_LOG_DB` | `lib/attempt-log.js` | (none) | -| `GITTENSORY_MINER_CLAIM_LEDGER_DB` | `lib/claim-ledger.js` | (none) | -| `GITTENSORY_MINER_CONFIG_DIR` | `lib/deny-hook-synthesis.js` | `""` | -| `GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB` | `lib/deny-hook-synthesis.js` | `""` | -| `GITTENSORY_MINER_EVENT_LEDGER_DB` | `lib/event-ledger.js` | (none) | -| `GITTENSORY_MINER_GOVERNOR_LEDGER_DB` | `lib/governor-ledger.js` | `""` | -| `GITTENSORY_MINER_GOVERNOR_STATE_DB` | `lib/governor-state.js` | (none) | -| `GITTENSORY_MINER_KILL_SWITCH` | `lib/config-precedence.js` | `""` | -| `GITTENSORY_MINER_LOG_LEVEL` | `lib/logger.js` | `""` | -| `GITTENSORY_MINER_NO_UPDATE_CHECK` | `lib/update-check.js` | `""` | -| `GITTENSORY_MINER_ORB_EXPORT_DB` | `lib/orb-export.js` | `""` | -| `GITTENSORY_MINER_PLAN_STORE_DB` | `lib/plan-store.js` | `""` | -| `GITTENSORY_MINER_POLICY_DOC_CACHE_DB` | `lib/policy-doc-cache.js` | (none) | -| `GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB` | `lib/policy-verdict-cache.js` | (none) | -| `GITTENSORY_MINER_PORTFOLIO_QUEUE_DB` | `lib/portfolio-queue.js` | (none) | -| `GITTENSORY_MINER_PREDICTION_LEDGER_DB` | `lib/prediction-ledger.js` | `""` | -| `GITTENSORY_MINER_RANKED_CANDIDATES_DB` | `lib/ranked-candidates.js` | (none) | -| `GITTENSORY_MINER_REPLAY_SNAPSHOT_DB` | `lib/replay-snapshot.js` | (none) | -| `GITTENSORY_MINER_REPO_CLONE_DIR` | `lib/repo-clone.js` | `""` | -| `GITTENSORY_MINER_RUN_STATE_DB` | `lib/run-state.js` | (none) | -| `GITTENSORY_MINER_VERSION` | `lib/version.js` | `""` | -| `GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB` | `lib/worktree-allocator.js` | `""` | -| `GITTENSORY_MINER_WORKTREE_DIR` | `lib/worktree-allocator.js` | `""` | +| `LOOPOVER_MINER_AMS_COLLECTOR_TOKEN` | `lib/orb-export.js` | `""` | +| `LOOPOVER_MINER_AMS_COLLECTOR_URL` | `lib/orb-export.js` | `""` | +| `LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID` | `lib/oauth-device-flow.js` | `""` | +| `LOOPOVER_MINER_AMS_POLICY_PATH` | `lib/ams-policy.js` | (none) | +| `LOOPOVER_MINER_ATTEMPT_LOG_DB` | `lib/attempt-log.js` | (none) | +| `LOOPOVER_MINER_CLAIM_LEDGER_DB` | `lib/claim-ledger.js` | (none) | +| `LOOPOVER_MINER_CONFIG_DIR` | `lib/deny-hook-synthesis.js` | `""` | +| `LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB` | `lib/deny-hook-synthesis.js` | `""` | +| `LOOPOVER_MINER_EVENT_LEDGER_DB` | `lib/event-ledger.js` | (none) | +| `LOOPOVER_MINER_GOVERNOR_LEDGER_DB` | `lib/governor-ledger.js` | `""` | +| `LOOPOVER_MINER_GOVERNOR_STATE_DB` | `lib/governor-state.js` | (none) | +| `LOOPOVER_MINER_KILL_SWITCH` | `lib/config-precedence.js` | `""` | +| `LOOPOVER_MINER_LOG_LEVEL` | `lib/logger.js` | `""` | +| `LOOPOVER_MINER_NO_UPDATE_CHECK` | `lib/update-check.js` | `""` | +| `LOOPOVER_MINER_ORB_EXPORT_DB` | `lib/orb-export.js` | `""` | +| `LOOPOVER_MINER_PLAN_STORE_DB` | `lib/plan-store.js` | `""` | +| `LOOPOVER_MINER_POLICY_DOC_CACHE_DB` | `lib/policy-doc-cache.js` | (none) | +| `LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB` | `lib/policy-verdict-cache.js` | (none) | +| `LOOPOVER_MINER_PORTFOLIO_QUEUE_DB` | `lib/portfolio-queue.js` | (none) | +| `LOOPOVER_MINER_PREDICTION_LEDGER_DB` | `lib/prediction-ledger.js` | `""` | +| `LOOPOVER_MINER_RANKED_CANDIDATES_DB` | `lib/ranked-candidates.js` | (none) | +| `LOOPOVER_MINER_REPLAY_SNAPSHOT_DB` | `lib/replay-snapshot.js` | (none) | +| `LOOPOVER_MINER_REPO_CLONE_DIR` | `lib/repo-clone.js` | `""` | +| `LOOPOVER_MINER_RUN_STATE_DB` | `lib/run-state.js` | (none) | +| `LOOPOVER_MINER_VERSION` | `lib/version.js` | `""` | +| `LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB` | `lib/worktree-allocator.js` | `""` | +| `LOOPOVER_MINER_WORKTREE_DIR` | `lib/worktree-allocator.js` | `""` | | `MINER_CODING_AGENT_PROVIDER` | `lib/laptop-init.js` | (none) | diff --git a/packages/gittensory-miner/docs/miner-goal-spec.md b/packages/gittensory-miner/docs/miner-goal-spec.md index f6b748b9f2..fa2bfb275d 100644 --- a/packages/gittensory-miner/docs/miner-goal-spec.md +++ b/packages/gittensory-miner/docs/miner-goal-spec.md @@ -65,12 +65,12 @@ Per-repo tuning for the Governor self-plagiarism throttle consulted before `open ### `killSwitch` (object, default: `{ paused: false }`) -Per-repo kill-switch consulted by the Governor chokepoint before every write action (#2341). Distinct from `minerEnabled`: `minerEnabled` is a discovery-time opt-out (a miner never even considers the repo), while `killSwitch.paused` is a runtime halt of an already-in-flight queue — un-pausing resumes exactly where the queue left off. A separate, operator-controlled GLOBAL kill-switch (env var `GITTENSORY_MINER_KILL_SWITCH`) halts every repo at once and always wins over this per-repo flag. +Per-repo kill-switch consulted by the Governor chokepoint before every write action (#2341). Distinct from `minerEnabled`: `minerEnabled` is a discovery-time opt-out (a miner never even considers the repo), while `killSwitch.paused` is a runtime halt of an already-in-flight queue — un-pausing resumes exactly where the queue left off. A separate, operator-controlled GLOBAL kill-switch (env var `LOOPOVER_MINER_KILL_SWITCH`) halts every repo at once and always wins over this per-repo flag. - `paused` (boolean, default: `false`) — halts all miner WRITE actions for this repo without deregistering it from targeting/discovery. ### `execution` (object, default: `{ liveModeOptIn: null }`) -Per-repo dry-run/live execution opt-in consulted by the Governor chokepoint (#2342). A freshly-configured miner always defaults to dry-run (observe/log only, never execute a write) — this field is the only per-repo path to live mode, and it alone is not sufficient: the miner's own operator must also separately opt in globally (env var `GITTENSORY_MINER_LIVE_MODE=live`) before writes actually execute. A repo that wants to guarantee it never receives live automated writes, regardless of any operator's global setting, should use `killSwitch.paused: true` instead — the kill-switch always takes precedence over any live-mode opt-in. +Per-repo dry-run/live execution opt-in consulted by the Governor chokepoint (#2342). A freshly-configured miner always defaults to dry-run (observe/log only, never execute a write) — this field is the only per-repo path to live mode, and it alone is not sufficient: the miner's own operator must also separately opt in globally (env var `LOOPOVER_MINER_LIVE_MODE=live`) before writes actually execute. A repo that wants to guarantee it never receives live automated writes, regardless of any operator's global setting, should use `killSwitch.paused: true` instead — the kill-switch always takes precedence over any live-mode opt-in. - `liveModeOptIn` (string or `null`, default: `null`) — must equal EXACTLY the literal `"live"` to opt in. Any other value (a typo, `"yes"`, `"on"`, or a boolean `true` from a malformed file) is treated as not opted in — deliberately not a boolean flag, so a fat-fingered config can never accidentally enable live writes. diff --git a/packages/gittensory-miner/docs/observability.md b/packages/gittensory-miner/docs/observability.md index b66f1dc688..cfe7aa729c 100644 --- a/packages/gittensory-miner/docs/observability.md +++ b/packages/gittensory-miner/docs/observability.md @@ -6,7 +6,7 @@ operations, see your ops runbook. ## What's observable -The miner writes append-only SQLite ledgers under `GITTENSORY_MINER_CONFIG_DIR` (default +The miner writes append-only SQLite ledgers under `LOOPOVER_MINER_CONFIG_DIR` (default `~/.config/gittensory-miner` on a laptop, or `/data/miner` in the fleet Docker image — see [`DEPLOYMENT.md`](../DEPLOYMENT.md)): @@ -17,7 +17,7 @@ The miner writes append-only SQLite ledgers under `GITTENSORY_MINER_CONFIG_DIR` - **`prediction-ledger.sqlite3`** — recorded predicted-gate verdicts for later scoring. Those live files can contain free-form payloads, repo/target identifiers, readiness scores, and blocker/warning -codes. Keep `GITTENSORY_MINER_CONFIG_DIR` private to the miner. Grafana should read only sanitized reporting +codes. Keep `LOOPOVER_MINER_CONFIG_DIR` private to the miner. Grafana should read only sanitized reporting exports that operators create from those ledgers. ## Point Grafana at reporting exports @@ -41,10 +41,10 @@ not under the miner config directory. docker compose --profile ams-observability up -d ``` - Set `GITTENSORY_MINER_CONFIG_DIR` in your `.env` (see [`.env.example`](../../../.env.example)) to the same + Set `LOOPOVER_MINER_CONFIG_DIR` in your `.env` (see [`.env.example`](../../../.env.example)) to the same directory your miner uses. The `ams-reporting-exporter` container mounts it **read-only**, runs [`scripts/export-ams-reporting-db.sh`](../../../scripts/export-ams-reporting-db.sh) on an interval - (`GITTENSORY_AMS_REPORTING_EXPORT_INTERVAL_SECONDS`, default 30s), and writes the redacted snapshots into the + (`LOOPOVER_AMS_REPORTING_EXPORT_INTERVAL_SECONDS`, default 30s), and writes the redacted snapshots into the same `reporting` volume Grafana already reads — Grafana itself never mounts the live ledgers. The exported schema drops `attempt_log_events.reason`/`.payload_json` (the free-form fields) entirely; every other column, including the `predictions` table's `blocker_codes_json`/`warning_codes_json` (fixed, engine-defined codes — @@ -78,16 +78,16 @@ None of these is a long-running HTTP server — Prometheus can't scrape a one-sh wire [`scripts/export-miner-prometheus-textfile.sh`](../../../scripts/export-miner-prometheus-textfile.sh) into your own cron/systemd timer alongside [node_exporter's textfile collector](https://github.com/prometheus/node_exporter#textfile-collector): the script runs all four commands and -atomically writes their concatenated output to `$GITTENSORY_MINER_PROMETHEUS_TEXTFILE` (default +atomically writes their concatenated output to `$LOOPOVER_MINER_PROMETHEUS_TEXTFILE` (default `/var/lib/node_exporter/textfile_collector/gittensory_miner.prom`), the standard directory node_exporter's -textfile collector watches. Point `GITTENSORY_MINER_BIN` at the miner binary if it isn't on `PATH`. +textfile collector watches. Point `LOOPOVER_MINER_BIN` at the miner binary if it isn't on `PATH`. A broken/corrupt local store for one family (e.g. the portfolio queue) never blocks the other three — that family's metrics are simply omitted from the file for that run (logged to stderr), not the whole export. ```sh # crontab -e -*/5 * * * * GITTENSORY_MINER_CONFIG_DIR=/data/miner sh /path/to/gittensory/scripts/export-miner-prometheus-textfile.sh +*/5 * * * * LOOPOVER_MINER_CONFIG_DIR=/data/miner sh /path/to/gittensory/scripts/export-miner-prometheus-textfile.sh ``` Then point your own `prometheus.yml` at node_exporter as usual — no changes to this repo's `prometheus/` config @@ -120,6 +120,6 @@ maintainer-side collector) — every invocation requires `--enable --send` expli | Variable | Purpose | | --- | --- | -| `GITTENSORY_MINER_AMS_COLLECTOR_URL` | Override the collector endpoint (default: gittensory's hosted collector). | -| `GITTENSORY_MINER_AMS_COLLECTOR_TOKEN` | Optional bearer credential, only needed if your collector requires one. | -| `GITTENSORY_MINER_ORB_EXPORT_DB` | Override the local secret+cursor store path (default: `orb-export.sqlite3` under `GITTENSORY_MINER_CONFIG_DIR`). | +| `LOOPOVER_MINER_AMS_COLLECTOR_URL` | Override the collector endpoint (default: gittensory's hosted collector). | +| `LOOPOVER_MINER_AMS_COLLECTOR_TOKEN` | Optional bearer credential, only needed if your collector requires one. | +| `LOOPOVER_MINER_ORB_EXPORT_DB` | Override the local secret+cursor store path (default: `orb-export.sqlite3` under `LOOPOVER_MINER_CONFIG_DIR`). | diff --git a/packages/gittensory-miner/docs/operations-runbook.md b/packages/gittensory-miner/docs/operations-runbook.md index 7733c6a84a..aa2efdb4fb 100644 --- a/packages/gittensory-miner/docs/operations-runbook.md +++ b/packages/gittensory-miner/docs/operations-runbook.md @@ -6,7 +6,7 @@ Operator-facing runbook for **local SQLite state**: what the concurrency guarant ## Local state at a glance -Every miner keeps **independent SQLite files** under one state directory (default `~/.config/gittensory-miner/`, override with `GITTENSORY_MINER_CONFIG_DIR`). Each store has its own file, table, and optional per-store env override — see the table in [`../README.md`](../README.md#local-storage) and [`env-reference.md`](env-reference.md). +Every miner keeps **independent SQLite files** under one state directory (default `~/.config/gittensory-miner/`, override with `LOOPOVER_MINER_CONFIG_DIR`). Each store has its own file, table, and optional per-store env override — see the table in [`../README.md`](../README.md#local-storage) and [`env-reference.md`](env-reference.md). Common files you will touch in incidents: @@ -41,9 +41,9 @@ PRAGMA busy_timeout = 5000; | Two **short-lived** writers on the **same file** (e.g. CLI command finishing while `loop` is idle, or Grafana reading while the miner appends) | SQLite waits up to **5 seconds** for the lock, then proceeds or surfaces `database is locked` | | Append-only ledgers (`event-ledger`, `attempt-log`, …) | Writes use **`BEGIN IMMEDIATE`** (or equivalent single-statement atomicity) so sequence allocation cannot interleave | | Claim / queue stores | **`INSERT … ON CONFLICT`** and **`UPDATE … RETURNING`** patterns avoid read-then-write races **within one file** | -| Two **long-running `gittensory-miner loop` daemons** on the **same `GITTENSORY_MINER_CONFIG_DIR`** | **Unsupported.** `busy_timeout` reduces transient lock errors; it does **not** make multi-process loop workers safe on one volume | +| Two **long-running `gittensory-miner loop` daemons** on the **same `LOOPOVER_MINER_CONFIG_DIR`** | **Unsupported.** `busy_timeout` reduces transient lock errors; it does **not** make multi-process loop workers safe on one volume | -**Invariant:** one active loop (or one intentional writer set) per state directory. Horizontal scale = **isolated state dirs** (separate compose projects, separate `GITTENSORY_MINER_CONFIG_DIR`, or the k8s StatefulSet pattern in [`../DEPLOYMENT.md`](../DEPLOYMENT.md)). +**Invariant:** one active loop (or one intentional writer set) per state directory. Horizontal scale = **isolated state dirs** (separate compose projects, separate `LOOPOVER_MINER_CONFIG_DIR`, or the k8s StatefulSet pattern in [`../DEPLOYMENT.md`](../DEPLOYMENT.md)). ### Quick health check @@ -94,7 +94,7 @@ gittensory-miner status --json docker compose -p miner-b -f docker-compose.miner.yml up -d ``` - Or set distinct `GITTENSORY_MINER_CONFIG_DIR` per worker. + Or set distinct `LOOPOVER_MINER_CONFIG_DIR` per worker. 3. Re-run `gittensory-miner doctor`. If locks persist with a single process, see **Ledger corrupted** below. @@ -106,7 +106,7 @@ Proactive tooling (#4872), not just the reactive "ledger corrupted" scenario bel schedule (cron, systemd timer, etc.) so a good restore point always exists before anything goes wrong. - **[`scripts/backup-miner.sh`](../../../scripts/backup-miner.sh)** — backs up every `*.sqlite3` file currently - present under `GITTENSORY_MINER_CONFIG_DIR` into a new timestamped directory, using SQLite's own online + present under `LOOPOVER_MINER_CONFIG_DIR` into a new timestamped directory, using SQLite's own online `.backup` command (safe even while the miner is running — see the corruption scenario's warning below about why a plain `cp` is not) plus a `PRAGMA integrity_check` on each resulting file before it's kept. Stores discovered by glob, not a hardcoded list, so a newly added store is backed up automatically without this doc @@ -114,8 +114,8 @@ schedule (cron, systemd timer, etc.) so a good restore point always exists befor ```sh sh scripts/backup-miner.sh - # Env overrides: GITTENSORY_MINER_CONFIG_DIR (source), GITTENSORY_MINER_BACKUP_DIR (default - # $GITTENSORY_MINER_CONFIG_DIR/backups), GITTENSORY_MINER_BACKUP_RETAIN (default 7 — oldest backups beyond + # Env overrides: LOOPOVER_MINER_CONFIG_DIR (source), LOOPOVER_MINER_BACKUP_DIR (default + # $LOOPOVER_MINER_CONFIG_DIR/backups), LOOPOVER_MINER_BACKUP_RETAIN (default 7 — oldest backups beyond # this count are pruned after a fully successful run; a run with any failed store skips pruning so no older, # good backup is ever lost to make room for a bad one). ``` diff --git a/packages/gittensory-miner/docs/sizing.md b/packages/gittensory-miner/docs/sizing.md index c6727ac525..5ab92d8164 100644 --- a/packages/gittensory-miner/docs/sizing.md +++ b/packages/gittensory-miner/docs/sizing.md @@ -29,7 +29,7 @@ dominated by the operator's chosen coding-agent CLI process, not by anything thi ## Methodology - **Laptop mode CPU/RAM**: GNU `/usr/bin/time -v` around the CLI process directly (no container). -- **Laptop mode disk**: `du -sh`/`du -ah` on the resolved `GITTENSORY_MINER_CONFIG_DIR` after the run. +- **Laptop mode disk**: `du -sh`/`du -ah` on the resolved `LOOPOVER_MINER_CONFIG_DIR` after the run. - **Fleet mode CPU/RAM**: `docker stats --no-stream` polled once per second per container while each worker ran `discover` followed by a `sleep` tail (so short-lived containers stay observable long enough to sample); the reported number is the peak observed sample per container. @@ -43,10 +43,10 @@ dominated by the operator's chosen coding-agent CLI process, not by anything thi ### Exact commands (laptop mode) ```sh -GITTENSORY_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ +LOOPOVER_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ node packages/gittensory-miner/bin/gittensory-miner.js init --json -GITTENSORY_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ +LOOPOVER_MINER_CONFIG_DIR=/tmp/sizing-laptop /usr/bin/time -v \ node packages/gittensory-miner/bin/gittensory-miner.js discover octocat/Hello-World --dry-run --json du -sh /tmp/sizing-laptop diff --git a/packages/gittensory-miner/docs/unattended-scheduling.md b/packages/gittensory-miner/docs/unattended-scheduling.md index d4392ab425..c816a759fa 100644 --- a/packages/gittensory-miner/docs/unattended-scheduling.md +++ b/packages/gittensory-miner/docs/unattended-scheduling.md @@ -19,7 +19,7 @@ Both commands follow the same convention, so any scheduler can detect a failed r For scheduled runs, two flags matter: -- `--no-update-check` (or `GITTENSORY_MINER_NO_UPDATE_CHECK=1`) — skip the npm-registry version nudge so +- `--no-update-check` (or `LOOPOVER_MINER_NO_UPDATE_CHECK=1`) — skip the npm-registry version nudge so an unattended run never depends on / prints it. - `--json` — machine-parseable stdout, so an alert handler can attach the structured output. @@ -28,7 +28,7 @@ For scheduled runs, two flags matter: ```cron # crontab env applies to every job below. MAILTO=you@example.com -GITTENSORY_MINER_NO_UPDATE_CHECK=1 +LOOPOVER_MINER_NO_UPDATE_CHECK=1 # Poll a tracked PR every 10 minutes. The `||` branch fires on any non-zero exit: it logs the failing # code to syslog AND re-raises it with `exit "$status"`, so the failure stays visible to exit-status @@ -61,7 +61,7 @@ OnFailure=gittensory-miner-alert@%n.service [Service] Type=oneshot -Environment=GITTENSORY_MINER_NO_UPDATE_CHECK=1 +Environment=LOOPOVER_MINER_NO_UPDATE_CHECK=1 # A non-zero exit (2) marks the unit failed and triggers OnFailure=. ExecStart=/usr/local/bin/gittensory-miner discover --search "label:good-first-issue" --json ``` diff --git a/packages/gittensory-miner/lib/ams-policy.js b/packages/gittensory-miner/lib/ams-policy.js index 5a5bdfe505..2270552485 100644 --- a/packages/gittensory-miner/lib/ams-policy.js +++ b/packages/gittensory-miner/lib/ams-policy.js @@ -12,10 +12,10 @@ import { resolveLocalStoreDbPath } from "./local-store.js"; const AMS_POLICY_FILENAME = ".gittensory-ams.yml"; -/** Resolve the operator's local AMS policy file path: explicit env var > `GITTENSORY_MINER_CONFIG_DIR` > +/** Resolve the operator's local AMS policy file path: explicit env var > `LOOPOVER_MINER_CONFIG_DIR` > * `XDG_CONFIG_HOME`/`~/.config`, mirroring every other local-store path in this package. */ export function resolveAmsPolicyConfigPath(env = process.env) { - return resolveLocalStoreDbPath(AMS_POLICY_FILENAME, "GITTENSORY_MINER_AMS_POLICY_PATH", env); + return resolveLocalStoreDbPath(AMS_POLICY_FILENAME, "LOOPOVER_MINER_AMS_POLICY_PATH", env); } function normalizeOptions(options = {}) { diff --git a/packages/gittensory-miner/lib/attempt-log.js b/packages/gittensory-miner/lib/attempt-log.js index 1ed29152e9..b16be599aa 100644 --- a/packages/gittensory-miner/lib/attempt-log.js +++ b/packages/gittensory-miner/lib/attempt-log.js @@ -15,7 +15,7 @@ const defaultDbFileName = "attempt-log.sqlite3"; let defaultAttemptLog = null; export function resolveAttemptLogDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_ATTEMPT_LOG_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_ATTEMPT_LOG_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/claim-ledger.js b/packages/gittensory-miner/lib/claim-ledger.js index 1faa8a7218..5275be2611 100644 --- a/packages/gittensory-miner/lib/claim-ledger.js +++ b/packages/gittensory-miner/lib/claim-ledger.js @@ -16,7 +16,7 @@ const defaultDbFileName = "claim-ledger.sqlite3"; let defaultClaimLedger = null; export function resolveClaimLedgerDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_CLAIM_LEDGER_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_CLAIM_LEDGER_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/cli.js b/packages/gittensory-miner/lib/cli.js index 4524cea08b..3ca7c3fc8c 100644 --- a/packages/gittensory-miner/lib/cli.js +++ b/packages/gittensory-miner/lib/cli.js @@ -60,9 +60,9 @@ export function printHelp(input) { " Right-to-be-forgotten: delete a repo's rows from every local store", "", "Options:", - " --no-update-check Skip the npm registry version nudge (also GITTENSORY_MINER_NO_UPDATE_CHECK=1)", - " --quiet Log only warnings and errors (also GITTENSORY_MINER_LOG_LEVEL=error)", - " --verbose Log debug-level diagnostics (also GITTENSORY_MINER_LOG_LEVEL=debug)", + " --no-update-check Skip the npm registry version nudge (also LOOPOVER_MINER_NO_UPDATE_CHECK=1)", + " --quiet Log only warnings and errors (also LOOPOVER_MINER_LOG_LEVEL=error)", + " --verbose Log debug-level diagnostics (also LOOPOVER_MINER_LOG_LEVEL=debug)", " --log-level Set the log level explicitly: silent|error|warn|info|debug", ].join("\n"), ); diff --git a/packages/gittensory-miner/lib/config-precedence.js b/packages/gittensory-miner/lib/config-precedence.js index 27b1bbe71e..d14c68233d 100644 --- a/packages/gittensory-miner/lib/config-precedence.js +++ b/packages/gittensory-miner/lib/config-precedence.js @@ -11,7 +11,7 @@ import { resolveForgeConfig } from "./forge-config.js"; /** Kill-switch scope from operator env + parsed goal-spec `killSwitch.paused`. */ export function resolveDocumentedKillSwitchScope(env, repoPaused) { - const global = /^(1|true|yes|on)$/i.test(env.GITTENSORY_MINER_KILL_SWITCH ?? ""); + const global = /^(1|true|yes|on)$/i.test(env.LOOPOVER_MINER_KILL_SWITCH ?? ""); return resolveMinerKillSwitch({ global, repoPaused }); } diff --git a/packages/gittensory-miner/lib/deny-hook-synthesis.js b/packages/gittensory-miner/lib/deny-hook-synthesis.js index 127205f42e..f041659871 100644 --- a/packages/gittensory-miner/lib/deny-hook-synthesis.js +++ b/packages/gittensory-miner/lib/deny-hook-synthesis.js @@ -59,13 +59,13 @@ function normalizeApiBaseUrl(apiBaseUrl) { } export function resolveDenyHookSynthesisDbPath(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB === "string" - ? env.GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB.trim() + const explicitPath = typeof env.LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB === "string" + ? env.LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); diff --git a/packages/gittensory-miner/lib/deployment-docs-audit.js b/packages/gittensory-miner/lib/deployment-docs-audit.js index 424f816929..b815a7b03c 100644 --- a/packages/gittensory-miner/lib/deployment-docs-audit.js +++ b/packages/gittensory-miner/lib/deployment-docs-audit.js @@ -1,11 +1,11 @@ // Docs-accuracy audit for the miner's DEPLOYMENT.md (#5180). Mirrors the self-host docs audit // (apps/gittensory-ui/src/lib/selfhost-docs-audit.ts): parse the deployment doc, then assert every -// GITTENSORY_MINER_* / MINER_* env var, repo-relative file path, and `gittensory-miner ` +// LOOPOVER_MINER_* / MINER_* env var, repo-relative file path, and `gittensory-miner ` // it documents still exists under packages/gittensory-miner/**. A rename or move that leaves the doc // stale then fails CI with a message naming the exact stale claim, instead of misleading operators. -/** The miner's own env-var namespace: GITTENSORY_MINER_* and the shorter MINER_* aliases it reads. */ -const ENV_VAR_PATTERN = /\b(?:GITTENSORY_MINER|MINER)_[A-Z0-9_]+\b/g; +/** The miner's own env-var namespace: LOOPOVER_MINER_* and the shorter MINER_* aliases it reads. */ +const ENV_VAR_PATTERN = /\b(?:LOOPOVER_MINER|MINER)_[A-Z0-9_]+\b/g; /** `gittensory-miner ` CLI invocations, excluding the `@loopover/miner` package spelling. */ const SUBCOMMAND_PATTERN = /(?"` guards in the miner bin — the CLI's registered top-level command table. */ const CLI_DISPATCH_PATTERN = /cliArgs\[0\]\s*===\s*"([a-z][a-z0-9-]*)"/g; -/** Collect every GITTENSORY_MINER_* / MINER_* token that appears in `text` (doc prose/code or source). */ +/** Collect every LOOPOVER_MINER_* / MINER_* token that appears in `text` (doc prose/code or source). */ export function scanEnvVarTokens(text) { const tokens = new Set(); for (const match of text.matchAll(ENV_VAR_PATTERN)) { diff --git a/packages/gittensory-miner/lib/event-ledger.js b/packages/gittensory-miner/lib/event-ledger.js index d012530ae5..14a99823f5 100644 --- a/packages/gittensory-miner/lib/event-ledger.js +++ b/packages/gittensory-miner/lib/event-ledger.js @@ -24,7 +24,7 @@ const defaultDbFileName = "event-ledger.sqlite3"; let defaultEventLedger = null; export function resolveEventLedgerDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_EVENT_LEDGER_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_EVENT_LEDGER_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/governor-ledger.js b/packages/gittensory-miner/lib/governor-ledger.js index 55544c611e..7e09473b41 100644 --- a/packages/gittensory-miner/lib/governor-ledger.js +++ b/packages/gittensory-miner/lib/governor-ledger.js @@ -23,13 +23,13 @@ const defaultDbFileName = "governor-ledger.sqlite3"; let defaultGovernorLedger = null; export function resolveGovernorLedgerDbPath(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB === "string" - ? env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB.trim() + const explicitPath = typeof env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB === "string" + ? env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); diff --git a/packages/gittensory-miner/lib/governor-state.js b/packages/gittensory-miner/lib/governor-state.js index 16cf46b26b..39199444e6 100644 --- a/packages/gittensory-miner/lib/governor-state.js +++ b/packages/gittensory-miner/lib/governor-state.js @@ -26,7 +26,7 @@ const DEFAULT_REPUTATION_HISTORY = Object.freeze({ decided: 0, unfavorable: 0 }) let defaultGovernorState = null; export function resolveGovernorStateDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_GOVERNOR_STATE_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_GOVERNOR_STATE_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/init-wizard.js b/packages/gittensory-miner/lib/init-wizard.js index f100f8571d..d4b384b1cd 100644 --- a/packages/gittensory-miner/lib/init-wizard.js +++ b/packages/gittensory-miner/lib/init-wizard.js @@ -13,7 +13,7 @@ import { DeviceFlowError, resolveAmsOauthClientId, runDeviceFlowAuthorization } // this module never calls verifyGithubToken (that stays behind the separate, explicitly opt-in // `init --verify-token` flag). // -// #5682: when GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID is configured, the wizard offers "Authorize with GitHub" +// #5682: when LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID is configured, the wizard offers "Authorize with GitHub" // (device flow -- see oauth-device-flow.js) as an ADDITIONAL onboarding path alongside the original pasted-PAT // prompt, never replacing it. Unconfigured (today's default -- the App isn't registered yet) is byte-identical // to the original prompt-only flow, so every existing deployment is unaffected until an operator opts in. @@ -54,7 +54,7 @@ async function promptAuthMethod(io) { } /** - * Collect a GitHub credential for the wizard's starter .env. When GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID isn't + * Collect a GitHub credential for the wizard's starter .env. When LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID isn't * configured (today's default, before the loopover-ams App is registered), this is IDENTICAL to the original * masked-token-only prompt -- no menu, no behavior change. Once configured, offers device-flow authorization as * the default choice, with the original pasted-token path still available (option 2) and as the automatic diff --git a/packages/gittensory-miner/lib/laptop-init.js b/packages/gittensory-miner/lib/laptop-init.js index 6db4509225..a557582846 100644 --- a/packages/gittensory-miner/lib/laptop-init.js +++ b/packages/gittensory-miner/lib/laptop-init.js @@ -12,8 +12,8 @@ const defaultDbFileName = "laptop-state.sqlite3"; /** Local state directory (mirrors `resolveMinerStateDir` in status.js — kept local to avoid import cycles). */ function resolveMinerStateDir(env = process.env) { - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return explicitConfigDir; diff --git a/packages/gittensory-miner/lib/local-store.js b/packages/gittensory-miner/lib/local-store.js index 7b093c4aef..c9640ccb3c 100644 --- a/packages/gittensory-miner/lib/local-store.js +++ b/packages/gittensory-miner/lib/local-store.js @@ -10,15 +10,15 @@ import { registerCleanupResource } from "./process-lifecycle.js"; // (env-var/config-dir/XDG path resolution, mkdirSync(0o700) + chmodSync(0o600), and `PRAGMA busy_timeout`). /** - * Resolve a local store's DB path from, in order: an explicit env var, `GITTENSORY_MINER_CONFIG_DIR`, + * Resolve a local store's DB path from, in order: an explicit env var, `LOOPOVER_MINER_CONFIG_DIR`, * `XDG_CONFIG_HOME` (falling back to `~/.config`) — mirroring every store's prior hand-written resolver. */ export function resolveLocalStoreDbPath(defaultDbFileName, explicitEnvVarName, env = process.env) { const explicitPath = typeof env[explicitEnvVarName] === "string" ? env[explicitEnvVarName].trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); diff --git a/packages/gittensory-miner/lib/logger.js b/packages/gittensory-miner/lib/logger.js index 0ca43a6445..33c389019a 100644 --- a/packages/gittensory-miner/lib/logger.js +++ b/packages/gittensory-miner/lib/logger.js @@ -119,7 +119,7 @@ export function formatLine({ level, message, fields, pretty, timestamp }) { /** * Build a level-aware logger. All I/O is injectable for tests: `streams` (defaults to process stdout/stderr), * `now` (defaults to an ISO-8601 clock, only consulted in `pretty` mode), and `env` (defaults to process.env, - * read for `GITTENSORY_MINER_LOG_LEVEL`). `fields` seeds every line with contextual fields; `child(extra)` + * read for `LOOPOVER_MINER_LOG_LEVEL`). `fields` seeds every line with contextual fields; `child(extra)` * returns a logger that merges additional fields onto this one. * @param {import("./logger.js").LoggerOptions} [options] * @returns {import("./logger.js").Logger} @@ -129,7 +129,7 @@ export function createLogger(options = {}) { const stdout = streams?.stdout ?? process.stdout; const stderr = streams?.stderr ?? process.stderr; const clock = now ?? defaultClock; - const envLevel = env.GITTENSORY_MINER_LOG_LEVEL ?? ""; + const envLevel = env.LOOPOVER_MINER_LOG_LEVEL ?? ""; const activeLevel = resolveLogLevel({ level, quiet, verbose, envLevel }); const threshold = LEVEL_RANK[activeLevel]; diff --git a/packages/gittensory-miner/lib/oauth-device-flow.js b/packages/gittensory-miner/lib/oauth-device-flow.js index a45fd1f372..384666b61f 100644 --- a/packages/gittensory-miner/lib/oauth-device-flow.js +++ b/packages/gittensory-miner/lib/oauth-device-flow.js @@ -19,7 +19,7 @@ const DEFAULT_INTERVAL_SECONDS = 5; /** The centrally-held loopover-ams App's OAuth client id -- public (not secret), so it's safe to read from a * plain env var. Empty/unset means device-flow authorization isn't available in this build/deployment. */ export function resolveAmsOauthClientId(env = process.env) { - return typeof env.GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID === "string" ? env.GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID.trim() : ""; + return typeof env.LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID === "string" ? env.LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID.trim() : ""; } export class DeviceFlowError extends Error { diff --git a/packages/gittensory-miner/lib/orb-export.js b/packages/gittensory-miner/lib/orb-export.js index 265f023982..f20a0c7a43 100644 --- a/packages/gittensory-miner/lib/orb-export.js +++ b/packages/gittensory-miner/lib/orb-export.js @@ -27,11 +27,11 @@ const defaultDbFileName = "orb-export.sqlite3"; export function resolveOrbExportDbPath(env = process.env) { const explicitPath = - typeof env.GITTENSORY_MINER_ORB_EXPORT_DB === "string" ? env.GITTENSORY_MINER_ORB_EXPORT_DB.trim() : ""; + typeof env.LOOPOVER_MINER_ORB_EXPORT_DB === "string" ? env.LOOPOVER_MINER_ORB_EXPORT_DB.trim() : ""; if (explicitPath) return explicitPath; const explicitConfigDir = - typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" ? env.GITTENSORY_MINER_CONFIG_DIR.trim() : ""; + typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); const configHome = @@ -166,7 +166,7 @@ export function latestClosedAt(batch) { export const DEFAULT_AMS_COLLECTOR_URL = "https://api.loopover.ai/v1/ams/ingest"; export function resolveAmsCollectorUrl(env = process.env) { - const explicit = typeof env.GITTENSORY_MINER_AMS_COLLECTOR_URL === "string" ? env.GITTENSORY_MINER_AMS_COLLECTOR_URL.trim() : ""; + const explicit = typeof env.LOOPOVER_MINER_AMS_COLLECTOR_URL === "string" ? env.LOOPOVER_MINER_AMS_COLLECTOR_URL.trim() : ""; return explicit || DEFAULT_AMS_COLLECTOR_URL; } @@ -292,7 +292,7 @@ export async function runOrbExportCli(args, options = {}) { const send = options.sendAmsExportBatch ?? sendAmsExportBatch; const secret = store.getOrCreateAnonSecret(); const env = options.env ?? process.env; - const collectorToken = env.GITTENSORY_MINER_AMS_COLLECTOR_TOKEN ?? ""; + const collectorToken = env.LOOPOVER_MINER_AMS_COLLECTOR_TOKEN ?? ""; const sendResult = await send({ batch: toSend, secret, collectorToken }); if (sendResult.sent > 0) { const nextCursor = latestClosedAt(toSend); diff --git a/packages/gittensory-miner/lib/plan-store.js b/packages/gittensory-miner/lib/plan-store.js index 251c3781b6..c548275745 100644 --- a/packages/gittensory-miner/lib/plan-store.js +++ b/packages/gittensory-miner/lib/plan-store.js @@ -21,13 +21,13 @@ const defaultDbFileName = "plan-store.sqlite3"; let defaultPlanStore = null; export function resolvePlanStoreDbPath(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_PLAN_STORE_DB === "string" - ? env.GITTENSORY_MINER_PLAN_STORE_DB.trim() + const explicitPath = typeof env.LOOPOVER_MINER_PLAN_STORE_DB === "string" + ? env.LOOPOVER_MINER_PLAN_STORE_DB.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); diff --git a/packages/gittensory-miner/lib/policy-doc-cache.js b/packages/gittensory-miner/lib/policy-doc-cache.js index 910eab45a4..6abb490f9a 100644 --- a/packages/gittensory-miner/lib/policy-doc-cache.js +++ b/packages/gittensory-miner/lib/policy-doc-cache.js @@ -13,7 +13,7 @@ import { applySchemaMigrations } from "./schema-version.js"; const defaultDbFileName = "policy-doc-cache.sqlite3"; export function resolvePolicyDocCacheDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_POLICY_DOC_CACHE_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_POLICY_DOC_CACHE_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/policy-verdict-cache.js b/packages/gittensory-miner/lib/policy-verdict-cache.js index 3f87e6094c..88048cdc36 100644 --- a/packages/gittensory-miner/lib/policy-verdict-cache.js +++ b/packages/gittensory-miner/lib/policy-verdict-cache.js @@ -18,7 +18,7 @@ const defaultDbFileName = "policy-verdict-cache.sqlite3"; const DECISIVE_DOCS = new Set(["AI-USAGE.md", "CONTRIBUTING.md"]); export function resolvePolicyVerdictCacheDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/portfolio-queue.js b/packages/gittensory-miner/lib/portfolio-queue.js index 094b84eda0..765b688bc0 100644 --- a/packages/gittensory-miner/lib/portfolio-queue.js +++ b/packages/gittensory-miner/lib/portfolio-queue.js @@ -14,7 +14,7 @@ const defaultDbFileName = "portfolio-queue.sqlite3"; let defaultPortfolioQueueStore = null; export function resolvePortfolioQueueDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_PORTFOLIO_QUEUE_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/prediction-ledger.js b/packages/gittensory-miner/lib/prediction-ledger.js index 4dfedeaad3..83bf68ca7c 100644 --- a/packages/gittensory-miner/lib/prediction-ledger.js +++ b/packages/gittensory-miner/lib/prediction-ledger.js @@ -24,13 +24,13 @@ const defaultDbFileName = "prediction-ledger.sqlite3"; let defaultPredictionLedger = null; export function resolvePredictionLedgerDbPath(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_PREDICTION_LEDGER_DB === "string" - ? env.GITTENSORY_MINER_PREDICTION_LEDGER_DB.trim() + const explicitPath = typeof env.LOOPOVER_MINER_PREDICTION_LEDGER_DB === "string" + ? env.LOOPOVER_MINER_PREDICTION_LEDGER_DB.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); diff --git a/packages/gittensory-miner/lib/ranked-candidates.js b/packages/gittensory-miner/lib/ranked-candidates.js index 25ef075ec1..e9139bb7fe 100644 --- a/packages/gittensory-miner/lib/ranked-candidates.js +++ b/packages/gittensory-miner/lib/ranked-candidates.js @@ -21,7 +21,7 @@ const defaultDbFileName = "ranked-candidates.sqlite3"; let defaultRankedCandidatesStore = null; export function resolveRankedCandidatesDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_RANKED_CANDIDATES_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_RANKED_CANDIDATES_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/replay-snapshot.js b/packages/gittensory-miner/lib/replay-snapshot.js index dd03136559..f078896d7e 100644 --- a/packages/gittensory-miner/lib/replay-snapshot.js +++ b/packages/gittensory-miner/lib/replay-snapshot.js @@ -35,7 +35,7 @@ const defaultDbFileName = "replay-snapshot.sqlite3"; let defaultDb = null; export function resolveReplaySnapshotDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_REPLAY_SNAPSHOT_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_REPLAY_SNAPSHOT_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/repo-clone.js b/packages/gittensory-miner/lib/repo-clone.js index 150395e586..848ff8308a 100644 --- a/packages/gittensory-miner/lib/repo-clone.js +++ b/packages/gittensory-miner/lib/repo-clone.js @@ -18,10 +18,10 @@ const DEFAULT_CLONE_DIR_NAME = "repos"; const DEFAULT_BASE_BRANCH = "main"; export function resolveRepoCloneBaseDir(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_REPO_CLONE_DIR === "string" ? env.GITTENSORY_MINER_REPO_CLONE_DIR.trim() : ""; + const explicitPath = typeof env.LOOPOVER_MINER_REPO_CLONE_DIR === "string" ? env.LOOPOVER_MINER_REPO_CLONE_DIR.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" ? env.GITTENSORY_MINER_CONFIG_DIR.trim() : ""; + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; 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"); diff --git a/packages/gittensory-miner/lib/run-state.js b/packages/gittensory-miner/lib/run-state.js index 558e506ce7..159cac563d 100644 --- a/packages/gittensory-miner/lib/run-state.js +++ b/packages/gittensory-miner/lib/run-state.js @@ -9,7 +9,7 @@ const defaultDbFileName = "run-state.sqlite3"; let defaultRunStateStore = null; export function resolveRunStateDbPath(env = process.env) { - return resolveLocalStoreDbPath(defaultDbFileName, "GITTENSORY_MINER_RUN_STATE_DB", env); + return resolveLocalStoreDbPath(defaultDbFileName, "LOOPOVER_MINER_RUN_STATE_DB", env); } function normalizeDbPath(dbPath) { diff --git a/packages/gittensory-miner/lib/status.js b/packages/gittensory-miner/lib/status.js index 0382c4957f..760e16cf9d 100644 --- a/packages/gittensory-miner/lib/status.js +++ b/packages/gittensory-miner/lib/status.js @@ -50,8 +50,8 @@ const CONFIG_FILE_CANDIDATES = Object.freeze([ /** The miner's local-state directory (holds the run-state / queue / ledger SQLite files). */ export function resolveMinerStateDir(env = process.env) { - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return explicitConfigDir; diff --git a/packages/gittensory-miner/lib/store-maintenance.js b/packages/gittensory-miner/lib/store-maintenance.js index 02d2f27837..073d2a1bfe 100644 --- a/packages/gittensory-miner/lib/store-maintenance.js +++ b/packages/gittensory-miner/lib/store-maintenance.js @@ -15,8 +15,8 @@ import { existsSync } from "node:fs"; import { DatabaseSync } from "node:sqlite"; /** Env opt-ins for ledger retention (unset ⇒ retention disabled). */ -export const LEDGER_RETENTION_DAYS_ENV = "GITTENSORY_MINER_LEDGER_RETENTION_DAYS"; -export const LEDGER_RETENTION_MAX_ROWS_ENV = "GITTENSORY_MINER_LEDGER_RETENTION_MAX_ROWS"; +export const LEDGER_RETENTION_DAYS_ENV = "LOOPOVER_MINER_LEDGER_RETENTION_DAYS"; +export const LEDGER_RETENTION_MAX_ROWS_ENV = "LOOPOVER_MINER_LEDGER_RETENTION_MAX_ROWS"; /** Fixed retention specs for the three append-only ledgers. These identifiers are INTERNAL constants — never * caller/user text — and are validated as plain identifiers before interpolation as defence in depth. */ diff --git a/packages/gittensory-miner/lib/update-check.js b/packages/gittensory-miner/lib/update-check.js index 551b18035d..c918dc4231 100644 --- a/packages/gittensory-miner/lib/update-check.js +++ b/packages/gittensory-miner/lib/update-check.js @@ -40,7 +40,7 @@ export function resolveUpgradeCommand(packageName = defaultPackageName) { } export function shouldSkipUpdateCheck(cliArgs, env = process.env) { - if (/^(1|true|yes)$/i.test(env.GITTENSORY_MINER_NO_UPDATE_CHECK ?? "")) + if (/^(1|true|yes)$/i.test(env.LOOPOVER_MINER_NO_UPDATE_CHECK ?? "")) return true; return cliArgs.includes("--no-update-check"); } diff --git a/packages/gittensory-miner/lib/version.js b/packages/gittensory-miner/lib/version.js index eb4d31aa5a..866e1f6b41 100644 --- a/packages/gittensory-miner/lib/version.js +++ b/packages/gittensory-miner/lib/version.js @@ -3,8 +3,8 @@ import ownPackageJson from "../package.json" with { type: "json" }; /** Package.json semver at import time — the laptop npm-install default. */ export const MINER_PACKAGE_VERSION = ownPackageJson.version; -/** Resolved miner release id: `GITTENSORY_MINER_VERSION` wins when set (fleet Docker image builds). */ +/** Resolved miner release id: `LOOPOVER_MINER_VERSION` wins when set (fleet Docker image builds). */ export function resolveMinerVersion(env = process.env) { - const override = typeof env.GITTENSORY_MINER_VERSION === "string" ? env.GITTENSORY_MINER_VERSION.trim() : ""; + const override = typeof env.LOOPOVER_MINER_VERSION === "string" ? env.LOOPOVER_MINER_VERSION.trim() : ""; return override || MINER_PACKAGE_VERSION; } diff --git a/packages/gittensory-miner/lib/worktree-allocator.js b/packages/gittensory-miner/lib/worktree-allocator.js index 1a35427c62..c50c83abfd 100644 --- a/packages/gittensory-miner/lib/worktree-allocator.js +++ b/packages/gittensory-miner/lib/worktree-allocator.js @@ -13,13 +13,13 @@ const defaultMaxConcurrency = 2; let defaultWorktreeAllocator = null; export function resolveWorktreeAllocatorDbPath(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB === "string" - ? env.GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB.trim() + const explicitPath = typeof env.LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB === "string" + ? env.LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultDbFileName); @@ -30,13 +30,13 @@ export function resolveWorktreeAllocatorDbPath(env = process.env) { } export function resolveWorktreeBaseDir(env = process.env) { - const explicitPath = typeof env.GITTENSORY_MINER_WORKTREE_DIR === "string" - ? env.GITTENSORY_MINER_WORKTREE_DIR.trim() + const explicitPath = typeof env.LOOPOVER_MINER_WORKTREE_DIR === "string" + ? env.LOOPOVER_MINER_WORKTREE_DIR.trim() : ""; if (explicitPath) return explicitPath; - const explicitConfigDir = typeof env.GITTENSORY_MINER_CONFIG_DIR === "string" - ? env.GITTENSORY_MINER_CONFIG_DIR.trim() + const explicitConfigDir = typeof env.LOOPOVER_MINER_CONFIG_DIR === "string" + ? env.LOOPOVER_MINER_CONFIG_DIR.trim() : ""; if (explicitConfigDir) return join(explicitConfigDir, defaultWorktreeDirName); diff --git a/packages/gittensory-miner/schema/miner-goal-spec.schema.json b/packages/gittensory-miner/schema/miner-goal-spec.schema.json index e6d5a78d7e..da1944f2bf 100644 --- a/packages/gittensory-miner/schema/miner-goal-spec.schema.json +++ b/packages/gittensory-miner/schema/miner-goal-spec.schema.json @@ -103,7 +103,7 @@ "liveModeOptIn": { "type": ["string", "null"], "default": null, - "description": "Must equal exactly \"live\" to opt this repo into live write execution; any other value stays dry-run. Also requires the operator's own global opt-in (GITTENSORY_MINER_LIVE_MODE=live) unless the operator's own config already grants it. Default: null." + "description": "Must equal exactly \"live\" to opt this repo into live write execution; any other value stays dry-run. Also requires the operator's own global opt-in (LOOPOVER_MINER_LIVE_MODE=live) unless the operator's own config already grants it. Default: null." } } } diff --git a/packages/gittensory-miner/scripts/generate-env-reference.mjs b/packages/gittensory-miner/scripts/generate-env-reference.mjs index 153dbff776..618d048c74 100644 --- a/packages/gittensory-miner/scripts/generate-env-reference.mjs +++ b/packages/gittensory-miner/scripts/generate-env-reference.mjs @@ -11,7 +11,7 @@ export const DEFAULT_SOURCE_ROOTS = [ "packages/gittensory-miner/scripts", ]; -const MINER_ENV_PREFIXES = ["GITTENSORY_MINER_", "MINER_"]; +const MINER_ENV_PREFIXES = ["LOOPOVER_MINER_", "MINER_"]; const SOURCE_FILE_EXTENSIONS = new Set([".cjs", ".js", ".mjs", ".ts", ".tsx"]); const DEFAULT_PATTERNS = [ /env\.([A-Z][A-Z0-9_]*)\s*\?\?\s*""/g, diff --git a/packages/gittensory-miner/terraform/README.md b/packages/gittensory-miner/terraform/README.md index e78a60aca5..38463f9f21 100644 --- a/packages/gittensory-miner/terraform/README.md +++ b/packages/gittensory-miner/terraform/README.md @@ -60,4 +60,4 @@ The module provisions the **host**; you finish the miner setup over SSH (secrets | `server_ipv6` | Public IPv6 of the host | | `ssh_command` | Ready-to-run SSH command | | `volume_device` | Block device path for the data volume | -| `data_mount` | `/data/miner` — the miner's `GITTENSORY_MINER_CONFIG_DIR`; the run mount | +| `data_mount` | `/data/miner` — the miner's `LOOPOVER_MINER_CONFIG_DIR`; the run mount | diff --git a/packages/gittensory-miner/terraform/main.tf b/packages/gittensory-miner/terraform/main.tf index 523c5ca5d3..1f5ce29feb 100644 --- a/packages/gittensory-miner/terraform/main.tf +++ b/packages/gittensory-miner/terraform/main.tf @@ -1,6 +1,6 @@ # Terraform starter module for a dedicated fleet-mode AMS (Autonomous Miner System) host on Hetzner Cloud. # Provisions a single, firewalled VM with Docker pre-installed via cloud-init and a persistent volume mounted at -# /data/miner (the miner's built-in GITTENSORY_MINER_CONFIG_DIR default), so the append-only attempt log, +# /data/miner (the miner's built-in LOOPOVER_MINER_CONFIG_DIR default), so the append-only attempt log, # prediction ledger, and every other local store survive instance recreation. # # This is the CLI-worker profile — it exposes NO public endpoints by default (unlike the root terraform/ module, diff --git a/packages/gittensory-miner/terraform/outputs.tf b/packages/gittensory-miner/terraform/outputs.tf index e2d60638eb..6004b99615 100644 --- a/packages/gittensory-miner/terraform/outputs.tf +++ b/packages/gittensory-miner/terraform/outputs.tf @@ -19,6 +19,6 @@ output "volume_device" { } output "data_mount" { - description = "Where the persistent volume is mounted — the miner's GITTENSORY_MINER_CONFIG_DIR. Point the miner container's state mount here." + description = "Where the persistent volume is mounted — the miner's LOOPOVER_MINER_CONFIG_DIR. Point the miner container's state mount here." value = "/data/miner" } diff --git a/scripts/backup-miner.sh b/scripts/backup-miner.sh index d09e5d8656..fa387771b3 100644 --- a/scripts/backup-miner.sh +++ b/scripts/backup-miner.sh @@ -1,6 +1,6 @@ #!/bin/sh # gittensory-miner local-state backup (#4872): every store is an independent SQLite file directly under -# GITTENSORY_MINER_CONFIG_DIR (packages/gittensory-miner/docs/operations-runbook.md's "Local state at a +# LOOPOVER_MINER_CONFIG_DIR (packages/gittensory-miner/docs/operations-runbook.md's "Local state at a # glance") -- there is no Postgres/Qdrant involved, so this is deliberately a simpler sibling to # scripts/backup.sh, not a reuse of it (that script's manifest/multi-target logic has nothing to compose with # here). Backs up EVERY *.sqlite3 file currently present, discovered by glob rather than a hardcoded filename @@ -14,12 +14,12 @@ # # Usage: # sh scripts/backup-miner.sh -# GITTENSORY_MINER_CONFIG_DIR=/data/miner GITTENSORY_MINER_BACKUP_RETAIN=14 sh scripts/backup-miner.sh +# LOOPOVER_MINER_CONFIG_DIR=/data/miner LOOPOVER_MINER_BACKUP_RETAIN=14 sh scripts/backup-miner.sh set -eu -STATE_DIR="${GITTENSORY_MINER_CONFIG_DIR:-$HOME/.config/gittensory-miner}" -OUT_DIR="${GITTENSORY_MINER_BACKUP_DIR:-$STATE_DIR/backups}" -RETAIN="${GITTENSORY_MINER_BACKUP_RETAIN:-7}" +STATE_DIR="${LOOPOVER_MINER_CONFIG_DIR:-$HOME/.config/gittensory-miner}" +OUT_DIR="${LOOPOVER_MINER_BACKUP_DIR:-$STATE_DIR/backups}" +RETAIN="${LOOPOVER_MINER_BACKUP_RETAIN:-7}" if ! command -v sqlite3 >/dev/null 2>&1; then echo "[backup-miner] sqlite3 not found; cannot take a safe online backup" >&2 diff --git a/scripts/export-ams-reporting-db.sh b/scripts/export-ams-reporting-db.sh index 0ec390d513..599f6fa4ef 100644 --- a/scripts/export-ams-reporting-db.sh +++ b/scripts/export-ams-reporting-db.sh @@ -2,7 +2,7 @@ set -eu # AMS (gittensory-miner) redacted reporting export (#5184 follow-up; closes the gap PR #5471 flagged: Grafana must -# never mount the miner's live GITTENSORY_MINER_CONFIG_DIR ledgers directly -- attempt_log_events.reason and +# never mount the miner's live LOOPOVER_MINER_CONFIG_DIR ledgers directly -- attempt_log_events.reason and # .payload_json are free-form and can carry arbitrary internal detail). Mirrors export-grafana-reporting-db.sh's # shape (incremental fingerprint fast-path, atomic tmp-then-move, fail-open on a missing/unreadable source) but is # deliberately a SEPARATE script: the two AMS ledgers are SQLite-only (the miner has no Postgres mode) and each @@ -18,7 +18,7 @@ set -eu # would otherwise serve the previous run's output forever. SCRIPT_VERSION="${GITTENSORY_AMS_REPORTING_SCRIPT_VERSION:-1}" -OUT_DIR="${GITTENSORY_REPORTING_DIR:-/reporting}" +OUT_DIR="${LOOPOVER_REPORTING_DIR:-/reporting}" ATTEMPT_LOG_SOURCE_DB="${GITTENSORY_AMS_ATTEMPT_LOG_SOURCE_DB:-/ams-ledgers/attempt-log.sqlite3}" ATTEMPT_LOG_OUT_DB="${GITTENSORY_AMS_ATTEMPT_LOG_REPORTING_DB:-$OUT_DIR/ams-attempt-log.sqlite}" PREDICTION_LEDGER_SOURCE_DB="${GITTENSORY_AMS_PREDICTION_LEDGER_SOURCE_DB:-/ams-ledgers/prediction-ledger.sqlite3}" diff --git a/scripts/export-grafana-reporting-db.sh b/scripts/export-grafana-reporting-db.sh index 4aef9f9d7d..7123b6d1bd 100644 --- a/scripts/export-grafana-reporting-db.sh +++ b/scripts/export-grafana-reporting-db.sh @@ -9,10 +9,10 @@ set -eu # purely so a test can simulate "the script logic changed" without editing this file. SCRIPT_VERSION="${GITTENSORY_REPORTING_SCRIPT_VERSION:-2}" -APP_DB="${GITTENSORY_REPORTING_SOURCE_DB:-/appdb/loopover.sqlite}" +APP_DB="${LOOPOVER_REPORTING_SOURCE_DB:-/appdb/loopover.sqlite}" PG_DB="${GITTENSORY_REPORTING_SOURCE_DATABASE_URL:-${DATABASE_URL:-}}" -OUT_DIR="${GITTENSORY_REPORTING_DIR:-/reporting}" -OUT_DB="${GITTENSORY_REPORTING_DB:-$OUT_DIR/loopover-reporting.sqlite}" +OUT_DIR="${LOOPOVER_REPORTING_DIR:-/reporting}" +OUT_DB="${LOOPOVER_REPORTING_DB:-$OUT_DIR/loopover-reporting.sqlite}" TMP_DB="${OUT_DB}.tmp" FINGERPRINT_FILE="${OUT_DB}.fingerprint" CSV_TMP_DIR="$(mktemp -d)" diff --git a/scripts/export-miner-prometheus-textfile.sh b/scripts/export-miner-prometheus-textfile.sh index 28122145ea..e0c6606690 100644 --- a/scripts/export-miner-prometheus-textfile.sh +++ b/scripts/export-miner-prometheus-textfile.sh @@ -19,8 +19,8 @@ set -eu # aborting the whole export -- Prometheus treats an absent series as "no data", not an error, so a partial # export is strictly better than a stale-forever or entirely-missing one. -MINER_BIN="${GITTENSORY_MINER_BIN:-gittensory-miner}" -OUT_FILE="${GITTENSORY_MINER_PROMETHEUS_TEXTFILE:-/var/lib/node_exporter/textfile_collector/gittensory_miner.prom}" +MINER_BIN="${LOOPOVER_MINER_BIN:-gittensory-miner}" +OUT_FILE="${LOOPOVER_MINER_PROMETHEUS_TEXTFILE:-/var/lib/node_exporter/textfile_collector/gittensory_miner.prom}" TMP_FILE="${OUT_FILE}.tmp" mkdir -p "$(dirname "$OUT_FILE")" diff --git a/scripts/restore-miner.sh b/scripts/restore-miner.sh index 2bd59690d3..fcd3b0f637 100644 --- a/scripts/restore-miner.sh +++ b/scripts/restore-miner.sh @@ -15,8 +15,8 @@ # sh scripts/restore-miner.sh --yes /path/to/backups/ # restores a specific backup set -eu -STATE_DIR="${GITTENSORY_MINER_CONFIG_DIR:-$HOME/.config/gittensory-miner}" -BACKUP_DIR="${GITTENSORY_MINER_BACKUP_DIR:-$STATE_DIR/backups}" +STATE_DIR="${LOOPOVER_MINER_CONFIG_DIR:-$HOME/.config/gittensory-miner}" +BACKUP_DIR="${LOOPOVER_MINER_BACKUP_DIR:-$STATE_DIR/backups}" usage() { cat <&2 @@ -25,7 +25,7 @@ Usage: $0 --yes [BACKUP_DIR] Restores gittensory-miner local state from a backup produced by backup-miner.sh. BACKUP_DIR A specific timestamped backup directory. Defaults to the newest one - under \$GITTENSORY_MINER_BACKUP_DIR ($BACKUP_DIR). + under \$LOOPOVER_MINER_BACKUP_DIR ($BACKUP_DIR). --yes Required. This OVERWRITES the live state directory ($STATE_DIR). STOP the miner (and any loop/systemd/docker service using this state dir) first -- diff --git a/secrets/README.md b/secrets/README.md index a85b8e3cc2..5040e1d4cd 100644 --- a/secrets/README.md +++ b/secrets/README.md @@ -58,8 +58,8 @@ see the tradeoff explained above for why `600` breaks the app's own ability to r |---|---|---| | `github_app_private_key.pem` | `GITHUB_APP_PRIVATE_KEY_FILE` | Your GitHub App's private key (PEM). | | `github_webhook_secret.txt` | `GITHUB_WEBHOOK_SECRET_FILE` | HMAC key GitHub webhook deliveries are verified against. | -| `loopover_api_token.txt` | `GITTENSORY_API_TOKEN_FILE` | Server-to-server API bearer token. | -| `loopover_mcp_token.txt` | `GITTENSORY_MCP_TOKEN_FILE` | Shared MCP bearer token. | +| `loopover_api_token.txt` | `LOOPOVER_API_TOKEN_FILE` | Server-to-server API bearer token. | +| `loopover_mcp_token.txt` | `LOOPOVER_MCP_TOKEN_FILE` | Shared MCP bearer token. | | `internal_job_token.txt` | `INTERNAL_JOB_TOKEN_FILE` | Gates internal-only routes (e.g. `/v1/internal/*`). | | `selfhost_setup_token.txt` | `SELFHOST_SETUP_TOKEN_FILE` | Unlocks the first-run `/setup` wizard. | | `token_encryption_secret.txt` | `TOKEN_ENCRYPTION_SECRET_FILE` | AES-256-GCM master secret for maintainer BYOK keys at rest. | diff --git a/systemd/gittensory-miner-ui.service.example b/systemd/gittensory-miner-ui.service.example index 3ac72f3e4b..7fc700fa7c 100644 --- a/systemd/gittensory-miner-ui.service.example +++ b/systemd/gittensory-miner-ui.service.example @@ -26,7 +26,7 @@ # journalctl -u gittensory-miner-ui -f # follow the dashboard server's output # # The dashboard reads the SAME local SQLite stores gittensory-miner.service.example's loop daemon writes to -# (see packages/gittensory-miner/README.md's "Local storage" table) -- point GITTENSORY_MINER_CONFIG_DIR at +# (see packages/gittensory-miner/README.md's "Local storage" table) -- point LOOPOVER_MINER_CONFIG_DIR at # the same directory as the loop service's unit if you run both on one host. [Unit] @@ -49,7 +49,7 @@ ExecStart=/usr/bin/npm --workspace @loopover/ui-miner run preview Restart=on-failure RestartSec=10 # Optional overrides (see packages/gittensory-miner/README.md's "Local storage" table for the full list): -# Environment=GITTENSORY_MINER_CONFIG_DIR=/var/lib/gittensory-miner/config +# Environment=LOOPOVER_MINER_CONFIG_DIR=/var/lib/gittensory-miner/config TimeoutStopSec=30 [Install] diff --git a/systemd/gittensory-miner.service.example b/systemd/gittensory-miner.service.example index 62603303a8..8e18d9f74d 100644 --- a/systemd/gittensory-miner.service.example +++ b/systemd/gittensory-miner.service.example @@ -40,7 +40,7 @@ RestartSec=30 # Keep secrets out of this unit file -- use a root-owned 0600 EnvironmentFile instead: # EnvironmentFile=/etc/gittensory-miner.env # Optional overrides (see the package README for the full list): -# Environment=GITTENSORY_MINER_CONFIG_DIR=/var/lib/gittensory-miner/config +# Environment=LOOPOVER_MINER_CONFIG_DIR=/var/lib/gittensory-miner/config # Environment=MINER_CODING_AGENT_PROVIDER=claude-code # Kill switch: `systemctl stop` sends SIGTERM; the loop checks its kill switch each cycle and exits cleanly. TimeoutStopSec=120 diff --git a/test/unit/mcp-feasibility-gate.test.ts b/test/unit/mcp-feasibility-gate.test.ts index 194866cd1b..a92b669ad3 100644 --- a/test/unit/mcp-feasibility-gate.test.ts +++ b/test/unit/mcp-feasibility-gate.test.ts @@ -109,8 +109,8 @@ describe("loopover_feasibility_gate: local claim-ledger sourcing (#5157)", () => async function connectWithLedgerDb(dbPath: string | undefined) { ledgerConfigDir = mkdtempSync(join(tmpdir(), "gittensory-feasibility-gate-ledger-")); const env: Record = { ...(process.env as Record), GITTENSORY_CONFIG_DIR: ledgerConfigDir }; - if (dbPath !== undefined) env.GITTENSORY_MINER_CLAIM_LEDGER_DB = dbPath; - else delete env.GITTENSORY_MINER_CLAIM_LEDGER_DB; + if (dbPath !== undefined) env.LOOPOVER_MINER_CLAIM_LEDGER_DB = dbPath; + else delete env.LOOPOVER_MINER_CLAIM_LEDGER_DB; ledgerTransport = new StdioClientTransport({ command: "node", args: [bin, "--stdio"], env }); ledgerClient = new Client({ name: "feasibility-gate-ledger-test", version: "0.0.1" }); await ledgerClient.connect(ledgerTransport); diff --git a/test/unit/miner-ams-policy.test.ts b/test/unit/miner-ams-policy.test.ts index e7f301bfd7..9eddd395e0 100644 --- a/test/unit/miner-ams-policy.test.ts +++ b/test/unit/miner-ams-policy.test.ts @@ -24,15 +24,15 @@ function tempRoot() { describe("resolveAmsPolicyConfigPath (#5132)", () => { it("resolves from explicit env, config dir, and XDG default, in precedence order", () => { - expect(resolveAmsPolicyConfigPath({ GITTENSORY_MINER_AMS_POLICY_PATH: "/custom/policy.yml" })).toBe("/custom/policy.yml"); - expect(resolveAmsPolicyConfigPath({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe(join("/cfg", ".gittensory-ams.yml")); + expect(resolveAmsPolicyConfigPath({ LOOPOVER_MINER_AMS_POLICY_PATH: "/custom/policy.yml" })).toBe("/custom/policy.yml"); + expect(resolveAmsPolicyConfigPath({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe(join("/cfg", ".gittensory-ams.yml")); }); }); describe("resolveAmsPolicy (#5132)", () => { it("returns the engine's safe defaults when no local operator policy exists", async () => { const root = tempRoot(); - const result = await resolveAmsPolicy("acme/widgets", { env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("acme/widgets", { env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result).toEqual({ spec: DEFAULT_AMS_POLICY_SPEC, source: "default", warnings: [] }); }); @@ -41,7 +41,7 @@ describe("resolveAmsPolicy (#5132)", () => { const fetchImpl = vi.fn(async () => { throw new Error("target repo policy must not be fetched"); }); - const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result).toEqual({ spec: DEFAULT_AMS_POLICY_SPEC, source: "default", warnings: [] }); expect(fetchImpl).not.toHaveBeenCalled(); }); @@ -52,7 +52,7 @@ describe("resolveAmsPolicy (#5132)", () => { const fetchImpl = vi.fn(async () => { throw new Error("target repo policy must not be fetched"); }); - const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result.source).toBe("local"); expect(result.spec.submissionMode).toBe("observe"); expect(result.spec.slopThreshold).toBe("clean"); @@ -67,7 +67,7 @@ describe("resolveAmsPolicy (#5132)", () => { fetchCalls += 1; throw new Error("target repo policy must not be fetched"); }; - const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result.source).toBe("local"); expect(fetchCalls).toBe(0); }); @@ -80,7 +80,7 @@ describe("resolveAmsPolicy (#5132)", () => { fetchCalls += 1; throw new Error("target repo policy must not be fetched"); }; - const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("acme/widgets", { fetchImpl, env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result.source).toBe("local"); expect(result.spec).toEqual(DEFAULT_AMS_POLICY_SPEC); expect(result.warnings.join(" ")).toMatch(/not valid YAML/i); @@ -90,7 +90,7 @@ describe("resolveAmsPolicy (#5132)", () => { it("returns defaults for any repoFullName, without ever calling fetch", async () => { const root = tempRoot(); const fetchImpl = vi.fn(); - const result = await resolveAmsPolicy("not-a-repo", { fetchImpl, env: { GITTENSORY_MINER_CONFIG_DIR: root } }); + const result = await resolveAmsPolicy("not-a-repo", { fetchImpl, env: { LOOPOVER_MINER_CONFIG_DIR: root } }); expect(result).toEqual({ spec: DEFAULT_AMS_POLICY_SPEC, source: "default", warnings: [] }); expect(fetchImpl).not.toHaveBeenCalled(); }); diff --git a/test/unit/miner-attempt-cli.test.ts b/test/unit/miner-attempt-cli.test.ts index 394ee4a31d..4a23d535d0 100644 --- a/test/unit/miner-attempt-cli.test.ts +++ b/test/unit/miner-attempt-cli.test.ts @@ -463,7 +463,7 @@ describe("runAttempt (#5132)", () => { vi.spyOn(console, "log").mockImplementation(() => undefined); const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-governor-state-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ outcome: "submitted", spec: { command: "gh pr create", cwd: "/fake", timeoutMs: 1000 }, @@ -614,7 +614,7 @@ describe("runAttempt (#5132)", () => { vi.spyOn(console, "log").mockImplementation(() => undefined); const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-cli-portfolio-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ outcome: "abandon", loopResult: { outcome: "abandon", totalTurnsUsed: 0, totalCostUsd: 0, iterationsUsed: 0 }, diff --git a/test/unit/miner-attempt-input-builder.test.ts b/test/unit/miner-attempt-input-builder.test.ts index 07efe9df04..d6e2ef1464 100644 --- a/test/unit/miner-attempt-input-builder.test.ts +++ b/test/unit/miner-attempt-input-builder.test.ts @@ -34,7 +34,7 @@ function reviewContext() { describe("buildAttemptGovernorContext (#5132)", () => { it("reflects the global kill switch and live-mode env vars, uses AmsPolicySpec's real capLimits", () => { const ctx = buildAttemptGovernorContext( - { GITTENSORY_MINER_KILL_SWITCH: "1", GITTENSORY_MINER_LIVE_MODE: "live" }, + { LOOPOVER_MINER_KILL_SWITCH: "1", LOOPOVER_MINER_LIVE_MODE: "live" }, { ...DEFAULT_AMS_POLICY_SPEC, capLimits: { budget: 9, turns: 8, elapsedMs: 7 } }, ); expect(ctx.killSwitchGlobal).toBe(true); @@ -80,7 +80,7 @@ describe("buildAttemptGovernorContext (#5132)", () => { it("REGRESSION (#5675): a repo's real unfavorable-outcome streak, threaded through the governor context, throttles the chokepoint", () => { const ctx = buildAttemptGovernorContext( - { GITTENSORY_MINER_LIVE_MODE: "live" }, + { LOOPOVER_MINER_LIVE_MODE: "live" }, DEFAULT_AMS_POLICY_SPEC, false, undefined, diff --git a/test/unit/miner-attempt-log.test.ts b/test/unit/miner-attempt-log.test.ts index 17e19f5f4d..7255f74837 100644 --- a/test/unit/miner-attempt-log.test.ts +++ b/test/unit/miner-attempt-log.test.ts @@ -43,10 +43,10 @@ afterEach(() => { describe("gittensory-miner attempt log (#4294)", () => { it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveAttemptLogDbPath({ GITTENSORY_MINER_ATTEMPT_LOG_DB: "/custom/a.sqlite3" })).toBe( + expect(resolveAttemptLogDbPath({ LOOPOVER_MINER_ATTEMPT_LOG_DB: "/custom/a.sqlite3" })).toBe( "/custom/a.sqlite3", ); - expect(resolveAttemptLogDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveAttemptLogDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/attempt-log.sqlite3", ); expect(resolveAttemptLogDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -213,8 +213,8 @@ describe("gittensory-miner attempt log (#4294)", () => { it("uses the default singleton helpers and closes cleanly", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-log-default-")); roots.push(root); - const previousConfigDir = process.env.GITTENSORY_MINER_CONFIG_DIR; - process.env.GITTENSORY_MINER_CONFIG_DIR = root; + const previousConfigDir = process.env.LOOPOVER_MINER_CONFIG_DIR; + process.env.LOOPOVER_MINER_CONFIG_DIR = root; try { const entry = appendAttemptLogEvent({ eventType: "attempt_started", ...baseEvent }); expect(readAttemptLogEvents()).toEqual([entry]); @@ -222,8 +222,8 @@ describe("gittensory-miner attempt log (#4294)", () => { closeDefaultAttemptLog(); closeDefaultAttemptLog(); } finally { - if (previousConfigDir === undefined) delete process.env.GITTENSORY_MINER_CONFIG_DIR; - else process.env.GITTENSORY_MINER_CONFIG_DIR = previousConfigDir; + if (previousConfigDir === undefined) delete process.env.LOOPOVER_MINER_CONFIG_DIR; + else process.env.LOOPOVER_MINER_CONFIG_DIR = previousConfigDir; } }); diff --git a/test/unit/miner-attempt-runner.test.ts b/test/unit/miner-attempt-runner.test.ts index 7ceadb8e3d..5862416024 100644 --- a/test/unit/miner-attempt-runner.test.ts +++ b/test/unit/miner-attempt-runner.test.ts @@ -270,7 +270,7 @@ describe("runMinerAttempt (#2337) — the real create->review->gate->submit pipe it("falls back to the real default governor-ledger append when governorLedgerAppend is omitted", async () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-runner-default-governor-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_GOVERNOR_LEDGER_DB", join(root, "default-governor.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_GOVERNOR_LEDGER_DB", join(root, "default-governor.sqlite3")); const deps = baseDeps(); delete (deps as { governorLedgerAppend?: unknown }).governorLedgerAppend; @@ -283,7 +283,7 @@ describe("runMinerAttempt (#2337) — the real create->review->gate->submit pipe it("falls back to the real default governor-state store when governorState is omitted", async () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-attempt-runner-default-governor-state-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_GOVERNOR_STATE_DB", join(root, "default-governor-state.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_GOVERNOR_STATE_DB", join(root, "default-governor-state.sqlite3")); const deps = baseDeps(); delete (deps as { governorState?: unknown }).governorState; diff --git a/test/unit/miner-backup-restore-scripts.test.ts b/test/unit/miner-backup-restore-scripts.test.ts index 4ab387becb..c60e33da9f 100644 --- a/test/unit/miner-backup-restore-scripts.test.ts +++ b/test/unit/miner-backup-restore-scripts.test.ts @@ -78,8 +78,8 @@ function runBackup(stateDir: string, backupDir: string, sqliteBin: string, extra encoding: "utf8", env: { ...process.env, - GITTENSORY_MINER_CONFIG_DIR: stateDir, - GITTENSORY_MINER_BACKUP_DIR: backupDir, + LOOPOVER_MINER_CONFIG_DIR: stateDir, + LOOPOVER_MINER_BACKUP_DIR: backupDir, PATH: `${sqliteBin}:${process.env.PATH ?? ""}`, ...extraEnv, }, @@ -98,8 +98,8 @@ function runRestore( encoding: "utf8", env: { ...process.env, - GITTENSORY_MINER_CONFIG_DIR: stateDir, - GITTENSORY_MINER_BACKUP_DIR: backupDir, + LOOPOVER_MINER_CONFIG_DIR: stateDir, + LOOPOVER_MINER_BACKUP_DIR: backupDir, PATH: `${sqliteBin}:${process.env.PATH ?? ""}`, }, stdio: ["ignore", "pipe", "pipe"], @@ -209,7 +209,7 @@ describe("backup-miner.sh", () => { writeFileSync(join(backupDir, ts, "run-state.sqlite3"), "old content"); } - runBackup(stateDir, backupDir, sqliteBin, { GITTENSORY_MINER_BACKUP_RETAIN: "2" }); + runBackup(stateDir, backupDir, sqliteBin, { LOOPOVER_MINER_BACKUP_RETAIN: "2" }); const remaining = readdirSync(backupDir).sort(); // The 3 pre-seeded + 1 new run = 4 total; RETAIN=2 keeps only the 2 newest (by mtime, which favors the @@ -225,7 +225,7 @@ describe("backup-miner.sh", () => { writeFileSync(join(backupDir, "20260101T000000Z", "run-state.sqlite3"), "old good content"); writeSqliteFile(stateDir, "backup-fails.sqlite3"); - expect(() => runBackup(stateDir, backupDir, sqliteBin, { GITTENSORY_MINER_BACKUP_RETAIN: "1" })).toThrow(); + expect(() => runBackup(stateDir, backupDir, sqliteBin, { LOOPOVER_MINER_BACKUP_RETAIN: "1" })).toThrow(); // Both the pre-seeded backup AND the new (failed) run's directory survive -- pruning never ran. expect(readdirSync(backupDir).length).toBe(2); diff --git a/test/unit/miner-calibration-cli.test.ts b/test/unit/miner-calibration-cli.test.ts index 0f4c46aef6..111e4901b3 100644 --- a/test/unit/miner-calibration-cli.test.ts +++ b/test/unit/miner-calibration-cli.test.ts @@ -19,7 +19,7 @@ afterEach(() => { function envForTempStores(): Record { const dir = mkdtempSync(join(tmpdir(), "miner-calibration-cli-")); tempDirs.push(dir); - return { GITTENSORY_MINER_CONFIG_DIR: dir }; + return { LOOPOVER_MINER_CONFIG_DIR: dir }; } function seedPrediction(env: Record, targetId: number, conclusion: string) { diff --git a/test/unit/miner-claim-ledger.test.ts b/test/unit/miner-claim-ledger.test.ts index 3e1192b8b2..c2a4dbfdb1 100644 --- a/test/unit/miner-claim-ledger.test.ts +++ b/test/unit/miner-claim-ledger.test.ts @@ -44,10 +44,10 @@ describe("gittensory-miner claim ledger (#2314)", () => { }); it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveClaimLedgerDbPath({ GITTENSORY_MINER_CLAIM_LEDGER_DB: "/custom/c.sqlite3" })).toBe( + expect(resolveClaimLedgerDbPath({ LOOPOVER_MINER_CLAIM_LEDGER_DB: "/custom/c.sqlite3" })).toBe( "/custom/c.sqlite3", ); - expect(resolveClaimLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveClaimLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/claim-ledger.sqlite3", ); expect(resolveClaimLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -173,7 +173,7 @@ describe("gittensory-miner claim ledger (#2314)", () => { it("top-level claimIssue and listActiveClaims use the default ledger store", () => { const root = tempRoot(); - vi.stubEnv("GITTENSORY_MINER_CLAIM_LEDGER_DB", join(root, "claim-ledger.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_CLAIM_LEDGER_DB", join(root, "claim-ledger.sqlite3")); closeDefaultClaimLedger(); const claim = claimIssue("o/a", 99, "default-store"); expect(claim).toMatchObject({ issueNumber: 99, status: "active" }); @@ -184,7 +184,7 @@ describe("gittensory-miner claim ledger (#2314)", () => { it("top-level recordClaim, releaseClaim, expireClaim, and listClaims use the default ledger store, forwarding apiBaseUrl (#5563)", () => { const root = tempRoot(); - vi.stubEnv("GITTENSORY_MINER_CLAIM_LEDGER_DB", join(root, "claim-ledger.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_CLAIM_LEDGER_DB", join(root, "claim-ledger.sqlite3")); closeDefaultClaimLedger(); const ghClaim = recordClaim({ repoFullName: "o/a", issueNumber: 5, apiBaseUrl: "https://api.github.com" }); const geClaim = recordClaim({ repoFullName: "o/a", issueNumber: 5, apiBaseUrl: "https://ghe.example.com/api/v3" }); diff --git a/test/unit/miner-cli-doctor-checks.test.ts b/test/unit/miner-cli-doctor-checks.test.ts index beeb2c9e5d..dcf13ddcdb 100644 --- a/test/unit/miner-cli-doctor-checks.test.ts +++ b/test/unit/miner-cli-doctor-checks.test.ts @@ -58,7 +58,7 @@ describe("gittensory-miner doctor — coding-agent CLI checks (#4304)", () => { }); it("runDoctorChecks includes both coding-agent CLI checks", () => { - const names = runDoctorChecks({ GITTENSORY_MINER_CONFIG_DIR: tempRoot() }).map((check) => check.name); + const names = runDoctorChecks({ LOOPOVER_MINER_CONFIG_DIR: tempRoot() }).map((check) => check.name); expect(names).toContain("claude-cli-present"); expect(names).toContain("codex-cli-present"); }); @@ -442,7 +442,7 @@ describe("gittensory-miner doctor — credential presence checks (#5170)", () => }); it("runDoctorChecks now includes the github-token and coding-agent-credential checks", () => { - const names = runDoctorChecks({ GITTENSORY_MINER_CONFIG_DIR: tempRoot() }).map((check) => check.name); + const names = runDoctorChecks({ LOOPOVER_MINER_CONFIG_DIR: tempRoot() }).map((check) => check.name); expect(names).toContain("github-token"); expect(names).toContain("coding-agent-credential"); }); @@ -453,7 +453,7 @@ describe("gittensory-miner doctor — credential presence checks (#5170)", () => const checks = runDoctorChecks({ MINER_CODING_AGENT_PROVIDER: "claude-cli", GITHUB_TOKEN: "ghp_present", - GITTENSORY_MINER_CONFIG_DIR: tempRoot(), + LOOPOVER_MINER_CONFIG_DIR: tempRoot(), }); const credential = checks.find((check) => check.name === "coding-agent-credential"); expect(credential?.ok).toBe(false); @@ -468,7 +468,7 @@ describe("gittensory-miner doctor — credential presence checks (#5170)", () => GITHUB_TOKEN: SECRET_GH, CLAUDE_CODE_OAUTH_TOKEN: SECRET_CLAUDE, ANTHROPIC_API_KEY: SECRET_ANTHROPIC, - GITTENSORY_MINER_CONFIG_DIR: tempRoot(), + LOOPOVER_MINER_CONFIG_DIR: tempRoot(), }); for (const check of checks) { expect(check.detail).not.toContain(SECRET_GH); diff --git a/test/unit/miner-cli-e2e.test.ts b/test/unit/miner-cli-e2e.test.ts index 7270d50e60..af9cda6e1b 100644 --- a/test/unit/miner-cli-e2e.test.ts +++ b/test/unit/miner-cli-e2e.test.ts @@ -12,8 +12,8 @@ const roots: string[] = []; function isolatedMinerEnv(configDir: string): Record { return { - GITTENSORY_MINER_CONFIG_DIR: configDir, - GITTENSORY_MINER_NO_UPDATE_CHECK: "1", + LOOPOVER_MINER_CONFIG_DIR: configDir, + LOOPOVER_MINER_NO_UPDATE_CHECK: "1", GITHUB_TOKEN: "e2e-fixture-token", }; } diff --git a/test/unit/miner-cli.test.ts b/test/unit/miner-cli.test.ts index 162261763c..fa6e34faa0 100644 --- a/test/unit/miner-cli.test.ts +++ b/test/unit/miner-cli.test.ts @@ -153,18 +153,18 @@ describe("gittensory-miner startup update check (#2331)", () => { ).toBe("http://localhost:4873"); }); - it("skips the check when --no-update-check or GITTENSORY_MINER_NO_UPDATE_CHECK=1 is set", () => { + it("skips the check when --no-update-check or LOOPOVER_MINER_NO_UPDATE_CHECK=1 is set", () => { expect(shouldSkipUpdateCheck(["--version", "--no-update-check"])).toBe( true, ); expect( shouldSkipUpdateCheck(["version"], { - GITTENSORY_MINER_NO_UPDATE_CHECK: "1", + LOOPOVER_MINER_NO_UPDATE_CHECK: "1", }), ).toBe(true); expect( shouldSkipUpdateCheck(["version"], { - GITTENSORY_MINER_NO_UPDATE_CHECK: "true", + LOOPOVER_MINER_NO_UPDATE_CHECK: "true", }), ).toBe(true); expect(shouldSkipUpdateCheck(["version"], {})).toBe(false); diff --git a/test/unit/miner-config-precedence.test.ts b/test/unit/miner-config-precedence.test.ts index e799c0c702..6d47aef6bc 100644 --- a/test/unit/miner-config-precedence.test.ts +++ b/test/unit/miner-config-precedence.test.ts @@ -17,7 +17,7 @@ import { resolveCodingAgentModeFromConfig } from "../../packages/gittensory-engi describe("miner config precedence (#5198)", () => { describe("kill switch: env global > .gittensory-miner.yml repo pause", () => { it("global env wins when both global env and repo yml pause are set", () => { - expect(resolveDocumentedKillSwitchScope({ GITTENSORY_MINER_KILL_SWITCH: "true" }, true)).toBe("global"); + expect(resolveDocumentedKillSwitchScope({ LOOPOVER_MINER_KILL_SWITCH: "true" }, true)).toBe("global"); }); it("falls back to repo yml pause when global env is unset", () => { diff --git a/test/unit/miner-deployment-doc.test.ts b/test/unit/miner-deployment-doc.test.ts index 952e562667..142a8708dc 100644 --- a/test/unit/miner-deployment-doc.test.ts +++ b/test/unit/miner-deployment-doc.test.ts @@ -12,7 +12,7 @@ describe("miner deployment guide (#2330)", () => { expect(doc).toContain("Fleet mode"); expect(doc).toContain("gittensory-miner status"); expect(doc).toContain("gittensory-miner doctor"); - expect(doc).toContain("GITTENSORY_MINER_CONFIG_DIR"); + expect(doc).toContain("LOOPOVER_MINER_CONFIG_DIR"); expect(doc).toContain("100% client-side"); expect(doc).toContain("credentials"); expect(doc).toContain("docker build"); @@ -29,7 +29,7 @@ describe("miner deployment guide (#2330)", () => { expect(dockerfile).toContain("npm prune --omit=dev --ignore-scripts"); expect(dockerfile).toContain("@loopover/engine"); expect(dockerfile).toContain("USER node"); - expect(dockerfile).toContain("GITTENSORY_MINER_CONFIG_DIR=/data/miner"); + expect(dockerfile).toContain("LOOPOVER_MINER_CONFIG_DIR=/data/miner"); expect(dockerfile).toContain("VOLUME"); expect(dockerfile).toMatch(/No HEALTHCHECK/i); expect(dockerfile).not.toMatch(/GITHUB_TOKEN|ghp_|github_pat_/i); diff --git a/test/unit/miner-deployment-docs-audit.test.ts b/test/unit/miner-deployment-docs-audit.test.ts index 8b6f6170de..69bfd8cc29 100644 --- a/test/unit/miner-deployment-docs-audit.test.ts +++ b/test/unit/miner-deployment-docs-audit.test.ts @@ -79,9 +79,9 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { expect(reality.hasEnvRead("MINER_CODING_AGENT_TIMEOUT_MS")).toBe(true); }); - it("extracts every documented GITTENSORY_MINER_* / MINER_* env var", () => { - expect(claims.envVars).toContain("GITTENSORY_MINER_CONFIG_DIR"); - expect(claims.envVars.every((name) => /^(?:GITTENSORY_MINER|MINER)_/.test(name))).toBe(true); + it("extracts every documented LOOPOVER_MINER_* / MINER_* env var", () => { + expect(claims.envVars).toContain("LOOPOVER_MINER_CONFIG_DIR"); + expect(claims.envVars.every((name) => /^(?:LOOPOVER_MINER|MINER)_/.test(name))).toBe(true); }); it("extracts repo-relative file paths and drops external issue links", () => { @@ -111,8 +111,8 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { it("scanEnvVarTokens keeps the namespaced token whole and finds bare MINER_* aliases", () => { expect( - [...scanEnvVarTokens("read GITTENSORY_MINER_CONFIG_DIR and MINER_PING_STATUS here")].sort(), - ).toEqual(["GITTENSORY_MINER_CONFIG_DIR", "MINER_PING_STATUS"]); + [...scanEnvVarTokens("read LOOPOVER_MINER_CONFIG_DIR and MINER_PING_STATUS here")].sort(), + ).toEqual(["LOOPOVER_MINER_CONFIG_DIR", "MINER_PING_STATUS"]); expect(scanEnvVarTokens("no env vars here").size).toBe(0); }); @@ -144,21 +144,21 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { it("auditDeploymentDocs reports ok when every claim is backed by reality", () => { const result = auditDeploymentDocs( - { envVars: ["GITTENSORY_MINER_CONFIG_DIR"], filePaths: ["Dockerfile"], subcommands: ["loop"] }, + { envVars: ["LOOPOVER_MINER_CONFIG_DIR"], filePaths: ["Dockerfile"], subcommands: ["loop"] }, ALWAYS_IN_SYNC, ); expect(result).toEqual({ ok: true, failures: [] }); }); it("flags a documented env var with no corresponding read (renamed-var regression)", () => { - // Regression: an operator renames GITTENSORY_MINER_CONFIG_DIR in code but leaves the doc untouched. + // Regression: an operator renames LOOPOVER_MINER_CONFIG_DIR in code but leaves the doc untouched. const result = auditDeploymentDocs( - { envVars: ["GITTENSORY_MINER_CONFIG_DIR"], filePaths: [], subcommands: [] }, - { ...ALWAYS_IN_SYNC, hasEnvRead: (name) => name !== "GITTENSORY_MINER_CONFIG_DIR" }, + { envVars: ["LOOPOVER_MINER_CONFIG_DIR"], filePaths: [], subcommands: [] }, + { ...ALWAYS_IN_SYNC, hasEnvRead: (name) => name !== "LOOPOVER_MINER_CONFIG_DIR" }, ); expect(result.ok).toBe(false); expect(result.failures).toHaveLength(1); - expect(result.failures[0]).toContain("GITTENSORY_MINER_CONFIG_DIR"); + expect(result.failures[0]).toContain("LOOPOVER_MINER_CONFIG_DIR"); expect(result.failures[0]).toContain("no read"); }); @@ -187,10 +187,10 @@ describe("gittensory-miner DEPLOYMENT.md docs-accuracy audit (#5180)", () => { it("assertDeploymentDocsInSync throws and names every stale claim at once", () => { expect(() => assertDeploymentDocsInSync( - { envVars: ["GITTENSORY_MINER_GONE"], filePaths: ["gone.yml"], subcommands: ["gone"] }, + { envVars: ["LOOPOVER_MINER_GONE"], filePaths: ["gone.yml"], subcommands: ["gone"] }, { hasEnvRead: () => false, pathExists: () => false, isRegisteredCommand: () => false }, ), - ).toThrow(/GITTENSORY_MINER_GONE[\s\S]*gone\.yml[\s\S]*gittensory-miner gone/); + ).toThrow(/LOOPOVER_MINER_GONE[\s\S]*gone\.yml[\s\S]*gittensory-miner gone/); }); it("assertDeploymentDocsInSync returns the ok result without throwing when in sync", () => { diff --git a/test/unit/miner-discover-cli.test.ts b/test/unit/miner-discover-cli.test.ts index d3f7775fe1..83034cb205 100644 --- a/test/unit/miner-discover-cli.test.ts +++ b/test/unit/miner-discover-cli.test.ts @@ -573,8 +573,8 @@ describe("runDiscover (#4247)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-discover-cli-default-")); roots.push(root); const dbPath = join(root, "portfolio-queue.sqlite3"); - const previousDbPath = process.env.GITTENSORY_MINER_PORTFOLIO_QUEUE_DB; - process.env.GITTENSORY_MINER_PORTFOLIO_QUEUE_DB = dbPath; + const previousDbPath = process.env.LOOPOVER_MINER_PORTFOLIO_QUEUE_DB; + process.env.LOOPOVER_MINER_PORTFOLIO_QUEUE_DB = dbPath; try { const fetchCandidateIssuesWithSummary = vi.fn(async () => ({ issues: [fanOutIssue({ issueNumber: 5 })], @@ -599,8 +599,8 @@ describe("runDiscover (#4247)", () => { stores.push(reopened); expect(reopened.listQueue().map((entry) => entry.identifier)).toEqual(["issue:5"]); } finally { - if (previousDbPath === undefined) delete process.env.GITTENSORY_MINER_PORTFOLIO_QUEUE_DB; - else process.env.GITTENSORY_MINER_PORTFOLIO_QUEUE_DB = previousDbPath; + if (previousDbPath === undefined) delete process.env.LOOPOVER_MINER_PORTFOLIO_QUEUE_DB; + else process.env.LOOPOVER_MINER_PORTFOLIO_QUEUE_DB = previousDbPath; } }); @@ -762,8 +762,8 @@ describe("runDiscover (#4247)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-discover-cli-pdc-default-")); roots.push(root); const cacheDbPath = join(root, "policy-doc-cache.sqlite3"); - const previousCacheDbPath = process.env.GITTENSORY_MINER_POLICY_DOC_CACHE_DB; - process.env.GITTENSORY_MINER_POLICY_DOC_CACHE_DB = cacheDbPath; + const previousCacheDbPath = process.env.LOOPOVER_MINER_POLICY_DOC_CACHE_DB; + process.env.LOOPOVER_MINER_POLICY_DOC_CACHE_DB = cacheDbPath; try { const portfolioQueue = tempQueueStore(); const fetchCandidateIssuesWithSummary = vi.fn(async () => ({ @@ -790,8 +790,8 @@ describe("runDiscover (#4247)", () => { stores.push(reopened); expect(reopened.get("https://api.github.com/repos/acme/widgets/contents/AI-USAGE.md")).toBeNull(); } finally { - if (previousCacheDbPath === undefined) delete process.env.GITTENSORY_MINER_POLICY_DOC_CACHE_DB; - else process.env.GITTENSORY_MINER_POLICY_DOC_CACHE_DB = previousCacheDbPath; + if (previousCacheDbPath === undefined) delete process.env.LOOPOVER_MINER_POLICY_DOC_CACHE_DB; + else process.env.LOOPOVER_MINER_POLICY_DOC_CACHE_DB = previousCacheDbPath; } }); @@ -832,8 +832,8 @@ describe("runDiscover (#4247)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-discover-cli-pvc-default-")); roots.push(root); const cacheDbPath = join(root, "policy-verdict-cache.sqlite3"); - const previousCacheDbPath = process.env.GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB; - process.env.GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB = cacheDbPath; + const previousCacheDbPath = process.env.LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB; + process.env.LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB = cacheDbPath; try { const portfolioQueue = tempQueueStore(); const fetchCandidateIssuesWithSummary = vi.fn(async () => ({ @@ -860,8 +860,8 @@ describe("runDiscover (#4247)", () => { stores.push(reopened); expect(reopened.get("acme/widgets")).toBeNull(); } finally { - if (previousCacheDbPath === undefined) delete process.env.GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB; - else process.env.GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB = previousCacheDbPath; + if (previousCacheDbPath === undefined) delete process.env.LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB; + else process.env.LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB = previousCacheDbPath; } }); @@ -942,8 +942,8 @@ describe("runDiscover (#4247)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-discover-cli-rc-default-")); roots.push(root); const rankedCandidatesDbPath = join(root, "ranked-candidates.sqlite3"); - const previousDbPath = process.env.GITTENSORY_MINER_RANKED_CANDIDATES_DB; - process.env.GITTENSORY_MINER_RANKED_CANDIDATES_DB = rankedCandidatesDbPath; + const previousDbPath = process.env.LOOPOVER_MINER_RANKED_CANDIDATES_DB; + process.env.LOOPOVER_MINER_RANKED_CANDIDATES_DB = rankedCandidatesDbPath; try { const portfolioQueue = tempQueueStore(); const fetchCandidateIssuesWithSummary = vi.fn(async () => ({ @@ -970,8 +970,8 @@ describe("runDiscover (#4247)", () => { stores.push(reopened); expect(reopened.listRankedCandidates()).toHaveLength(1); } finally { - if (previousDbPath === undefined) delete process.env.GITTENSORY_MINER_RANKED_CANDIDATES_DB; - else process.env.GITTENSORY_MINER_RANKED_CANDIDATES_DB = previousDbPath; + if (previousDbPath === undefined) delete process.env.LOOPOVER_MINER_RANKED_CANDIDATES_DB; + else process.env.LOOPOVER_MINER_RANKED_CANDIDATES_DB = previousDbPath; } }); diff --git a/test/unit/miner-docker-compose.test.ts b/test/unit/miner-docker-compose.test.ts index 2724dafac4..431431d869 100644 --- a/test/unit/miner-docker-compose.test.ts +++ b/test/unit/miner-docker-compose.test.ts @@ -38,9 +38,9 @@ describe("docker-compose.miner.yml (#5177)", () => { const envBlock = JSON.stringify(miner.environment ?? {}); // no secret-named key is assigned a value directly in the compose `environment` block expect(envBlock).not.toMatch(/TOKEN|API_KEY|SECRET|PASSWORD/i); - // regression: GITTENSORY_MINER_CONFIG_DIR must NOT be pinned in `environment` — Compose's `environment` + // regression: LOOPOVER_MINER_CONFIG_DIR must NOT be pinned in `environment` — Compose's `environment` // silently overrides `env_file`, so pinning it here would make any env-file override a dead footgun. - expect(envBlock).not.toMatch(/GITTENSORY_MINER_CONFIG_DIR/); + expect(envBlock).not.toMatch(/LOOPOVER_MINER_CONFIG_DIR/); }); it("gitignores the operator's real env file while keeping the committed example", () => { diff --git a/test/unit/miner-env-file-indirection.test.ts b/test/unit/miner-env-file-indirection.test.ts index 0eb2e0dddb..476d5407ab 100644 --- a/test/unit/miner-env-file-indirection.test.ts +++ b/test/unit/miner-env-file-indirection.test.ts @@ -138,7 +138,7 @@ describe("loadMinerFileSecrets (#5178)", () => { encoding: "utf8", env: { ...process.env, - GITTENSORY_MINER_CONFIG_DIR: join(root, "state"), + LOOPOVER_MINER_CONFIG_DIR: join(root, "state"), GITHUB_TOKEN: "", GITHUB_TOKEN_FILE: secretPath, }, diff --git a/test/unit/miner-env-reference-script.test.ts b/test/unit/miner-env-reference-script.test.ts index 9feaaa62ae..d45e10d5f5 100644 --- a/test/unit/miner-env-reference-script.test.ts +++ b/test/unit/miner-env-reference-script.test.ts @@ -17,9 +17,9 @@ function fixtureRoot(): string { [ "export function readEnv(env = process.env) {", " const ignored = process.env.OTHER_APP_VAR;", - " const config = env.GITTENSORY_MINER_CONFIG_DIR ?? '';", + " const config = env.LOOPOVER_MINER_CONFIG_DIR ?? '';", " const provider = env.MINER_CODING_AGENT_PROVIDER ?? '';", - " return resolveLocalStoreDbPath('state.sqlite3', 'GITTENSORY_MINER_RUN_STATE_DB', env);", + " return resolveLocalStoreDbPath('state.sqlite3', 'LOOPOVER_MINER_RUN_STATE_DB', env);", "}", "", ].join("\n"), @@ -28,7 +28,7 @@ function fixtureRoot(): string { join(root, "packages", "gittensory-miner", "lib", "b.js"), [ "export function duplicate(env = process.env) {", - " return env.GITTENSORY_MINER_CONFIG_DIR;", + " return env.LOOPOVER_MINER_CONFIG_DIR;", "}", "", ].join("\n"), @@ -37,8 +37,8 @@ function fixtureRoot(): string { } describe("generate-env-reference (#5179)", () => { - it("filters to GITTENSORY_MINER_* and MINER_* vars only", () => { - expect(isMinerEnvVar("GITTENSORY_MINER_CONFIG_DIR")).toBe(true); + it("filters to LOOPOVER_MINER_* and MINER_* vars only", () => { + expect(isMinerEnvVar("LOOPOVER_MINER_CONFIG_DIR")).toBe(true); expect(isMinerEnvVar("MINER_CODING_AGENT_PROVIDER")).toBe(true); expect(isMinerEnvVar("OTHER_APP_VAR")).toBe(false); }); @@ -46,12 +46,12 @@ describe("generate-env-reference (#5179)", () => { it("extracts static env reads, resolveLocalStoreDbPath names, and first references", () => { expect(collectMinerEnvVars({ rootDir: fixtureRoot() })).toEqual([ { - name: "GITTENSORY_MINER_CONFIG_DIR", + name: "LOOPOVER_MINER_CONFIG_DIR", firstReference: "lib/a.js", defaultValue: "", }, { - name: "GITTENSORY_MINER_RUN_STATE_DB", + name: "LOOPOVER_MINER_RUN_STATE_DB", firstReference: "lib/a.js", defaultValue: null, }, @@ -66,8 +66,8 @@ describe("generate-env-reference (#5179)", () => { it("renders a deterministic markdown table with names, references, and defaults", () => { expect( renderMinerEnvReferenceMarkdown([ - { name: "GITTENSORY_MINER_CONFIG_DIR", firstReference: "lib/a.js", defaultValue: "" }, - { name: "GITTENSORY_MINER_RUN_STATE_DB", firstReference: "lib/run-state.js", defaultValue: null }, + { name: "LOOPOVER_MINER_CONFIG_DIR", firstReference: "lib/a.js", defaultValue: "" }, + { name: "LOOPOVER_MINER_RUN_STATE_DB", firstReference: "lib/run-state.js", defaultValue: null }, ]), ).toBe( [ @@ -77,8 +77,8 @@ describe("generate-env-reference (#5179)", () => { "", "| Name | First reference | Default |", "| --- | --- | --- |", - "| `GITTENSORY_MINER_CONFIG_DIR` | `lib/a.js` | `\"\"` |", - "| `GITTENSORY_MINER_RUN_STATE_DB` | `lib/run-state.js` | (none) |", + "| `LOOPOVER_MINER_CONFIG_DIR` | `lib/a.js` | `\"\"` |", + "| `LOOPOVER_MINER_RUN_STATE_DB` | `lib/run-state.js` | (none) |", "", ].join("\n"), ); @@ -93,7 +93,7 @@ describe("generate-env-reference (#5179)", () => { expect(written.changed).toBe(true); expect(existsSync(outputAbs)).toBe(true); const generated = readFileSync(outputAbs, "utf8"); - expect(generated).toContain("GITTENSORY_MINER_CONFIG_DIR"); + expect(generated).toContain("LOOPOVER_MINER_CONFIG_DIR"); expect(writeMinerEnvReference({ rootDir: root, outputPath, check: true }).changed).toBe(false); diff --git a/test/unit/miner-event-ledger-cli.test.ts b/test/unit/miner-event-ledger-cli.test.ts index 2518a6a16b..f6bab5499c 100644 --- a/test/unit/miner-event-ledger-cli.test.ts +++ b/test/unit/miner-event-ledger-cli.test.ts @@ -208,14 +208,14 @@ describe("gittensory-miner ledger metrics CLI (#4841)", () => { seed.appendEvent({ type: "plan_built", payload: { steps: 1 } }); seed.close(); - const prev = process.env.GITTENSORY_MINER_EVENT_LEDGER_DB; - process.env.GITTENSORY_MINER_EVENT_LEDGER_DB = dbPath; + const prev = process.env.LOOPOVER_MINER_EVENT_LEDGER_DB; + process.env.LOOPOVER_MINER_EVENT_LEDGER_DB = dbPath; const log = vi.spyOn(console, "log").mockImplementation(() => undefined); try { expect(runLedgerMetrics([])).toBe(0); } finally { - if (prev === undefined) delete process.env.GITTENSORY_MINER_EVENT_LEDGER_DB; - else process.env.GITTENSORY_MINER_EVENT_LEDGER_DB = prev; + 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'); }); diff --git a/test/unit/miner-event-ledger.test.ts b/test/unit/miner-event-ledger.test.ts index f5e85278c5..a9c874f9f5 100644 --- a/test/unit/miner-event-ledger.test.ts +++ b/test/unit/miner-event-ledger.test.ts @@ -27,10 +27,10 @@ afterEach(() => { describe("gittensory-miner event ledger (#2290)", () => { it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveEventLedgerDbPath({ GITTENSORY_MINER_EVENT_LEDGER_DB: "/custom/e.sqlite3" })).toBe( + expect(resolveEventLedgerDbPath({ LOOPOVER_MINER_EVENT_LEDGER_DB: "/custom/e.sqlite3" })).toBe( "/custom/e.sqlite3", ); - expect(resolveEventLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveEventLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/event-ledger.sqlite3", ); expect(resolveEventLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( diff --git a/test/unit/miner-extension-content.test.ts b/test/unit/miner-extension-content.test.ts index 1b04365285..5eaf8e9ce0 100644 --- a/test/unit/miner-extension-content.test.ts +++ b/test/unit/miner-extension-content.test.ts @@ -210,7 +210,7 @@ describe("miner extension opportunity badge", () => { "#syncNow": { addEventListener: () => {} }, }; const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, TextEncoder, document: { querySelector: (selector: string) => elements[selector as keyof typeof elements] ?? null }, chrome: { @@ -349,7 +349,7 @@ describe("miner extension opportunity badge", () => { "#syncNow": { addEventListener: () => {} }, }; const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, Date: { now: () => fakeNowMs }, TextEncoder, document: { querySelector: (selector: string) => elements[selector as keyof typeof elements] ?? null }, @@ -402,7 +402,7 @@ describe("miner extension opportunity badge", () => { "#syncNow": { addEventListener: () => {} }, }; const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, TextEncoder, document: { querySelector: (selector: string) => elements[selector as keyof typeof elements] ?? null }, chrome: { @@ -482,7 +482,7 @@ function createMockContainer() { function loadBadgeInternals() { const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, }; context.globalThis = context; const vmContext = createContext(context); @@ -501,7 +501,7 @@ function loadBadgeInternals() { function loadContentInternals() { const badge = loadBadgeInternals(); const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, __gittensoryMinerOpportunityBadge: badge, location: { pathname: "/JSONbored/gittensory/pull/146" }, document: { @@ -532,7 +532,7 @@ function loadBackgroundInternals({ rankedCandidatesSavedAt = null as number | null, } = {}) { const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, chrome: { storage: { sync: { @@ -565,7 +565,7 @@ function loadBackgroundInternals({ function loadOptionsInternals() { const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, TextEncoder, document: { querySelector: () => null }, chrome: { diff --git a/test/unit/miner-extension-live-fetch.test.ts b/test/unit/miner-extension-live-fetch.test.ts index 174f1913a6..c4eeffd50e 100644 --- a/test/unit/miner-extension-live-fetch.test.ts +++ b/test/unit/miner-extension-live-fetch.test.ts @@ -72,7 +72,7 @@ function loadBackgroundWithFakeChrome({ } const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, chrome, fetch: fetchImpl, }; @@ -241,7 +241,7 @@ describe("options.js miner-UI URL field + Sync now button (#4859)", () => { "#syncNow": createClickMock(), }; const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, TextEncoder, document: { querySelector: (selector: string) => elements[selector as keyof typeof elements] ?? null }, chrome: { diff --git a/test/unit/miner-governor-action-mode.test.ts b/test/unit/miner-governor-action-mode.test.ts index ffad7c7d6a..e90ecc5005 100644 --- a/test/unit/miner-governor-action-mode.test.ts +++ b/test/unit/miner-governor-action-mode.test.ts @@ -35,7 +35,7 @@ describe("resolveMinerActionModeGate (#2342)", () => { it("the operator's global env opt-in alone also stays dry_run without repo opt-in", () => { expect( - resolveMinerActionModeGate({ killSwitchScope: "none", env: { GITTENSORY_MINER_LIVE_MODE: "live" } }), + resolveMinerActionModeGate({ killSwitchScope: "none", env: { LOOPOVER_MINER_LIVE_MODE: "live" } }), ).toEqual({ mode: "dry_run", executes: false }); }); @@ -44,34 +44,34 @@ describe("resolveMinerActionModeGate (#2342)", () => { resolveMinerActionModeGate({ killSwitchScope: "none", repoLiveModeOptIn: "live", - env: { GITTENSORY_MINER_LIVE_MODE: "live" }, + env: { LOOPOVER_MINER_LIVE_MODE: "live" }, }), ).toEqual({ mode: "live", executes: true }); }); it("a near-miss opt-in value stays dry_run (fail closed)", () => { expect( - resolveMinerActionModeGate({ killSwitchScope: "none", repoLiveModeOptIn: "YES", env: { GITTENSORY_MINER_LIVE_MODE: "1" } }), + resolveMinerActionModeGate({ killSwitchScope: "none", repoLiveModeOptIn: "YES", env: { LOOPOVER_MINER_LIVE_MODE: "1" } }), ).toEqual({ mode: "dry_run", executes: false }); }); it("the kill-switch always wins over a live opt-in", () => { expect( - resolveMinerActionModeGate({ killSwitchScope: "repo", repoLiveModeOptIn: "live", env: { GITTENSORY_MINER_LIVE_MODE: "live" } }), + resolveMinerActionModeGate({ killSwitchScope: "repo", repoLiveModeOptIn: "live", env: { LOOPOVER_MINER_LIVE_MODE: "live" } }), ).toEqual({ mode: "paused", executes: false }); }); it("defaults to reading process.env when no env override is given", () => { - const original = process.env.GITTENSORY_MINER_LIVE_MODE; + const original = process.env.LOOPOVER_MINER_LIVE_MODE; try { - process.env.GITTENSORY_MINER_LIVE_MODE = "live"; + process.env.LOOPOVER_MINER_LIVE_MODE = "live"; expect(resolveMinerActionModeGate({ killSwitchScope: "none", repoLiveModeOptIn: "live" })).toEqual({ mode: "live", executes: true, }); } finally { - if (original === undefined) delete process.env.GITTENSORY_MINER_LIVE_MODE; - else process.env.GITTENSORY_MINER_LIVE_MODE = original; + if (original === undefined) delete process.env.LOOPOVER_MINER_LIVE_MODE; + else process.env.LOOPOVER_MINER_LIVE_MODE = original; } }); }); diff --git a/test/unit/miner-governor-chokepoint-persisted.test.ts b/test/unit/miner-governor-chokepoint-persisted.test.ts index 351980f5cd..394d831c16 100644 --- a/test/unit/miner-governor-chokepoint-persisted.test.ts +++ b/test/unit/miner-governor-chokepoint-persisted.test.ts @@ -162,14 +162,14 @@ describe("evaluateGovernorChokepointGatePersisted (#5134)", () => { it("opens and closes its own default governor-state store when the caller supplies none", () => { const { root, ledger } = tempStore(); - process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB = join(root, "governor-state.sqlite3"); + process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB = join(root, "governor-state.sqlite3"); try { const result = evaluateGovernorChokepointGatePersisted(baseInput(), { append: (event) => ledger.appendGovernorEvent(event as never), }); expect(result.decision.allowed).toBe(true); } finally { - delete process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB; + delete process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; } // The default store's mutation was persisted to the same on-disk file a reopened handle can see. diff --git a/test/unit/miner-governor-kill-switch.test.ts b/test/unit/miner-governor-kill-switch.test.ts index c1b39e7053..2b4dea6c04 100644 --- a/test/unit/miner-governor-kill-switch.test.ts +++ b/test/unit/miner-governor-kill-switch.test.ts @@ -20,11 +20,11 @@ afterEach(() => { describe("checkMinerKillSwitch (#2341)", () => { it("global env switch halts regardless of per-repo state", () => { - expect(checkMinerKillSwitch({ repoPaused: false, env: { GITTENSORY_MINER_KILL_SWITCH: "true" } })).toEqual({ + expect(checkMinerKillSwitch({ repoPaused: false, env: { LOOPOVER_MINER_KILL_SWITCH: "true" } })).toEqual({ scope: "global", active: true, }); - expect(checkMinerKillSwitch({ repoPaused: true, env: { GITTENSORY_MINER_KILL_SWITCH: "true" } })).toEqual({ + expect(checkMinerKillSwitch({ repoPaused: true, env: { LOOPOVER_MINER_KILL_SWITCH: "true" } })).toEqual({ scope: "global", active: true, }); @@ -36,13 +36,13 @@ describe("checkMinerKillSwitch (#2341)", () => { }); it("defaults to reading process.env when no env override is given", () => { - const original = process.env.GITTENSORY_MINER_KILL_SWITCH; + const original = process.env.LOOPOVER_MINER_KILL_SWITCH; try { - process.env.GITTENSORY_MINER_KILL_SWITCH = "1"; + process.env.LOOPOVER_MINER_KILL_SWITCH = "1"; expect(checkMinerKillSwitch({ repoPaused: false })).toEqual({ scope: "global", active: true }); } finally { - if (original === undefined) delete process.env.GITTENSORY_MINER_KILL_SWITCH; - else process.env.GITTENSORY_MINER_KILL_SWITCH = original; + if (original === undefined) delete process.env.LOOPOVER_MINER_KILL_SWITCH; + else process.env.LOOPOVER_MINER_KILL_SWITCH = original; } }); }); diff --git a/test/unit/miner-governor-ledger.test.ts b/test/unit/miner-governor-ledger.test.ts index 520a4b393e..8631b7e38f 100644 --- a/test/unit/miner-governor-ledger.test.ts +++ b/test/unit/miner-governor-ledger.test.ts @@ -35,10 +35,10 @@ afterEach(() => { describe("gittensory-miner governor ledger (#2328)", () => { it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveGovernorLedgerDbPath({ GITTENSORY_MINER_GOVERNOR_LEDGER_DB: "/custom/g.sqlite3" })).toBe( + expect(resolveGovernorLedgerDbPath({ LOOPOVER_MINER_GOVERNOR_LEDGER_DB: "/custom/g.sqlite3" })).toBe( "/custom/g.sqlite3", ); - expect(resolveGovernorLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveGovernorLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/governor-ledger.sqlite3", ); expect(resolveGovernorLedgerDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -197,8 +197,8 @@ describe("gittensory-miner governor ledger (#2328)", () => { it("uses the default singleton ledger helpers and closes cleanly", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-default-")); roots.push(root); - const previousConfigDir = process.env.GITTENSORY_MINER_CONFIG_DIR; - process.env.GITTENSORY_MINER_CONFIG_DIR = root; + const previousConfigDir = process.env.LOOPOVER_MINER_CONFIG_DIR; + process.env.LOOPOVER_MINER_CONFIG_DIR = root; try { const entry = appendGovernorEvent({ eventType: "allowed", @@ -210,8 +210,8 @@ describe("gittensory-miner governor ledger (#2328)", () => { closeDefaultGovernorLedger(); closeDefaultGovernorLedger(); } finally { - if (previousConfigDir === undefined) delete process.env.GITTENSORY_MINER_CONFIG_DIR; - else process.env.GITTENSORY_MINER_CONFIG_DIR = previousConfigDir; + if (previousConfigDir === undefined) delete process.env.LOOPOVER_MINER_CONFIG_DIR; + else process.env.LOOPOVER_MINER_CONFIG_DIR = previousConfigDir; } }); }); diff --git a/test/unit/miner-governor-metrics-cli.test.ts b/test/unit/miner-governor-metrics-cli.test.ts index 8833547f55..5004c156be 100644 --- a/test/unit/miner-governor-metrics-cli.test.ts +++ b/test/unit/miner-governor-metrics-cli.test.ts @@ -208,15 +208,15 @@ describe("runGovernorMetrics (#5187)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-metrics-cli-default-")); roots.push(root); const dbPath = join(root, "governor-state.sqlite3"); - const previousDbPath = process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB; - process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB = dbPath; + const previousDbPath = process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; + process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB = dbPath; try { const log = vi.spyOn(console, "log").mockImplementation(() => undefined); expect(await runGovernorMetrics([])).toBe(0); expect(log).toHaveBeenCalled(); } finally { - if (previousDbPath === undefined) delete process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB; - else process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB = previousDbPath; + if (previousDbPath === undefined) delete process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; + else process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB = previousDbPath; } }); diff --git a/test/unit/miner-governor-pause-cli.test.ts b/test/unit/miner-governor-pause-cli.test.ts index 6f8b3e47ec..c076881149 100644 --- a/test/unit/miner-governor-pause-cli.test.ts +++ b/test/unit/miner-governor-pause-cli.test.ts @@ -251,8 +251,8 @@ describe("gittensory-miner governor pause/resume/status CLI (#4851)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-pause-cli-default-")); roots.push(root); const dbPath = join(root, "governor-state.sqlite3"); - const previousDbPath = process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB; - process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB = dbPath; + const previousDbPath = process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; + process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB = dbPath; try { vi.spyOn(console, "log").mockImplementation(() => undefined); expect(await runGovernorPause(["--reason", "default path"])).toBe(0); @@ -261,8 +261,8 @@ describe("gittensory-miner governor pause/resume/status CLI (#4851)", () => { states.push(reopened); expect(reopened.loadPauseState()).toMatchObject({ paused: true, reason: "default path" }); } finally { - if (previousDbPath === undefined) delete process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB; - else process.env.GITTENSORY_MINER_GOVERNOR_STATE_DB = previousDbPath; + if (previousDbPath === undefined) delete process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB; + else process.env.LOOPOVER_MINER_GOVERNOR_STATE_DB = previousDbPath; } }); }); diff --git a/test/unit/miner-governor-state.test.ts b/test/unit/miner-governor-state.test.ts index 65bf23d9d0..4fb2e8cfb9 100644 --- a/test/unit/miner-governor-state.test.ts +++ b/test/unit/miner-governor-state.test.ts @@ -413,7 +413,7 @@ describe("governor-state module-level default singleton (#5134)", () => { it("loadPauseState/savePauseState module-level wrappers round-trip through the default singleton (#4851)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-state-singleton-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); expect(loadPauseState()).toEqual({ paused: false, reason: null, pausedAt: null }); const written = savePauseState({ paused: true, reason: "singleton pause" }); expect(written).toMatchObject({ paused: true, reason: "singleton pause" }); @@ -423,7 +423,7 @@ describe("governor-state module-level default singleton (#5134)", () => { it("loadReputationHistory/saveReputationHistory module-level wrappers round-trip through the default singleton, forwarding apiBaseUrl (#5563)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-governor-state-singleton-reputation-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_GOVERNOR_STATE_DB", join(root, "governor-state.sqlite3")); expect(loadReputationHistory("acme/widgets", "https://ghe.example.com/api/v3")).toEqual({ decided: 0, unfavorable: 0, diff --git a/test/unit/miner-init-verify-token.test.ts b/test/unit/miner-init-verify-token.test.ts index 8c736f5271..0259a227e6 100644 --- a/test/unit/miner-init-verify-token.test.ts +++ b/test/unit/miner-init-verify-token.test.ts @@ -12,7 +12,7 @@ function makeTempEnv() { return { env: { ...process.env, - GITTENSORY_MINER_CONFIG_DIR: configDir, + LOOPOVER_MINER_CONFIG_DIR: configDir, }, configDir, dbPath: join(configDir, "laptop-state.sqlite3"), diff --git a/test/unit/miner-init-wizard.test.ts b/test/unit/miner-init-wizard.test.ts index 9f5a41e5bd..e21a1af64f 100644 --- a/test/unit/miner-init-wizard.test.ts +++ b/test/unit/miner-init-wizard.test.ts @@ -78,7 +78,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { }); it("resolveWizardEnvFilePath writes to the same state dir init already uses", () => { - expect(resolveWizardEnvFilePath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/state" })).toBe( + expect(resolveWizardEnvFilePath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/state" })).toBe( "/custom/state/.env", ); }); @@ -132,7 +132,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { it("writes a starter .env (mode 0600), initializes laptop state, and passes a clean doctor run when the provider is skipped", async () => { const stateDir = join(tempRoot(), "state"); const cwd = tempRoot(); // no .gittensory-miner.yml here => config-content check passes - const env = { GITTENSORY_MINER_CONFIG_DIR: stateDir }; + const env = { LOOPOVER_MINER_CONFIG_DIR: stateDir }; const io = createFakeIo({ maskedAnswers: ["ghp_test_token_123"], textAnswers: [""] }); const exitCode = await runInteractiveInit(env, cwd, io); @@ -155,7 +155,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { it("re-prompts when the token is left empty before accepting a valid one", async () => { const stateDir = join(tempRoot(), "state"); const cwd = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: stateDir }; + const env = { LOOPOVER_MINER_CONFIG_DIR: stateDir }; const io = createFakeIo({ maskedAnswers: ["", "ghp_after_retry"], textAnswers: [""] }); await runInteractiveInit(env, cwd, io); @@ -167,7 +167,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { it("writes the selected provider and its filled-in companion var, skipping the one left empty", async () => { const stateDir = join(tempRoot(), "state"); const cwd = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: stateDir }; + const env = { LOOPOVER_MINER_CONFIG_DIR: stateDir }; const claudeIndex = CODING_AGENT_DRIVER_NAMES.indexOf("claude-cli"); const io = createFakeIo({ maskedAnswers: ["ghp_provider_case"], @@ -184,7 +184,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { it("reports the sqlite file as already existing on a second run against the same state dir", async () => { const stateDir = join(tempRoot(), "state"); const cwd = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: stateDir }; + const env = { LOOPOVER_MINER_CONFIG_DIR: stateDir }; await runInteractiveInit(env, cwd, createFakeIo({ maskedAnswers: ["ghp_first"], textAnswers: [""] })); const secondIo = createFakeIo({ maskedAnswers: ["ghp_second"], textAnswers: [""] }); @@ -195,7 +195,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { }); describe("runInteractiveInit with device-flow authorization configured (#5682)", () => { - const deviceEnv = (stateDir: string) => ({ GITTENSORY_MINER_CONFIG_DIR: stateDir, GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID: "client-abc" }); + const deviceEnv = (stateDir: string) => ({ LOOPOVER_MINER_CONFIG_DIR: stateDir, LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID: "client-abc" }); const jsonResponse = (body: unknown, ok = true, status = 200) => ({ ok, status, json: async () => body }); const noSleep = async () => undefined; @@ -321,7 +321,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { // wizard (distinct prompt text, distinct code path) without hanging; the full multi-turn prompt flow is // exercised precisely and deterministically by the direct runInteractiveInit tests above. const stateDir = tempRoot(); - const result = runCliResult(["init", "--interactive"], { GITTENSORY_MINER_CONFIG_DIR: stateDir }); + const result = runCliResult(["init", "--interactive"], { LOOPOVER_MINER_CONFIG_DIR: stateDir }); expect(result.output).toContain("GitHub token (input hidden)"); expect(result.output).not.toContain("initialized " + stateDir); }); diff --git a/test/unit/miner-k8s-manifests.test.ts b/test/unit/miner-k8s-manifests.test.ts index 301170d6b9..c035c7e405 100644 --- a/test/unit/miner-k8s-manifests.test.ts +++ b/test/unit/miner-k8s-manifests.test.ts @@ -69,7 +69,7 @@ describe("k8s miner manifests (#5181)", () => { throw new Error("no container in the StatefulSet pod template"); expect(container.args).toContain("run"); const env = container.env as Array>; - const configDir = env.find((e) => e.name === "GITTENSORY_MINER_CONFIG_DIR"); + const configDir = env.find((e) => e.name === "LOOPOVER_MINER_CONFIG_DIR"); expect(configDir?.value).toBe("/data/miner"); const token = env.find((e) => e.name === "GITHUB_TOKEN"); expect(token?.valueFrom?.secretKeyRef?.key).toBe("GITHUB_TOKEN"); diff --git a/test/unit/miner-laptop-init.test.ts b/test/unit/miner-laptop-init.test.ts index 43a227804d..1cd2ca5965 100644 --- a/test/unit/miner-laptop-init.test.ts +++ b/test/unit/miner-laptop-init.test.ts @@ -34,7 +34,7 @@ afterEach(() => { describe("gittensory-miner laptop init (#2329)", () => { it("resolves the laptop SQLite path from the state-dir override and XDG fallback", () => { - expect(resolveLaptopStateDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/state" })) + 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"); @@ -42,7 +42,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("fresh init creates the state dir and SQLite file", () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; const first = initLaptopState(env); expect(first.created).toBe(true); expect(existsSync(first.dbPath)).toBe(true); @@ -52,7 +52,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("re-running init is idempotent and does not clobber existing metadata", () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; const first = initLaptopState(env); writeFileSync(join(first.stateDir, "marker.txt"), "keep-me"); const second = initLaptopState(env); @@ -62,7 +62,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("runInit prints human text (0) and machine JSON with --json", async () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; const log = vi.spyOn(console, "log").mockImplementation(() => {}); expect(await runInit([], env)).toBe(0); expect(String(log.mock.calls[0]?.[0])).toContain("initialized"); @@ -75,7 +75,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("doctor sqlite check reports a missing file with guidance", () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; const check = checkLaptopStateSqlite(env); expect(check.ok).toBe(false); expect(check.detail).toContain("gittensory-miner init"); @@ -83,7 +83,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("doctor sqlite check reports unreadable files", () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; const dbPath = resolveLaptopStateDbPath(env); mkdirSync(join(root, "state"), { recursive: true }); writeFileSync(dbPath, "not-a-sqlite-db"); @@ -129,7 +129,7 @@ describe("gittensory-miner laptop init (#2329)", () => { it("runInit notes when sqlite already existed", async () => { const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; initLaptopState(env); const log = vi.spyOn(console, "log").mockImplementation(() => {}); expect(await runInit([], env)).toBe(0); @@ -142,7 +142,7 @@ describe("gittensory-miner laptop init (#2329)", () => { }); vi.stubGlobal("fetch", fetchStub); const root = tempRoot(); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; vi.spyOn(console, "log").mockImplementation(() => {}); await runInit([], env); checkDockerPresent(); diff --git a/test/unit/miner-local-store-readme.test.ts b/test/unit/miner-local-store-readme.test.ts index 827a84746f..3619dc3449 100644 --- a/test/unit/miner-local-store-readme.test.ts +++ b/test/unit/miner-local-store-readme.test.ts @@ -10,21 +10,21 @@ describe("gittensory-miner local storage README (#4272, #4876)", () => { expect(readme).toContain("## Local storage"); for (const row of [ ["laptop-state.sqlite3", "laptop_meta", "laptop-init.js"], - ["run-state.sqlite3", "miner_run_state", "run-state.js", "GITTENSORY_MINER_RUN_STATE_DB"], - ["claim-ledger.sqlite3", "miner_claims", "claim-ledger.js", "GITTENSORY_MINER_CLAIM_LEDGER_DB"], - ["portfolio-queue.sqlite3", "miner_portfolio_queue", "portfolio-queue.js", "GITTENSORY_MINER_PORTFOLIO_QUEUE_DB"], - ["event-ledger.sqlite3", "miner_event_ledger", "event-ledger.js", "GITTENSORY_MINER_EVENT_LEDGER_DB"], - ["plan-store.sqlite3", "miner_plans", "plan-store.js", "GITTENSORY_MINER_PLAN_STORE_DB"], - ["governor-ledger.sqlite3", "governor_events", "governor-ledger.js", "GITTENSORY_MINER_GOVERNOR_LEDGER_DB"], - ["governor-state.sqlite3", "governor_scalar_state", "governor-state.js", "GITTENSORY_MINER_GOVERNOR_STATE_DB"], - ["attempt-log.sqlite3", "attempt_log_events", "attempt-log.js", "GITTENSORY_MINER_ATTEMPT_LOG_DB"], - ["prediction-ledger.sqlite3", "predictions", "prediction-ledger.js", "GITTENSORY_MINER_PREDICTION_LEDGER_DB"], - ["replay-snapshot.sqlite3", "replay_snapshots", "replay-snapshot.js", "GITTENSORY_MINER_REPLAY_SNAPSHOT_DB"], - ["deny-hook-synthesis.sqlite3", "deny_rule_proposals", "deny-hook-synthesis.js", "GITTENSORY_MINER_DENY_HOOK_SYNTHESIS_DB"], - ["worktree-allocator.sqlite3", "worktree_slots", "worktree-allocator.js", "GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB"], - ["orb-export.sqlite3", "orb_export_meta", "orb-export.js", "GITTENSORY_MINER_ORB_EXPORT_DB"], - ["policy-doc-cache.sqlite3", "policy_doc_cache", "policy-doc-cache.js", "GITTENSORY_MINER_POLICY_DOC_CACHE_DB"], - ["policy-verdict-cache.sqlite3", "policy_verdict_cache", "policy-verdict-cache.js", "GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB"], + ["run-state.sqlite3", "miner_run_state", "run-state.js", "LOOPOVER_MINER_RUN_STATE_DB"], + ["claim-ledger.sqlite3", "miner_claims", "claim-ledger.js", "LOOPOVER_MINER_CLAIM_LEDGER_DB"], + ["portfolio-queue.sqlite3", "miner_portfolio_queue", "portfolio-queue.js", "LOOPOVER_MINER_PORTFOLIO_QUEUE_DB"], + ["event-ledger.sqlite3", "miner_event_ledger", "event-ledger.js", "LOOPOVER_MINER_EVENT_LEDGER_DB"], + ["plan-store.sqlite3", "miner_plans", "plan-store.js", "LOOPOVER_MINER_PLAN_STORE_DB"], + ["governor-ledger.sqlite3", "governor_events", "governor-ledger.js", "LOOPOVER_MINER_GOVERNOR_LEDGER_DB"], + ["governor-state.sqlite3", "governor_scalar_state", "governor-state.js", "LOOPOVER_MINER_GOVERNOR_STATE_DB"], + ["attempt-log.sqlite3", "attempt_log_events", "attempt-log.js", "LOOPOVER_MINER_ATTEMPT_LOG_DB"], + ["prediction-ledger.sqlite3", "predictions", "prediction-ledger.js", "LOOPOVER_MINER_PREDICTION_LEDGER_DB"], + ["replay-snapshot.sqlite3", "replay_snapshots", "replay-snapshot.js", "LOOPOVER_MINER_REPLAY_SNAPSHOT_DB"], + ["deny-hook-synthesis.sqlite3", "deny_rule_proposals", "deny-hook-synthesis.js", "LOOPOVER_MINER_DENY_HOOK_SYNTHESIS_DB"], + ["worktree-allocator.sqlite3", "worktree_slots", "worktree-allocator.js", "LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB"], + ["orb-export.sqlite3", "orb_export_meta", "orb-export.js", "LOOPOVER_MINER_ORB_EXPORT_DB"], + ["policy-doc-cache.sqlite3", "policy_doc_cache", "policy-doc-cache.js", "LOOPOVER_MINER_POLICY_DOC_CACHE_DB"], + ["policy-verdict-cache.sqlite3", "policy_verdict_cache", "policy-verdict-cache.js", "LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB"], ]) { for (const token of row) expect(readme).toContain(token); } diff --git a/test/unit/miner-local-store.test.ts b/test/unit/miner-local-store.test.ts index d88b16aff7..181e4b288b 100644 --- a/test/unit/miner-local-store.test.ts +++ b/test/unit/miner-local-store.test.ts @@ -43,19 +43,19 @@ afterEach(() => { describe("gittensory-miner shared local-store helper (#4272)", () => { it("resolveLocalStoreDbPath prefers the explicit env var, then config dir, then XDG, then the home default", () => { expect( - resolveLocalStoreDbPath("thing.sqlite3", "GITTENSORY_MINER_THING_DB", { - GITTENSORY_MINER_THING_DB: "/custom/thing.sqlite3", + resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", { + LOOPOVER_MINER_THING_DB: "/custom/thing.sqlite3", }), ).toBe("/custom/thing.sqlite3"); expect( - resolveLocalStoreDbPath("thing.sqlite3", "GITTENSORY_MINER_THING_DB", { - GITTENSORY_MINER_CONFIG_DIR: "/custom/config", + resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", { + LOOPOVER_MINER_CONFIG_DIR: "/custom/config", }), ).toBe("/custom/config/thing.sqlite3"); expect( - resolveLocalStoreDbPath("thing.sqlite3", "GITTENSORY_MINER_THING_DB", { XDG_CONFIG_HOME: "/xdg" }), + resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", { XDG_CONFIG_HOME: "/xdg" }), ).toBe("/xdg/gittensory-miner/thing.sqlite3"); - expect(resolveLocalStoreDbPath("thing.sqlite3", "GITTENSORY_MINER_THING_DB", {})).toMatch( + expect(resolveLocalStoreDbPath("thing.sqlite3", "LOOPOVER_MINER_THING_DB", {})).toMatch( /\/\.config\/gittensory-miner\/thing\.sqlite3$/, ); }); @@ -126,10 +126,10 @@ describe("gittensory-miner shared local-store helper (#4272)", () => { it("regression: the four migrated stores still resolve to independent files, and each on-disk file only has its own table (#4272)", () => { const configDir = tempRoot(); - const runStatePath = resolveRunStateDbPath({ GITTENSORY_MINER_CONFIG_DIR: configDir }); - const claimLedgerPath = resolveClaimLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: configDir }); - const portfolioQueuePath = resolvePortfolioQueueDbPath({ GITTENSORY_MINER_CONFIG_DIR: configDir }); - const eventLedgerPath = resolveEventLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: configDir }); + const runStatePath = resolveRunStateDbPath({ LOOPOVER_MINER_CONFIG_DIR: configDir }); + const claimLedgerPath = resolveClaimLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: configDir }); + const portfolioQueuePath = resolvePortfolioQueueDbPath({ LOOPOVER_MINER_CONFIG_DIR: configDir }); + const eventLedgerPath = resolveEventLedgerDbPath({ LOOPOVER_MINER_CONFIG_DIR: configDir }); const paths = [runStatePath, claimLedgerPath, portfolioQueuePath, eventLedgerPath]; expect(new Set(paths).size).toBe(paths.length); // no accidental merge into one shared file diff --git a/test/unit/miner-logger.test.ts b/test/unit/miner-logger.test.ts index fb53a93a7f..6ee7f5b19d 100644 --- a/test/unit/miner-logger.test.ts +++ b/test/unit/miner-logger.test.ts @@ -190,9 +190,9 @@ describe("createLogger pretty timestamps (#4835)", () => { }); describe("createLogger env + default streams (#4835)", () => { - it("reads GITTENSORY_MINER_LOG_LEVEL when no explicit level is given", () => { + it("reads LOOPOVER_MINER_LOG_LEVEL when no explicit level is given", () => { const { out, err, streams } = capture(); - const logger = createLogger({ env: { GITTENSORY_MINER_LOG_LEVEL: "debug" }, streams }); + const logger = createLogger({ env: { LOOPOVER_MINER_LOG_LEVEL: "debug" }, streams }); expect(logger.level).toBe("debug"); logger.debug("d"); expect(out).toEqual(["d\n"]); diff --git a/test/unit/miner-metrics-cli.test.ts b/test/unit/miner-metrics-cli.test.ts index 18730de2e7..705e6bb567 100644 --- a/test/unit/miner-metrics-cli.test.ts +++ b/test/unit/miner-metrics-cli.test.ts @@ -71,14 +71,14 @@ describe("gittensory-miner metrics CLI (#4838)", () => { appendPrediction(seed, 1, "hold"); seed.close(); - const prev = process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB; - process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB = dbPath; + const prev = process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB; + process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB = dbPath; const log = vi.spyOn(console, "log").mockImplementation(() => undefined); try { expect(runMetrics([])).toBe(0); } finally { - if (prev === undefined) delete process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB; - else process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB = prev; + 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'); }); diff --git a/test/unit/miner-migrate-cli.test.ts b/test/unit/miner-migrate-cli.test.ts index c512dd7ff1..d279f3b5a2 100644 --- a/test/unit/miner-migrate-cli.test.ts +++ b/test/unit/miner-migrate-cli.test.ts @@ -12,7 +12,7 @@ const roots: string[] = []; function tempEnv() { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-migrate-")); roots.push(root); - return { GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }; + return { LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }; } const STORE_NAMES = [ diff --git a/test/unit/miner-oauth-device-flow.test.ts b/test/unit/miner-oauth-device-flow.test.ts index 01d9cbe309..d527a2bac8 100644 --- a/test/unit/miner-oauth-device-flow.test.ts +++ b/test/unit/miner-oauth-device-flow.test.ts @@ -13,9 +13,9 @@ function jsonResponse(body: unknown, ok = true, status = 200) { describe("resolveAmsOauthClientId (#5682)", () => { it("returns the trimmed configured client id, or empty when unset/blank", () => { - expect(resolveAmsOauthClientId({ GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID: " client-abc " })).toBe("client-abc"); + expect(resolveAmsOauthClientId({ LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID: " client-abc " })).toBe("client-abc"); expect(resolveAmsOauthClientId({})).toBe(""); - expect(resolveAmsOauthClientId({ GITTENSORY_MINER_AMS_OAUTH_CLIENT_ID: " " })).toBe(""); + expect(resolveAmsOauthClientId({ LOOPOVER_MINER_AMS_OAUTH_CLIENT_ID: " " })).toBe(""); }); }); diff --git a/test/unit/miner-orb-export.test.ts b/test/unit/miner-orb-export.test.ts index fbe132ded6..cc04019d76 100644 --- a/test/unit/miner-orb-export.test.ts +++ b/test/unit/miner-orb-export.test.ts @@ -184,8 +184,8 @@ describe("filterBatchSinceCursor / latestClosedAt (#5681)", () => { describe("resolveAmsCollectorUrl (#5681)", () => { it("defaults to gittensory's hosted collector; an explicit env var overrides it", () => { expect(resolveAmsCollectorUrl({})).toBe(DEFAULT_AMS_COLLECTOR_URL); - expect(resolveAmsCollectorUrl({ GITTENSORY_MINER_AMS_COLLECTOR_URL: " " })).toBe(DEFAULT_AMS_COLLECTOR_URL); - expect(resolveAmsCollectorUrl({ GITTENSORY_MINER_AMS_COLLECTOR_URL: "https://example.test/ingest" })).toBe("https://example.test/ingest"); + expect(resolveAmsCollectorUrl({ LOOPOVER_MINER_AMS_COLLECTOR_URL: " " })).toBe(DEFAULT_AMS_COLLECTOR_URL); + expect(resolveAmsCollectorUrl({ LOOPOVER_MINER_AMS_COLLECTOR_URL: "https://example.test/ingest" })).toBe("https://example.test/ingest"); }); }); diff --git a/test/unit/miner-package-skeleton.test.ts b/test/unit/miner-package-skeleton.test.ts index f16826ee8a..04bac78591 100644 --- a/test/unit/miner-package-skeleton.test.ts +++ b/test/unit/miner-package-skeleton.test.ts @@ -67,7 +67,7 @@ describe("gittensory-miner package skeleton (#2287)", () => { expect(runCapture(["--version", "--no-update-check"])).toContain("@loopover/miner/"); expect( runCapture(["--version", "--no-update-check"], { - GITTENSORY_MINER_VERSION: "gittensory-miner-fleet@abc1234", + LOOPOVER_MINER_VERSION: "gittensory-miner-fleet@abc1234", }), ).toContain("gittensory-miner-fleet@abc1234"); }); diff --git a/test/unit/miner-plan-store.test.ts b/test/unit/miner-plan-store.test.ts index 54cf97253d..eab53fde5c 100644 --- a/test/unit/miner-plan-store.test.ts +++ b/test/unit/miner-plan-store.test.ts @@ -42,8 +42,8 @@ describe("gittensory-miner plan store (#2318)", () => { }); it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolvePlanStoreDbPath({ GITTENSORY_MINER_PLAN_STORE_DB: "/custom/p.sqlite3" })).toBe("/custom/p.sqlite3"); - expect(resolvePlanStoreDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolvePlanStoreDbPath({ LOOPOVER_MINER_PLAN_STORE_DB: "/custom/p.sqlite3" })).toBe("/custom/p.sqlite3"); + 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"); diff --git a/test/unit/miner-policy-doc-cache.test.ts b/test/unit/miner-policy-doc-cache.test.ts index 16975a2f1a..8277532a2d 100644 --- a/test/unit/miner-policy-doc-cache.test.ts +++ b/test/unit/miner-policy-doc-cache.test.ts @@ -32,10 +32,10 @@ afterEach(() => { describe("resolvePolicyDocCacheDbPath (#4842)", () => { it("prefers the store-specific env var, then the config dir, then XDG/~config", () => { - expect(resolvePolicyDocCacheDbPath({ GITTENSORY_MINER_POLICY_DOC_CACHE_DB: "/custom/pdc.sqlite3" })).toBe( + expect(resolvePolicyDocCacheDbPath({ LOOPOVER_MINER_POLICY_DOC_CACHE_DB: "/custom/pdc.sqlite3" })).toBe( "/custom/pdc.sqlite3", ); - expect(resolvePolicyDocCacheDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe( + expect(resolvePolicyDocCacheDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe( join("/cfg", "policy-doc-cache.sqlite3"), ); expect(resolvePolicyDocCacheDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -96,7 +96,7 @@ describe("gittensory-miner policy-doc cache store (#4842)", () => { it("resolves its default path from the env when no path is passed", () => { const dbPath = tempDbPath(); - vi.stubEnv("GITTENSORY_MINER_POLICY_DOC_CACHE_DB", dbPath); + vi.stubEnv("LOOPOVER_MINER_POLICY_DOC_CACHE_DB", dbPath); // Call with no argument so the default parameter resolves the path from the env. const store = initPolicyDocCacheStore(); stores.push(store); diff --git a/test/unit/miner-policy-verdict-cache.test.ts b/test/unit/miner-policy-verdict-cache.test.ts index 3fddab3ac5..b647748647 100644 --- a/test/unit/miner-policy-verdict-cache.test.ts +++ b/test/unit/miner-policy-verdict-cache.test.ts @@ -34,10 +34,10 @@ afterEach(() => { describe("resolvePolicyVerdictCacheDbPath (#4843)", () => { it("prefers the store-specific env var, then the config dir, then XDG/~config", () => { - expect(resolvePolicyVerdictCacheDbPath({ GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB: "/custom/pvc.sqlite3" })).toBe( + expect(resolvePolicyVerdictCacheDbPath({ LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB: "/custom/pvc.sqlite3" })).toBe( "/custom/pvc.sqlite3", ); - expect(resolvePolicyVerdictCacheDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe( + expect(resolvePolicyVerdictCacheDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe( join("/cfg", "policy-verdict-cache.sqlite3"), ); expect(resolvePolicyVerdictCacheDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -125,7 +125,7 @@ describe("gittensory-miner policy-verdict cache store (#4843)", () => { it("resolves its default path from the env when no path is passed", () => { const dbPath = tempDbPath(); - vi.stubEnv("GITTENSORY_MINER_POLICY_VERDICT_CACHE_DB", dbPath); + vi.stubEnv("LOOPOVER_MINER_POLICY_VERDICT_CACHE_DB", dbPath); // Call with no argument so the default parameter resolves the path from the env. const store = initPolicyVerdictCacheStore(); stores.push(store); diff --git a/test/unit/miner-portfolio-queue.test.ts b/test/unit/miner-portfolio-queue.test.ts index 4dd182dc17..9b6a330c26 100644 --- a/test/unit/miner-portfolio-queue.test.ts +++ b/test/unit/miner-portfolio-queue.test.ts @@ -47,10 +47,10 @@ describe("gittensory-miner portfolio/queue store (#2292)", () => { }); it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolvePortfolioQueueDbPath({ GITTENSORY_MINER_PORTFOLIO_QUEUE_DB: "/custom/q.sqlite3" })).toBe( + expect(resolvePortfolioQueueDbPath({ LOOPOVER_MINER_PORTFOLIO_QUEUE_DB: "/custom/q.sqlite3" })).toBe( "/custom/q.sqlite3", ); - expect(resolvePortfolioQueueDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolvePortfolioQueueDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/portfolio-queue.sqlite3", ); expect(resolvePortfolioQueueDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -186,7 +186,7 @@ describe("gittensory-miner portfolio/queue store (#2292)", () => { it("module-level markFailed delegates to the default portfolio-queue store (#2347)", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-portfolio-default-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); enqueue({ repoFullName: "o/a", identifier: "work", priority: 1 }); expect(dequeueNext()?.status).toBe("in_progress"); expect(markFailed("o/a", "work")?.status).toBe("queued"); @@ -212,7 +212,7 @@ describe("gittensory-miner portfolio/queue store (#2292)", () => { it("module-level markDone delegates to the default portfolio-queue store", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-portfolio-default-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); enqueue({ repoFullName: "o/a", identifier: "work", priority: 1 }); expect(markDone("o/a", "work")?.status).toBe("done"); expect(markDone("o/a", "work")).toBeNull(); @@ -458,7 +458,7 @@ describe("gittensory-miner portfolio/queue store (#2292)", () => { it("module-level getAttemptHistory delegates to the default portfolio-queue store", () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-portfolio-default-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_PORTFOLIO_QUEUE_DB", join(root, "portfolio-queue.sqlite3")); enqueue({ repoFullName: "o/a", identifier: "work", priority: 1 }); dequeueNext(); expect(getAttemptHistory("o/a", "work").attempts).toBe(1); diff --git a/test/unit/miner-prediction-ledger.test.ts b/test/unit/miner-prediction-ledger.test.ts index cba2205b6b..910ca37fcd 100644 --- a/test/unit/miner-prediction-ledger.test.ts +++ b/test/unit/miner-prediction-ledger.test.ts @@ -32,8 +32,8 @@ const VALID = { describe("miner prediction ledger (#4263)", () => { it("resolvePredictionLedgerDbPath honors the explicit DB, config-dir, XDG, then home default", () => { - expect(resolvePredictionLedgerDbPath({ GITTENSORY_MINER_PREDICTION_LEDGER_DB: "/custom/pred.sqlite3" })).toBe("/custom/pred.sqlite3"); - expect(resolvePredictionLedgerDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/state" })).toBe(join("/state", "prediction-ledger.sqlite3")); + 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$/); }); diff --git a/test/unit/miner-purge-cli.test.ts b/test/unit/miner-purge-cli.test.ts index 4540195dc0..2b6f47af8a 100644 --- a/test/unit/miner-purge-cli.test.ts +++ b/test/unit/miner-purge-cli.test.ts @@ -235,24 +235,24 @@ describe("runPurge --dry-run (#5564)", () => { it("opens the real default on-disk stores in dry-run when no resolveDbPaths override is supplied", () => { const root = tempDir(); const previousDirs: Record = { - GITTENSORY_MINER_CLAIM_LEDGER_DB: process.env.GITTENSORY_MINER_CLAIM_LEDGER_DB, - GITTENSORY_MINER_EVENT_LEDGER_DB: process.env.GITTENSORY_MINER_EVENT_LEDGER_DB, - GITTENSORY_MINER_GOVERNOR_LEDGER_DB: process.env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB, - GITTENSORY_MINER_PREDICTION_LEDGER_DB: process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB, - GITTENSORY_MINER_ATTEMPT_LOG_DB: process.env.GITTENSORY_MINER_ATTEMPT_LOG_DB, + LOOPOVER_MINER_CLAIM_LEDGER_DB: process.env.LOOPOVER_MINER_CLAIM_LEDGER_DB, + LOOPOVER_MINER_EVENT_LEDGER_DB: process.env.LOOPOVER_MINER_EVENT_LEDGER_DB, + LOOPOVER_MINER_GOVERNOR_LEDGER_DB: process.env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB, + LOOPOVER_MINER_PREDICTION_LEDGER_DB: process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB, + LOOPOVER_MINER_ATTEMPT_LOG_DB: process.env.LOOPOVER_MINER_ATTEMPT_LOG_DB, }; - process.env.GITTENSORY_MINER_CLAIM_LEDGER_DB = join(root, "claim-ledger.sqlite3"); - process.env.GITTENSORY_MINER_EVENT_LEDGER_DB = join(root, "event-ledger.sqlite3"); - process.env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB = join(root, "governor-ledger.sqlite3"); - process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB = join(root, "prediction-ledger.sqlite3"); - process.env.GITTENSORY_MINER_ATTEMPT_LOG_DB = join(root, "attempt-log.sqlite3"); + process.env.LOOPOVER_MINER_CLAIM_LEDGER_DB = join(root, "claim-ledger.sqlite3"); + process.env.LOOPOVER_MINER_EVENT_LEDGER_DB = join(root, "event-ledger.sqlite3"); + process.env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB = join(root, "governor-ledger.sqlite3"); + process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB = join(root, "prediction-ledger.sqlite3"); + process.env.LOOPOVER_MINER_ATTEMPT_LOG_DB = join(root, "attempt-log.sqlite3"); try { const log = vi.spyOn(console, "log").mockImplementation(() => undefined); expect(runPurge(["--repo", "acme/widgets", "--dry-run", "--json"])).toBe(0); const result = JSON.parse(String(log.mock.calls[0]?.[0])); expect(result.stores.every((entry: { wouldPurge: number }) => entry.wouldPurge === 0)).toBe(true); // Nothing was created — dry run against nonexistent default-path stores makes zero writes. - expect(existsSync(process.env.GITTENSORY_MINER_CLAIM_LEDGER_DB)).toBe(false); + expect(existsSync(process.env.LOOPOVER_MINER_CLAIM_LEDGER_DB)).toBe(false); } finally { for (const [key, value] of Object.entries(previousDirs)) { if (value === undefined) delete process.env[key]; @@ -382,16 +382,16 @@ describe("runPurge (real, #5564)", () => { it("opens and closes the real default on-disk stores when no override is supplied (owned stores)", () => { const root = tempDir(); const previousDirs: Record = { - GITTENSORY_MINER_CLAIM_LEDGER_DB: process.env.GITTENSORY_MINER_CLAIM_LEDGER_DB, - GITTENSORY_MINER_EVENT_LEDGER_DB: process.env.GITTENSORY_MINER_EVENT_LEDGER_DB, - GITTENSORY_MINER_GOVERNOR_LEDGER_DB: process.env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB, - GITTENSORY_MINER_PREDICTION_LEDGER_DB: process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB, + LOOPOVER_MINER_CLAIM_LEDGER_DB: process.env.LOOPOVER_MINER_CLAIM_LEDGER_DB, + LOOPOVER_MINER_EVENT_LEDGER_DB: process.env.LOOPOVER_MINER_EVENT_LEDGER_DB, + LOOPOVER_MINER_GOVERNOR_LEDGER_DB: process.env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB, + LOOPOVER_MINER_PREDICTION_LEDGER_DB: process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB, }; const claimDbPath = join(root, "claim-ledger.sqlite3"); - process.env.GITTENSORY_MINER_CLAIM_LEDGER_DB = claimDbPath; - process.env.GITTENSORY_MINER_EVENT_LEDGER_DB = join(root, "event-ledger.sqlite3"); - process.env.GITTENSORY_MINER_GOVERNOR_LEDGER_DB = join(root, "governor-ledger.sqlite3"); - process.env.GITTENSORY_MINER_PREDICTION_LEDGER_DB = join(root, "prediction-ledger.sqlite3"); + process.env.LOOPOVER_MINER_CLAIM_LEDGER_DB = claimDbPath; + process.env.LOOPOVER_MINER_EVENT_LEDGER_DB = join(root, "event-ledger.sqlite3"); + process.env.LOOPOVER_MINER_GOVERNOR_LEDGER_DB = join(root, "governor-ledger.sqlite3"); + process.env.LOOPOVER_MINER_PREDICTION_LEDGER_DB = join(root, "prediction-ledger.sqlite3"); try { // Seed a real claim via the default store path before purging through it. const seeded = openClaimLedger(claimDbPath); diff --git a/test/unit/miner-ranked-candidates.test.ts b/test/unit/miner-ranked-candidates.test.ts index 2da3e5db25..bed7234486 100644 --- a/test/unit/miner-ranked-candidates.test.ts +++ b/test/unit/miner-ranked-candidates.test.ts @@ -42,10 +42,10 @@ const fullCandidate = { describe("gittensory-miner ranked-candidates store (#4859 prerequisite)", () => { it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveRankedCandidatesDbPath({ GITTENSORY_MINER_RANKED_CANDIDATES_DB: "/custom/ranked.sqlite3" })).toBe( + expect(resolveRankedCandidatesDbPath({ LOOPOVER_MINER_RANKED_CANDIDATES_DB: "/custom/ranked.sqlite3" })).toBe( "/custom/ranked.sqlite3", ); - expect(resolveRankedCandidatesDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveRankedCandidatesDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/ranked-candidates.sqlite3", ); expect(resolveRankedCandidatesDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -241,7 +241,7 @@ describe("gittensory-miner ranked-candidates store (#4859 prerequisite)", () => it("module-level convenience functions operate on the lazily-opened default store", () => { const root = tempRoot(); - vi.stubEnv("GITTENSORY_MINER_RANKED_CANDIDATES_DB", join(root, "ranked-candidates.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_RANKED_CANDIDATES_DB", join(root, "ranked-candidates.sqlite3")); const result = saveRankedCandidates([fullCandidate], Date.parse("2026-07-13T12:00:00.000Z")); expect(result.count).toBe(1); expect(listRankedCandidates()).toEqual([{ ...fullCandidate, rankedAt: "2026-07-13T12:00:00.000Z" }]); diff --git a/test/unit/miner-replay-snapshot.test.ts b/test/unit/miner-replay-snapshot.test.ts index b7a842fe1e..41e533ccb3 100644 --- a/test/unit/miner-replay-snapshot.test.ts +++ b/test/unit/miner-replay-snapshot.test.ts @@ -382,7 +382,7 @@ describe("exportReplaySnapshot (#3010)", () => { it("falls back to the default (env-resolved) store when deps.store is omitted", async () => { const root = mkdtempSync(join(tmpdir(), "gittensory-miner-replay-snapshot-default-")); roots.push(root); - vi.stubEnv("GITTENSORY_MINER_REPLAY_SNAPSHOT_DB", join(root, "default.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_REPLAY_SNAPSHOT_DB", join(root, "default.sqlite3")); const { exec } = scriptedExec(happyPathScripts()); const snapshot = await exportReplaySnapshot({ repoPath: "/repo", repoFullName: "acme/widgets", commitSha: "abc123" }, { exec }); diff --git a/test/unit/miner-repo-clone.test.ts b/test/unit/miner-repo-clone.test.ts index c6a9e0eb26..ed2d42033a 100644 --- a/test/unit/miner-repo-clone.test.ts +++ b/test/unit/miner-repo-clone.test.ts @@ -37,9 +37,9 @@ function commitFile(originPath: string, fileName: string, content: string) { describe("resolveRepoCloneBaseDir / resolveRepoCloneDir (#5132)", () => { it("resolves from explicit env, config dir, and XDG default, in precedence order", () => { - expect(resolveRepoCloneBaseDir({ GITTENSORY_MINER_REPO_CLONE_DIR: "/custom/repos" })).toBe("/custom/repos"); - expect(resolveRepoCloneBaseDir({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/repos"); - expect(resolveRepoCloneDir("acme/widgets", { GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/repos/acme/widgets"); + expect(resolveRepoCloneBaseDir({ LOOPOVER_MINER_REPO_CLONE_DIR: "/custom/repos" })).toBe("/custom/repos"); + expect(resolveRepoCloneBaseDir({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/repos"); + expect(resolveRepoCloneDir("acme/widgets", { LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/repos/acme/widgets"); }); it("rejects a malformed repoFullName", () => { diff --git a/test/unit/miner-run-state.test.ts b/test/unit/miner-run-state.test.ts index fd04a76f78..07fd4c5a44 100644 --- a/test/unit/miner-run-state.test.ts +++ b/test/unit/miner-run-state.test.ts @@ -39,10 +39,10 @@ describe("gittensory-miner run-state store (#2289)", () => { }); it("resolves the DB path from env override, miner config dir, XDG config, then the home default", () => { - expect(resolveRunStateDbPath({ GITTENSORY_MINER_RUN_STATE_DB: "/custom/state.sqlite3" })).toBe( + expect(resolveRunStateDbPath({ LOOPOVER_MINER_RUN_STATE_DB: "/custom/state.sqlite3" })).toBe( "/custom/state.sqlite3", ); - expect(resolveRunStateDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/custom/config" })).toBe( + expect(resolveRunStateDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/custom/config" })).toBe( "/custom/config/run-state.sqlite3", ); expect(resolveRunStateDbPath({ XDG_CONFIG_HOME: "/xdg" })).toBe( @@ -106,7 +106,7 @@ describe("gittensory-miner run-state store (#2289)", () => { }); it("exposes module-level get/set helpers backed by the default local DB path", () => { - vi.stubEnv("GITTENSORY_MINER_RUN_STATE_DB", join(tempRoot(), "default.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_RUN_STATE_DB", join(tempRoot(), "default.sqlite3")); expect(getRunState("acme/widgets")).toBeNull(); expect(setRunState("acme/widgets", "discovering")).toMatchObject({ @@ -209,7 +209,7 @@ describe("gittensory-miner run-state store (#2289)", () => { }); it("exposes the module-level listRunStates helper backed by the default local DB path", () => { - vi.stubEnv("GITTENSORY_MINER_RUN_STATE_DB", join(tempRoot(), "default-list.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_RUN_STATE_DB", join(tempRoot(), "default-list.sqlite3")); expect(listRunStates()).toEqual([]); setRunState("acme/widgets", "preparing"); @@ -219,7 +219,7 @@ describe("gittensory-miner run-state store (#2289)", () => { }); it("module-level getRunState forwards apiBaseUrl to the default store (#5563)", () => { - vi.stubEnv("GITTENSORY_MINER_RUN_STATE_DB", join(tempRoot(), "default-get.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_RUN_STATE_DB", join(tempRoot(), "default-get.sqlite3")); setRunState("acme/widgets", "planning", "https://ghe.example.com/api/v3"); expect(getRunState("acme/widgets")).toBeNull(); // github.com default: no row there expect(getRunState("acme/widgets", "https://ghe.example.com/api/v3")).toBe("planning"); diff --git a/test/unit/miner-status.test.ts b/test/unit/miner-status.test.ts index 57a858df70..3bcfcfe00a 100644 --- a/test/unit/miner-status.test.ts +++ b/test/unit/miner-status.test.ts @@ -44,7 +44,7 @@ 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({ GITTENSORY_MINER_CONFIG_DIR: "/custom/state" })).toBe("/custom/state"); + 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$/); }); @@ -52,7 +52,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("collectStatus reports the installed versions, state dir, and config-file discovery", () => { const root = tempRoot(); writeFileSync(join(root, ".gittensory-miner.yml"), "minerEnabled: true\n"); - const status = collectStatus({ GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }, root); + const status = collectStatus({ LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }, root); expect(status.package.name).toBe("@loopover/miner"); expect(typeof status.package.version).toBe("string"); expect(status.engine.name).toBe("@loopover/engine"); @@ -62,7 +62,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("REGRESSION: collectStatus reports the REAL installed engine version, not the declared dependency range", () => { const root = tempRoot(); - const status = collectStatus({ GITTENSORY_MINER_CONFIG_DIR: join(root, "state") }, root); + const status = collectStatus({ LOOPOVER_MINER_CONFIG_DIR: join(root, "state") }, root); // The monorepo declares "*" for this workspace dependency -- a self-hoster asking "what's installed" // needs the real resolved semver (matching what doctor's own engine-version-skew check already shows), // not the meaningless declared range. @@ -78,11 +78,11 @@ describe("gittensory-miner status/doctor (#2288)", () => { expect(buildEngineVersionDisplay(() => null)).toBe("*"); }); - it("collectStatus prefers GITTENSORY_MINER_VERSION over package.json (#4310)", () => { + it("collectStatus prefers LOOPOVER_MINER_VERSION over package.json (#4310)", () => { const status = collectStatus( { - GITTENSORY_MINER_CONFIG_DIR: "/s", - GITTENSORY_MINER_VERSION: "gittensory-miner-fleet@deadbeef", + LOOPOVER_MINER_CONFIG_DIR: "/s", + LOOPOVER_MINER_VERSION: "gittensory-miner-fleet@deadbeef", }, tempRoot(), ); @@ -91,10 +91,10 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("runStatus prints human-readable text (0) and machine JSON with --json", () => { const log = vi.spyOn(console, "log").mockImplementation(() => {}); - expect(runStatus([], { GITTENSORY_MINER_CONFIG_DIR: "/s" }, tempRoot())).toBe(0); + expect(runStatus([], { LOOPOVER_MINER_CONFIG_DIR: "/s" }, tempRoot())).toBe(0); expect(String(log.mock.calls[0]?.[0])).toContain("@loopover/miner"); log.mockClear(); - expect(runStatus(["--json"], { GITTENSORY_MINER_CONFIG_DIR: "/s" }, tempRoot())).toBe(0); + expect(runStatus(["--json"], { LOOPOVER_MINER_CONFIG_DIR: "/s" }, tempRoot())).toBe(0); expect(JSON.parse(String(log.mock.calls[0]?.[0])).stateDir).toBe("/s"); }); @@ -102,7 +102,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { const log = vi.spyOn(console, "log").mockImplementation(() => {}); // A healthy setup now also requires GITHUB_TOKEN (#5170); no coding-agent provider is configured, so the // provider-credential check is a clean skip. - const env = { GITTENSORY_MINER_CONFIG_DIR: join(tempRoot(), "state"), GITHUB_TOKEN: "ghp_present" }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state"), GITHUB_TOKEN: "ghp_present" }; initLaptopState(env); const cwd = tempRoot(); // a config-less working dir ⇒ config-content check is a clean pass const checks = runDoctorChecks(env, cwd); @@ -132,7 +132,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { }); it("doctor flags a corrupted store (#4834)", () => { - const env = { GITTENSORY_MINER_CONFIG_DIR: join(tempRoot(), "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state") }; const eventLedgerPath = resolveEventLedgerDbPath(env); mkdirSync(dirname(eventLedgerPath), { recursive: true }); writeFileSync(eventLedgerPath, "this is not a sqlite database"); @@ -178,7 +178,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { }); it("doctor flags a malformed config file (#4873)", () => { - const env = { GITTENSORY_MINER_CONFIG_DIR: join(tempRoot(), "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state") }; const cwd = tempRoot(); writeFileSync(join(cwd, ".gittensory-miner.yml"), "wantedPaths: not-a-list\n"); expect(runDoctorChecks(env, cwd).find((check) => check.name === "config-content")?.ok).toBe(false); @@ -242,7 +242,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("runDoctor supports --json output", () => { const log = vi.spyOn(console, "log").mockImplementation(() => {}); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(tempRoot(), "state"), GITHUB_TOKEN: "ghp_present" }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state"), GITHUB_TOKEN: "ghp_present" }; initLaptopState(env); expect(runDoctor(["--json"], env)).toBe(0); expect(JSON.parse(String(log.mock.calls[0]?.[0])).checks).toBeDefined(); @@ -273,7 +273,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { const root = tempRoot(); const filePath = join(root, "not-a-dir"); writeFileSync(filePath, ""); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(filePath, "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(filePath, "state") }; expect(runDoctorChecks(env).find((check) => check.name === "state-dir-writable")?.ok).toBe(false); expect(runDoctor([], env)).toBe(1); expect(errorLog).toHaveBeenCalled(); @@ -285,7 +285,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { }); vi.stubGlobal("fetch", fetchStub); vi.spyOn(console, "log").mockImplementation(() => {}); - const env = { GITTENSORY_MINER_CONFIG_DIR: join(tempRoot(), "state") }; + const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state") }; initLaptopState(env); runStatus(["--json"], env, tempRoot()); runDoctor([], env); @@ -294,13 +294,13 @@ describe("gittensory-miner status/doctor (#2288)", () => { describe("driver section of status/status --json (#5164)", () => { it("reports provider: null, modelEnvVar: null, cliPresent: null when no provider is configured", () => { - const status = collectStatus({ GITTENSORY_MINER_CONFIG_DIR: "/s", PATH: "" }, tempRoot()); + const status = collectStatus({ LOOPOVER_MINER_CONFIG_DIR: "/s", PATH: "" }, tempRoot()); expect(status.driver).toEqual({ provider: null, modelEnvVar: null, cliPresent: null }); }); it("reports the noop provider with no model env var and no CLI to check (cliPresent: null)", () => { const status = collectStatus( - { GITTENSORY_MINER_CONFIG_DIR: "/s", PATH: "", MINER_CODING_AGENT_PROVIDER: "noop" }, + { LOOPOVER_MINER_CONFIG_DIR: "/s", PATH: "", MINER_CODING_AGENT_PROVIDER: "noop" }, tempRoot(), ); expect(status.driver).toEqual({ provider: "noop", modelEnvVar: null, cliPresent: null }); @@ -308,7 +308,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("reports the agent-sdk provider with no model env var and no CLI to check (cliPresent: null)", () => { const status = collectStatus( - { GITTENSORY_MINER_CONFIG_DIR: "/s", PATH: "", MINER_CODING_AGENT_PROVIDER: "agent-sdk" }, + { LOOPOVER_MINER_CONFIG_DIR: "/s", PATH: "", MINER_CODING_AGENT_PROVIDER: "agent-sdk" }, tempRoot(), ); expect(status.driver).toEqual({ provider: "agent-sdk", modelEnvVar: null, cliPresent: null }); @@ -317,7 +317,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("claude-cli configured + CLI present on PATH: reports the model env-var name and cliPresent: true", () => { const status = collectStatus( { - GITTENSORY_MINER_CONFIG_DIR: "/s", + LOOPOVER_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "claude-cli", PATH: fakeBinDir("claude"), }, @@ -332,7 +332,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("claude-cli configured + CLI absent from PATH: cliPresent: false", () => { const status = collectStatus( - { GITTENSORY_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "claude-cli", PATH: tempRoot() }, + { LOOPOVER_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "claude-cli", PATH: tempRoot() }, tempRoot(), ); expect(status.driver.cliPresent).toBe(false); @@ -341,7 +341,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("codex-cli configured + CLI present on PATH: reports the model env-var name and cliPresent: true", () => { const status = collectStatus( { - GITTENSORY_MINER_CONFIG_DIR: "/s", + LOOPOVER_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "codex-cli", PATH: fakeBinDir("codex"), }, @@ -356,7 +356,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("codex-cli configured + CLI absent from PATH: cliPresent: false", () => { const status = collectStatus( - { GITTENSORY_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "codex-cli", PATH: tempRoot() }, + { LOOPOVER_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "codex-cli", PATH: tempRoot() }, tempRoot(), ); expect(status.driver.cliPresent).toBe(false); @@ -364,12 +364,12 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("human-readable status text renders the driver line for both configured and unconfigured cases", () => { const log = vi.spyOn(console, "log").mockImplementation(() => {}); - runStatus([], { GITTENSORY_MINER_CONFIG_DIR: "/s", PATH: "" }, tempRoot()); + runStatus([], { LOOPOVER_MINER_CONFIG_DIR: "/s", PATH: "" }, tempRoot()); expect(String(log.mock.calls[0]?.[0])).toContain("driver: none configured"); log.mockClear(); runStatus( [], - { GITTENSORY_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "codex-cli", PATH: fakeBinDir("codex") }, + { LOOPOVER_MINER_CONFIG_DIR: "/s", MINER_CODING_AGENT_PROVIDER: "codex-cli", PATH: fakeBinDir("codex") }, tempRoot(), ); expect(String(log.mock.calls[0]?.[0])).toContain( @@ -386,7 +386,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { runStatus( ["--json"], { - GITTENSORY_MINER_CONFIG_DIR: "/s", + LOOPOVER_MINER_CONFIG_DIR: "/s", ...(provider ? { MINER_CODING_AGENT_PROVIDER: provider } : {}), MINER_CODING_AGENT_CLAUDE_MODEL: secretModelValue, MINER_CODING_AGENT_CODEX_MODEL: secretModelValue, diff --git a/test/unit/miner-toolbar-badge.test.ts b/test/unit/miner-toolbar-badge.test.ts index 3340bf4e94..59f2d4bedd 100644 --- a/test/unit/miner-toolbar-badge.test.ts +++ b/test/unit/miner-toolbar-badge.test.ts @@ -113,7 +113,7 @@ function loadBackground( if (withAction) chrome.action = { setBadgeText, setBadgeBackgroundColor }; const warn = vi.fn(); const context: Record = { - __GITTENSORY_MINER_EXTENSION_TEST__: true, + __LOOPOVER_MINER_EXTENSION_TEST__: true, chrome, console: { warn }, }; diff --git a/test/unit/miner-version.test.ts b/test/unit/miner-version.test.ts index d239f7758e..3f4a445ef5 100644 --- a/test/unit/miner-version.test.ts +++ b/test/unit/miner-version.test.ts @@ -5,19 +5,19 @@ import { } from "../../packages/gittensory-miner/lib/version.js"; describe("gittensory-miner version resolution (#4310)", () => { - it("defaults to the package.json semver when GITTENSORY_MINER_VERSION is unset", () => { + it("defaults to the package.json semver when LOOPOVER_MINER_VERSION is unset", () => { expect(MINER_PACKAGE_VERSION).toMatch(/^\d+\.\d+\.\d+$/); expect(resolveMinerVersion({})).toBe(MINER_PACKAGE_VERSION); - expect(resolveMinerVersion({ GITTENSORY_MINER_VERSION: "" })).toBe(MINER_PACKAGE_VERSION); - expect(resolveMinerVersion({ GITTENSORY_MINER_VERSION: " " })).toBe(MINER_PACKAGE_VERSION); + expect(resolveMinerVersion({ LOOPOVER_MINER_VERSION: "" })).toBe(MINER_PACKAGE_VERSION); + expect(resolveMinerVersion({ LOOPOVER_MINER_VERSION: " " })).toBe(MINER_PACKAGE_VERSION); }); - it("prefers a nonblank GITTENSORY_MINER_VERSION override (fleet Docker build ref)", () => { + it("prefers a nonblank LOOPOVER_MINER_VERSION override (fleet Docker build ref)", () => { expect( - resolveMinerVersion({ GITTENSORY_MINER_VERSION: "gittensory-miner-fleet@abc1234" }), + resolveMinerVersion({ LOOPOVER_MINER_VERSION: "gittensory-miner-fleet@abc1234" }), ).toBe("gittensory-miner-fleet@abc1234"); expect( - resolveMinerVersion({ GITTENSORY_MINER_VERSION: " 0.9.0-beta.1 " }), + resolveMinerVersion({ LOOPOVER_MINER_VERSION: " 0.9.0-beta.1 " }), ).toBe("0.9.0-beta.1"); }); }); diff --git a/test/unit/miner-wire-cli-modules.test.ts b/test/unit/miner-wire-cli-modules.test.ts index 2ccac40e64..309f61621d 100644 --- a/test/unit/miner-wire-cli-modules.test.ts +++ b/test/unit/miner-wire-cli-modules.test.ts @@ -306,8 +306,8 @@ describe("orb export — wires the anonymized telemetry batch-builder (#4833)", // Isolated tmp DB paths (never touches a real ~/.config/gittensory-miner), matching the pattern already // established for the analogous getAttemptHistory/recordOwnSubmission DI-fallback tests. const dir = tempDir(); - vi.stubEnv("GITTENSORY_MINER_ORB_EXPORT_DB", join(dir, "orb-export.sqlite3")); - vi.stubEnv("GITTENSORY_MINER_EVENT_LEDGER_DB", join(dir, "ledger.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_ORB_EXPORT_DB", join(dir, "orb-export.sqlite3")); + vi.stubEnv("LOOPOVER_MINER_EVENT_LEDGER_DB", join(dir, "ledger.sqlite3")); // Seed via the SAME real default ledger path runOrbExportCli will open — closedAt omitted (→ null) so the // send path's `latestClosedAt` also exercises its null branch (no cursor advance possible). diff --git a/test/unit/miner-worktree-allocator.test.ts b/test/unit/miner-worktree-allocator.test.ts index e497526352..3cebbadf54 100644 --- a/test/unit/miner-worktree-allocator.test.ts +++ b/test/unit/miner-worktree-allocator.test.ts @@ -36,15 +36,15 @@ afterEach(() => { describe("gittensory-miner worktree allocator scaffolding (#4298)", () => { it("resolves DB and worktree base paths from env overrides", () => { expect( - resolveWorktreeAllocatorDbPath({ GITTENSORY_MINER_WORKTREE_ALLOCATOR_DB: "/custom/alloc.sqlite3" }), + resolveWorktreeAllocatorDbPath({ LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB: "/custom/alloc.sqlite3" }), ).toBe("/custom/alloc.sqlite3"); - expect(resolveWorktreeBaseDir({ GITTENSORY_MINER_WORKTREE_DIR: "/custom/worktrees" })).toBe( + expect(resolveWorktreeBaseDir({ LOOPOVER_MINER_WORKTREE_DIR: "/custom/worktrees" })).toBe( "/custom/worktrees", ); - expect(resolveWorktreeAllocatorDbPath({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe( + expect(resolveWorktreeAllocatorDbPath({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe( "/cfg/worktree-allocator.sqlite3", ); - expect(resolveWorktreeBaseDir({ GITTENSORY_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/worktrees"); + expect(resolveWorktreeBaseDir({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe("/cfg/worktrees"); }); it("creates a permissioned SQLite store and allocates distinct worktree paths", () => { diff --git a/test/unit/selfhost-ams-reporting.test.ts b/test/unit/selfhost-ams-reporting.test.ts index 7cdde2e7a3..2af211762d 100644 --- a/test/unit/selfhost-ams-reporting.test.ts +++ b/test/unit/selfhost-ams-reporting.test.ts @@ -5,7 +5,7 @@ import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; // Export coverage for scripts/export-ams-reporting-db.sh (#5184 follow-up / PR #5471's flagged confidentiality -// gap): Grafana must never mount the miner's live GITTENSORY_MINER_CONFIG_DIR ledgers directly, so this script +// gap): Grafana must never mount the miner's live LOOPOVER_MINER_CONFIG_DIR ledgers directly, so this script // reads them read-only and writes a redacted snapshot for ams-ledgers-datasource.test.ts's provisioning to point // at. Mirrors selfhost-grafana-reporting.test.ts's spawn-the-real-script style. const tmpRoots: string[] = []; @@ -41,7 +41,7 @@ function runExporter( ...process.env, GITTENSORY_AMS_ATTEMPT_LOG_SOURCE_DB: overrides.attemptLogSource ?? join(root, "attempt-log.sqlite3"), GITTENSORY_AMS_PREDICTION_LEDGER_SOURCE_DB: overrides.predictionLedgerSource ?? join(root, "prediction-ledger.sqlite3"), - GITTENSORY_REPORTING_DIR: reportingDir, + LOOPOVER_REPORTING_DIR: reportingDir, ...(overrides.scriptVersion ? { GITTENSORY_AMS_REPORTING_SCRIPT_VERSION: overrides.scriptVersion } : {}), }, stdio: "pipe", diff --git a/test/unit/selfhost-compose-resource-limits.test.ts b/test/unit/selfhost-compose-resource-limits.test.ts index 033bf8db62..26df9d8803 100644 --- a/test/unit/selfhost-compose-resource-limits.test.ts +++ b/test/unit/selfhost-compose-resource-limits.test.ts @@ -15,7 +15,7 @@ function readYaml(path: string): Record { // would be unreliable/environment-dependent here (same constraint as docker-compose-override-example.test.ts). describe("docker-compose.yml — per-service memory limits (#1828, #2495, #3893)", () => { const EXPECTED_LIMITS: Record = { - loopover: "${GITTENSORY_MEM_LIMIT:-2g}", + loopover: "${LOOPOVER_MEM_LIMIT:-2g}", redis: "${REDIS_MEM_LIMIT:-512m}", postgres: "${POSTGRES_MEM_LIMIT:-2g}", qdrant: "${QDRANT_MEM_LIMIT:-2g}", @@ -51,7 +51,7 @@ describe("docker-compose.yml — per-service memory limits (#1828, #2495, #3893) const env = readFileSync(".env.example", "utf8"); for (const key of [ - "GITTENSORY_MEM_LIMIT", + "LOOPOVER_MEM_LIMIT", "REDIS_MEM_LIMIT", "POSTGRES_MEM_LIMIT", "QDRANT_MEM_LIMIT", diff --git a/test/unit/selfhost-grafana-reporting.test.ts b/test/unit/selfhost-grafana-reporting.test.ts index 0f68bcfee7..c83e11fecc 100644 --- a/test/unit/selfhost-grafana-reporting.test.ts +++ b/test/unit/selfhost-grafana-reporting.test.ts @@ -33,9 +33,9 @@ function runExporter(root: string, sourceDb: string, outDb: string, env: Record< cwd: process.cwd(), env: { ...process.env, - GITTENSORY_REPORTING_SOURCE_DB: sourceDb, - GITTENSORY_REPORTING_DIR: root, - GITTENSORY_REPORTING_DB: outDb, + LOOPOVER_REPORTING_SOURCE_DB: sourceDb, + LOOPOVER_REPORTING_DIR: root, + LOOPOVER_REPORTING_DB: outDb, ...env, }, stdio: "pipe",