@jaguilar87/gaia 5.0.4 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +56 -0
  4. package/INSTALL.md +0 -2
  5. package/README.md +1 -6
  6. package/bin/README.md +0 -1
  7. package/bin/cli/_install_helpers.py +1 -1
  8. package/bin/cli/cleanup.py +0 -1
  9. package/bin/cli/doctor.py +1 -1
  10. package/bin/cli/memory.py +2 -0
  11. package/bin/cli/update.py +1 -1
  12. package/bin/pre-publish-validate.js +48 -5
  13. package/config/README.md +22 -44
  14. package/config/surface-routing.json +0 -1
  15. package/dist/gaia-ops/.claude-plugin/plugin.json +1 -1
  16. package/dist/gaia-ops/config/README.md +22 -44
  17. package/dist/gaia-ops/config/surface-routing.json +0 -1
  18. package/dist/gaia-ops/hooks/modules/agents/handoff_persister.py +2 -0
  19. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +2 -0
  20. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +2 -0
  21. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +90 -55
  22. package/dist/gaia-ops/skills/README.md +1 -1
  23. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +1 -1
  24. package/dist/gaia-ops/skills/gaia-patterns/reference.md +0 -1
  25. package/dist/gaia-ops/skills/gaia-release/SKILL.md +60 -24
  26. package/dist/gaia-ops/skills/gaia-release/reference.md +35 -11
  27. package/dist/gaia-ops/skills/git-conventions/SKILL.md +6 -2
  28. package/dist/gaia-ops/skills/orchestrator-present-approval/SKILL.md +10 -2
  29. package/dist/gaia-ops/skills/readme-writing/SKILL.md +1 -1
  30. package/dist/gaia-ops/skills/readme-writing/reference.md +0 -1
  31. package/dist/gaia-ops/tools/scan/ui.py +20 -4
  32. package/dist/gaia-ops/tools/scan/verify.py +3 -3
  33. package/dist/gaia-ops/tools/validation/README.md +15 -24
  34. package/dist/gaia-security/.claude-plugin/plugin.json +1 -1
  35. package/dist/gaia-security/hooks/modules/agents/handoff_persister.py +2 -0
  36. package/dist/gaia-security/hooks/modules/security/approval_grants.py +2 -0
  37. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +2 -0
  38. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +90 -55
  39. package/hooks/modules/agents/handoff_persister.py +2 -0
  40. package/hooks/modules/security/approval_grants.py +2 -0
  41. package/hooks/modules/tools/bash_validator.py +2 -0
  42. package/hooks/modules/validation/commit_validator.py +90 -55
  43. package/index.js +2 -12
  44. package/package.json +4 -6
  45. package/pyproject.toml +3 -3
  46. package/scripts/bootstrap_database.sh +88 -439
  47. package/scripts/check_schema_drift.py +208 -0
  48. package/scripts/migrations/README.md +78 -28
  49. package/scripts/migrations/schema.checksum +8 -0
  50. package/scripts/release-prepare.mjs +199 -0
  51. package/skills/README.md +1 -1
  52. package/skills/gaia-patterns/SKILL.md +1 -1
  53. package/skills/gaia-patterns/reference.md +0 -1
  54. package/skills/gaia-release/SKILL.md +60 -24
  55. package/skills/gaia-release/reference.md +35 -11
  56. package/skills/git-conventions/SKILL.md +6 -2
  57. package/skills/orchestrator-present-approval/SKILL.md +10 -2
  58. package/skills/readme-writing/SKILL.md +1 -1
  59. package/skills/readme-writing/reference.md +0 -1
  60. package/tools/scan/ui.py +20 -4
  61. package/tools/scan/verify.py +3 -3
  62. package/tools/validation/README.md +15 -24
  63. package/commands/README.md +0 -64
  64. package/commands/gaia.md +0 -37
  65. package/commands/scan-project.md +0 -74
  66. package/config/crons-schema.md +0 -81
  67. package/config/git_standards.json +0 -72
  68. package/dist/gaia-ops/commands/gaia.md +0 -37
  69. package/dist/gaia-ops/config/crons-schema.md +0 -81
  70. package/dist/gaia-ops/config/git_standards.json +0 -72
  71. package/dist/gaia-ops/tools/agentic-loop/decide-status.py +0 -210
  72. package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +0 -106
  73. package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +0 -223
  74. package/git-hooks/commit-msg +0 -41
  75. package/scripts/migrations/v10_to_v11.sql +0 -170
  76. package/scripts/migrations/v10_to_v11_fresh.sql +0 -18
  77. package/scripts/migrations/v11_to_v12.sql +0 -195
  78. package/scripts/migrations/v11_to_v12_fresh.sql +0 -19
  79. package/scripts/migrations/v12_to_v13.sql +0 -48
  80. package/scripts/migrations/v12_to_v13_fresh.sql +0 -17
  81. package/scripts/migrations/v13_to_v14.sql +0 -44
  82. package/scripts/migrations/v13_to_v14_fresh.sql +0 -17
  83. package/scripts/migrations/v14_to_v15.sql +0 -71
  84. package/scripts/migrations/v14_to_v15_fresh.sql +0 -19
  85. package/scripts/migrations/v15_to_v16.sql +0 -57
  86. package/scripts/migrations/v15_to_v16_fresh.sql +0 -18
  87. package/scripts/migrations/v16_to_v17.sql +0 -51
  88. package/scripts/migrations/v16_to_v17_fresh.sql +0 -18
  89. package/scripts/migrations/v17_to_v18.sql +0 -66
  90. package/scripts/migrations/v17_to_v18_fresh.sql +0 -24
  91. package/scripts/migrations/v1_to_v2.sql +0 -97
  92. package/scripts/migrations/v2_to_v3.sql +0 -68
  93. package/scripts/migrations/v2_to_v3_merge.sql +0 -69
  94. package/scripts/migrations/v3_to_v4.sql +0 -67
  95. package/scripts/migrations/v3_to_v4_fresh.sql +0 -20
  96. package/scripts/migrations/v4_to_v5.sql +0 -55
  97. package/scripts/migrations/v4_to_v5_fresh.sql +0 -20
  98. package/scripts/migrations/v5_to_v6.sql +0 -48
  99. package/scripts/migrations/v5_to_v6_fresh.sql +0 -17
  100. package/scripts/migrations/v6_to_v7.sql +0 -26
  101. package/scripts/migrations/v6_to_v7_fresh.sql +0 -13
  102. package/scripts/migrations/v7_to_v8.sql +0 -44
  103. package/scripts/migrations/v7_to_v8_fresh.sql +0 -14
  104. package/scripts/migrations/v8_to_v9.sql +0 -87
  105. package/scripts/migrations/v8_to_v9_fresh.sql +0 -15
  106. package/scripts/migrations/v9_to_v10.sql +0 -109
  107. package/scripts/migrations/v9_to_v10_episodes_workspace.sql +0 -109
  108. package/scripts/migrations/v9_to_v10_fresh.sql +0 -18
  109. package/templates/README.md +0 -70
  110. package/templates/managed-settings.template.json +0 -43
  111. package/tools/agentic-loop/decide-status.py +0 -210
  112. package/tools/agentic-loop/parse-metric.py +0 -106
  113. package/tools/agentic-loop/record-iteration.py +0 -223
@@ -1,48 +0,0 @@
1
- -- Migration v12 -> v13 (gaia-scan-overhaul: workspace->group->repo model, AC-2)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v12 schema has the durable approvals / approval_events tables from the
6
- -- approval-model-redesign brief. v13 adds a `group_name` column to the
7
- -- `projects` table to support the workspace->group->repo hierarchy introduced
8
- -- by the gaia-scan-overhaul brief (AC-2).
9
- --
10
- -- Why `group_name` and not `group`
11
- -- ---------------------------------
12
- -- `group` is a reserved keyword in SQL. Using it as a column name requires
13
- -- quoting everywhere and produces subtle bugs in hand-written queries.
14
- -- `group_name` is the canonical column name for this feature.
15
- --
16
- -- Column semantics
17
- -- ----------------
18
- -- group_name TEXT (nullable)
19
- -- The optional organizational group or team this project belongs to within
20
- -- its workspace. For example, in a GitHub organization the group_name might
21
- -- be a team slug, a monorepo sub-directory, or any intermediate container
22
- -- between the workspace and the individual project (repo).
23
- --
24
- -- NULL = ungrouped (the default for all pre-existing rows after migration).
25
- -- The value is assigned by populate_project (T2.2 of the plan) using
26
- -- scanner-specific detection logic. This migration only adds the column;
27
- -- it does NOT back-fill existing rows.
28
- --
29
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
30
- -- A failure mid-flight rolls back to v12 state; the ledger row is NOT
31
- -- inserted, so the next bootstrap retry sees the same pending migration.
32
- -- Closes T1.1 (schema + writer plumbing) of brief gaia-scan-overhaul.
33
-
34
- -- ---------------------------------------------------------------------------
35
- -- Step 1: Add group_name column to projects
36
- -- ---------------------------------------------------------------------------
37
- ALTER TABLE projects ADD COLUMN group_name TEXT;
38
-
39
- -- ---------------------------------------------------------------------------
40
- -- Step 2: Bump schema_version to 13
41
- -- ---------------------------------------------------------------------------
42
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
43
- VALUES (13, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
44
- 'projects.group_name column (workspace->group->repo, AC-2)');
45
-
46
- -- Verification queries (run after applying):
47
- -- SELECT MAX(version) FROM schema_version; -- expect: 13
48
- -- PRAGMA table_info(projects); -- expect group_name column present
@@ -1,17 +0,0 @@
1
- -- Migration v12 -> v13 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v13 state (i.e. schema.sql already declares the group_name
5
- -- column on the projects table).
6
- --
7
- -- On a fresh install:
8
- -- - schema.sql creates projects with all columns including group_name -> no DDL needed
9
- --
10
- -- This variant is a no-op; it only exists so the bootstrap guard-probe branch
11
- -- can select it and stamp the ledger without applying DDL.
12
- --
13
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
14
- -- No DDL is executed; the COMMIT is harmless.
15
-
16
- -- No-op: fresh install already at v13 state (schema.sql created all objects).
17
- SELECT 1;
@@ -1,44 +0,0 @@
1
- -- Migration v13 -> v14 (gaia-scan-overhaul: projects.path column, findability)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v13 schema added `group_name` to the `projects` table (workspace->group->repo
6
- -- hierarchy). v14 adds a `path TEXT` column to the same table so that the
7
- -- scanner can persist the absolute on-disk path of each project, enabling
8
- -- name-based findability (project name -> path + workspace) without
9
- -- re-scanning or relying on external tooling.
10
- --
11
- -- Column semantics
12
- -- ----------------
13
- -- path TEXT (nullable)
14
- -- Absolute filesystem path to the project root directory on the machine
15
- -- where the scanner ran. For example: '/home/jorge/ws/me/gaia'.
16
- --
17
- -- NULL = path not yet recorded (the default for all pre-existing rows
18
- -- after migration; also the default for rows created before the scanner
19
- -- logic that assigns the value is deployed).
20
- -- The value is assigned by populate_project (T2.x of the plan) using
21
- -- the project_path argument already threaded through the scanner API.
22
- -- This migration only adds the column; it does NOT back-fill existing
23
- -- rows.
24
- --
25
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
26
- -- A failure mid-flight rolls back to v13 state; the ledger row is NOT
27
- -- inserted, so the next bootstrap retry sees the same pending migration.
28
- -- Closes T1.2 (schema + writer plumbing) of brief gaia-scan-overhaul.
29
-
30
- -- ---------------------------------------------------------------------------
31
- -- Step 1: Add path column to projects
32
- -- ---------------------------------------------------------------------------
33
- ALTER TABLE projects ADD COLUMN path TEXT;
34
-
35
- -- ---------------------------------------------------------------------------
36
- -- Step 2: Bump schema_version to 14
37
- -- ---------------------------------------------------------------------------
38
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
39
- VALUES (14, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
40
- 'projects.path column (findability: project -> path + workspace)');
41
-
42
- -- Verification queries (run after applying):
43
- -- SELECT MAX(version) FROM schema_version; -- expect: 14
44
- -- PRAGMA table_info(projects); -- expect path column present
@@ -1,17 +0,0 @@
1
- -- Migration v13 -> v14 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v14 state (i.e. schema.sql already declares the path column
5
- -- on the projects table).
6
- --
7
- -- On a fresh install:
8
- -- - schema.sql creates projects with all columns including path -> no DDL needed
9
- --
10
- -- This variant is a no-op; it only exists so the bootstrap guard-probe branch
11
- -- can select it and stamp the ledger without applying DDL.
12
- --
13
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
14
- -- No DDL is executed; the COMMIT is harmless.
15
-
16
- -- No-op: fresh install already at v14 state (schema.sql created all objects).
17
- SELECT 1;
@@ -1,71 +0,0 @@
1
- -- Migration v14 -> v15 (child-table FK column rename: repo -> project)
2
- --
3
- -- Background
4
- -- ----------
5
- -- Commit be9698f ("feat(substrate): rename projects->workspaces, repos->projects")
6
- -- renamed the substrate hierarchy. The OLD `repos` concept (git-bearing units)
7
- -- became `projects`, and the OLD `projects` container became `workspaces`.
8
- --
9
- -- schema.sql and the writer/populator code were updated to use the `project`
10
- -- column on the nine per-project child tables:
11
- -- apps, libraries, services, features, tf_modules, tf_live, releases,
12
- -- workloads, clusters_defined
13
- -- ...but NO migration was ever shipped to rename the live column. Because every
14
- -- child table is declared with `CREATE TABLE IF NOT EXISTS`, schema.sql silently
15
- -- no-ops on a DB that already has these tables, so existing installations (at
16
- -- v14) still carry the legacy column name `repo`. The writer/populator code,
17
- -- which already emits `project` in every INSERT / SELECT / ON CONFLICT /
18
- -- delete_missing path, then fails at runtime with "no such column: project" the
19
- -- first time `gaia scan` populates infra/app rows.
20
- --
21
- -- This was latent because scan_workspace_to_store had never run end-to-end via
22
- -- the CLI (it was only wired in T3.1), and the unit tests mock the writer or
23
- -- use fixtures with no infra/app content, so the column mismatch never executed.
24
- --
25
- -- Fix direction
26
- -- -------------
27
- -- `project` is the canonical name: it is what schema.sql declares, what every
28
- -- writer/populator SQL path emits, and what the writer's PK maps in
29
- -- delete_missing_in use. The live DB is the sole outlier. The lowest-blast-
30
- -- radius fix is therefore a forward migration that renames the legacy `repo`
31
- -- column to `project` on each of the nine child tables. No code change is
32
- -- required.
33
- --
34
- -- Mechanism
35
- -- ---------
36
- -- SQLite >= 3.25 supports `ALTER TABLE ... RENAME COLUMN`, which rewrites the
37
- -- stored DDL in place, automatically updating the column's appearance in the
38
- -- table's PRIMARY KEY and in its own FOREIGN KEY clause. The FTS5 mirror tables
39
- -- (apps_fts, services_fts) index text content columns (name, etc.), NOT the FK
40
- -- column, so they are unaffected. Verified on sqlite 3.45.x: PRAGMA
41
- -- foreign_key_check returns no rows after the rename and project-keyed INSERTs
42
- -- succeed.
43
- --
44
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A failure
45
- -- mid-flight rolls back to v14 state; the ledger row is NOT inserted, so the
46
- -- next bootstrap retry sees the same pending migration.
47
-
48
- -- ---------------------------------------------------------------------------
49
- -- Step 1: Rename repo -> project on each per-project child table
50
- -- ---------------------------------------------------------------------------
51
- ALTER TABLE apps RENAME COLUMN repo TO project;
52
- ALTER TABLE libraries RENAME COLUMN repo TO project;
53
- ALTER TABLE services RENAME COLUMN repo TO project;
54
- ALTER TABLE features RENAME COLUMN repo TO project;
55
- ALTER TABLE tf_modules RENAME COLUMN repo TO project;
56
- ALTER TABLE tf_live RENAME COLUMN repo TO project;
57
- ALTER TABLE releases RENAME COLUMN repo TO project;
58
- ALTER TABLE workloads RENAME COLUMN repo TO project;
59
- ALTER TABLE clusters_defined RENAME COLUMN repo TO project;
60
-
61
- -- ---------------------------------------------------------------------------
62
- -- Step 2: Bump schema_version to 15
63
- -- ---------------------------------------------------------------------------
64
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
65
- VALUES (15, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
66
- 'rename child-table FK column repo -> project (substrate rename catch-up)');
67
-
68
- -- Verification queries (run after applying):
69
- -- SELECT MAX(version) FROM schema_version; -- expect: 15
70
- -- PRAGMA table_info(apps); -- expect: project (not repo)
71
- -- PRAGMA foreign_key_check; -- expect: no rows
@@ -1,19 +0,0 @@
1
- -- Migration v14 -> v15 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v15 state -- i.e. the per-project child tables (apps, services,
5
- -- tf_modules, ...) already carry the `project` column because schema.sql
6
- -- declared them that way.
7
- --
8
- -- On a fresh install there is no legacy `repo` column to rename, so the
9
- -- RENAME COLUMN statements in v14_to_v15.sql would fail with "no such column:
10
- -- repo". This variant is a no-op; it exists only so the bootstrap guard-probe
11
- -- branch (Section 3c, case 15) can select it and stamp the ledger without
12
- -- attempting the rename.
13
- --
14
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
15
- -- No DDL is executed; the COMMIT is harmless.
16
-
17
- -- No-op: fresh install already at v15 state (schema.sql created child tables
18
- -- with the `project` column).
19
- SELECT 1;
@@ -1,57 +0,0 @@
1
- -- Migration v15 -> v16 (gaia-scan-overhaul: projects soft-delete columns)
2
- --
3
- -- Background
4
- -- ----------
5
- -- The prune step in scan_workspace_to_store currently issues hard DELETEs for
6
- -- projects that are no longer found on disk. Brief gaia-scan-overhaul replaces
7
- -- that with a soft-delete: projects are marked 'missing' instead of removed,
8
- -- so historical context (memory atoms, episodes, briefs keyed on that project)
9
- -- survives the scan cycle.
10
- --
11
- -- This migration adds two scanner-owned columns to the `projects` table:
12
- --
13
- -- status TEXT NOT NULL DEFAULT 'active'
14
- -- Values: 'active' | 'missing'.
15
- -- 'active' -- project was present on the last scan run.
16
- -- 'missing' -- project was NOT found on the most recent scan; kept as a
17
- -- tombstone so child-table data and historical context survive.
18
- -- Default 'active': existing rows (which were present at migration time)
19
- -- are classified as active. New rows inserted by the scanner also default
20
- -- to 'active' without requiring callers to supply the column.
21
- --
22
- -- missing_since TEXT (nullable)
23
- -- ISO8601 UTC timestamp of when status was first set to 'missing'.
24
- -- NULL when status='active'. The scanner sets this on the first cycle
25
- -- where it cannot find the project; subsequent cycles leave it unchanged
26
- -- (the timestamp records the FIRST disappearance, not the most recent).
27
- --
28
- -- Scope of this migration
29
- -- -----------------------
30
- -- ONLY the DDL changes. The prune logic (DELETE -> UPDATE status='missing') is
31
- -- implemented in the NEXT task (scan populator changes). This migration only
32
- -- ensures the columns exist and that the writer accepts them.
33
- --
34
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A failure
35
- -- mid-flight rolls back to v15 state; the ledger row is NOT inserted, so the
36
- -- next bootstrap retry sees the same pending migration.
37
-
38
- -- ---------------------------------------------------------------------------
39
- -- Step 1: Add status column to projects (NOT NULL DEFAULT 'active')
40
- -- ---------------------------------------------------------------------------
41
- ALTER TABLE projects ADD COLUMN status TEXT NOT NULL DEFAULT 'active';
42
-
43
- -- ---------------------------------------------------------------------------
44
- -- Step 2: Add missing_since column to projects (nullable)
45
- -- ---------------------------------------------------------------------------
46
- ALTER TABLE projects ADD COLUMN missing_since TEXT;
47
-
48
- -- ---------------------------------------------------------------------------
49
- -- Step 3: Bump schema_version to 16
50
- -- ---------------------------------------------------------------------------
51
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
52
- VALUES (16, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
53
- 'projects soft-delete: status + missing_since columns');
54
-
55
- -- Verification queries (run after applying):
56
- -- SELECT MAX(version) FROM schema_version; -- expect: 16
57
- -- PRAGMA table_info(projects); -- expect: status, missing_since columns present
@@ -1,18 +0,0 @@
1
- -- Migration v15 -> v16 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v16 state -- i.e. the `projects` table already carries the
5
- -- `status` and `missing_since` columns because schema.sql declared them that way.
6
- --
7
- -- On a fresh install there are no legacy rows to alter, so the ALTER TABLE
8
- -- statements in v15_to_v16.sql would fail with "duplicate column name".
9
- -- This variant is a no-op; it exists only so the bootstrap guard-probe branch
10
- -- (Section 3c, case 16) can select it and stamp the ledger without attempting
11
- -- the ALTER.
12
- --
13
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
14
- -- No DDL is executed; the COMMIT is harmless.
15
-
16
- -- No-op: fresh install already at v16 state (schema.sql created projects with
17
- -- status and missing_since columns).
18
- SELECT 1;
@@ -1,51 +0,0 @@
1
- -- Migration v16 -> v17 (DEMOTE case: workspaces soft-delete columns)
2
- --
3
- -- Background
4
- -- ----------
5
- -- v16 added soft-delete (status / missing_since) to the `projects` table. The
6
- -- multi-workspace DEMOTE test revealed the same gap one level up: when a
7
- -- workspace loses its Gaia install footprint (the user removes its `.claude/`,
8
- -- "demoting" it), the `workspaces` row had no way to record that. A re-scan of
9
- -- a demoted directory would persist the row and refresh `last_scan_at` as if it
10
- -- were still a live workspace.
11
- --
12
- -- This migration adds two scanner-owned columns to the `workspaces` table,
13
- -- mirroring the v16 projects soft-delete contract:
14
- --
15
- -- status TEXT NOT NULL DEFAULT 'active'
16
- -- Values: 'active' | 'missing'.
17
- -- 'active' -- the workspace carried a Gaia install on the last scan.
18
- -- 'missing' -- the workspace's install footprint disappeared (demoted);
19
- -- kept as a tombstone so its projects/history survive.
20
- -- Default 'active': existing rows (live workspaces at migration time) are
21
- -- classified active without requiring callers to supply the column.
22
- --
23
- -- missing_since TEXT (nullable)
24
- -- ISO8601 UTC timestamp of when status was first set to 'missing'.
25
- -- NULL when status='active'. Set on the first scan that finds the install
26
- -- gone; subsequent scans leave it unchanged (records the FIRST demote).
27
- --
28
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A failure
29
- -- mid-flight rolls back to v16 state; the ledger row is NOT inserted, so the
30
- -- next bootstrap retry sees the same pending migration.
31
-
32
- -- ---------------------------------------------------------------------------
33
- -- Step 1: Add status column to workspaces (NOT NULL DEFAULT 'active')
34
- -- ---------------------------------------------------------------------------
35
- ALTER TABLE workspaces ADD COLUMN status TEXT NOT NULL DEFAULT 'active';
36
-
37
- -- ---------------------------------------------------------------------------
38
- -- Step 2: Add missing_since column to workspaces (nullable)
39
- -- ---------------------------------------------------------------------------
40
- ALTER TABLE workspaces ADD COLUMN missing_since TEXT;
41
-
42
- -- ---------------------------------------------------------------------------
43
- -- Step 3: Bump schema_version to 17
44
- -- ---------------------------------------------------------------------------
45
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
46
- VALUES (17, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
47
- 'workspaces soft-delete: status + missing_since columns (DEMOTE)');
48
-
49
- -- Verification queries (run after applying):
50
- -- SELECT MAX(version) FROM schema_version; -- expect: 17
51
- -- PRAGMA table_info(workspaces); -- expect: status, missing_since columns present
@@ -1,18 +0,0 @@
1
- -- Migration v16 -> v17 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v17 state -- i.e. the `workspaces` table already carries the
5
- -- `status` and `missing_since` columns because schema.sql declared them that way.
6
- --
7
- -- On a fresh install there are no legacy rows to alter, so the ALTER TABLE
8
- -- statements in v16_to_v17.sql would fail with "duplicate column name".
9
- -- This variant is a no-op; it exists only so the bootstrap guard-probe branch
10
- -- (Section 3c, case 17) can select it and stamp the ledger without attempting
11
- -- the ALTER.
12
- --
13
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
14
- -- No DDL is executed; the COMMIT is harmless.
15
-
16
- -- No-op: fresh install already at v17 state (schema.sql created workspaces with
17
- -- status and missing_since columns).
18
- SELECT 1;
@@ -1,66 +0,0 @@
1
- -- Migration v17 -> v18 (stable project identity: collapse same repo across vantages)
2
- --
3
- -- Background
4
- -- ----------
5
- -- The `projects` table is keyed (workspace, name). The scanner derives `name`
6
- -- from the on-disk basename and `workspace` from the scan vantage's identity.
7
- -- The SAME physical repository scanned from two different roots -- e.g. once
8
- -- from the workspace root and once from inside the repo's own subdirectory
9
- -- (which resolves a different *workspace* identity) -- produced TWO distinct
10
- -- (workspace, name) rows: a duplicate of one physical project.
11
- --
12
- -- This migration adds a stable, vantage-independent project identity so the
13
- -- UPSERT can collapse those duplicates into one row. Identity is resolved by
14
- -- the scanner (tools/scan/store_populator.resolve_project_identity) in this
15
- -- order: git-common-dir (realpath) > normalized remote (host/owner/repo) >
16
- -- realpath of the project path.
17
- --
18
- -- Two additive, NON-DESTRUCTIVE changes:
19
- --
20
- -- 1. ALTER TABLE projects ADD COLUMN project_identity TEXT (nullable)
21
- -- Scanner-owned. NULL allowed for legacy/uninitialized rows so the column
22
- -- adds cleanly to an existing DB without backfill. A subsequent `gaia scan`
23
- -- populates it for every live project.
24
- --
25
- -- 2. CREATE UNIQUE INDEX idx_projects_identity ... WHERE project_identity IS NOT NULL
26
- -- PARTIAL unique index. Enforces one row per physical repo for rows that
27
- -- HAVE an identity, while exempting legacy NULL-identity rows from the
28
- -- uniqueness constraint (so multiple NULL rows can coexist until the next
29
- -- scan backfills them). This is the ON CONFLICT target the writer uses.
30
- --
31
- -- Backfill note
32
- -- -------------
33
- -- This migration does NOT backfill project_identity for existing rows -- it
34
- -- cannot derive git-common-dir from SQL alone, and the value is cheap to
35
- -- recompute on the next scan. Existing duplicate rows (if any) are left intact;
36
- -- the first scan after migration assigns identities and any genuine duplicate
37
- -- collapses on the following scan once both rows share an identity. Because the
38
- -- index is PARTIAL, the ADD COLUMN (all rows NULL) cannot fail on existing
39
- -- duplicates.
40
- --
41
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A failure
42
- -- mid-flight rolls back to v17 state; the ledger row is NOT inserted, so the
43
- -- next bootstrap retry sees the same pending migration.
44
-
45
- -- ---------------------------------------------------------------------------
46
- -- Step 1: Add project_identity column to projects (nullable, scanner-owned)
47
- -- ---------------------------------------------------------------------------
48
- ALTER TABLE projects ADD COLUMN project_identity TEXT;
49
-
50
- -- ---------------------------------------------------------------------------
51
- -- Step 2: Partial UNIQUE index that collapses the same physical repo to one row
52
- -- ---------------------------------------------------------------------------
53
- CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_identity
54
- ON projects(project_identity) WHERE project_identity IS NOT NULL;
55
-
56
- -- ---------------------------------------------------------------------------
57
- -- Step 3: Bump schema_version to 18
58
- -- ---------------------------------------------------------------------------
59
- INSERT OR IGNORE INTO schema_version (version, applied_at, description)
60
- VALUES (18, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
61
- 'projects stable identity: project_identity column + partial unique index (collapse same repo across vantages)');
62
-
63
- -- Verification queries (run after applying):
64
- -- SELECT MAX(version) FROM schema_version; -- expect: 18
65
- -- SELECT name FROM pragma_table_info('projects') WHERE name='project_identity'; -- expect: project_identity
66
- -- SELECT name FROM sqlite_master WHERE type='index' AND name='idx_projects_identity'; -- expect: idx_projects_identity
@@ -1,24 +0,0 @@
1
- -- Migration v17 -> v18 fresh-install variant
2
- --
3
- -- Used by bootstrap_database.sh when the live DB was created directly from
4
- -- schema.sql at v18 state -- i.e. the `projects` table already carries the
5
- -- `project_identity` column because schema.sql declared it that way.
6
- --
7
- -- On a fresh install there are no legacy rows to alter, so the ALTER TABLE
8
- -- statement in v17_to_v18.sql would fail with "duplicate column name".
9
- -- This variant therefore SKIPS the ALTER but still creates the partial unique
10
- -- index -- the index is intentionally NOT declared in schema.sql because
11
- -- referencing project_identity there would parse-fail when bootstrapping a
12
- -- legacy (pre-v18) DB whose CREATE TABLE IF NOT EXISTS short-circuits before
13
- -- the column exists. Creating it here (idempotent IF NOT EXISTS) is the only
14
- -- place the index lands on a fresh install. Same convention as
15
- -- idx_memory_class_status (scripts/migrations/v3_to_v4_fresh.sql).
16
- --
17
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
18
-
19
- -- Step 1 (skipped on fresh install): the project_identity column already exists.
20
-
21
- -- Step 2: create the partial unique index that collapses the same physical repo
22
- -- (same project_identity) to one row, exempting NULL-identity legacy rows.
23
- CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_identity
24
- ON projects(project_identity) WHERE project_identity IS NOT NULL;
@@ -1,97 +0,0 @@
1
- -- Migration v1 -> v2: widen memory.type CHECK constraint.
2
- --
3
- -- Background
4
- -- ----------
5
- -- v1 schema: memory.type CHECK (type IN ('project', 'user', 'feedback'))
6
- -- v2 schema: memory.type CHECK (type IN ('project', 'user', 'feedback', 'atom', 'decision', 'negative'))
7
- --
8
- -- The bug this migration fixes
9
- -- ----------------------------
10
- -- bootstrap_database.sh applies schema.sql with `CREATE TABLE IF NOT EXISTS`.
11
- -- On DBs created under v1 the CREATE short-circuits and the widened CHECK in
12
- -- schema.sql never lands -- yet the bootstrap historically stamped the
13
- -- schema_version ledger row for v2 unconditionally. Result: the ledger lied
14
- -- and writes of the new types ('atom', 'decision', 'negative') failed at
15
- -- runtime with CHECK constraint errors while `gaia doctor` reported OK.
16
- --
17
- -- Pattern: SQLite cannot ALTER a CHECK constraint. Canonical workaround:
18
- -- 1. Drop the FTS5 mirror triggers (avoid duplicate writes during copy).
19
- -- 2. Rename the old table out of the way.
20
- -- 3. Create the new table with the widened CHECK matching schema.sql.
21
- -- 4. Copy rows preserving rowid (memory_fts joins on rowid).
22
- -- 5. Drop the renamed old table.
23
- -- 6. Recreate the indexes on the new table.
24
- -- 7. Recreate the FTS5 mirror triggers verbatim.
25
- -- 8. Rebuild memory_fts from the new memory table.
26
- --
27
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A
28
- -- failure mid-flight rolls back to the v1 state and the ledger row is NOT
29
- -- inserted -- the next bootstrap retry will see the same pending migration.
30
- --
31
- -- Pre-conditions: caller has verified that the live memory.type CHECK does
32
- -- NOT yet include 'atom'. Applying this on an already-widened table would
33
- -- still succeed (the rename-create-copy ends in the same state) but the
34
- -- caller skips it to avoid unnecessary work.
35
-
36
- -- 1. Drop the FTS5 trigger trio. They mirror writes into memory_fts; we do
37
- -- not want them to fire during the bulk copy below. memory_fts itself is
38
- -- untouched here -- we will rebuild it after the copy completes.
39
- DROP TRIGGER IF EXISTS memory_ai;
40
- DROP TRIGGER IF EXISTS memory_ad;
41
- DROP TRIGGER IF EXISTS memory_au;
42
-
43
- -- 2. Rename the old table out of the way. The indexes (idx_memory_project,
44
- -- idx_memory_workspace, idx_memory_type) move with the table under their
45
- -- original names -- SQLite ALTER TABLE RENAME carries indexes along.
46
- ALTER TABLE memory RENAME TO memory_v1_legacy;
47
-
48
- -- 3. Create the new memory table with the widened CHECK constraint that
49
- -- matches schema.sql verbatim (6 allowed types).
50
- CREATE TABLE memory (
51
- workspace TEXT NOT NULL,
52
- name TEXT NOT NULL,
53
- type TEXT NOT NULL CHECK (type IN ('project', 'user', 'feedback', 'atom', 'decision', 'negative')),
54
- description TEXT,
55
- body TEXT NOT NULL,
56
- origin_session_id TEXT,
57
- updated_at TEXT,
58
- PRIMARY KEY (workspace, name),
59
- FOREIGN KEY (workspace) REFERENCES workspaces(name) ON DELETE CASCADE
60
- );
61
-
62
- -- 4. Copy all rows preserving rowid. This is critical: memory_fts joins on
63
- -- rowid, so changing them would invalidate the FTS5 index. We list rowid
64
- -- explicitly to bypass SQLite's default rowid allocation.
65
- INSERT INTO memory (rowid, workspace, name, type, description, body, origin_session_id, updated_at)
66
- SELECT rowid, workspace, name, type, description, body, origin_session_id, updated_at
67
- FROM memory_v1_legacy;
68
-
69
- -- 5. Drop the renamed old table. Its indexes go with it.
70
- DROP TABLE memory_v1_legacy;
71
-
72
- -- 6. Recreate the indexes on the new table. Same names as schema.sql.
73
- CREATE INDEX IF NOT EXISTS idx_memory_workspace ON memory(workspace);
74
- CREATE INDEX IF NOT EXISTS idx_memory_type ON memory(type);
75
-
76
- -- 7. Recreate the three FTS5 mirror triggers verbatim from schema.sql.
77
- CREATE TRIGGER memory_ai AFTER INSERT ON memory BEGIN
78
- INSERT INTO memory_fts(rowid, workspace, name, description, body)
79
- VALUES (new.rowid, new.workspace, new.name, new.description, new.body);
80
- END;
81
-
82
- CREATE TRIGGER memory_ad AFTER DELETE ON memory BEGIN
83
- INSERT INTO memory_fts(memory_fts, rowid, workspace, name, description, body)
84
- VALUES ('delete', old.rowid, old.workspace, old.name, old.description, old.body);
85
- END;
86
-
87
- CREATE TRIGGER memory_au AFTER UPDATE ON memory BEGIN
88
- INSERT INTO memory_fts(memory_fts, rowid, workspace, name, description, body)
89
- VALUES ('delete', old.rowid, old.workspace, old.name, old.description, old.body);
90
- INSERT INTO memory_fts(rowid, workspace, name, description, body)
91
- VALUES (new.rowid, new.workspace, new.name, new.description, new.body);
92
- END;
93
-
94
- -- 8. Rebuild memory_fts from the new memory table. FTS5's native reindex:
95
- -- clears the internal state and rescans the backing table. Cleaner than
96
- -- DELETE + INSERT loops.
97
- INSERT INTO memory_fts(memory_fts) VALUES('rebuild');
@@ -1,68 +0,0 @@
1
- -- Migration v2 -> v3 (rename path).
2
- --
3
- -- Background
4
- -- ----------
5
- -- v2 schema had:
6
- -- context_contracts (workspace, section_name, payload, metadata, updated_at)
7
- -- PK: (workspace, section_name)
8
- --
9
- -- v3 schema has:
10
- -- project_context_contracts (workspace, contract_name, payload, metadata, updated_at)
11
- -- PK: (workspace, contract_name)
12
- -- + new table agent_contract_permissions
13
- -- + new index idx_agent_contract_perms_agent
14
- --
15
- -- The rename of `context_contracts` -> `project_context_contracts` reflects
16
- -- its actual role: rows are project-context contracts, not permission grants.
17
- -- The column rename `section_name` -> `contract_name` aligns the vocabulary
18
- -- with the permission model introduced alongside it.
19
- --
20
- -- Three real-world entry states
21
- -- -----------------------------
22
- -- State 1 (only old): context_contracts exists, project_context_contracts does NOT.
23
- -- Typical of a clean v2 install upgrading for the first time.
24
- -- This script handles state 1 via ALTER TABLE RENAME.
25
- -- State 2 (only new): project_context_contracts exists, context_contracts does NOT,
26
- -- agent_contract_permissions exists. Nothing to do -- the guard
27
- -- probe in bootstrap_database.sh detects state 2 and stamps the
28
- -- ledger without invoking this script.
29
- -- State 3 (both): Both tables exist. Caused by a previous bootstrap where
30
- -- schema.sql under v3 was applied (CREATE TABLE IF NOT EXISTS
31
- -- created the new table) but the legacy context_contracts was
32
- -- never dropped. State 3 needs row migration + drop, handled
33
- -- by v2_to_v3_merge.sql -- not by this script.
34
- --
35
- -- bootstrap_database.sh selects state 1 vs 3 via the guard probe and runs the
36
- -- matching script. Each script is therefore single-purpose and atomic.
37
- --
38
- -- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A failure
39
- -- mid-flight rolls back to v2 state and the ledger row is NOT inserted, so the
40
- -- next bootstrap retry will see the same pending migration.
41
-
42
- -- 1. Rename the table.
43
- ALTER TABLE context_contracts RENAME TO project_context_contracts;
44
-
45
- -- 2. Rename the column.
46
- ALTER TABLE project_context_contracts RENAME COLUMN section_name TO contract_name;
47
-
48
- -- 3. Index on workspace -- name reflects the new table identity. The old
49
- -- index moved with the table on RENAME TO, but its name still references
50
- -- the legacy table. Drop + recreate keeps the index name consistent
51
- -- with the new table identity.
52
- DROP INDEX IF EXISTS idx_context_contracts_workspace;
53
- CREATE INDEX IF NOT EXISTS idx_project_context_contracts_workspace
54
- ON project_context_contracts(workspace);
55
-
56
- -- 4. New permissions table + its index. IF NOT EXISTS makes the script
57
- -- safe to re-run if a partial earlier attempt already created them.
58
- CREATE TABLE IF NOT EXISTS agent_contract_permissions (
59
- agent_name TEXT NOT NULL,
60
- contract_name TEXT NOT NULL,
61
- can_read INTEGER NOT NULL DEFAULT 0,
62
- can_write INTEGER NOT NULL DEFAULT 0,
63
- cloud_scope TEXT,
64
- PRIMARY KEY (agent_name, contract_name, cloud_scope)
65
- );
66
-
67
- CREATE INDEX IF NOT EXISTS idx_agent_contract_perms_agent
68
- ON agent_contract_permissions(agent_name);