File size: 2,985 Bytes
88d2f2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""One-shot migration: add ``events.mode`` column + index.

W5-A1 (2026-05-26): introduces a 2-mode system for the event lifecycle:

* ``live`` (default) β€” real LLM, real Arc tx, real RSS, real judges.
* ``mock``           β€” MockLLM + ``0xsim_*`` tx hashes + canned news + judges short-circuit.

This script applies the schema delta to the local SQLite DB outside the
SQLModel ``create_all`` path because (a) the table already exists with rows
and (b) ``ALTER TABLE`` is the safe non-destructive way to add a
``NOT NULL`` column with a default. We use the stdlib ``sqlite3`` driver
directly rather than the shell ``sqlite3`` binary because the shell client
has surfaced "malformed file" errors on the WAL-mode DB during the wave3
debugging session.

The same delta is also applied at backend startup by
``polyglot_alpha.persistence.db._migrate_events_add_mode`` so fresh checkouts
do not need to run this script β€” it remains here as documentation + an
operator escape hatch.

Usage::

    python scripts/migrate_add_mode_column.py

Idempotent: re-running is a no-op (the helper checks ``PRAGMA table_info``
before issuing the ``ALTER TABLE``).
"""

from __future__ import annotations

import os
import sqlite3
import sys
from pathlib import Path

# Resolve the DB path relative to the repo root so the script works no
# matter where it's invoked from.
_REPO_ROOT = Path(__file__).resolve().parents[1]
_DEFAULT_DB_PATH = _REPO_ROOT / "polyglot_alpha.db"


def main(db_path: Path = _DEFAULT_DB_PATH) -> int:
    if not db_path.exists():
        print(f"[migrate] no DB at {db_path} β€” nothing to do", file=sys.stderr)
        return 0

    conn = sqlite3.connect(str(db_path))
    try:
        cols = {row[1] for row in conn.execute("PRAGMA table_info(events)").fetchall()}
        if "mode" in cols:
            print("[migrate] events.mode already present β€” skipping ALTER")
        else:
            conn.execute(
                "ALTER TABLE events ADD COLUMN mode VARCHAR DEFAULT 'live' NOT NULL"
            )
            print("[migrate] added events.mode VARCHAR (default 'live')")
        conn.execute("CREATE INDEX IF NOT EXISTS idx_events_mode ON events(mode)")
        print("[migrate] ensured idx_events_mode on events(mode)")
        conn.commit()

        # Verification pass.
        cols_after = conn.execute("PRAGMA table_info(events)").fetchall()
        mode_col = next((c for c in cols_after if c[1] == "mode"), None)
        if mode_col is None:
            print("[migrate] ERROR: mode column not visible after ALTER", file=sys.stderr)
            return 2
        print(f"[migrate] verified: {mode_col}")

        # Show distribution of mode values for confidence.
        for row in conn.execute(
            "SELECT mode, COUNT(*) FROM events GROUP BY mode"
        ).fetchall():
            print(f"[migrate] mode={row[0]!r} -> {row[1]} row(s)")
    finally:
        conn.close()
    return 0


if __name__ == "__main__":
    raise SystemExit(main())