import type { Pool as MySqlPool } from "mysql2/promise"; import type { Pool as PgPool, PoolClient } from "pg"; import type { TaskOutcome as CoreTaskOutcome } from "@sema-agent/core"; import { type SqlDriver } from "./sql-driver.js"; import { type IndexSpec } from "./ensure-index.js"; /** Mechanical signals — the ONLY tier a future self-scheduler may read (council blocker 1). */ export interface MechanicalOutcome { route?: "single" | "fanout"; workerCount?: number; oraclePassed?: number; oracleTotal?: number; assembleExit?: number; lintExit?: number; mergeOk?: boolean; replanTriggers?: string[]; costMicroUsd?: number; turns?: number; } /** LLM-assisted signals — dashboard-only, NEVER drives automatic change, NEVER co-weighted. */ export interface LlmAssistedOutcome { stuckEvents?: number; verifier?: { verdict: string; confidence: number; }; } /** Raw inputs to the v1 task-signature (council Q11 candidate (a): structural/keyword hash). */ export interface SignatureInputs { taskType?: string; toolset?: string[]; targetLang?: string; moduleCount?: number; /** Optional explicit tag override (council Q11 candidate (c)). When set, it IS the signature. */ tag?: string; } /** * Run-status classification (council blocker 3 — attribution noise). Gates whether the * mechanical signal reflects TASK quality at all: an `infra-aborted` run died in the basework (sandbox * OOM / git-ownership / timeout / harvest fail) BEFORE reaching the grader, so its 0/total oracle is an * infra-health signal, NOT a task-difficulty signal. Route/budget learning must read `completed-graded` * rows ONLY; `infra-aborted` rows are kept for the infra-health dashboard but excluded from training. * (Found live: the task#2b backfill showed 9% pass-rate that was really 10/11 infra deaths since fixed.) */ export type RunStatus = "completed-graded" | "infra-aborted"; export interface TaskOutcome { taskId?: string; model: string; /** Default "completed-graded" if omitted. Set "infra-aborted" for runs that never reached the grader. */ runStatus?: RunStatus; signatureInputs: SignatureInputs; mechanical: MechanicalOutcome; llmAssisted?: LlmAssistedOutcome; /** [ref] §1 consumption: the VERBATIM core `TaskOutcome` fact this row was derived from (status/ * errorCode/oracleHadRedRun/oracle blob — fields the v1 columns predate). Stored as-is in `core_outcome` * so red-line ② (`oracleHadRedRun`) and the free-form oracle survive lossless; the mapped mechanical * columns stay the aggregate/query surface. */ core?: unknown; } /** * v1 task-signature (council Q11, recommended candidate (a)): a deterministic structural hash — zero * embedder, coarse on purpose (routing is a coarse decision). An explicit `tag` short-circuits to the * tag itself (candidate (c)). */ export declare function taskSignature(s: SignatureInputs): string; /** * Derive the coarse outcome from MECHANICAL fields only (council blocker 1: llmAssisted never participates). * pass = all hidden tests green AND both build exits 0 AND merge ok; fail = nothing graded green; else partial. */ export declare function deriveOutcome(m: MechanicalOutcome, runStatus?: RunStatus): "pass" | "partial" | "fail" | "aborted"; /** * [ref] §1 → §7 bridge: project one CORE `TaskOutcome` fact (the `RunnerDeps.onTaskOutcome` seam, * core 1.226) onto a v1 ledger row. Lossless: the verbatim fact rides `core` → the `core_outcome` JSON * column (red-line ② `oracleHadRedRun` + the free-form oracle blob have no v1 columns); the mapped * mechanical fields keep the existing aggregate surface working. Mapping rules: * - `signatureInputs.tag = o.taskSignature` — core already emits THE aggregation key, so the ledger's * tag short-circuit adopts it verbatim (no re-derivation drift); * - oracle counts: `oracle.oraclePassed/oracleTotal` when the harness supplied numeric counts, else the * required `green` bit as 1/0 over 1 (an honest degenerate count, not a fabrication); * - `runStatus` stays "completed-graded": core's red line ③ means emission only happens at a REAL * mechanical-oracle terminal (an infra-aborted run never reaches the emit point). */ export declare function coreOutcomeToLedgerRow(o: CoreTaskOutcome): TaskOutcome; /** * PG translation of the `outcome_ledger` DDL in tidb-pool.ts SCHEMA_STATEMENTS: * JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3), TINYINT(1)→SMALLINT, INT→INTEGER, inline KEY→separate CREATE INDEX. * The table is DISJOINT from every other store's tables, so this self-contained set is safe (no shadowing). * * SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are * drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead. */ export declare const PG_OUTCOME_LEDGER_SCHEMA: string[]; /** S-287:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgOutcomeLedgerSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */ export declare const OUTCOME_LEDGER_INDEXES: readonly IndexSpec[]; /** Idempotent self-contained PG schema apply (for the integration test; central aggregation via pg-pool.ts). */ export declare function ensurePgOutcomeLedgerSchema(pool: PgPool | PoolClient): Promise; /** Dual-dialect outcome ledger. See the file header for the dialect-delta ledger. */ export declare class SqlOutcomeLedger { private readonly db; constructor(db: SqlDriver); /** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */ private q; /** JSON column encode: TiDB stores `JSON.stringify` verbatim; PG runs the deep NUL/lone-surrogate * sanitize (a raw tool_result/core blob can carry bytes PG's jsonb column rejects, ERRCODE 22P05) — this * store's blobs are observability/dashboard data, so the lossy (U+FFFD) sanitize is the right tier * (not the lossless envelope checkpoint-store-sql.ts uses for the approval trust boundary). */ private json; /** Record one graded task run. Idempotent only by row id; callers pass distinct runs. */ record(o: TaskOutcome): Promise; /** [ref] §1 seam consumption: record one CORE outcome fact (see {@link coreOutcomeToLedgerRow}). */ recordCore(o: CoreTaskOutcome): Promise; /** * Read-only aggregate for the dashboard / offline backtest: pass-rate + mean cost per (signature, model). * 🔴 Defaults to `completed-graded` rows ONLY — the route/budget-learning signal must exclude infra-aborted * runs (council blocker 3: a basework death is not a task-difficulty signal). Pass * `includeAborted: true` only for the infra-health view, never for training. */ summary(opts?: { taskSignature?: string; includeAborted?: boolean; }): Promise>; } /** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */ export declare class TiDBOutcomeLedger extends SqlOutcomeLedger { constructor(pool: MySqlPool); } /** PostgreSQL binding — historical class name + ctor shape preserved. */ export declare class PgOutcomeLedger extends SqlOutcomeLedger { constructor(pool: PgPool); } //# sourceMappingURL=outcome-ledger-sql.d.ts.map