From fbed5a960ab411ecb3dda4a73b08fb2919e58222 Mon Sep 17 00:00:00 2001 From: davion-knight <298846663+davion-knight@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:34:09 -0500 Subject: [PATCH] docs(miner): add an 'Observing your miner' Grafana/ledger observability guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add packages/gittensory-miner/docs/observability.md documenting how to point Grafana at the miner's local SQLite ledgers (attempt-log + prediction-ledger) via the read-only frser-sqlite datasources shipped in grafana/provisioning/datasources/ams-ledgers.yml (#5184): install the plugin, mount GITTENSORY_MINER_CONFIG_DIR read-only at /ams-ledgers, and load a dashboard from grafana/dashboards/. Concrete copy-pasteable steps; cross-references DEPLOYMENT.md and is linked from coding-agent-driver.md so it is discoverable from the existing entry point. Docs only — observability/Grafana setup, not a duplication of the general ops runbook (#5190). Closes #5190 --- .../docs/coding-agent-driver.md | 31 ++++++----- .../gittensory-miner/docs/observability.md | 52 +++++++++++++++++++ 2 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 packages/gittensory-miner/docs/observability.md diff --git a/packages/gittensory-miner/docs/coding-agent-driver.md b/packages/gittensory-miner/docs/coding-agent-driver.md index a378ce6c00..67486cfa52 100644 --- a/packages/gittensory-miner/docs/coding-agent-driver.md +++ b/packages/gittensory-miner/docs/coding-agent-driver.md @@ -9,6 +9,9 @@ The interface itself lives in `@jsonbored/gittensory-engine` ([`packages/gittensory-engine/src/miner/coding-agent-driver.ts`](../../gittensory-engine/src/miner/coding-agent-driver.ts)); the orchestration around it (mode gating, invocation, the factory) lives in the sibling modules described below. +> **See also:** [Observing your miner](observability.md) — point Grafana at the miner's local SQLite ledgers +> (attempt log, prediction ledger) to see what the driver actually did. + ## Why a seam, and why this shape The design deliberately mirrors the review stack's `SelfHostAi` (`src/selfhost/ai.ts`) rather than inventing a new @@ -23,18 +26,18 @@ autonomous continue/stop decisions — the task handed to a driver is already sc ```ts type CodingAgentDriverTask = { - attemptId: string; // stable id for this attempt (keys the attempt log) - workingDirectory: string; // the ONLY directory a driver may edit (see worktree isolation below) + attemptId: string; // stable id for this attempt (keys the attempt log) + workingDirectory: string; // the ONLY directory a driver may edit (see worktree isolation below) acceptanceCriteriaPath: string; // path to the immutable acceptance-criteria file written before the run - instructions: string; // the metadata-only prompt (no source contents) - maxTurns: number; // hard cap on agent iterations for this attempt + instructions: string; // the metadata-only prompt (no source contents) + maxTurns: number; // hard cap on agent iterations for this attempt }; type CodingAgentDriverResult = { ok: boolean; changedFiles: readonly string[]; summary: string; - transcript?: string; // opaque provider transcript for operator inspection + transcript?: string; // opaque provider transcript for operator inspection turnsUsed?: number; error?: string; }; @@ -53,15 +56,15 @@ Agent-SDK driver (#4267) — register in `createCodingAgentDriver` as `claude-cl A driver never runs in isolation. The neighborhood it plugs into: -| Concern | Module | What it provides | -|---|---|---| -| Execution mode | `coding-agent-mode.ts` | `paused` / `dry_run` / `live` with deny-toward-safety precedence; `codingAgentModeExecutes(mode)` is the single "should this attempt actually spawn?" boolean. A `dry_run` is a pure no-op at the driver boundary. | -| Invocation | `coding-agent-invoke.ts` | `invokeCodingAgentDriver(driver, task, mode?, log?)` — gates on the mode, calls `driver.run`, and streams lifecycle events to an `AttemptLogSink`. | -| Factory | `driver-factory.ts` | `createCodingAgentDriver(options)` resolves a driver by configured name; `resolveConfiguredCodingAgentDriverNames` / `isConfiguredCodingAgentDriver` deny unknown names by default; `runCodingAgentAttempt(options)` is the top-level "resolve + invoke" convenience. | -| Attempt log | `attempt-log.ts` (#4294) | `ATTEMPT_LOG_EVENT_TYPES` + `normalizeAttemptLogEvent` + `createAttemptLogBuffer` + `formatAttemptLogJsonl` — an append-only, JSONL-exportable event trace per attempt, independent of any driver's own transcript. Durable persistence: `packages/gittensory-miner/lib/attempt-log.js` (sibling SQLite store; imports the engine normalizer). | -| Metering | `attempt-metering.ts` (#4311) | `accumulateAttemptUsage` / `meterAttemptUsage` / `evaluateAttemptBudget` over `AttemptBudgetAxis` (`tokens` / `turns` / `wallClockMs` / `costUsd`). | -| Acceptance criteria | (#4271) | The immutable criteria file at `task.acceptanceCriteriaPath`, written before the driver starts. | -| Worktree isolation | (#4269) | Each attempt's `task.workingDirectory` is a dedicated git worktree; a driver must never edit outside it. | +| Concern | Module | What it provides | +| ------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Execution mode | `coding-agent-mode.ts` | `paused` / `dry_run` / `live` with deny-toward-safety precedence; `codingAgentModeExecutes(mode)` is the single "should this attempt actually spawn?" boolean. A `dry_run` is a pure no-op at the driver boundary. | +| Invocation | `coding-agent-invoke.ts` | `invokeCodingAgentDriver(driver, task, mode?, log?)` — gates on the mode, calls `driver.run`, and streams lifecycle events to an `AttemptLogSink`. | +| Factory | `driver-factory.ts` | `createCodingAgentDriver(options)` resolves a driver by configured name; `resolveConfiguredCodingAgentDriverNames` / `isConfiguredCodingAgentDriver` deny unknown names by default; `runCodingAgentAttempt(options)` is the top-level "resolve + invoke" convenience. | +| Attempt log | `attempt-log.ts` (#4294) | `ATTEMPT_LOG_EVENT_TYPES` + `normalizeAttemptLogEvent` + `createAttemptLogBuffer` + `formatAttemptLogJsonl` — an append-only, JSONL-exportable event trace per attempt, independent of any driver's own transcript. Durable persistence: `packages/gittensory-miner/lib/attempt-log.js` (sibling SQLite store; imports the engine normalizer). | +| Metering | `attempt-metering.ts` (#4311) | `accumulateAttemptUsage` / `meterAttemptUsage` / `evaluateAttemptBudget` over `AttemptBudgetAxis` (`tokens` / `turns` / `wallClockMs` / `costUsd`). | +| Acceptance criteria | (#4271) | The immutable criteria file at `task.acceptanceCriteriaPath`, written before the driver starts. | +| Worktree isolation | (#4269) | Each attempt's `task.workingDirectory` is a dedicated git worktree; a driver must never edit outside it. | ## Authoring a third driver diff --git a/packages/gittensory-miner/docs/observability.md b/packages/gittensory-miner/docs/observability.md new file mode 100644 index 0000000000..db85e4220d --- /dev/null +++ b/packages/gittensory-miner/docs/observability.md @@ -0,0 +1,52 @@ +# Observing your miner + +How to point Grafana at a running miner's local SQLite ledgers to see its attempt and prediction history. This +covers the **miner-specific** observability wiring only; for general self-host operations, see your ops runbook. + +## What's observable + +The miner writes append-only SQLite ledgers under `GITTENSORY_MINER_CONFIG_DIR` (default +`~/.config/gittensory-miner` on a laptop, or `/data/miner` in the fleet Docker image — see +[`DEPLOYMENT.md`](../DEPLOYMENT.md)): + +- **`attempt-log.sqlite3`** — the driver-level attempt event trace (event type, action class, mode, reason, + timestamps), table `attempt_log_events`. +- **`prediction-ledger.sqlite3`** — recorded predicted-gate verdicts for later scoring. + +## Point Grafana at the ledgers + +The repo ships datasource provisioning at +[`grafana/provisioning/datasources/ams-ledgers.yml`](../../../grafana/provisioning/datasources/ams-ledgers.yml) +— two **read-only** `frser-sqlite-datasource` entries: `AMS Attempt Log` (uid `ams-attempt-log`) and +`AMS Prediction Ledger` (uid `ams-prediction-ledger`). + +1. **Install the SQLite plugin** in Grafana — the same one the maintainer `GittensoryDB` datasource uses: + + ```sh + GF_INSTALL_PLUGINS=frser-sqlite-datasource + ``` + +2. **Mount your ledger directory** into the Grafana container, read-only, at `/ams-ledgers` so the provisioned + `path:` values resolve (the `:ro` mount plus the query-only plugin mean Grafana can never write the live + ledgers): + + ```yaml + # in your Grafana service (docker-compose) + volumes: + - "${GITTENSORY_MINER_CONFIG_DIR:-~/.config/gittensory-miner}:/ams-ledgers:ro" + ``` + + The two datasources point at `/ams-ledgers/attempt-log.sqlite3` and `/ams-ledgers/prediction-ledger.sqlite3`. + If you mount elsewhere, edit the two `path:` values in `ams-ledgers.yml` to match. + +3. **Restart Grafana.** The two datasources appear under **Connections → Data sources**, already provisioned + (non-editable) so they survive restarts. + +## Load a dashboard + +Dashboards live in [`grafana/dashboards/`](../../../grafana/dashboards/) and are auto-provisioned from that +directory. To visualize the ledgers, add an AMS dashboard JSON there — or import one at runtime via the Grafana +UI (**Dashboards → Import**) — and point its panels at the `AMS Attempt Log` / `AMS Prediction Ledger` +datasources above. Panels query the ledger tables directly (e.g. `SELECT * FROM attempt_log_events`); the +`frser-sqlite-datasource` plugin also supports `json_extract(payload_json, '$.…')` to read fields nested inside +an event's payload.