From 2ce290bda4bf56f3515b24fe98b08ee7be6db0b9 Mon Sep 17 00:00:00 2001 From: kiannidev <156195510+kiannidev@users.noreply.github.com> Date: Mon, 6 Jul 2026 00:01:03 +0200 Subject: [PATCH] feat(miner): document claim ledger and verify schema via PRAGMA (#2291) Add README coverage for the foundation claim ledger API and PRAGMA-based schema regression tests for miner_claims (#3352). Co-authored-by: Cursor --- packages/gittensory-miner/README.md | 4 ++ test/unit/miner-claim-ledger-readme.test.ts | 16 ++++++++ test/unit/miner-claim-ledger.test.ts | 44 +++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 test/unit/miner-claim-ledger-readme.test.ts diff --git a/packages/gittensory-miner/README.md b/packages/gittensory-miner/README.md index 817df5b7de..4959b3ec47 100644 --- a/packages/gittensory-miner/README.md +++ b/packages/gittensory-miner/README.md @@ -28,6 +28,10 @@ The package also includes an append-only governor decision ledger: `initGovernor persist structured allow/deny/throttle/kill-switch outcomes in local SQLite for contributor audit. Insert-only — no enforcement wiring yet. (#2328) +The package also includes a local soft-claim ledger: `openClaimLedger` / `claimIssue` / `releaseClaim` / +`listActiveClaims` persist which issues this miner instance has claimed on this machine. The table is local +bookkeeping only — duplicate winners are adjudicated elsewhere via `@jsonbored/gittensory-engine`. (#2291) + ## 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. diff --git a/test/unit/miner-claim-ledger-readme.test.ts b/test/unit/miner-claim-ledger-readme.test.ts new file mode 100644 index 0000000000..df45bd0eff --- /dev/null +++ b/test/unit/miner-claim-ledger-readme.test.ts @@ -0,0 +1,16 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; + +const readmePath = join(process.cwd(), "packages/gittensory-miner/README.md"); + +describe("gittensory-miner claim ledger README (#2291)", () => { + it("documents the foundation claim ledger API surface", () => { + const readme = readFileSync(readmePath, "utf8"); + expect(readme).toContain("claimIssue"); + expect(readme).toContain("releaseClaim"); + expect(readme).toContain("listActiveClaims"); + expect(readme).toContain("bookkeeping only"); + expect(readme).toContain("@jsonbored/gittensory-engine"); + }); +}); diff --git a/test/unit/miner-claim-ledger.test.ts b/test/unit/miner-claim-ledger.test.ts index 07bb9c6457..e5f5218ef0 100644 --- a/test/unit/miner-claim-ledger.test.ts +++ b/test/unit/miner-claim-ledger.test.ts @@ -1,6 +1,7 @@ import { mkdtempSync, readFileSync, rmSync, statSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { DatabaseSync } from "node:sqlite"; import { afterEach, describe, expect, it, vi } from "vitest"; import { CLAIM_STATUSES, @@ -175,6 +176,49 @@ describe("gittensory-miner claim ledger (#2314)", () => { expect(listActiveClaims("o/a")).toEqual([claim]); expect(listActiveClaims("o/missing")).toEqual([]); }); + + it("creates miner_claims with the foundation schema (#3352)", () => { + const ledger = tempLedger(); + const db = new DatabaseSync(ledger.dbPath, { readonly: true }); + type TableColumn = { name: string; notnull: number; dflt_value: string | null; pk: number }; + const columns = db.prepare("PRAGMA table_info(miner_claims)").all() as TableColumn[]; + expect(columns.map((column) => column.name)).toEqual([ + "id", + "repo_full_name", + "issue_number", + "claimed_at", + "status", + "note", + ]); + for (const name of ["repo_full_name", "issue_number", "claimed_at", "status"]) { + expect(columns.find((column) => column.name === name)?.notnull).toBe(1); + } + expect(columns.find((column) => column.name === "status")?.dflt_value).toBe("'active'"); + expect(columns.find((column) => column.name === "id")?.pk).toBe(1); + + const uniqueIndexes = (db.prepare("PRAGMA index_list(miner_claims)").all() as Array<{ name: string; unique: number }>) + .filter((index) => index.unique === 1); + expect(uniqueIndexes.length).toBeGreaterThan(0); + const indexCols = db.prepare(`PRAGMA index_info('${uniqueIndexes[0]!.name}')`).all() as Array<{ name: string }>; + expect(indexCols.map((column) => column.name).sort()).toEqual(["issue_number", "repo_full_name"]); + db.close(); + + const writable = new DatabaseSync(ledger.dbPath); + expect(() => + writable.exec( + "INSERT INTO miner_claims (repo_full_name, issue_number, claimed_at, status) VALUES ('o/a', 1, '2026-01-01T00:00:00.000Z', 'bogus')", + ), + ).toThrow(); + writable.close(); + }); + + it("scopes active claims per repo (#3354)", () => { + const ledger = tempLedger(); + ledger.claimIssue("o/a", 1); + ledger.claimIssue("o/b", 2); + expect(ledger.listActiveClaims("o/a").map((claim) => claim.issueNumber)).toEqual([1]); + expect(ledger.listActiveClaims("o/b").map((claim) => claim.issueNumber)).toEqual([2]); + }); }); function tempRoot() {