fix: complete gate cost micro-usd migration
This commit is contained in:
parent
7c39165c81
commit
c0973ac287
2 changed files with 110 additions and 14 deletions
|
|
@ -731,7 +731,8 @@ function initSchema(db, fileBacked) {
|
|||
max_attempts INTEGER NOT NULL DEFAULT 1,
|
||||
retryable INTEGER NOT NULL DEFAULT 0,
|
||||
evaluated_at TEXT NOT NULL DEFAULT '',
|
||||
duration_ms INTEGER DEFAULT NULL
|
||||
duration_ms INTEGER DEFAULT NULL,
|
||||
cost_micro_usd INTEGER DEFAULT NULL
|
||||
)
|
||||
`);
|
||||
db.exec(`
|
||||
|
|
@ -936,11 +937,6 @@ function migrateCostUsdToMicroUsd(db) {
|
|||
// Purpose: Enable accurate cost tracking at scale without rounding errors
|
||||
// Consumer: gate_runs cost tracking, cost analytics, budget checks
|
||||
|
||||
// Check if cost_micro_usd already exists (avoid re-running migration)
|
||||
if (columnExists(db, "gate_runs", "cost_micro_usd")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add cost_micro_usd column if it doesn't exist
|
||||
if (!columnExists(db, "gate_runs", "cost_micro_usd")) {
|
||||
db.exec(
|
||||
|
|
@ -955,6 +951,7 @@ function migrateCostUsdToMicroUsd(db) {
|
|||
UPDATE gate_runs
|
||||
SET cost_micro_usd = CAST(ROUND(cost_usd * 1000000) AS INTEGER)
|
||||
WHERE cost_usd IS NOT NULL
|
||||
AND cost_micro_usd IS NULL
|
||||
`).run();
|
||||
}
|
||||
|
||||
|
|
@ -1551,12 +1548,13 @@ function migrateSchema(db) {
|
|||
rationale TEXT NOT NULL DEFAULT '',
|
||||
findings TEXT NOT NULL DEFAULT '',
|
||||
attempt INTEGER NOT NULL DEFAULT 1,
|
||||
max_attempts INTEGER NOT NULL DEFAULT 1,
|
||||
retryable INTEGER NOT NULL DEFAULT 0,
|
||||
evaluated_at TEXT NOT NULL DEFAULT '',
|
||||
duration_ms INTEGER DEFAULT NULL
|
||||
)
|
||||
`);
|
||||
max_attempts INTEGER NOT NULL DEFAULT 1,
|
||||
retryable INTEGER NOT NULL DEFAULT 0,
|
||||
evaluated_at TEXT NOT NULL DEFAULT '',
|
||||
duration_ms INTEGER DEFAULT NULL,
|
||||
cost_micro_usd INTEGER DEFAULT NULL
|
||||
)
|
||||
`);
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS turn_git_transactions (
|
||||
trace_id TEXT NOT NULL,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,12 @@ import { tmpdir } from "node:os";
|
|||
import { join } from "node:path";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import { afterEach, test } from "vitest";
|
||||
import { closeDatabase, getDatabase, openDatabase } from "../sf-db.js";
|
||||
import {
|
||||
closeDatabase,
|
||||
getDatabase,
|
||||
insertGateRun,
|
||||
openDatabase,
|
||||
} from "../sf-db.js";
|
||||
|
||||
const tmpDirs = [];
|
||||
|
||||
|
|
@ -131,6 +136,58 @@ function makeLegacyV27Db() {
|
|||
return dbPath;
|
||||
}
|
||||
|
||||
function makeLegacyV35GateRunsDb() {
|
||||
const dir = mkdtempSync(join(tmpdir(), "sf-legacy-v35-gates-"));
|
||||
tmpDirs.push(dir);
|
||||
const sfDir = join(dir, ".sf");
|
||||
mkdirSync(sfDir, { recursive: true });
|
||||
const dbPath = join(sfDir, "sf.db");
|
||||
const db = new DatabaseSync(dbPath);
|
||||
db.exec(`
|
||||
CREATE TABLE schema_version (
|
||||
version INTEGER NOT NULL,
|
||||
applied_at TEXT NOT NULL
|
||||
);
|
||||
INSERT INTO schema_version (version, applied_at)
|
||||
VALUES (35, '2026-05-07T00:00:00.000Z');
|
||||
|
||||
CREATE TABLE gate_runs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
trace_id TEXT NOT NULL,
|
||||
turn_id TEXT NOT NULL,
|
||||
gate_id TEXT NOT NULL,
|
||||
gate_type TEXT NOT NULL DEFAULT '',
|
||||
unit_type TEXT DEFAULT NULL,
|
||||
unit_id TEXT DEFAULT NULL,
|
||||
milestone_id TEXT DEFAULT NULL,
|
||||
slice_id TEXT DEFAULT NULL,
|
||||
task_id TEXT DEFAULT NULL,
|
||||
outcome TEXT NOT NULL DEFAULT 'pass',
|
||||
failure_class TEXT NOT NULL DEFAULT 'none',
|
||||
rationale TEXT NOT NULL DEFAULT '',
|
||||
findings TEXT NOT NULL DEFAULT '',
|
||||
attempt INTEGER NOT NULL DEFAULT 1,
|
||||
max_attempts INTEGER NOT NULL DEFAULT 1,
|
||||
retryable INTEGER NOT NULL DEFAULT 0,
|
||||
evaluated_at TEXT NOT NULL DEFAULT '',
|
||||
duration_ms INTEGER DEFAULT NULL,
|
||||
cost_usd REAL DEFAULT NULL
|
||||
);
|
||||
INSERT INTO gate_runs (
|
||||
trace_id, turn_id, gate_id, gate_type, unit_type, unit_id,
|
||||
milestone_id, slice_id, task_id, outcome, failure_class, rationale,
|
||||
findings, attempt, max_attempts, retryable, evaluated_at, duration_ms,
|
||||
cost_usd
|
||||
) VALUES (
|
||||
'trace-1', 'turn-1', 'cost-gate', 'policy', 'execute-task',
|
||||
'M001/S01/T01', 'M001', 'S01', 'T01', 'pass', 'none', 'ok',
|
||||
'', 1, 1, 0, '2026-05-07T00:00:00.000Z', 12, 0.123456
|
||||
);
|
||||
`);
|
||||
db.close();
|
||||
return dbPath;
|
||||
}
|
||||
|
||||
test("openDatabase_migrates_v27_tasks_without_created_at_through_spec_backfill", () => {
|
||||
const dbPath = makeLegacyV27Db();
|
||||
|
||||
|
|
@ -142,7 +199,7 @@ test("openDatabase_migrates_v27_tasks_without_created_at_through_spec_backfill",
|
|||
const version = db
|
||||
.prepare("SELECT MAX(version) AS version FROM schema_version")
|
||||
.get();
|
||||
assert.equal(version.version, 35);
|
||||
assert.equal(version.version, 36);
|
||||
const taskSpec = db
|
||||
.prepare(
|
||||
"SELECT milestone_id, slice_id, task_id, verify FROM task_specs WHERE task_id = 'T01'",
|
||||
|
|
@ -155,3 +212,44 @@ test("openDatabase_migrates_v27_tasks_without_created_at_through_spec_backfill",
|
|||
verify: "go test ./portal",
|
||||
});
|
||||
});
|
||||
|
||||
test("openDatabase_when_fresh_db_supports_gate_run_micro_usd", () => {
|
||||
assert.equal(openDatabase(":memory:"), true);
|
||||
|
||||
insertGateRun({
|
||||
traceId: "trace-1",
|
||||
turnId: "turn-1",
|
||||
gateId: "cost-gate",
|
||||
gateType: "policy",
|
||||
outcome: "pass",
|
||||
failureClass: "none",
|
||||
rationale: "ok",
|
||||
attempt: 1,
|
||||
maxAttempts: 1,
|
||||
retryable: false,
|
||||
evaluatedAt: "2026-05-07T00:00:00.000Z",
|
||||
durationMs: 12,
|
||||
costMicroUsd: 123_456,
|
||||
});
|
||||
|
||||
const row = getDatabase()
|
||||
.prepare("SELECT cost_micro_usd FROM gate_runs WHERE gate_id = 'cost-gate'")
|
||||
.get();
|
||||
assert.equal(row.cost_micro_usd, 123_456);
|
||||
});
|
||||
|
||||
test("openDatabase_migrates_v35_gate_cost_usd_to_micro_usd", () => {
|
||||
const dbPath = makeLegacyV35GateRunsDb();
|
||||
|
||||
assert.equal(openDatabase(dbPath), true);
|
||||
const db = getDatabase();
|
||||
const columns = db.prepare("PRAGMA table_info(gate_runs)").all();
|
||||
assert.ok(columns.some((row) => row.name === "cost_micro_usd"));
|
||||
const row = db
|
||||
.prepare(
|
||||
"SELECT cost_usd, cost_micro_usd FROM gate_runs WHERE gate_id = 'cost-gate'",
|
||||
)
|
||||
.get();
|
||||
assert.equal(row.cost_usd, 0.123456);
|
||||
assert.equal(row.cost_micro_usd, 123_456);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue