| 1 | -- Oak benchmark dashboard schema v2 (ADDITIVE migration over schema.sql).
|
| 2 | --
|
| 3 | -- Apply after schema.sql. Only ALTER TABLE ... ADD COLUMN and new tables /
|
| 4 | -- indexes: nothing existing is renamed, retyped, or dropped, so replaying R2
|
| 5 | -- raw objects against either schema version stays valid.
|
| 6 |
|
| 7 | PRAGMA foreign_keys = ON;
|
| 8 |
|
| 9 | -- Runner identity (ADR-0007) and lane context on measurements. Null means
|
| 10 | -- the producing lane did not record the signal (ADR-0002), never 0/''.
|
| 11 | ALTER TABLE measurements ADD COLUMN runner_id TEXT;
|
| 12 | ALTER TABLE measurements ADD COLUMN runner_class TEXT;
|
| 13 | ALTER TABLE measurements ADD COLUMN load_tier TEXT;
|
| 14 | ALTER TABLE measurements ADD COLUMN netshape_profile TEXT;
|
| 15 |
|
| 16 | -- p95 sits between the existing p90/p99 columns; nearest-rank like the rest.
|
| 17 | ALTER TABLE aggregates ADD COLUMN p95_ms REAL;
|
| 18 |
|
| 19 | -- Subject identity (review fix): identity is the deterministic subject_id,
|
| 20 | -- a stable hash of (run_key, effective subject, subject_kind, binary_sha256)
|
| 21 | -- computed at ingest. Two different binary_sha256 values for the same subject
|
| 22 | -- name in one run are two distinct subject records; `name` stays the plain
|
| 23 | -- subject string and is no longer an identity. The ingest upsert keys
|
| 24 | -- ON CONFLICT(subject_id), so this explicit unique index names the conflict
|
| 25 | -- target (it mirrors the PRIMARY KEY; redundant on disk, additive and
|
| 26 | -- self-documenting).
|
| 27 | --
|
| 28 | -- Supersession note: schema.sql originally declared an inline
|
| 29 | -- UNIQUE (run_key, name) on subjects. SQLite cannot drop an inline table
|
| 30 | -- constraint via ALTER TABLE, so no additive migration statement can remove
|
| 31 | -- it from already-created databases. Resolution, additive-only:
|
| 32 | -- * schema.sql's CREATE TABLE (which only runs on fresh databases, via
|
| 33 | -- IF NOT EXISTS) no longer carries the inline UNIQUE — fresh/rebuilt
|
| 34 | -- databases accept multiple shas per name;
|
| 35 | -- * databases created before this revision still carry the old inline
|
| 36 | -- constraint and will reject a second sha for one name; they are
|
| 37 | -- rebuildable by replaying R2 raw objects (the schema.sql header
|
| 38 | -- documents R2 as the source of truth), which sheds the constraint;
|
| 39 | -- * measurements, aggregates, and comparisons all reference subjects by
|
| 40 | -- subject_id (foreign keys + dashboard_comparisons view joins), so
|
| 41 | -- nothing else changes.
|
| 42 | CREATE UNIQUE INDEX IF NOT EXISTS idx_subjects_subject_id
|
| 43 | ON subjects (subject_id);
|
| 44 |
|
| 45 | -- Non-unique lookup index replacing the implicit index the old inline
|
| 46 | -- UNIQUE (run_key, name) provided on fresh databases.
|
| 47 | CREATE INDEX IF NOT EXISTS idx_subjects_run_name
|
| 48 | ON subjects (run_key, name);
|
| 49 |
|
| 50 | -- Committed Git Baseline Books (ADR-0006): compact JSON summaries served by
|
| 51 | -- GET /api/baseline-book/:id. book_json is oakbench.baseline_book.book_json
|
| 52 | -- output; manifest_json is the provenance manifest.
|
| 53 | CREATE TABLE IF NOT EXISTS baseline_books (
|
| 54 | book_id TEXT PRIMARY KEY,
|
| 55 | runner_class TEXT,
|
| 56 | manifest_json TEXT,
|
| 57 | book_json TEXT NOT NULL,
|
| 58 | created_utc TEXT NOT NULL
|
| 59 | );
|
| 60 |
|
| 61 | CREATE INDEX IF NOT EXISTS idx_baseline_books_runner_class
|
| 62 | ON baseline_books (runner_class, created_utc DESC);
|
| 63 |
|
| 64 | -- Repro-bundle verification results served by GET /api/verifications.
|
| 65 | CREATE TABLE IF NOT EXISTS verifications (
|
| 66 | id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 67 | bundle_sha256 TEXT NOT NULL,
|
| 68 | verdict TEXT NOT NULL,
|
| 69 | detail_json TEXT,
|
| 70 | created_utc TEXT NOT NULL
|
| 71 | );
|
| 72 |
|
| 73 | CREATE INDEX IF NOT EXISTS idx_verifications_bundle
|
| 74 | ON verifications (bundle_sha256, created_utc DESC);
|
| 75 |
|
| 76 | -- Stored target scorecards (oakbench.scorecard.evaluate_targets output);
|
| 77 | -- GET /api/scorecard returns the most recent row.
|
| 78 | CREATE TABLE IF NOT EXISTS scorecards (
|
| 79 | id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 80 | bench_id TEXT,
|
| 81 | profile TEXT,
|
| 82 | scorecard_json TEXT NOT NULL,
|
| 83 | created_utc TEXT NOT NULL
|
| 84 | );
|
| 85 |
|
| 86 | CREATE INDEX IF NOT EXISTS idx_scorecards_created
|
| 87 | ON scorecards (created_utc DESC);
|
| 88 |
|
| 89 | -- HMAC-verified GitHub webhook deliveries (POST /webhook/github).
|
| 90 | CREATE TABLE IF NOT EXISTS webhook_events (
|
| 91 | id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 92 | event TEXT,
|
| 93 | delivery_id TEXT,
|
| 94 | payload_json TEXT,
|
| 95 | signature_valid INTEGER NOT NULL DEFAULT 0,
|
| 96 | created_utc TEXT NOT NULL
|
| 97 | );
|
| 98 |
|
| 99 | CREATE INDEX IF NOT EXISTS idx_webhook_events_created
|
| 100 | ON webhook_events (created_utc DESC);
|
| 101 |
|
| 102 | -- Which dimensions breached for a regression verdict (review fix): JSON
|
| 103 | -- array string like '["p90"]'; null/'[]' when no breach. Without this the
|
| 104 | -- computed regression_dimensions field died at ingest and readers could not
|
| 105 | -- tell a p50 breach from a p90 breach.
|
| 106 | ALTER TABLE comparisons ADD COLUMN regression_dimensions TEXT;
|
| 107 |
|
| 108 | -- Refresh the readback view to expose the new column (views carry no data;
|
| 109 | -- drop+recreate is a definition refresh, not a destructive migration).
|
| 110 | DROP VIEW IF EXISTS dashboard_comparisons;
|
| 111 | CREATE VIEW dashboard_comparisons AS
|
| 112 | SELECT
|
| 113 | c.comparison_id,
|
| 114 | c.run_key,
|
| 115 | r.bench_id,
|
| 116 | r.timestamp_utc,
|
| 117 | r.profile,
|
| 118 | r.host_id,
|
| 119 | target.name AS target_subject,
|
| 120 | baseline.name AS baseline_subject,
|
| 121 | c.baseline_kind,
|
| 122 | c.scenario,
|
| 123 | c.operation,
|
| 124 | c.p50_delta_ms,
|
| 125 | c.p50_slower_pct,
|
| 126 | c.p90_delta_ms,
|
| 127 | c.p90_slower_pct,
|
| 128 | c.p99_delta_ms,
|
| 129 | c.p99_slower_pct,
|
| 130 | c.avg_token_delta,
|
| 131 | c.token_higher_pct,
|
| 132 | c.avg_output_byte_delta,
|
| 133 | c.output_byte_higher_pct,
|
| 134 | c.avg_tool_call_delta,
|
| 135 | c.tool_call_higher_pct,
|
| 136 | c.failure_rate_delta_pp,
|
| 137 | c.state,
|
| 138 | c.is_regression,
|
| 139 | c.regression_dimensions,
|
| 140 | c.severity_score
|
| 141 | FROM comparisons c
|
| 142 | JOIN benchmark_runs r ON r.run_key = c.run_key
|
| 143 | JOIN subjects target ON target.subject_id = c.target_subject_id
|
| 144 | JOIN subjects baseline ON baseline.subject_id = c.baseline_subject_id;
|