diff --git a/docs/governance/stage-01-baseline.md b/docs/governance/stage-01-baseline.md new file mode 100644 index 0000000..efada7b --- /dev/null +++ b/docs/governance/stage-01-baseline.md @@ -0,0 +1,60 @@ +# Stage 01: Governance Baseline + +Date: 2026-07-29 + +Baseline commit: `0030bb8cc18c5aa7107dd8fd866355a6507bd6da` + +## Purpose + +This baseline freezes observable behavior before architecture governance begins. Later stages +may move code and introduce internal contracts, but must not change API behavior, account +boundaries, persisted user data, desktop presentation, or existing workflows unless a change +is approved separately. + +## Deployment Contract + +- One Python process serves the API and static browser client. +- One SQLite database is persisted at `data/review.db`. +- Docker exposes `0.0.0.0:8765` and mounts only `./data` at `/app/data`. +- Public market data is shared; private records are scoped by `user_id`. +- Market-data and LLM credentials remain server-side. + +## Verified Baseline + +- Python: 169 tests passed. +- Playwright: 45 tests passed at desktop and mobile viewports. +- JavaScript entry points pass `node --check`. +- `git diff --check` reports no patch errors. +- SQLite `PRAGMA integrity_check` returns `ok`. +- The database was backed up with the SQLite backup API to + `data/backups/governance-stage-01-0030bb8.db` and the backup independently passed + `PRAGMA integrity_check`. The backup is intentionally excluded from Git. + +## Repeatable Verification + +Run the fast baseline on every structural change: + +```shell +python tools/verify_baseline.py +``` + +Run the browser suite at phase boundaries: + +```shell +python tools/verify_baseline.py --e2e +``` + +## Regression Gates + +1. API routes and response fields remain compatible until a versioned contract says otherwise. +2. Existing SQLite files must upgrade without deleting or reassigning user-owned rows. +3. A failed external data request must not synthesize market prices. +4. Ordinary, member, and administrator permissions must remain distinct. +5. Desktop visual refactors require 1080P and 4K comparison in both themes. +6. Mobile work is isolated from the approved desktop shell and workflows. +7. Old code is deleted only after its replacement is active and reference scans are clean. + +## Rollback + +Code can return to this point with Git commit `0030bb8`. Database rollback must use the +matching backup above; a code rollback alone is not sufficient after a schema migration. diff --git a/tools/verify_baseline.py b/tools/verify_baseline.py new file mode 100644 index 0000000..f788c82 --- /dev/null +++ b/tools/verify_baseline.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import argparse +import shutil +import sqlite3 +import subprocess +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def run(label: str, command: list[str]) -> None: + print(f"\n[{label}] {' '.join(command)}", flush=True) + subprocess.run(command, cwd=ROOT, check=True) + + +def verify_database() -> None: + database = ROOT / "data" / "review.db" + if not database.exists(): + print("\n[database] skipped: data/review.db does not exist") + return + with sqlite3.connect(f"file:{database.as_posix()}?mode=ro", uri=True) as connection: + result = connection.execute("PRAGMA integrity_check").fetchone() + if not result or result[0] != "ok": + raise RuntimeError(f"SQLite integrity check failed: {result}") + print(f"\n[database] integrity_check=ok size={database.stat().st_size}") + + +def main() -> int: + parser = argparse.ArgumentParser(description="Verify the governance regression baseline") + parser.add_argument( + "--e2e", + action="store_true", + help="also run the Playwright browser suite", + ) + args = parser.parse_args() + + run("python", [sys.executable, "-m", "unittest", "discover", "-s", "tests"]) + node = shutil.which("node") + if not node: + raise RuntimeError("node is required for JavaScript syntax checks") + for script in ("static/app.js", "static/heaven-loading-v2.js"): + run("javascript", [node, "--check", script]) + run("patch", ["git", "diff", "--check"]) + verify_database() + + if args.e2e: + npm = shutil.which("npm.cmd" if sys.platform == "win32" else "npm") + if not npm: + raise RuntimeError("npm is required for the Playwright suite") + run("playwright", [npm, "run", "test:e2e"]) + print("\nBaseline verification passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())