From c4ec90b7c3f6529ee6e4a8a2380110d4e038b4ba Mon Sep 17 00:00:00 2001 From: Helios531 <57456290+Helios531@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:54:09 +0200 Subject: [PATCH] feat(signals): add MinerGoalSpec type contract --- src/signals/miner-goal-spec.ts | 44 +++++++++++++++++++++++++++++++ test/unit/miner-goal-spec.test.ts | 26 ++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/signals/miner-goal-spec.ts create mode 100644 test/unit/miner-goal-spec.test.ts diff --git a/src/signals/miner-goal-spec.ts b/src/signals/miner-goal-spec.ts new file mode 100644 index 0000000000..cf04628cb1 --- /dev/null +++ b/src/signals/miner-goal-spec.ts @@ -0,0 +1,44 @@ +import type { FocusManifestIssueDiscoveryPolicy } from "./focus-manifest"; + +/** Values carried over from `.gittensory.yml`'s focus-manifest discovery policy. */ +export type MinerGoalSpecIssueDiscoveryPolicy = FocusManifestIssueDiscoveryPolicy; + +/** + * Maintainer-authored miner targeting preferences declared in `.gittensory-miner.yml`. + * + * This is intentionally small in the foundation phase: it only captures whether autonomous miner + * work is allowed for the repo at all, which paths are preferred/blocked, which labels are preferred, + * how many concurrent claims a single miner should hold, and whether issue discovery is encouraged. + * Parsing and file discovery land in a follow-up issue. + */ +export type MinerGoalSpec = { + /** Whether autonomous miners may target this repo. Default: true. */ + minerEnabled: boolean; + /** Preferred work areas for miner-created changes. Glob list. Default: []. */ + wantedPaths: string[]; + /** Paths miners should avoid touching. Glob list. Default: []. */ + blockedPaths: string[]; + /** Labels miners should prefer when selecting or filing work. Default: []. */ + preferredLabels: string[]; + /** Maximum concurrent claims a miner should hold against this repo. Default: 1. */ + maxConcurrentClaims: number; + /** Whether issue discovery work is encouraged for the repo. Default: neutral. */ + issueDiscoveryPolicy: MinerGoalSpecIssueDiscoveryPolicy; +}; + +/** + * Safe defaults for an absent `.gittensory-miner.yml`. + * + * - `minerEnabled: true` keeps public repos targetable unless the owner explicitly opts out. + * - empty path/label lists mean "no additional preference" rather than hidden policy. + * - `maxConcurrentClaims: 1` keeps a miner from claiming multiple issues in the same repo by default. + * - `issueDiscoveryPolicy: neutral` mirrors `.gittensory.yml`'s own default stance. + */ +export const DEFAULT_MINER_GOAL_SPEC: MinerGoalSpec = { + minerEnabled: true, + wantedPaths: [], + blockedPaths: [], + preferredLabels: [], + maxConcurrentClaims: 1, + issueDiscoveryPolicy: "neutral", +}; diff --git a/test/unit/miner-goal-spec.test.ts b/test/unit/miner-goal-spec.test.ts new file mode 100644 index 0000000000..bf663eeb16 --- /dev/null +++ b/test/unit/miner-goal-spec.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from "vitest"; +import { DEFAULT_MINER_GOAL_SPEC, type MinerGoalSpec } from "../../src/signals/miner-goal-spec"; + +describe("MinerGoalSpec", () => { + it("exports safe defaults matching the declared type contract", () => { + const typed: MinerGoalSpec = DEFAULT_MINER_GOAL_SPEC; + expect(typed).toEqual({ + minerEnabled: true, + wantedPaths: [], + blockedPaths: [], + preferredLabels: [], + maxConcurrentClaims: 1, + issueDiscoveryPolicy: "neutral", + }); + }); + + it("documents the default for every field in a co-located comment", async () => { + const source = await import("node:fs/promises").then((fs) => fs.readFile("src/signals/miner-goal-spec.ts", "utf8")); + expect(source).toMatch(/Whether autonomous miners may target this repo\. Default: true\./); + expect(source).toMatch(/Preferred work areas for miner-created changes\. Glob list\. Default: \[\]\./); + expect(source).toMatch(/Paths miners should avoid touching\. Glob list\. Default: \[\]\./); + expect(source).toMatch(/Labels miners should prefer when selecting or filing work\. Default: \[\]\./); + expect(source).toMatch(/Maximum concurrent claims a miner should hold against this repo\. Default: 1\./); + expect(source).toMatch(/Whether issue discovery work is encouraged for the repo\. Default: neutral\./); + }); +});