feat(db): migration 027 — additive §22 M3 schema (type/initial_state, deployment, review cols)
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
-- §22 M3 (Plan A) — additive registry/runtime-config schema.
|
||||||
|
--
|
||||||
|
-- This is the additive half of M3's backend. It adds the project `type` and
|
||||||
|
-- `initial_state` columns (mirrored from the registry), the deployment
|
||||||
|
-- singleton (deployment name/tagline mirrored from the registry), and the
|
||||||
|
-- §22.4c review columns on cached_rfcs. NO table rebuilds: the §22.13 PK
|
||||||
|
-- rebuilds and the default->slug re-stamp ride a later migration (Plan B),
|
||||||
|
-- just before a second project can collide (see migration 026's DEFERRED
|
||||||
|
-- block and docs/superpowers/specs/2026-06-03-m3-backend-design.md §1/§6).
|
||||||
|
|
||||||
|
ALTER TABLE projects ADD COLUMN type TEXT NOT NULL DEFAULT 'document'
|
||||||
|
CHECK (type IN ('document', 'specification', 'bdd'));
|
||||||
|
ALTER TABLE projects ADD COLUMN initial_state TEXT NOT NULL DEFAULT 'super-draft'
|
||||||
|
CHECK (initial_state IN ('super-draft', 'active'));
|
||||||
|
|
||||||
|
-- Deployment-level identity (name, tagline) mirrored from the registry's
|
||||||
|
-- `deployment:` block. A singleton: the CHECK pins it to one row.
|
||||||
|
CREATE TABLE IF NOT EXISTS deployment (
|
||||||
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
|
name TEXT,
|
||||||
|
tagline TEXT,
|
||||||
|
registry_sha TEXT,
|
||||||
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
INSERT OR IGNORE INTO deployment (id) VALUES (1);
|
||||||
|
|
||||||
|
-- §22.4c review flag + provenance. unreviewed is git-truth (mirrored from
|
||||||
|
-- entry frontmatter); it survives a cache rebuild like `state` does.
|
||||||
|
ALTER TABLE cached_rfcs ADD COLUMN unreviewed INTEGER NOT NULL DEFAULT 0;
|
||||||
|
ALTER TABLE cached_rfcs ADD COLUMN reviewed_at TEXT;
|
||||||
|
ALTER TABLE cached_rfcs ADD COLUMN reviewed_by TEXT;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
"""Migration 027 — additive §22 M3 schema (projects.type/initial_state, the
|
||||||
|
deployment singleton, cached_rfcs review columns). No table rebuilds in Plan A."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
def _fresh_config() -> Config:
|
||||||
|
tmp = Path(tempfile.mkdtemp(prefix="mig027-")) / "t.db"
|
||||||
|
return Config(
|
||||||
|
gitea_url="x", gitea_bot_user="x", gitea_bot_token="x", gitea_org="x",
|
||||||
|
meta_repo="meta", registry_repo="registry",
|
||||||
|
oauth_client_id="x", oauth_client_secret="x", app_url="x",
|
||||||
|
secret_key="x", database_path=tmp, owner_gitea_login="x",
|
||||||
|
webhook_secret="x",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_027_adds_project_type_and_initial_state():
|
||||||
|
cfg = _fresh_config()
|
||||||
|
db.run_migrations(cfg)
|
||||||
|
conn = db.connect(cfg.database_path)
|
||||||
|
cols = {r["name"]: r for r in conn.execute("PRAGMA table_info(projects)")}
|
||||||
|
assert "type" in cols and cols["type"]["dflt_value"] == "'document'"
|
||||||
|
assert "initial_state" in cols and cols["initial_state"]["dflt_value"] == "'super-draft'"
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_027_creates_deployment_singleton():
|
||||||
|
cfg = _fresh_config()
|
||||||
|
db.run_migrations(cfg)
|
||||||
|
conn = db.connect(cfg.database_path)
|
||||||
|
rows = list(conn.execute("SELECT id FROM deployment"))
|
||||||
|
assert [r["id"] for r in rows] == [1]
|
||||||
|
try:
|
||||||
|
conn.execute("INSERT INTO deployment (id) VALUES (2)")
|
||||||
|
raised = False
|
||||||
|
except Exception:
|
||||||
|
raised = True
|
||||||
|
assert raised
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_027_adds_review_columns_to_cached_rfcs():
|
||||||
|
cfg = _fresh_config()
|
||||||
|
db.run_migrations(cfg)
|
||||||
|
conn = db.connect(cfg.database_path)
|
||||||
|
cols = {r["name"] for r in conn.execute("PRAGMA table_info(cached_rfcs)")}
|
||||||
|
assert {"unreviewed", "reviewed_at", "reviewed_by"} <= cols
|
||||||
|
conn.close()
|
||||||
Reference in New Issue
Block a user