diff --git a/.gitignore b/.gitignore index 5576955107..8af72bc464 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,8 @@ output/ .env.* !.env.example # Operator-filled miner secrets for docker-compose fleet mode (#5177); the .example is committed. -.gittensory-miner.env -!.gittensory-miner.env.example +.loopover-miner.env +!.loopover-miner.env.example !.env.selfhost.example # Docker Compose secret files: the actual secret VALUES an operator drops into # secrets/.txt for the native `secrets:` mount (docker-compose.yml), read via the existing generic diff --git a/.gittensory-ams.yml.example b/.loopover-ams.yml.example similarity index 90% rename from .gittensory-ams.yml.example rename to .loopover-ams.yml.example index 8b23206b6a..9b4e4a7e18 100644 --- a/.gittensory-ams.yml.example +++ b/.loopover-ams.yml.example @@ -1,8 +1,8 @@ # ============================================================================ -# .gittensory-ams.yml - operator execution policy (EXAMPLE) +# .loopover-ams.yml - operator execution policy (EXAMPLE) # ============================================================================ # This is the OPERATOR's own execution-risk policy for their autonomous miner -# (AMS) -- a deliberate structural sibling to `.gittensory-miner.yml` +# (AMS) -- a deliberate structural sibling to `.loopover-miner.yml` # (MinerGoalSpec), but answering a different question. MinerGoalSpec is what a # TARGET REPO wants from being mined (paths, labels, whether it's minable at # all). This file is how aggressive the OPERATOR wants their own agent to be @@ -11,7 +11,7 @@ # willing to do -- see below for why. # # OPERATOR-LOCAL ONLY: the miner reads this file from the operator's local -# gittensory-miner config dir. It intentionally does not fetch a target repo's +# loopover-miner config dir. It intentionally does not fetch a target repo's # checked-in AMS policy, because untrusted repo content must not loosen # operator-side budget, turn, slop, or submission controls. # @@ -20,7 +20,7 @@ # ignored, and a single malformed field falls back to its default with a # warning. # -# Copy to `.gittensory-ams.yml` and edit. YAML or JSON are both accepted. +# Copy to `.loopover-ams.yml` and edit. YAML or JSON are both accepted. # Whether a real attempt is allowed to actually submit (open a PR), or only # compute + log its decision. "observe" still runs every real signal/decision diff --git a/.gittensory-miner.env.example b/.loopover-miner.env.example similarity index 85% rename from .gittensory-miner.env.example rename to .loopover-miner.env.example index 249fa26466..a78015a81f 100644 --- a/.gittensory-miner.env.example +++ b/.loopover-miner.env.example @@ -1,9 +1,9 @@ -# gittensory-miner — starter env file +# loopover-miner — starter env file # -# Copy this to `.gittensory-miner.env` (gitignored), fill in GITHUB_TOKEN, then either `source` it or +# Copy this to `.loopover-miner.env` (gitignored), fill in GITHUB_TOKEN, then either `source` it or # point docker-compose / systemd at it — see packages/loopover-miner/DEPLOYMENT.md: # -# cp .gittensory-miner.env.example .gittensory-miner.env +# cp .loopover-miner.env.example .loopover-miner.env # # Every value below is a SAMPLE placeholder — never commit real secrets. For the generated, # always-current table of every miner env var and its default, see @@ -31,13 +31,13 @@ GITHUB_TOKEN=ghp_your_token_here # 3. Optional overrides — defaults are fine for a single-machine install # ============================================================================= # 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, +# ~/.config), in a loopover-miner/ subdirectory. Set the base dir, or any individual store path, # only to relocate state (e.g. onto a dedicated volume). -# LOOPOVER_MINER_CONFIG_DIR=/var/lib/gittensory-miner +# LOOPOVER_MINER_CONFIG_DIR=/var/lib/loopover-miner # Repo clones and git worktrees created during attempts: -# LOOPOVER_MINER_REPO_CLONE_DIR=/var/lib/gittensory-miner/clones -# LOOPOVER_MINER_WORKTREE_DIR=/var/lib/gittensory-miner/worktrees +# LOOPOVER_MINER_REPO_CLONE_DIR=/var/lib/loopover-miner/clones +# LOOPOVER_MINER_WORKTREE_DIR=/var/lib/loopover-miner/worktrees # Per-store SQLite file overrides (each defaults to a file under the config dir above): # LOOPOVER_MINER_CLAIM_LEDGER_DB= diff --git a/.gittensory-miner.yml.example b/.loopover-miner.yml.example similarity index 91% rename from .gittensory-miner.yml.example rename to .loopover-miner.yml.example index e271c45e9e..b4a4ba1e3e 100644 --- a/.gittensory-miner.yml.example +++ b/.loopover-miner.yml.example @@ -1,9 +1,9 @@ # ============================================================================ -# .gittensory-miner.yml - per-repo miner configuration (EXAMPLE) +# .loopover-miner.yml - per-repo miner configuration (EXAMPLE) # ============================================================================ # A repo owner drops this file in to tell an autonomous Gittensory miner what to # look for and how to behave when targeting their repo. It is the MINER-side -# analogue of `.gittensory.yml` (the review-side focus manifest). +# analogue of `.loopover.yml` (the review-side focus manifest). # # Every field is OPTIONAL and has a safe default (shown as "Default: X" below). # The file is parsed tolerantly: an unknown key is ignored, and a single @@ -11,10 +11,10 @@ # hard-fails the miner, it just falls back to the defaults. # # Discovery order (first match wins): -# .gittensory-miner.yml -> .github/gittensory-miner.yml -# -> .gittensory-miner.json -> .github/gittensory-miner.json +# .loopover-miner.yml -> .github/loopover-miner.yml +# -> .loopover-miner.json -> .github/loopover-miner.json # -# Copy to `.gittensory-miner.yml` and edit. YAML or JSON are both accepted. +# Copy to `.loopover-miner.yml` and edit. YAML or JSON are both accepted. # Whether this repo permits autonomous miners at all. Explicit OPT-OUT: a public # repo with no file is still minable. Set false to halt all miner targeting. diff --git a/packages/loopover-engine/README.md b/packages/loopover-engine/README.md index d9b83744fe..5e00bd1406 100644 --- a/packages/loopover-engine/README.md +++ b/packages/loopover-engine/README.md @@ -630,7 +630,7 @@ module defines the storage contract only — it does not wire into live governor ## MinerGoalSpec -`MinerGoalSpec` is the type surface for a repo's `.gittensory-miner.yml` (miner-side analogue of `.loopover.yml`). +`MinerGoalSpec` is the type surface for a repo's `.loopover-miner.yml` (miner-side analogue of `.loopover.yml`). `DEFAULT_MINER_GOAL_SPEC` is the safe default a repo with no file behaves as — minable (`minerEnabled: true`, an explicit opt-out), no path/label preferences, one concurrent claim, `neutral` discovery. @@ -639,13 +639,13 @@ never throw on malformed JSON/YAML; instead they return `{ present, spec, warnin safe defaults and `warnings` explains any dropped or invalid fields. `discoverMinerGoalSpecPath(exists)` returns the first present file in the documented order (`MINER_GOAL_SPEC_FILENAMES`: -`.gittensory-miner.yml` → `.github/gittensory-miner.yml` → the `.json` variants). It is IO-free — the caller injects +`.loopover-miner.yml` → `.github/loopover-miner.yml` → the `.json` variants). It is IO-free — the caller injects the existence check — so a caller reads the returned path and feeds its content to `parseMinerGoalSpecContent`. See -`.gittensory-miner.yml.example` for the documented fields. +`.loopover-miner.yml.example` for the documented fields. ## AmsPolicySpec -`AmsPolicySpec` is the type surface for `.gittensory-ams.yml` — the OPERATOR's own execution-risk policy for +`AmsPolicySpec` is the type surface for `.loopover-ams.yml` — the OPERATOR's own execution-risk policy for their miner (`submissionMode`, `slopThreshold`, `capLimits`, `convergenceThresholds`, `maxIterations`, `maxTurnsPerIteration`), a deliberate structural sibling to `MinerGoalSpec` but answering a different question: `MinerGoalSpec` is what the target repo wants from being mined; `AmsPolicySpec` is how aggressive the operator wants their own agent to be. No field on this @@ -656,11 +656,11 @@ submission mode (computes real decisions but never actually submits) and a `"low `parseAmsPolicySpec(raw)` / `parseAmsPolicySpecContent(content)` are the same tolerant-parser pair shape as `MinerGoalSpec`'s — never throw, return `{ present, spec, warnings }`. -Unlike `MinerGoalSpec`, this package does not resolve `.gittensory-ams.yml` from the filesystem itself (this +Unlike `MinerGoalSpec`, this package does not resolve `.loopover-ams.yml` from the filesystem itself (this package is IO-free) — `packages/loopover-miner/lib/ams-policy.js`'s `resolveAmsPolicy` is the real caller. That resolver reads only the operator's local policy and otherwise uses safe defaults; it intentionally does not fetch a target repo's checked-in AMS policy, because untrusted repo content must not loosen operator-side budget, -turn, slop, or submission controls. See `.gittensory-ams.yml.example`. +turn, slop, or submission controls. See `.loopover-ams.yml.example`. ## Repo map builder diff --git a/packages/loopover-engine/src/ams-policy-spec.ts b/packages/loopover-engine/src/ams-policy-spec.ts index b5f4741873..00bc6d7434 100644 --- a/packages/loopover-engine/src/ams-policy-spec.ts +++ b/packages/loopover-engine/src/ams-policy-spec.ts @@ -2,9 +2,9 @@ import { parse as parseYaml } from "yaml"; import { DEFAULT_PORTFOLIO_CONVERGENCE_THRESHOLDS, type PortfolioConvergenceThresholds } from "./portfolio/non-convergence.js"; -// AmsPolicySpec (#5132, Wave 3.5 follow-up). The type surface for `.gittensory-ams.yml` -- the OPERATOR's own +// AmsPolicySpec (#5132, Wave 3.5 follow-up). The type surface for `.loopover-ams.yml` -- the OPERATOR's own // execution-risk policy for their miner (AMS: the autonomous mining system this file's fields configure), as -// opposed to `.gittensory-miner.yml` / MinerGoalSpec (this file's direct structural sibling), which is the +// opposed to `.loopover-miner.yml` / MinerGoalSpec (this file's direct structural sibling), which is the // TARGET REPO's own preferences about being mined at all. That distinction is deliberate and load-bearing: a // target repo's own checked-in file legitimately gets to say "don't mine me" or "focus on these paths" -- // but it must NEVER get to say "let the operator's agent spend more budget" or "submit live instead of @@ -13,7 +13,7 @@ import { DEFAULT_PORTFOLIO_CONVERGENCE_THRESHOLDS, type PortfolioConvergenceThre // repo could use to loosen what an operator's agent is willing to do. // // Resolution deliberately stays operator-local: packages/loopover-miner/lib/ams-policy.js reads only the -// operator's own local `.gittensory-ams.yml` (in their `gittensory-miner` config dir) and otherwise uses safe +// operator's own local `.loopover-ams.yml` (in their `loopover-miner` config dir) and otherwise uses safe // defaults. It does not fetch a target repo's checked-in file, because that would let untrusted repo content // loosen operator-side budget, turn, slop, or submission controls. @@ -36,7 +36,7 @@ export type AmsCapLimits = { elapsedMs: number; }; -/** Per-operator AMS execution policy parsed from `.gittensory-ams.yml`. See {@link DEFAULT_AMS_POLICY_SPEC}. */ +/** Per-operator AMS execution policy parsed from `.loopover-ams.yml`. See {@link DEFAULT_AMS_POLICY_SPEC}. */ export type AmsPolicySpec = { /** Whether a real attempt may actually submit. Default: "observe" (deny-by-default). */ submissionMode: AmsSubmissionMode; @@ -53,7 +53,7 @@ export type AmsPolicySpec = { maxTurnsPerIteration: number; }; -/** The tolerant parser result for `.gittensory-ams.yml`. Mirrors `ParsedMinerGoalSpec`'s present/warnings shape. */ +/** The tolerant parser result for `.loopover-ams.yml`. Mirrors `ParsedMinerGoalSpec`'s present/warnings shape. */ export type ParsedAmsPolicySpec = { present: boolean; spec: AmsPolicySpec; @@ -61,7 +61,7 @@ export type ParsedAmsPolicySpec = { }; /** - * The safe defaults applied when a field is absent from `.gittensory-ams.yml` (or the file itself is + * The safe defaults applied when a field is absent from `.loopover-ams.yml` (or the file itself is * missing). Deep-frozen: a shared singleton, clone before layering overrides on top. */ export const DEFAULT_AMS_POLICY_SPEC: Readonly = Object.freeze({ @@ -183,7 +183,7 @@ function utf8ByteLength(value: string): number { } /** - * Tolerantly normalize an already-parsed `.gittensory-ams.yml` object into a {@link ParsedAmsPolicySpec}. + * Tolerantly normalize an already-parsed `.loopover-ams.yml` object into a {@link ParsedAmsPolicySpec}. * Never throws: malformed shapes degrade to safe defaults and accumulate warnings. */ export function parseAmsPolicySpec(raw: unknown): ParsedAmsPolicySpec { @@ -218,7 +218,7 @@ export function parseAmsPolicySpec(raw: unknown): ParsedAmsPolicySpec { } /** - * Parse raw `.gittensory-ams.yml` file content (JSON or YAML). Malformed content degrades to an absent + * Parse raw `.loopover-ams.yml` file content (JSON or YAML). Malformed content degrades to an absent * policy spec with a warning rather than throwing, mirroring `parseMinerGoalSpecContent`. */ export function parseAmsPolicySpecContent(content: string | null | undefined): ParsedAmsPolicySpec { @@ -241,5 +241,5 @@ export function parseAmsPolicySpecContent(content: string | null | undefined): P return parseAmsPolicySpec(parsed); } -/** The documented `.gittensory-ams` file-discovery order (first match wins), mirroring `MINER_GOAL_SPEC_FILENAMES`. */ -export const AMS_POLICY_SPEC_FILENAMES = [".gittensory-ams.yml", ".github/gittensory-ams.yml", ".gittensory-ams.json", ".github/gittensory-ams.json"] as const; +/** The documented `.loopover-ams` file-discovery order (first match wins), mirroring `MINER_GOAL_SPEC_FILENAMES`. */ +export const AMS_POLICY_SPEC_FILENAMES = [".loopover-ams.yml", ".github/loopover-ams.yml", ".loopover-ams.json", ".github/loopover-ams.json"] as const; diff --git a/packages/loopover-engine/src/fleet-run-manifest.ts b/packages/loopover-engine/src/fleet-run-manifest.ts index aa34e5f2a5..ba7ba65b35 100644 --- a/packages/loopover-engine/src/fleet-run-manifest.ts +++ b/packages/loopover-engine/src/fleet-run-manifest.ts @@ -2,7 +2,7 @@ import { parse as parseYaml } from "yaml"; // FleetRunManifest (#4299). The top-level config a *fleet operator* authors to run the miner across many repos: // which repos are in scope for a fleet run, and how a finite worktree/concurrency budget is split between them. -// This is the OPERATOR-side analogue of, and deliberately NOT the same file as, `.gittensory-miner.yml` (see +// This is the OPERATOR-side analogue of, and deliberately NOT the same file as, `.loopover-miner.yml` (see // miner-goal-spec.ts): that one is authored by a *target repo's maintainer* to say how their one repo wants to be // approached. Same tolerant-parser convention (every field optional, unknown keys ignored, malformed input // degrades to a documented default with a warning rather than throwing); opposite author and direction of intent. diff --git a/packages/loopover-engine/src/focus-manifest.ts b/packages/loopover-engine/src/focus-manifest.ts index 627a065a2e..8ba9da8c98 100644 --- a/packages/loopover-engine/src/focus-manifest.ts +++ b/packages/loopover-engine/src/focus-manifest.ts @@ -1,7 +1,7 @@ /** * Focus-manifest parse/compile core (#2280). Extracted to `@loopover/engine` so the maintainer * review stack and the miner's goal-spec parser share identical, versioned manifest logic instead of drifting - * apart. This is the MINER-side parse-pattern template for {@link MinerGoalSpec} (`.gittensory-miner.yml`) — + * apart. This is the MINER-side parse-pattern template for {@link MinerGoalSpec} (`.loopover-miner.yml`) — * same tolerant-parser shape: typed config + safe defaults + warnings, never throws. * * App-local resolver/guidance functions (`resolveEffectiveSettings`, `buildFocusManifestGuidance`, etc.) remain diff --git a/packages/loopover-engine/src/governor/action-mode.ts b/packages/loopover-engine/src/governor/action-mode.ts index e61646520f..b0161183dc 100644 --- a/packages/loopover-engine/src/governor/action-mode.ts +++ b/packages/loopover-engine/src/governor/action-mode.ts @@ -40,7 +40,7 @@ export function isGlobalMinerLiveModeOptIn(env: Record `"paused"` -- always wins, regardless of any live-mode opt-in. - * 2. BOTH the operator's global env config AND the target repo's own `.gittensory-miner.yml` + * 2. BOTH the operator's global env config AND the target repo's own `.loopover-miner.yml` * (`MinerGoalSpec.execution.liveModeOptIn`) explicitly opt in -> `"live"`. The repo field is a repo-side * allowance, not an operator-authored authorization to execute writes under the miner's credentials. * 3. Otherwise -> `"dry_run"`. No config anywhere, either side omitted, or a malformed/partial config that fails diff --git a/packages/loopover-engine/src/governor/kill-switch.ts b/packages/loopover-engine/src/governor/kill-switch.ts index 1889dbe22c..1f49f119e9 100644 --- a/packages/loopover-engine/src/governor/kill-switch.ts +++ b/packages/loopover-engine/src/governor/kill-switch.ts @@ -1,6 +1,6 @@ // Governor kill-switch (#2341): the emergency-halt primitive every write-adjacent governor decision consults // FIRST, before any other calculator. Two independent triggers compose into one scope: a GLOBAL env-level -// switch that halts every repo at once, and a PER-REPO switch (from `.gittensory-miner.yml`'s MinerGoalSpec +// switch that halts every repo at once, and a PER-REPO switch (from `.loopover-miner.yml`'s MinerGoalSpec // `killSwitch.paused` field) that halts only its own repo's queue while leaving the rest of the fleet running. // Mirrors `src/settings/agent-execution.ts`'s `isGlobalAgentPause` truthy-string idiom for the review-stack's // own kill-switch (#776) — a parallel mechanism for the miner's own local runtime, not the same one. diff --git a/packages/loopover-engine/src/governor/reputation-throttle.ts b/packages/loopover-engine/src/governor/reputation-throttle.ts index 17e04eb731..a1667d9d53 100644 --- a/packages/loopover-engine/src/governor/reputation-throttle.ts +++ b/packages/loopover-engine/src/governor/reputation-throttle.ts @@ -19,7 +19,7 @@ export type SelfReputationThresholds = { minCadenceFactor: number; }; -/** Conservative built-in defaults; a `.gittensory-miner.yml` override is merged over these. */ +/** Conservative built-in defaults; a `.loopover-miner.yml` override is merged over these. */ export const DEFAULT_SELF_REPUTATION_THRESHOLDS: SelfReputationThresholds = Object.freeze({ minSampleSize: 5, @@ -64,7 +64,7 @@ function round3(value: number): number { } /** - * Merge a partial (e.g. `.gittensory-miner.yml`-sourced) threshold config over the conservative defaults, + * Merge a partial (e.g. `.loopover-miner.yml`-sourced) threshold config over the conservative defaults, * normalizing every field so a malformed value can never produce a NaN/negative/out-of-range decision. The * throttle band is kept well-formed: `floorAtRatio` is pulled to at least `throttleAtRatio` so the interpolation * span is never negative. diff --git a/packages/loopover-engine/src/index.ts b/packages/loopover-engine/src/index.ts index df3c09ba4d..7f85cbd616 100644 --- a/packages/loopover-engine/src/index.ts +++ b/packages/loopover-engine/src/index.ts @@ -607,7 +607,7 @@ export { type ContributorCalibrationSignal, } from "./predicted-gate.js"; // Focus-manifest parse/compile core (#2280): shared by the maintainer review stack and the miner's -// `.gittensory-miner.yml` goal-spec parser (see miner-goal-spec.ts for the parallel surface). +// `.loopover-miner.yml` goal-spec parser (see miner-goal-spec.ts for the parallel surface). export { compileFocusManifestPolicy, contentLaneConfigToJson, diff --git a/packages/loopover-engine/src/miner-goal-spec.ts b/packages/loopover-engine/src/miner-goal-spec.ts index 710f657bb2..c6ee75a57b 100644 --- a/packages/loopover-engine/src/miner-goal-spec.ts +++ b/packages/loopover-engine/src/miner-goal-spec.ts @@ -6,7 +6,7 @@ import { resolveSelfPlagiarismConfig, } from "./governor/self-plagiarism.js"; -// MinerGoalSpec (#2293 / #2301). The type surface for `.gittensory-miner.yml` — the per-repo config a +// MinerGoalSpec (#2293 / #2301). The type surface for `.loopover-miner.yml` — the per-repo config a // maintainer/repo-owner drops in to tell an autonomous miner what to look for and how to behave when targeting // their repo. This is the MINER-side analogue of the review-side `.loopover.yml` focus manifest (see // `src/signals/focus-manifest.ts`'s `FocusManifest`): a small typed config object paired with explicit @@ -57,11 +57,11 @@ export type MinerExecutionPolicy = { liveModeOptIn: typeof MINER_LIVE_MODE_OPT_IN | null; }; -/** Per-repo miner configuration parsed from `.gittensory-miner.yml`. See {@link DEFAULT_MINER_GOAL_SPEC}. */ +/** Per-repo miner configuration parsed from `.loopover-miner.yml`. See {@link DEFAULT_MINER_GOAL_SPEC}. */ export type MinerGoalSpec = { /** * Whether this repo permits autonomous miners at all. Explicit OPT-OUT, not opt-in: a public repo with no - * `.gittensory-miner.yml` is still minable, mirroring `.loopover.yml`'s "safe by default" stance. Set `false` + * `.loopover-miner.yml` is still minable, mirroring `.loopover.yml`'s "safe by default" stance. Set `false` * to halt all miner targeting of this repo. Default: true. */ minerEnabled: boolean; @@ -117,7 +117,7 @@ export type MinerGoalSpec = { execution: MinerExecutionPolicy; }; -/** The tolerant parser result for `.gittensory-miner.yml`: the normalized spec plus parse warnings and whether the +/** The tolerant parser result for `.loopover-miner.yml`: the normalized spec plus parse warnings and whether the * file actually expressed any non-default goal fields. Mirrors `parseFocusManifest`'s present/warnings pattern * without forcing metadata onto downstream consumers that only need the config itself. */ export type ParsedMinerGoalSpec = { @@ -127,7 +127,7 @@ export type ParsedMinerGoalSpec = { }; /** - * The safe defaults applied when a field is absent from `.gittensory-miner.yml` (or the file itself is missing). + * The safe defaults applied when a field is absent from `.loopover-miner.yml` (or the file itself is missing). * Every value here matches the "Default: X" documented on its field above. Analogous to the defaults constant that * accompanies `FocusManifest` in `src/signals/focus-manifest.ts` — a repo with no file behaves as if it declared * this: minable, with no path/label preferences, one concurrent claim, and neutral discovery. @@ -352,7 +352,7 @@ function hasConfiguredGoalFields(spec: MinerGoalSpec): boolean { } /** - * Tolerantly normalize an already-parsed `.gittensory-miner.yml` object into a {@link ParsedMinerGoalSpec}. + * Tolerantly normalize an already-parsed `.loopover-miner.yml` object into a {@link ParsedMinerGoalSpec}. * Never throws: malformed shapes degrade to safe defaults and accumulate warnings so callers can surface * "your miner goal spec had problems" without hard-failing a run. */ @@ -411,7 +411,7 @@ export function parseMinerGoalSpec(raw: unknown): ParsedMinerGoalSpec { } /** - * Parse raw `.gittensory-miner.yml` file content (JSON or YAML). Malformed content degrades to an absent + * Parse raw `.loopover-miner.yml` file content (JSON or YAML). Malformed content degrades to an absent * goal spec with a warning rather than throwing, mirroring `parseFocusManifestContent`. */ export function parseMinerGoalSpecContent(content: string | null | undefined): ParsedMinerGoalSpec { @@ -437,14 +437,14 @@ export function parseMinerGoalSpecContent(content: string | null | undefined): P } /** - * The documented `.gittensory-miner` file-discovery order (first match wins), mirroring how `.loopover.yml` is + * The documented `.loopover-miner` file-discovery order (first match wins), mirroring how `.loopover.yml` is * discovered: repo-root YAML, then `.github/` YAML, then the JSON variants. */ export const MINER_GOAL_SPEC_FILENAMES = [ - ".gittensory-miner.yml", - ".github/gittensory-miner.yml", - ".gittensory-miner.json", - ".github/gittensory-miner.json", + ".loopover-miner.yml", + ".github/loopover-miner.yml", + ".loopover-miner.json", + ".github/loopover-miner.json", ] as const; /** diff --git a/packages/loopover-engine/src/miner/iterate-policy.ts b/packages/loopover-engine/src/miner/iterate-policy.ts index 5c593ce259..b7e9a13ee7 100644 --- a/packages/loopover-engine/src/miner/iterate-policy.ts +++ b/packages/loopover-engine/src/miner/iterate-policy.ts @@ -17,7 +17,7 @@ // // AUTONOMY DIAL (not yet wired): `src/settings/autonomy.ts`'s `resolveAutonomy`/`isActingAutonomyLevel` is the // existing reusable deny-by-default pattern this policy's eventual live autonomy-level check should consult -// once `.gittensory-miner.yml` defines autonomy fields -- that wiring is explicitly left to a later phase; this +// once `.loopover-miner.yml` defines autonomy fields -- that wiring is explicitly left to a later phase; this // module's `decideNextAction` is autonomy-level-agnostic today. import type { SelfReviewVerdict } from "./self-review-adapter.js"; diff --git a/packages/loopover-engine/src/phase7-calibration-loop.ts b/packages/loopover-engine/src/phase7-calibration-loop.ts index bbd1eb2215..3309e9b83d 100644 --- a/packages/loopover-engine/src/phase7-calibration-loop.ts +++ b/packages/loopover-engine/src/phase7-calibration-loop.ts @@ -195,7 +195,7 @@ function markdownList(values: readonly string[]): string { } /** - * Resolve the explicit Phase 7 loop config from a parsed `.gittensory-miner.yml`-style object. Default is disabled + * Resolve the explicit Phase 7 loop config from a parsed `.loopover-miner.yml`-style object. Default is disabled * and fail-closed when enabled but inputs are missing or degraded. */ export function resolvePhase7CalibrationConfig( diff --git a/packages/loopover-engine/test/ams-policy-spec-parser.test.ts b/packages/loopover-engine/test/ams-policy-spec-parser.test.ts index 41c1d690b2..9d80e87af6 100644 --- a/packages/loopover-engine/test/ams-policy-spec-parser.test.ts +++ b/packages/loopover-engine/test/ams-policy-spec-parser.test.ts @@ -11,10 +11,10 @@ test("barrel: the public entrypoint re-exports the AmsPolicySpec parser API", () assert.equal(typeof parseAmsPolicySpec, "function"); assert.equal(typeof parseAmsPolicySpecContent, "function"); assert.deepEqual(AMS_POLICY_SPEC_FILENAMES, [ - ".gittensory-ams.yml", - ".github/gittensory-ams.yml", - ".gittensory-ams.json", - ".github/gittensory-ams.json", + ".loopover-ams.yml", + ".github/loopover-ams.yml", + ".loopover-ams.json", + ".github/loopover-ams.json", ]); }); diff --git a/packages/loopover-engine/test/miner-goal-spec-discovery.test.ts b/packages/loopover-engine/test/miner-goal-spec-discovery.test.ts index 0d4bd583ff..84903cafa5 100644 --- a/packages/loopover-engine/test/miner-goal-spec-discovery.test.ts +++ b/packages/loopover-engine/test/miner-goal-spec-discovery.test.ts @@ -7,33 +7,33 @@ import { discoverMinerGoalSpecPath, MINER_GOAL_SPEC_FILENAMES } from "../dist/in test("MINER_GOAL_SPEC_FILENAMES lists the documented discovery order", () => { assert.deepEqual([...MINER_GOAL_SPEC_FILENAMES], [ - ".gittensory-miner.yml", - ".github/gittensory-miner.yml", - ".gittensory-miner.json", - ".github/gittensory-miner.json", + ".loopover-miner.yml", + ".github/loopover-miner.yml", + ".loopover-miner.json", + ".github/loopover-miner.json", ]); }); test("discoverMinerGoalSpecPath: returns the first existing candidate, first match wins", () => { - assert.equal(discoverMinerGoalSpecPath(() => true), ".gittensory-miner.yml"); + assert.equal(discoverMinerGoalSpecPath(() => true), ".loopover-miner.yml"); // repo-root yml missing but the .github yml present → that one is chosen assert.equal( - discoverMinerGoalSpecPath((p) => p !== ".gittensory-miner.yml"), - ".github/gittensory-miner.yml", + discoverMinerGoalSpecPath((p) => p !== ".loopover-miner.yml"), + ".github/loopover-miner.yml", ); // only a JSON variant present - assert.equal(discoverMinerGoalSpecPath((p) => p === ".gittensory-miner.json"), ".gittensory-miner.json"); + assert.equal(discoverMinerGoalSpecPath((p) => p === ".loopover-miner.json"), ".loopover-miner.json"); }); test("discoverMinerGoalSpecPath: short-circuits — stops probing once a candidate matches", () => { const probed: string[] = []; const result = discoverMinerGoalSpecPath((p) => { probed.push(p); - return p === ".github/gittensory-miner.yml"; // the 2nd candidate matches + return p === ".github/loopover-miner.yml"; // the 2nd candidate matches }); - assert.equal(result, ".github/gittensory-miner.yml"); + assert.equal(result, ".github/loopover-miner.yml"); // only the first two candidates are probed; the later .json variants are never reached - assert.deepEqual(probed, [".gittensory-miner.yml", ".github/gittensory-miner.yml"]); + assert.deepEqual(probed, [".loopover-miner.yml", ".github/loopover-miner.yml"]); }); test("discoverMinerGoalSpecPath: returns null when no candidate exists, and never probes unlisted paths", () => { diff --git a/packages/loopover-miner/.gittensory-miner.env.example b/packages/loopover-miner/.loopover-miner.env.example similarity index 85% rename from packages/loopover-miner/.gittensory-miner.env.example rename to packages/loopover-miner/.loopover-miner.env.example index 60d2bd61b7..7e61da4093 100644 --- a/packages/loopover-miner/.gittensory-miner.env.example +++ b/packages/loopover-miner/.loopover-miner.env.example @@ -1,4 +1,4 @@ -# Env file for docker-compose.miner.yml (#5177). Copy to `.gittensory-miner.env`, fill in real values, and do +# Env file for docker-compose.miner.yml (#5177). Copy to `.loopover-miner.env`, fill in real values, and do # NOT commit the filled-in copy. Values are intentionally EMPTY here (a real-looking value in a committed file # trips secret scanners). Compose reads `KEY=value` lines; leave a key blank or delete it if unused. # diff --git a/packages/loopover-miner/DEPLOYMENT.md b/packages/loopover-miner/DEPLOYMENT.md index 8c658b3bbb..e53f2facd5 100644 --- a/packages/loopover-miner/DEPLOYMENT.md +++ b/packages/loopover-miner/DEPLOYMENT.md @@ -73,7 +73,7 @@ For provider selection and the CLI-specific model/timeout overrides, see `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). +4. Optional per-repo miner goals: copy [`.loopover-miner.yml.example`](../../.loopover-miner.yml.example) to a target repo as `.loopover-miner.yml`. See [`docs/miner-goal-spec.md`](docs/miner-goal-spec.md). ## Fleet mode walkthrough @@ -129,7 +129,7 @@ The repo-root [`docker-compose.yml`](../../docker-compose.yml) documents the **s Instead of a hand-assembled `docker run`, [`docker-compose.miner.yml`](docker-compose.miner.yml) defines a long-lived `miner` service (built from this package's Dockerfile, `restart: unless-stopped`, state on a named `miner-data` volume). Credentials come from an env file, never inlined: ```sh -cp .gittensory-miner.env.example .gittensory-miner.env # fill in GITHUB_TOKEN (+ optional provider keys) +cp .loopover-miner.env.example .loopover-miner.env # fill in GITHUB_TOKEN (+ optional provider keys) docker compose -f docker-compose.miner.yml up -d --build ``` diff --git a/packages/loopover-miner/README.md b/packages/loopover-miner/README.md index f3878983fa..d5ba8e2764 100644 --- a/packages/loopover-miner/README.md +++ b/packages/loopover-miner/README.md @@ -16,7 +16,7 @@ Current scope is intentionally small: 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. -Config precedence (`.gittensory-miner.yml` vs operator env vs CLI flags) is documented in +Config precedence (`.loopover-miner.yml` vs operator env vs CLI flags) is documented in [`docs/config-precedence.md`](docs/config-precedence.md). A committed micro-benchmark for the discovery-ranking and local-store read/write paths lives at @@ -153,7 +153,7 @@ enough (e.g. a live-polling dashboard) that the per-read linear event-ledger sca ## Install -See [`docs/miner-goal-spec.md`](docs/miner-goal-spec.md) for the `.gittensory-miner.yml` field reference and [`.gittensory-miner.yml.example`](../../.gittensory-miner.yml.example) at the repo root. +See [`docs/miner-goal-spec.md`](docs/miner-goal-spec.md) for the `.loopover-miner.yml` field reference and [`.loopover-miner.yml.example`](../../.loopover-miner.yml.example) at the repo root. See [`docs/cross-repo-discovery-phase1.md`](docs/cross-repo-discovery-phase1.md) for the Phase 1 cross-repo discovery scope (re-scoped from [#1060](https://github.com/JSONbored/gittensory/issues/1060), paper trail for [#2299](https://github.com/JSONbored/gittensory/issues/2299)). diff --git a/packages/loopover-miner/docker-compose.miner.yml b/packages/loopover-miner/docker-compose.miner.yml index b0cd3356d2..a1a01b8260 100644 --- a/packages/loopover-miner/docker-compose.miner.yml +++ b/packages/loopover-miner/docker-compose.miner.yml @@ -5,7 +5,7 @@ # comments in packages/loopover-miner/Dockerfile. # # Usage: -# 1. Create the env file (never commit real values): cp .gittensory-miner.env.example .gittensory-miner.env +# 1. Create the env file (never commit real values): cp .loopover-miner.env.example .loopover-miner.env # 2. Start one worker: docker compose -f docker-compose.miner.yml up -d --build # # Scaling to N parallel workers: @@ -31,7 +31,7 @@ services: # Operator-supplied secrets/config (GITHUB_TOKEN, optional provider keys). Copy the .example, fill it in, # 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 + - .loopover-miner.env # 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, diff --git a/packages/loopover-miner/docs/coding-agent-driver.md b/packages/loopover-miner/docs/coding-agent-driver.md index dbebb188a9..48865ce37e 100644 --- a/packages/loopover-miner/docs/coding-agent-driver.md +++ b/packages/loopover-miner/docs/coding-agent-driver.md @@ -136,5 +136,5 @@ which axis (if any) triggered an abandon, for an operator reading the attempt lo - [`operations-runbook.md`](operations-runbook.md) — SQLite `busy_timeout` concurrency, corruption recovery, multi-process collisions, post-upgrade migration ([#4875](https://github.com/JSONbored/gittensory/issues/4875)). - [`env-reference.md`](env-reference.md) — env vars including ledger path overrides. - [`../DEPLOYMENT.md`](../DEPLOYMENT.md) — laptop vs fleet deployment and state directory layout. -- [`miner-goal-spec.md`](miner-goal-spec.md) — per-repo `.gittensory-miner.yml` targeting policy. +- [`miner-goal-spec.md`](miner-goal-spec.md) — per-repo `.loopover-miner.yml` targeting policy. - [`../README.md#mcp-server`](../README.md#mcp-server) — the `loopover-miner-mcp` read-only tool surface for querying this driver's resolved status (provider, model env-var name, CLI presence) and the rest of AMS's local state over MCP. diff --git a/packages/loopover-miner/docs/config-precedence.md b/packages/loopover-miner/docs/config-precedence.md index f70ba91ee9..b3615ff5ce 100644 --- a/packages/loopover-miner/docs/config-precedence.md +++ b/packages/loopover-miner/docs/config-precedence.md @@ -6,27 +6,27 @@ 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` | +| **Per-target-repo file** | `.loopover-miner.yml` (or `.github/loopover-miner.yml`, JSON variants) | One cloned target repo | `lib/miner-goal-spec.js`, engine `parseMinerGoalSpecContent` | | **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** | `loopover-miner …` argv | One invocation | `lib/attempt-cli.js`, `lib/discover-cli.js`, `lib/loop-cli.js`, … | -| **Operator file (not goal spec)** | `~/.config/loopover-miner/.gittensory-ams.yml` | Operator execution policy | `lib/ams-policy.js` | +| **Operator file (not goal spec)** | `~/.config/loopover-miner/.loopover-ams.yml` | Operator execution policy | `lib/ams-policy.js` | -`.gittensory-miner.yml` is **maintainer-authored in the target repo**. Operator env and CLI flags are **never overridden by a target repo's goal spec** for operator-owned policy (see `lib/ams-policy.js` header). +`.loopover-miner.yml` is **maintainer-authored in the target repo**. Operator env and CLI flags are **never overridden by a target repo's goal spec** for operator-owned policy (see `lib/ams-policy.js` header). -## `.gittensory-miner.yml` file discovery +## `.loopover-miner.yml` file discovery First existing file wins (engine `MINER_GOAL_SPEC_FILENAMES`): -1. `.gittensory-miner.yml` -2. `.github/gittensory-miner.yml` -3. `.gittensory-miner.json` -4. `.github/gittensory-miner.json` +1. `.loopover-miner.yml` +2. `.github/loopover-miner.yml` +3. `.loopover-miner.json` +4. `.github/loopover-miner.json` ## Precedence by concern ### Kill switch (halt miner writes) -**Sources:** `LOOPOVER_MINER_KILL_SWITCH` (operator env) and `.gittensory-miner.yml` → `killSwitch.paused`. +**Sources:** `LOOPOVER_MINER_KILL_SWITCH` (operator env) and `.loopover-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:** `LOOPOVER_MINER_LIVE_MODE=live` (operator env) and `.gittensory-miner.yml` → `execution.liveModeOptIn: live`. +**Sources:** `LOOPOVER_MINER_LIVE_MODE=live` (operator env) and `.loopover-miner.yml` → `execution.liveModeOptIn: live`. **Order (engine `resolveMinerActionMode`):** @@ -60,7 +60,7 @@ There is **no CLI flag wired to governor live mode** today. `attempt --live` / ` 2. Else CLI `--live` absent → `agentDryRun: true` → `"dry_run"` (`attempt-cli.js` enforces dry-run default for #2342). 3. Else CLI `--live` present → `"live"`. -There is **no `.gittensory-miner.yml` field** for coding-agent mode today. +There is **no `.loopover-miner.yml` field** for coding-agent mode today. ### Discover forge credential env var name @@ -72,7 +72,7 @@ There is **no `.gittensory-miner.yml` field** for coding-agent mode today. 2. Else programmatic `options.tokenEnv` 3. Else `resolveForgeConfig(...).tokenEnvVar` (default `GITHUB_TOKEN`) -There is **no `.gittensory-miner.yml` forge block** today; `--api-base-url` follows the same CLI → programmatic → default shape for the API host. +There is **no `.loopover-miner.yml` forge block** today; `--api-base-url` follows the same CLI → programmatic → default shape for the API host. ### Local SQLite store paths @@ -84,8 +84,8 @@ Explicit per-store env **wins** over config dir; config dir **wins** over XDG. N - **No unified precedence** across yml + env + CLI for a single knob — each concern owns its resolver. - **Live execution** spans two independent gates: coding-agent `--live` (spawn) vs governor env+yml (writes). Both must allow live for a full live open-pr attempt. -- **Forge tenant overrides** (`--api-base-url`, `--token-env`) are CLI/programmatic only; `.gittensory-miner.yml` cannot set them yet. -- **Operator AMS policy** (`.gittensory-ams.yml`) is separate from per-repo goal spec; goal spec never overrides operator policy. +- **Forge tenant overrides** (`--api-base-url`, `--token-env`) are CLI/programmatic only; `.loopover-miner.yml` cannot set them yet. +- **Operator AMS policy** (`.loopover-ams.yml`) is separate from per-repo goal spec; goal spec never overrides operator policy. If a future change adds yml or CLI for a setting documented here as env-only, update this file and extend `test/unit/miner-config-precedence.test.ts`. diff --git a/packages/loopover-miner/docs/cross-repo-discovery-phase1.md b/packages/loopover-miner/docs/cross-repo-discovery-phase1.md index b7aa1cfdcc..5165cde7b5 100644 --- a/packages/loopover-miner/docs/cross-repo-discovery-phase1.md +++ b/packages/loopover-miner/docs/cross-repo-discovery-phase1.md @@ -30,7 +30,7 @@ Hosted and stdio MCP surfaces expose the composed shortlist: `loopover_find_oppo | Issue | Title | |-------|-------| | [#2299](https://github.com/JSONbored/gittensory/issues/2299) | Scope correction note (this document) | -| [#2300](https://github.com/JSONbored/gittensory/issues/2300) | `.gittensory-miner.yml` MinerGoalSpec schema doc | +| [#2300](https://github.com/JSONbored/gittensory/issues/2300) | `.loopover-miner.yml` MinerGoalSpec schema doc | | [#2301](https://github.com/JSONbored/gittensory/issues/2301) | MinerGoalSpec parser with safe-default fallback | | [#2302](https://github.com/JSONbored/gittensory/issues/2302) | Pure ranker — `potential × feasibility × laneFit × freshness × (1 − dupRisk)` | | [#2303](https://github.com/JSONbored/gittensory/issues/2303) | Ranker invariant test suite | diff --git a/packages/loopover-miner/docs/discovery-plane-operator-guide.md b/packages/loopover-miner/docs/discovery-plane-operator-guide.md index 8bf796d4d9..e102ce715e 100644 --- a/packages/loopover-miner/docs/discovery-plane-operator-guide.md +++ b/packages/loopover-miner/docs/discovery-plane-operator-guide.md @@ -97,5 +97,5 @@ The server operating doc (maintainer-only) will restate the same boundary: **nev - [`cross-repo-discovery-phase1.md`](cross-repo-discovery-phase1.md) — local, metadata-only Phase 1 discovery (no hosted plane). - [`operations-runbook.md`](operations-runbook.md) — SQLite concurrency, corruption recovery, multi-process collisions, post-upgrade migration ([#4875](https://github.com/JSONbored/gittensory/issues/4875)). -- [`miner-goal-spec.md`](miner-goal-spec.md) — per-repo `.gittensory-miner.yml` targeting policy. +- [`miner-goal-spec.md`](miner-goal-spec.md) — per-repo `.loopover-miner.yml` targeting policy. - [`../DEPLOYMENT.md`](../DEPLOYMENT.md) — laptop vs fleet deployment and core miner invariants. diff --git a/packages/loopover-miner/docs/fleet-run-manifest.md b/packages/loopover-miner/docs/fleet-run-manifest.md index e1bfa9f5b0..ae0ec15715 100644 --- a/packages/loopover-miner/docs/fleet-run-manifest.md +++ b/packages/loopover-miner/docs/fleet-run-manifest.md @@ -5,12 +5,12 @@ at once: it declares which repos are in scope for a fleet run and how a finite w split between them. It is parsed by `parseFleetRunManifestContent` / `parseFleetRunManifest` in `@loopover/engine` (`packages/loopover-engine/src/fleet-run-manifest.ts`). -It is **not** the same file as `.gittensory-miner.yml` (see [`miner-goal-spec.md`](./miner-goal-spec.md)) — the +It is **not** the same file as `.loopover-miner.yml` (see [`miner-goal-spec.md`](./miner-goal-spec.md)) — the naming is easy to conflate. Same tolerant-parser convention (every field optional, unknown keys ignored, a malformed field degrades to a documented default with a warning rather than throwing), but the opposite author and the opposite direction of intent: -| | `.gittensory-miner.yml` (goal spec) | fleet run-manifest | +| | `.loopover-miner.yml` (goal spec) | fleet run-manifest | |---|---|---| | **Author** | a target repo's maintainer | the miner (fleet) operator | | **Lives in** | the target repo | the operator's fleet-run config | diff --git a/packages/loopover-miner/docs/miner-goal-spec.md b/packages/loopover-miner/docs/miner-goal-spec.md index 7121129541..389803c521 100644 --- a/packages/loopover-miner/docs/miner-goal-spec.md +++ b/packages/loopover-miner/docs/miner-goal-spec.md @@ -1,13 +1,13 @@ -# MinerGoalSpec (`.gittensory-miner.yml`) +# MinerGoalSpec (`.loopover-miner.yml`) -Per-repo configuration telling an autonomous LoopOver miner what to look for and how to behave when targeting a repo. Parsed by `@loopover/engine` (`parseMinerGoalSpec` / `parseMinerGoalSpecContent`); this document is the field reference. Machine-readable shape: [`../schema/miner-goal-spec.schema.json`](../schema/miner-goal-spec.schema.json). Copy [`.gittensory-miner.yml.example`](../../../.gittensory-miner.yml.example) to `.gittensory-miner.yml` and edit. +Per-repo configuration telling an autonomous LoopOver miner what to look for and how to behave when targeting a repo. Parsed by `@loopover/engine` (`parseMinerGoalSpec` / `parseMinerGoalSpecContent`); this document is the field reference. Machine-readable shape: [`../schema/miner-goal-spec.schema.json`](../schema/miner-goal-spec.schema.json). Copy [`.loopover-miner.yml.example`](../../../.loopover-miner.yml.example) to `.loopover-miner.yml` and edit. Discovery order (first match wins): -- `.gittensory-miner.yml` -- `.github/gittensory-miner.yml` -- `.gittensory-miner.json` -- `.github/gittensory-miner.json` +- `.loopover-miner.yml` +- `.github/loopover-miner.yml` +- `.loopover-miner.json` +- `.github/loopover-miner.json` Every field is optional. Unknown keys are ignored; a malformed field falls back to its documented default with a warning — a broken file never hard-fails the miner. @@ -16,7 +16,7 @@ Every field is optional. Unknown keys are ignored; a malformed field falls back | File | Actor | Purpose | |------|-------|---------| | `.loopover.yml` | Review stack | How a maintainer's repo **reviews** incoming PRs (focus manifest, gate, scoring knobs). | -| `.gittensory-miner.yml` | Miner runtime | How a miner **searches for and prioritizes** work in a target repo. Unrelated naming concern — not affected by the review-config rebrand above. | +| `.loopover-miner.yml` | Miner runtime | How a miner **searches for and prioritizes** work in a target repo. Unrelated naming concern — not affected by the review-config rebrand above. | They are read by different components and do not conflict. A miner should still treat a target repo's public `.loopover.yml` `wantedPaths` / `blockedPaths` as a hard floor when both files exist. diff --git a/packages/loopover-miner/docs/repo-agnostic-capability-audit.md b/packages/loopover-miner/docs/repo-agnostic-capability-audit.md index 3141bd69da..c5f9a0594d 100644 --- a/packages/loopover-miner/docs/repo-agnostic-capability-audit.md +++ b/packages/loopover-miner/docs/repo-agnostic-capability-audit.md @@ -9,10 +9,10 @@ surviving only as the default). Audit-and-document only — no code changes here ## Summary The miner's discovery/claim/scoring code is **already largely repo-agnostic**. Discovery queries are -caller-supplied, label preferences are generic per-tenant config (`.gittensory-miner.yml` uses plain +caller-supplied, label preferences are generic per-tenant config (`.loopover-miner.yml` uses plain `bug`/`enhancement`, not `gittensor:*`), ranking/feasibility are delegated to `@loopover/engine` with config-overridable inputs, and runtime knobs live in -`.gittensory-ams.yml`. The remaining assumptions fall into three buckets: +`.loopover-ams.yml`. The remaining assumptions fall into three buckets: 1. **GitHub as the only forge** — the fan-out hardcodes GitHub's REST paths, headers, API version, and search-qualifier syntax. This is the single largest gap for a non-GitHub tenant. @@ -45,7 +45,7 @@ whatever label strings the forge returns, with no `gittensor:*` filter. No chang | Line | Assumption | Category | Should become | | --- | --- | --- | --- | -| 289–290 (fanout) vs `runDiscover` | `opportunity-fanout` accepts `options.apiBaseUrl`, but `runDiscover`'s arg parser only handles `--search` / targets / `--json` — it never parses or passes `apiBaseUrl`, so the existing GitHub-Enterprise override is **unreachable from the CLI**. | (6) endpoint | Thread a forge base URL from `.gittensory-miner.yml` / a `--api-base-url` flag into the fan-out call. | +| 289–290 (fanout) vs `runDiscover` | `opportunity-fanout` accepts `options.apiBaseUrl`, but `runDiscover`'s arg parser only handles `--search` / targets / `--json` — it never parses or passes `apiBaseUrl`, so the existing GitHub-Enterprise override is **unreachable from the CLI**. | (6) endpoint | Thread a forge base URL from `.loopover-miner.yml` / a `--api-base-url` flag into the fan-out call. | | 102 | `process.env.GITHUB_TOKEN` | (6) auth | Per-forge credential env var (default `GITHUB_TOKEN`). | ### `lib/opportunity-ranker.js` — candidate ranking (delegated) @@ -73,12 +73,12 @@ redo them: - **Discovery query** — caller-supplied via `discover --search ` or explicit `owner/repo` targets; no hardcoded gittensory label query (`discover-cli.js`). -- **Label preferences** — `.gittensory-miner.yml` `preferredLabels` / `blockedLabels` are generic +- **Label preferences** — `.loopover-miner.yml` `preferredLabels` / `blockedLabels` are generic (`bug`, `enhancement`, `wontfix`, `duplicate`), not `gittensor:*`. - **Path scope, feasibility gate, self-plagiarism threshold, concurrency** — all per-tenant in - `.gittensory-miner.yml` (`wantedPaths`, `blockedPaths`, `feasibilityGate`, `selfPlagiarism`, + `.loopover-miner.yml` (`wantedPaths`, `blockedPaths`, `feasibilityGate`, `selfPlagiarism`, `maxConcurrentClaims`). -- **Runtime caps** — `.gittensory-ams.yml` (`submissionMode`, `capLimits`, `convergenceThresholds`, +- **Runtime caps** — `.loopover-ams.yml` (`submissionMode`, `capLimits`, `convergenceThresholds`, `maxIterations`) are generic runtime knobs. - **Local stores** — `portfolio-queue`, `claim-ledger`, `event-ledger`, etc. are generic SQLite bookkeeping with env-configurable DB paths; no gittensory-specific schema. diff --git a/packages/loopover-miner/lib/ams-policy.js b/packages/loopover-miner/lib/ams-policy.js index 2270552485..3574b2b15e 100644 --- a/packages/loopover-miner/lib/ams-policy.js +++ b/packages/loopover-miner/lib/ams-policy.js @@ -2,7 +2,7 @@ import { existsSync, readFileSync } from "node:fs"; import { DEFAULT_AMS_POLICY_SPEC, parseAmsPolicySpecContent } from "@loopover/engine"; import { resolveLocalStoreDbPath } from "./local-store.js"; -// Resolver for the operator-local `.gittensory-ams.yml` (#5132, Wave 3.5 follow-up). AmsPolicySpec +// Resolver for the operator-local `.loopover-ams.yml` (#5132, Wave 3.5 follow-up). AmsPolicySpec // (ams-policy-spec.ts, engine package) is the type/parser surface; this module is the actual local // read+resolve caller. // @@ -10,7 +10,7 @@ import { resolveLocalStoreDbPath } from "./local-store.js"; // read from the target repo: AmsPolicySpec's fields are the OPERATOR's own execution-risk policy, so an // untrusted target repo must never get final say over them. -const AMS_POLICY_FILENAME = ".gittensory-ams.yml"; +const AMS_POLICY_FILENAME = ".loopover-ams.yml"; /** 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. */ @@ -26,7 +26,7 @@ function normalizeOptions(options = {}) { }; } -/** Read the operator's own local `.gittensory-ams.yml`, if one exists. Never throws: an unreadable file is +/** Read the operator's own local `.loopover-ams.yml`, if one exists. Never throws: an unreadable file is * treated the same as an absent one, falling through to the next resolution layer. */ function readLocalAmsPolicyContent(resolved) { const path = resolveAmsPolicyConfigPath(resolved.env); @@ -40,7 +40,7 @@ function readLocalAmsPolicyContent(resolved) { /** * Resolve the real, effective AMS execution policy for one attempt: the operator's own local - * `.gittensory-ams.yml` when present (source: "local"), else the engine's safe defaults (source: "default"). + * `.loopover-ams.yml` when present (source: "local"), else the engine's safe defaults (source: "default"). * Never throws -- an unreadable/malformed local file degrades through the tolerant parser to the safe * defaults, same discipline as every other tolerant parser in this pipeline. * diff --git a/packages/loopover-miner/lib/attempt-cli.js b/packages/loopover-miner/lib/attempt-cli.js index 913579c811..3aadab2d58 100644 --- a/packages/loopover-miner/lib/attempt-cli.js +++ b/packages/loopover-miner/lib/attempt-cli.js @@ -378,7 +378,7 @@ export async function runAttempt(args, options = {}) { const amsPolicy = await (options.resolveAmsPolicy ?? resolveAmsPolicy)(parsed.repoFullName, { env }); - // Real per-repo pause (#5392): read straight from the already-cloned worktree's own .gittensory-miner.yml + // Real per-repo pause (#5392): read straight from the already-cloned worktree's own .loopover-miner.yml // (resolveMinerGoalSpec never throws -- a missing/malformed file degrades to killSwitch.paused: false, so // this can't fail this attempt on its own). Threaded into BOTH checkMinerKillSwitch (killSwitchScope, used // by the freshness/submission gate) and the governor context (killSwitchRepoPaused, used by the Governor diff --git a/packages/loopover-miner/lib/discover-cli.js b/packages/loopover-miner/lib/discover-cli.js index 77f5430cbf..0342bd5f0c 100644 --- a/packages/loopover-miner/lib/discover-cli.js +++ b/packages/loopover-miner/lib/discover-cli.js @@ -128,7 +128,7 @@ export function renderDiscoverSummary(result) { // spec is supplied, lane fit reflects gittensory's defaults, not the target repo's own conventions. if (result.usedDefaultGoalSpec) { lines.push( - "note: ranked with the built-in default goal spec (no per-tenant .gittensory-miner.yml supplied)", + "note: ranked with the built-in default goal spec (no per-tenant .loopover-miner.yml supplied)", ); } if (result.ranked.length === 0) { diff --git a/packages/loopover-miner/lib/governor-action-mode.js b/packages/loopover-miner/lib/governor-action-mode.js index ca2db0357a..c5234931e1 100644 --- a/packages/loopover-miner/lib/governor-action-mode.js +++ b/packages/loopover-miner/lib/governor-action-mode.js @@ -12,7 +12,7 @@ import { appendGovernorEvent } from "./governor-ledger.js"; /** * Resolve the miner's overall action mode from the kill-switch scope (see `checkMinerKillSwitch` in - * `./governor-kill-switch.js`), the repo's own `.gittensory-miner.yml` opt-in, and the operator's global env + * `./governor-kill-switch.js`), the repo's own `.loopover-miner.yml` opt-in, and the operator's global env * opt-in. Both sides must opt in before real writes execute; repo config alone only preserves dry-run. * * @param {object} input diff --git a/packages/loopover-miner/lib/governor-kill-switch.js b/packages/loopover-miner/lib/governor-kill-switch.js index 6cd2bdbf5d..ae780840d3 100644 --- a/packages/loopover-miner/lib/governor-kill-switch.js +++ b/packages/loopover-miner/lib/governor-kill-switch.js @@ -1,5 +1,5 @@ // Governor kill-switch gate (#2341). Resolves whether miner write activity is currently halted (globally, via -// env, or for one repo, via its .gittensory-miner.yml MinerGoalSpec) and records STATE TRANSITIONS to the +// env, or for one repo, via its .loopover-miner.yml MinerGoalSpec) and records STATE TRANSITIONS to the // append-only governor ledger. Every-check allow/deny recording for a real write action is the fail-closed // Governor chokepoint's job (#2340), which consults this module first in its "safest wins" precedence. @@ -13,7 +13,7 @@ import { appendGovernorEvent } from "./governor-ledger.js"; /** * Resolve the current kill-switch scope for a repo from process env plus a per-repo paused flag (typically - * `MinerGoalSpec.killSwitch.paused` from the repo's parsed `.gittensory-miner.yml`). + * `MinerGoalSpec.killSwitch.paused` from the repo's parsed `.loopover-miner.yml`). * * @param {object} [input] * @param {boolean} [input.repoPaused] diff --git a/packages/loopover-miner/lib/governor-metrics-cli.js b/packages/loopover-miner/lib/governor-metrics-cli.js index 194de79c06..0138841b11 100644 --- a/packages/loopover-miner/lib/governor-metrics-cli.js +++ b/packages/loopover-miner/lib/governor-metrics-cli.js @@ -13,14 +13,14 @@ import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js // (#5186) and event-ledger-cli.js's `ledger metrics` (#4841): opens the local governor-state store, composes // its EXISTING loadRateLimitState()/loadCapUsage() with the engine's already-exported PURE calculators // (evaluateLocalRateLimit, evaluateGovernorCaps) against the SAME defaults the production loop (loop-cli.js) -// already falls back to when no `.gittensory-ams.yml` override is configured (DEFAULT_WRITE_RATE_LIMIT_POLICIES, +// already falls back to when no `.loopover-ams.yml` override is configured (DEFAULT_WRITE_RATE_LIMIT_POLICIES, // DEFAULT_AMS_POLICY_SPEC.capLimits) -- it never invents a threshold of its own, and it does not gate, retry, // mutate, or otherwise touch governor decision logic (governor-chokepoint.js/governor-chokepoint-persisted.js // are completely untouched by this file). // // capLimits is intentionally NOT read per-repo: governor-state.js's capUsage row is a single global scalar (a // run-scoped cumulative counter, not indexed by repo -- see governor-state.js's own header comment), so a -// per-repo capLimits override from a resolved `.gittensory-miner.yml` has no matching per-repo usage row to +// per-repo capLimits override from a resolved `.loopover-miner.yml` has no matching per-repo usage row to // pair it with here. Using the fleet-wide DEFAULT_AMS_POLICY_SPEC.capLimits is the same approximation // loop-cli.js itself already makes for any repo without its own override. diff --git a/packages/loopover-miner/lib/governor-open-pr.js b/packages/loopover-miner/lib/governor-open-pr.js index 88d0e802ee..d98bbe9265 100644 --- a/packages/loopover-miner/lib/governor-open-pr.js +++ b/packages/loopover-miner/lib/governor-open-pr.js @@ -14,7 +14,7 @@ import { appendGovernorEvent } from "./governor-ledger.js"; * @param {object} input * @param {import("@loopover/engine").SelfPlagiarismCandidate} input.candidate * @param {readonly import("@loopover/engine").OwnSubmissionRecord[]} input.recentOwnSubmissions - * @param {unknown} [input.selfPlagiarismConfig] parsed `.gittensory-miner.yml` selfPlagiarism block + * @param {unknown} [input.selfPlagiarismConfig] parsed `.loopover-miner.yml` selfPlagiarism block * @param {{ append?: typeof appendGovernorEvent }} [options] */ export function evaluateOpenPrSelfPlagiarism(input, options = {}) { diff --git a/packages/loopover-miner/lib/miner-goal-spec.js b/packages/loopover-miner/lib/miner-goal-spec.js index 30419da5a2..7ba23a5a53 100644 --- a/packages/loopover-miner/lib/miner-goal-spec.js +++ b/packages/loopover-miner/lib/miner-goal-spec.js @@ -4,7 +4,7 @@ import { discoverMinerGoalSpecPath, parseMinerGoalSpecContent } from "@loopover/ const MAX_MINER_GOAL_SPEC_BYTES = 32_768; -// Real local .gittensory-miner.yml resolver (#5132, Wave 3.5 follow-up). MinerGoalSpec's own discovery +// Real local .loopover-miner.yml resolver (#5132, Wave 3.5 follow-up). MinerGoalSpec's own discovery // helper (discoverMinerGoalSpecPath, packages/loopover-engine) is deliberately IO-free -- the caller // injects the existence check. Unlike self-review-context.js/rejection-signal.js/ams-policy.js, which fetch // their target repo's files live over raw.githubusercontent.com BEFORE any clone exists, this resolver reads diff --git a/packages/loopover-miner/lib/portfolio-queue-manager.js b/packages/loopover-miner/lib/portfolio-queue-manager.js index c152ddc499..53cc160522 100644 --- a/packages/loopover-miner/lib/portfolio-queue-manager.js +++ b/packages/loopover-miner/lib/portfolio-queue-manager.js @@ -1,7 +1,7 @@ // Stateful PortfolioQueueManager (#4285): compose the persisted SQLite portfolio/queue store // (portfolio-queue.js, #2292) with the pure engine selector (nextEligibleItems, queue.ts, #2326) so batch // claiming respects global/per-repo WIP caps and cross-repo diversification instead of a naive priority-only -// single-row dequeue. Caps are plain constructor arguments — not wired to .gittensory-miner.yml here. +// single-row dequeue. Caps are plain constructor arguments — not wired to .loopover-miner.yml here. import { nextEligibleItems } from "@loopover/engine"; import { DEFAULT_FORGE_CONFIG } from "./forge-config.js"; import { initPortfolioQueueStore } from "./portfolio-queue.js"; diff --git a/packages/loopover-miner/lib/status.js b/packages/loopover-miner/lib/status.js index 04357824c4..b56850fa69 100644 --- a/packages/loopover-miner/lib/status.js +++ b/packages/loopover-miner/lib/status.js @@ -40,12 +40,12 @@ function moduleDir() { const PACKAGE_NAME = "@loopover/miner"; const ENGINE_PACKAGE = "@loopover/engine"; -// Config-file discovery order (mirrors the `.gittensory-miner.yml` precedence the goal-spec parser documents). +// Config-file discovery order (mirrors the `.loopover-miner.yml` precedence the goal-spec parser documents). const CONFIG_FILE_CANDIDATES = Object.freeze([ - ".gittensory-miner.yml", - ".github/gittensory-miner.yml", - ".gittensory-miner.json", - ".github/gittensory-miner.json", + ".loopover-miner.yml", + ".github/loopover-miner.yml", + ".loopover-miner.json", + ".github/loopover-miner.json", ]); /** The miner's local-state directory (holds the run-state / queue / ledger SQLite files). */ diff --git a/packages/loopover-miner/terraform/README.md b/packages/loopover-miner/terraform/README.md index 06cb415910..b5eb289510 100644 --- a/packages/loopover-miner/terraform/README.md +++ b/packages/loopover-miner/terraform/README.md @@ -45,8 +45,8 @@ Useful variables (see [`variables.tf`](variables.tf) for all): `server_type`, `l The module provisions the **host**; you finish the miner setup over SSH (secrets never live in Terraform state): 1. `terraform output ssh_command` → SSH in. -2. Create a `.gittensory-miner.env` with your `GITHUB_TOKEN` and coding-agent provider credentials — see - [`../.gittensory-miner.env.example`](../.gittensory-miner.env.example). +2. Create a `.loopover-miner.env` with your `GITHUB_TOKEN` and coding-agent provider credentials — see + [`../.loopover-miner.env.example`](../.loopover-miner.env.example). 3. Run the miner container against the mounted volume using the existing [`../docker-compose.miner.yml`](../docker-compose.miner.yml) (its state mount is already pinned to `/data/miner`, which `terraform output data_mount` confirms). Full run/upgrade guidance lives in diff --git a/prometheus/rules/alerts.yml b/prometheus/rules/alerts.yml index b4458aed4c..22f04b2543 100644 --- a/prometheus/rules/alerts.yml +++ b/prometheus/rules/alerts.yml @@ -706,7 +706,7 @@ groups: # ── Governor rate-limit/budget threshold pressure (#5187) ───────────────── # Same DORMANT-until-a-scrape-target-exists posture as the two miner groups above: an operator runs - # `gittensory-miner governor metrics` (packages/loopover-miner/lib/governor-metrics-cli.js's + # `loopover-miner governor metrics` (packages/loopover-miner/lib/governor-metrics-cli.js's # renderGovernorMetrics) to a file/pushgateway their Prometheus scrapes. Absent loopover_miner_governor_* # series simply yield no result. Read-only: these rules alert on the governor's already-persisted rate-limit # (#5134/write-rate-limit.ts) and cap-usage (#5134/budget-cap.ts) state; they do not gate, retry, or modify @@ -724,20 +724,20 @@ groups: labels: severity: warning annotations: - summary: "gittensory miner governor write-rate-limit bucket is nearly exhausted" + summary: "loopover miner governor write-rate-limit bucket is nearly exhausted" description: "{{ $labels.scope }}/{{ $labels.action_class }}{{ with $labels.repo }} ({{ . }}){{ end }} has had under 10% of its write-rate-limit headroom remaining for 10m." - runbook: "Check `gittensory-miner governor metrics` for the affected scope/action_class and slow down that write class (fewer concurrent attempts, longer loop --cycle-delay-ms), or raise the relevant DEFAULT_WRITE_RATE_LIMIT_POLICIES ceiling if the current limit is genuinely too conservative for this install." + runbook: "Check `loopover-miner governor metrics` for the affected scope/action_class and slow down that write class (fewer concurrent attempts, longer loop --cycle-delay-ms), or raise the relevant DEFAULT_WRITE_RATE_LIMIT_POLICIES ceiling if the current limit is genuinely too conservative for this install." - alert: LoopOverMinerGovernorCapUsageHigh # cap_usage_ratio compares governor-state's persisted cumulative capUsage (budget spent / turns taken / # elapsed session ms) against DEFAULT_AMS_POLICY_SPEC.capLimits, the same fleet-wide default loop-cli.js - # itself falls back to when a repo has no `.gittensory-ams.yml` override. 0.9 gives an operator a + # itself falls back to when a repo has no `.loopover-ams.yml` override. 0.9 gives an operator a # heads-up before evaluateGovernorCaps' own exceeded/kill_switch verdict actually halts the run. expr: loopover_miner_governor_cap_usage_ratio > 0.9 for: 10m labels: severity: warning annotations: - summary: "gittensory miner governor is approaching a run cap ceiling" + summary: "loopover miner governor is approaching a run cap ceiling" description: "The governor's {{ $labels.dimension }} cap usage has been over 90% of its configured limit for 10m." - runbook: "Run `gittensory-miner governor metrics` to see which dimension (budget/turns/elapsed_ms) is under pressure, and either let the current run finish (evaluateGovernorCaps will kill_switch/deny once the ceiling is actually reached) or raise the corresponding capLimits in `.gittensory-ams.yml` if the ceiling is too tight for this repo's normal attempts." + runbook: "Run `loopover-miner governor metrics` to see which dimension (budget/turns/elapsed_ms) is under pressure, and either let the current run finish (evaluateGovernorCaps will kill_switch/deny once the ceiling is actually reached) or raise the corresponding capLimits in `.loopover-ams.yml` if the ceiling is too tight for this repo's normal attempts." diff --git a/test/unit/ams-policy-spec-parser.test.ts b/test/unit/ams-policy-spec-parser.test.ts index 9f4df8126f..c7b428f9ef 100644 --- a/test/unit/ams-policy-spec-parser.test.ts +++ b/test/unit/ams-policy-spec-parser.test.ts @@ -11,10 +11,10 @@ describe("AmsPolicySpec parser (#5132)", () => { expect(typeof parseAmsPolicySpec).toBe("function"); expect(typeof parseAmsPolicySpecContent).toBe("function"); expect(AMS_POLICY_SPEC_FILENAMES).toEqual([ - ".gittensory-ams.yml", - ".github/gittensory-ams.yml", - ".gittensory-ams.json", - ".github/gittensory-ams.json", + ".loopover-ams.yml", + ".github/loopover-ams.yml", + ".loopover-ams.json", + ".github/loopover-ams.json", ]); }); diff --git a/test/unit/miner-ams-policy.test.ts b/test/unit/miner-ams-policy.test.ts index 07623dc922..874a3e4fc9 100644 --- a/test/unit/miner-ams-policy.test.ts +++ b/test/unit/miner-ams-policy.test.ts @@ -25,7 +25,7 @@ function tempRoot() { describe("resolveAmsPolicyConfigPath (#5132)", () => { it("resolves from explicit env, config dir, and XDG default, in precedence order", () => { 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")); + expect(resolveAmsPolicyConfigPath({ LOOPOVER_MINER_CONFIG_DIR: "/cfg" })).toBe(join("/cfg", ".loopover-ams.yml")); }); }); @@ -36,7 +36,7 @@ describe("resolveAmsPolicy (#5132)", () => { expect(result).toEqual({ spec: DEFAULT_AMS_POLICY_SPEC, source: "default", warnings: [] }); }); - it("REGRESSION: ignores target-repo .gittensory-ams.yml so repos cannot loosen operator risk policy", async () => { + it("REGRESSION: ignores target-repo .loopover-ams.yml so repos cannot loosen operator risk policy", async () => { const root = tempRoot(); const fetchImpl = vi.fn(async () => { throw new Error("target repo policy must not be fetched"); @@ -48,7 +48,7 @@ describe("resolveAmsPolicy (#5132)", () => { it("the operator's own local file supplies the effective policy", async () => { const root = tempRoot(); - writeFileSync(join(root, ".gittensory-ams.yml"), "submissionMode: observe\nslopThreshold: clean\n"); + writeFileSync(join(root, ".loopover-ams.yml"), "submissionMode: observe\nslopThreshold: clean\n"); const fetchImpl = vi.fn(async () => { throw new Error("target repo policy must not be fetched"); }); @@ -61,7 +61,7 @@ describe("resolveAmsPolicy (#5132)", () => { it("never calls fetch at all once a local file is found", async () => { const root = tempRoot(); - writeFileSync(join(root, ".gittensory-ams.yml"), "submissionMode: enforce\n"); + writeFileSync(join(root, ".loopover-ams.yml"), "submissionMode: enforce\n"); let fetchCalls = 0; const fetchImpl = async () => { fetchCalls += 1; @@ -74,7 +74,7 @@ describe("resolveAmsPolicy (#5132)", () => { it("falls through to defaults on a malformed local file (invalid YAML), still never touching the repo file", async () => { const root = tempRoot(); - writeFileSync(join(root, ".gittensory-ams.yml"), "submissionMode: [unterminated"); + writeFileSync(join(root, ".loopover-ams.yml"), "submissionMode: [unterminated"); let fetchCalls = 0; const fetchImpl = async () => { fetchCalls += 1; diff --git a/test/unit/miner-attempt-cli.test.ts b/test/unit/miner-attempt-cli.test.ts index 0fde987c47..5577192944 100644 --- a/test/unit/miner-attempt-cli.test.ts +++ b/test/unit/miner-attempt-cli.test.ts @@ -1276,12 +1276,12 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { expect(input.governor.killSwitchRepoPaused).toBe(true); }); - it("REGRESSION: reads a real .gittensory-miner.yml killSwitch.paused:true from the worktree's real repoPath, end to end", async () => { + it("REGRESSION: reads a real .loopover-miner.yml killSwitch.paused:true from the worktree's real repoPath, end to end", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); const repoRoot = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-repo-")); roots.push(repoRoot); - writeFileSync(join(repoRoot, ".gittensory-miner.yml"), "killSwitch:\n paused: true\n"); + writeFileSync(join(repoRoot, ".loopover-miner.yml"), "killSwitch:\n paused: true\n"); const runMinerAttemptSpy = vi.fn().mockResolvedValue({ outcome: "governed", decision: { allowed: false }, loopResult: fakeLoopResult() }); await runAttempt(["acme/widgets", "7", "--miner-login", "alice", "--json"], { @@ -1304,7 +1304,7 @@ describe("runAttempt: real per-repo kill switch (#5392)", () => { expect(input.governor.killSwitchRepoPaused).toBe(true); }); - it("does not gate on a repo pause when no .gittensory-miner.yml exists (real resolver, real empty dir)", async () => { + it("does not gate on a repo pause when no .loopover-miner.yml exists (real resolver, real empty dir)", async () => { const { allocator, claimLedger, eventLedger, attemptLog, governorLedger } = tempLedgers(); vi.spyOn(console, "log").mockImplementation(() => undefined); const repoRoot = mkdtempSync(join(tmpdir(), "loopover-miner-attempt-cli-repo-")); diff --git a/test/unit/miner-config-precedence.test.ts b/test/unit/miner-config-precedence.test.ts index 4acd95949a..f08c5cff4f 100644 --- a/test/unit/miner-config-precedence.test.ts +++ b/test/unit/miner-config-precedence.test.ts @@ -15,7 +15,7 @@ import { parseAttemptArgs } from "../../packages/loopover-miner/lib/attempt-cli. import { resolveCodingAgentModeFromConfig } from "../../packages/loopover-engine/src/index"; describe("miner config precedence (#5198)", () => { - describe("kill switch: env global > .gittensory-miner.yml repo pause", () => { + describe("kill switch: env global > .loopover-miner.yml repo pause", () => { it("global env wins when both global env and repo yml pause are set", () => { expect(resolveDocumentedKillSwitchScope({ LOOPOVER_MINER_KILL_SWITCH: "true" }, true)).toBe("global"); }); diff --git a/test/unit/miner-docker-compose.test.ts b/test/unit/miner-docker-compose.test.ts index 5088c683e4..14abe5e94a 100644 --- a/test/unit/miner-docker-compose.test.ts +++ b/test/unit/miner-docker-compose.test.ts @@ -12,7 +12,7 @@ const compose = parse( readFileSync(join(MINER_DIR, "docker-compose.miner.yml"), "utf8"), ) as Record; const envExample = readFileSync( - join(MINER_DIR, ".gittensory-miner.env.example"), + join(MINER_DIR, ".loopover-miner.env.example"), "utf8", ); @@ -34,7 +34,7 @@ describe("docker-compose.miner.yml (#5177)", () => { it("sources credentials from an env file and pins nothing overridable in `environment`", () => { const miner = compose.services.miner; - expect(miner.env_file).toContain(".gittensory-miner.env"); + expect(miner.env_file).toContain(".loopover-miner.env"); 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); @@ -45,8 +45,8 @@ describe("docker-compose.miner.yml (#5177)", () => { it("gitignores the operator's real env file while keeping the committed example", () => { const gitignore = readFileSync(join(process.cwd(), ".gitignore"), "utf8"); - expect(gitignore).toMatch(/^\.gittensory-miner\.env$/m); - expect(gitignore).toMatch(/^!\.gittensory-miner\.env\.example$/m); + expect(gitignore).toMatch(/^\.loopover-miner\.env$/m); + expect(gitignore).toMatch(/^!\.loopover-miner\.env\.example$/m); }); it("ships an env example with empty (scanner-safe) placeholder values for every credential", () => { diff --git a/test/unit/miner-goal-spec-doc.test.ts b/test/unit/miner-goal-spec-doc.test.ts index 5351a24ac4..6b845382bb 100644 --- a/test/unit/miner-goal-spec-doc.test.ts +++ b/test/unit/miner-goal-spec-doc.test.ts @@ -7,7 +7,7 @@ import { parseMinerGoalSpecContent } from "../../packages/loopover-engine/src/mi const repoRoot = process.cwd(); const schemaPath = join(repoRoot, "packages/loopover-miner/schema/miner-goal-spec.schema.json"); const docPath = join(repoRoot, "packages/loopover-miner/docs/miner-goal-spec.md"); -const examplePath = join(repoRoot, ".gittensory-miner.yml.example"); +const examplePath = join(repoRoot, ".loopover-miner.yml.example"); const SPEC_FIELDS = [ "minerEnabled", diff --git a/test/unit/miner-goal-spec-resolver.test.ts b/test/unit/miner-goal-spec-resolver.test.ts index ffcf464e29..532480b9f6 100644 --- a/test/unit/miner-goal-spec-resolver.test.ts +++ b/test/unit/miner-goal-spec-resolver.test.ts @@ -29,18 +29,18 @@ describe("resolveMinerGoalSpec (#5132)", () => { expect(parsed.spec.killSwitch).toEqual({ paused: false }); }); - it("REGRESSION: reads a real .gittensory-miner.yml from the cloned repo's root", () => { + it("REGRESSION: reads a real .loopover-miner.yml from the cloned repo's root", () => { const repoPath = tempRepo(); - writeFileSync(join(repoPath, ".gittensory-miner.yml"), "killSwitch:\n paused: true\n"); + writeFileSync(join(repoPath, ".loopover-miner.yml"), "killSwitch:\n paused: true\n"); const parsed = resolveMinerGoalSpec(repoPath); expect(parsed.present).toBe(true); expect(parsed.spec.killSwitch).toEqual({ paused: true }); }); - it("tries .github/gittensory-miner.yml when the root .yml is absent", () => { + it("tries .github/loopover-miner.yml when the root .yml is absent", () => { const repoPath = tempRepo(); mkdirSync(join(repoPath, ".github"), { recursive: true }); - writeFileSync(join(repoPath, ".github", "gittensory-miner.yml"), "killSwitch:\n paused: true\n"); + writeFileSync(join(repoPath, ".github", "loopover-miner.yml"), "killSwitch:\n paused: true\n"); const parsed = resolveMinerGoalSpec(repoPath); expect(parsed.present).toBe(true); expect(parsed.spec.killSwitch.paused).toBe(true); @@ -48,7 +48,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { it("tries the .json variants after both .yml candidates are absent", () => { const repoPath = tempRepo(); - writeFileSync(join(repoPath, ".gittensory-miner.json"), JSON.stringify({ killSwitch: { paused: true } })); + writeFileSync(join(repoPath, ".loopover-miner.json"), JSON.stringify({ killSwitch: { paused: true } })); const parsed = resolveMinerGoalSpec(repoPath); expect(parsed.present).toBe(true); expect(parsed.spec.killSwitch.paused).toBe(true); @@ -58,7 +58,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { const repoPath = tempRepo(); const outsidePath = join(tempRepo(), "outside.yml"); writeFileSync(outsidePath, "killSwitch:\n paused: true\n"); - symlinkSync(outsidePath, join(repoPath, ".gittensory-miner.yml")); + symlinkSync(outsidePath, join(repoPath, ".loopover-miner.yml")); const parsed = resolveMinerGoalSpec(repoPath); @@ -68,7 +68,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { it("REGRESSION: ignores oversized miner goal specs before reading them into memory", () => { const repoPath = tempRepo(); - writeFileSync(join(repoPath, ".gittensory-miner.yml"), `${"#".repeat(32_769)}\nkillSwitch:\n paused: true\n`); + writeFileSync(join(repoPath, ".loopover-miner.yml"), `${"#".repeat(32_769)}\nkillSwitch:\n paused: true\n`); const parsed = resolveMinerGoalSpec(repoPath); @@ -82,7 +82,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { // cap anyway -- simulating a file that grows after fstatSync ran but before the read loop finishes (the // TOCTOU window a size check alone, without also bounding the read, cannot close. const parsed = resolveMinerGoalSpec(repoPath, { - existsSync: (path) => path.endsWith(".gittensory-miner.yml") && !path.includes(".github"), + existsSync: (path) => path.endsWith(".loopover-miner.yml") && !path.includes(".github"), openSync: () => 999, fstatSync: () => ({ isFile: () => true, size: 10 }) as unknown as import("node:fs").Stats, readSync: (_fd, buffer, offset, length) => { @@ -99,7 +99,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { it("degrades to safe defaults on malformed content instead of throwing", () => { const repoPath = tempRepo(); - writeFileSync(join(repoPath, ".gittensory-miner.yml"), "killSwitch: [unterminated"); + writeFileSync(join(repoPath, ".loopover-miner.yml"), "killSwitch: [unterminated"); const parsed = resolveMinerGoalSpec(repoPath); expect(parsed.present).toBe(false); expect(parsed.spec.killSwitch).toEqual({ paused: false }); @@ -109,7 +109,7 @@ describe("resolveMinerGoalSpec (#5132)", () => { it("degrades to safe defaults when the discovered file can't actually be read", () => { const repoPath = tempRepo(); const parsed = resolveMinerGoalSpec(repoPath, { - existsSync: (path) => path.endsWith(".gittensory-miner.yml") && !path.includes(".github"), + existsSync: (path) => path.endsWith(".loopover-miner.yml") && !path.includes(".github"), openSync: () => { throw new Error("EACCES: permission denied"); }, diff --git a/test/unit/miner-init-wizard.test.ts b/test/unit/miner-init-wizard.test.ts index 091ffbded9..99ac77488b 100644 --- a/test/unit/miner-init-wizard.test.ts +++ b/test/unit/miner-init-wizard.test.ts @@ -131,7 +131,7 @@ describe("gittensory-miner init --interactive wizard (#5176)", () => { describe("runInteractiveInit", () => { 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 cwd = tempRoot(); // no .loopover-miner.yml here => config-content check passes const env = { LOOPOVER_MINER_CONFIG_DIR: stateDir }; const io = createFakeIo({ maskedAnswers: ["ghp_test_token_123"], textAnswers: [""] }); diff --git a/test/unit/miner-status.test.ts b/test/unit/miner-status.test.ts index e270e4af1e..2d7ba765d2 100644 --- a/test/unit/miner-status.test.ts +++ b/test/unit/miner-status.test.ts @@ -51,13 +51,13 @@ 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"); + writeFileSync(join(root, ".loopover-miner.yml"), "minerEnabled: true\n"); 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"); expect(status.stateDir).toBe(join(root, "state")); - expect(status.configFile).toBe(join(root, ".gittensory-miner.yml")); // discovered + expect(status.configFile).toBe(join(root, ".loopover-miner.yml")); // discovered }); it("REGRESSION: collectStatus reports the REAL installed engine version, not the declared dependency range", () => { @@ -149,7 +149,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("passes a well-formed config", () => { const cwd = tempRoot(); - writeFileSync(join(cwd, ".gittensory-miner.yml"), "wantedPaths:\n - src\n"); + writeFileSync(join(cwd, ".loopover-miner.yml"), "wantedPaths:\n - src\n"); const result = checkConfigContent(cwd); expect(result.ok).toBe(true); expect(result.detail).toContain("valid"); @@ -158,7 +158,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("flags a malformed config with the parser's specific warnings", () => { const cwd = tempRoot(); // wantedPaths must be a list; a scalar triggers a parser warning rather than a silent default. - writeFileSync(join(cwd, ".gittensory-miner.yml"), "wantedPaths: not-a-list\n"); + writeFileSync(join(cwd, ".loopover-miner.yml"), "wantedPaths: not-a-list\n"); const result = checkConfigContent(cwd); expect(result.ok).toBe(false); expect(result.detail).toMatch(/wantedPaths/); @@ -166,7 +166,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("reports a read failure (config discovered but unreadable)", () => { const cwd = tempRoot(); - writeFileSync(join(cwd, ".gittensory-miner.yml"), "wantedPaths:\n - src\n"); + writeFileSync(join(cwd, ".loopover-miner.yml"), "wantedPaths:\n - src\n"); const throwingRead = () => { throw new Error("EACCES: permission denied"); }; @@ -179,7 +179,7 @@ describe("gittensory-miner status/doctor (#2288)", () => { it("doctor flags a malformed config file (#4873)", () => { const env = { LOOPOVER_MINER_CONFIG_DIR: join(tempRoot(), "state") }; const cwd = tempRoot(); - writeFileSync(join(cwd, ".gittensory-miner.yml"), "wantedPaths: not-a-list\n"); + writeFileSync(join(cwd, ".loopover-miner.yml"), "wantedPaths: not-a-list\n"); expect(runDoctorChecks(env, cwd).find((check) => check.name === "config-content")?.ok).toBe(false); expect(runDoctor([], env, cwd)).toBe(1); });