@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +56 -0
- package/INSTALL.md +0 -2
- package/README.md +1 -6
- package/bin/README.md +0 -1
- package/bin/cli/_install_helpers.py +1 -1
- package/bin/cli/cleanup.py +0 -1
- package/bin/cli/doctor.py +1 -1
- package/bin/cli/memory.py +2 -0
- package/bin/cli/update.py +1 -1
- package/bin/pre-publish-validate.js +48 -5
- package/config/README.md +22 -44
- package/config/surface-routing.json +0 -1
- package/dist/gaia-ops/.claude-plugin/plugin.json +1 -1
- package/dist/gaia-ops/config/README.md +22 -44
- package/dist/gaia-ops/config/surface-routing.json +0 -1
- package/dist/gaia-ops/hooks/modules/agents/handoff_persister.py +2 -0
- package/dist/gaia-ops/hooks/modules/security/approval_grants.py +2 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +2 -0
- package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +90 -55
- package/dist/gaia-ops/skills/README.md +1 -1
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +1 -1
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +0 -1
- package/dist/gaia-ops/skills/gaia-release/SKILL.md +60 -24
- package/dist/gaia-ops/skills/gaia-release/reference.md +35 -11
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +6 -2
- package/dist/gaia-ops/skills/orchestrator-present-approval/SKILL.md +10 -2
- package/dist/gaia-ops/skills/readme-writing/SKILL.md +1 -1
- package/dist/gaia-ops/skills/readme-writing/reference.md +0 -1
- package/dist/gaia-ops/tools/scan/ui.py +20 -4
- package/dist/gaia-ops/tools/scan/verify.py +3 -3
- package/dist/gaia-ops/tools/validation/README.md +15 -24
- package/dist/gaia-security/.claude-plugin/plugin.json +1 -1
- package/dist/gaia-security/hooks/modules/agents/handoff_persister.py +2 -0
- package/dist/gaia-security/hooks/modules/security/approval_grants.py +2 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +2 -0
- package/dist/gaia-security/hooks/modules/validation/commit_validator.py +90 -55
- package/hooks/modules/agents/handoff_persister.py +2 -0
- package/hooks/modules/security/approval_grants.py +2 -0
- package/hooks/modules/tools/bash_validator.py +2 -0
- package/hooks/modules/validation/commit_validator.py +90 -55
- package/index.js +2 -12
- package/package.json +4 -6
- package/pyproject.toml +3 -3
- package/scripts/bootstrap_database.sh +88 -439
- package/scripts/check_schema_drift.py +208 -0
- package/scripts/migrations/README.md +78 -28
- package/scripts/migrations/schema.checksum +8 -0
- package/scripts/release-prepare.mjs +199 -0
- package/skills/README.md +1 -1
- package/skills/gaia-patterns/SKILL.md +1 -1
- package/skills/gaia-patterns/reference.md +0 -1
- package/skills/gaia-release/SKILL.md +60 -24
- package/skills/gaia-release/reference.md +35 -11
- package/skills/git-conventions/SKILL.md +6 -2
- package/skills/orchestrator-present-approval/SKILL.md +10 -2
- package/skills/readme-writing/SKILL.md +1 -1
- package/skills/readme-writing/reference.md +0 -1
- package/tools/scan/ui.py +20 -4
- package/tools/scan/verify.py +3 -3
- package/tools/validation/README.md +15 -24
- package/commands/README.md +0 -64
- package/commands/gaia.md +0 -37
- package/commands/scan-project.md +0 -74
- package/config/crons-schema.md +0 -81
- package/config/git_standards.json +0 -72
- package/dist/gaia-ops/commands/gaia.md +0 -37
- package/dist/gaia-ops/config/crons-schema.md +0 -81
- package/dist/gaia-ops/config/git_standards.json +0 -72
- package/dist/gaia-ops/tools/agentic-loop/decide-status.py +0 -210
- package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +0 -106
- package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +0 -223
- package/git-hooks/commit-msg +0 -41
- package/scripts/migrations/v10_to_v11.sql +0 -170
- package/scripts/migrations/v10_to_v11_fresh.sql +0 -18
- package/scripts/migrations/v11_to_v12.sql +0 -195
- package/scripts/migrations/v11_to_v12_fresh.sql +0 -19
- package/scripts/migrations/v12_to_v13.sql +0 -48
- package/scripts/migrations/v12_to_v13_fresh.sql +0 -17
- package/scripts/migrations/v13_to_v14.sql +0 -44
- package/scripts/migrations/v13_to_v14_fresh.sql +0 -17
- package/scripts/migrations/v14_to_v15.sql +0 -71
- package/scripts/migrations/v14_to_v15_fresh.sql +0 -19
- package/scripts/migrations/v15_to_v16.sql +0 -57
- package/scripts/migrations/v15_to_v16_fresh.sql +0 -18
- package/scripts/migrations/v16_to_v17.sql +0 -51
- package/scripts/migrations/v16_to_v17_fresh.sql +0 -18
- package/scripts/migrations/v17_to_v18.sql +0 -66
- package/scripts/migrations/v17_to_v18_fresh.sql +0 -24
- package/scripts/migrations/v1_to_v2.sql +0 -97
- package/scripts/migrations/v2_to_v3.sql +0 -68
- package/scripts/migrations/v2_to_v3_merge.sql +0 -69
- package/scripts/migrations/v3_to_v4.sql +0 -67
- package/scripts/migrations/v3_to_v4_fresh.sql +0 -20
- package/scripts/migrations/v4_to_v5.sql +0 -55
- package/scripts/migrations/v4_to_v5_fresh.sql +0 -20
- package/scripts/migrations/v5_to_v6.sql +0 -48
- package/scripts/migrations/v5_to_v6_fresh.sql +0 -17
- package/scripts/migrations/v6_to_v7.sql +0 -26
- package/scripts/migrations/v6_to_v7_fresh.sql +0 -13
- package/scripts/migrations/v7_to_v8.sql +0 -44
- package/scripts/migrations/v7_to_v8_fresh.sql +0 -14
- package/scripts/migrations/v8_to_v9.sql +0 -87
- package/scripts/migrations/v8_to_v9_fresh.sql +0 -15
- package/scripts/migrations/v9_to_v10.sql +0 -109
- package/scripts/migrations/v9_to_v10_episodes_workspace.sql +0 -109
- package/scripts/migrations/v9_to_v10_fresh.sql +0 -18
- package/templates/README.md +0 -70
- package/templates/managed-settings.template.json +0 -43
- package/tools/agentic-loop/decide-status.py +0 -210
- package/tools/agentic-loop/parse-metric.py +0 -106
- package/tools/agentic-loop/record-iteration.py +0 -223
|
@@ -149,48 +149,79 @@ sqlite3 "$GAIA_DB" <<'EOF'
|
|
|
149
149
|
DELETE FROM agent_permissions WHERE agent_name = 'gaia-operator';
|
|
150
150
|
EOF
|
|
151
151
|
|
|
152
|
-
# === Section 3b: Seed schema_version baseline (
|
|
152
|
+
# === Section 3b: Seed schema_version baseline (floor) ===
|
|
153
153
|
#
|
|
154
|
-
#
|
|
155
|
-
# v1
|
|
156
|
-
#
|
|
154
|
+
# Modelo de FLOOR (piso de schema), reemplaza al viejo "seed v1 + camina
|
|
155
|
+
# v1..v17". Gaia es una herramienta personal de un solo usuario: nadie
|
|
156
|
+
# actualiza una DB más vieja que la versión actual, y las instalaciones
|
|
157
|
+
# nuevas construyen el schema directamente desde schema.sql (que ya produce
|
|
158
|
+
# la forma del FLOOR). Por eso colapsamos la historia v1->v17 a un baseline.
|
|
157
159
|
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
160
|
+
# SCHEMA_FLOOR es la versión mínima soportada in-place. schema.sql produce
|
|
161
|
+
# exactamente esta forma. Reglas:
|
|
162
|
+
#
|
|
163
|
+
# - DB nueva (sin filas en schema_version): schema.sql ya creó el estado
|
|
164
|
+
# FLOOR, así que sellamos (version=SCHEMA_FLOOR) directamente. No se
|
|
165
|
+
# siembra v1 ni se camina la cadena.
|
|
166
|
+
# - DB en o por encima del FLOOR: no se hace nada aquí (Section 3c decide
|
|
167
|
+
# si hay migraciones forward pendientes hacia EXPECTED).
|
|
168
|
+
# - DB por debajo del FLOOR (1 <= version < FLOOR): NO soportada para
|
|
169
|
+
# upgrade in-place. Abortamos con un mensaje claro pidiendo recrear la DB.
|
|
163
170
|
#
|
|
164
171
|
# `gaia doctor` lee MAX(version) y lo compara contra EXPECTED_SCHEMA_VERSION
|
|
165
172
|
# baked in al CLI. Adicionalmente, check_schema_ddl_consistency compara el CHECK
|
|
166
173
|
# constraint vivo contra el de schema.sql para cazar drift de ledger.
|
|
174
|
+
SCHEMA_FLOOR=18
|
|
175
|
+
|
|
167
176
|
NOW_UTC="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
168
|
-
sqlite3 "$GAIA_DB"
|
|
177
|
+
EXISTING_VERSION="$(sqlite3 "$GAIA_DB" "SELECT COALESCE(MAX(version), 0) FROM schema_version;")"
|
|
178
|
+
|
|
179
|
+
if [ "$EXISTING_VERSION" -eq 0 ]; then
|
|
180
|
+
# Fresh install: schema.sql ya construyó el estado FLOOR. Sellamos el
|
|
181
|
+
# ledger directamente en el FLOOR. INSERT OR IGNORE mantiene idempotencia.
|
|
182
|
+
sqlite3 "$GAIA_DB" <<EOF
|
|
169
183
|
INSERT OR IGNORE INTO schema_version (version, applied_at, description)
|
|
170
|
-
VALUES (
|
|
184
|
+
VALUES (${SCHEMA_FLOOR}, '${NOW_UTC}', 'baseline floor: schema.sql at v${SCHEMA_FLOOR}');
|
|
171
185
|
EOF
|
|
172
|
-
echo "[bootstrap] schema_version baseline seeded (
|
|
186
|
+
echo "[bootstrap] schema_version baseline seeded at floor (v${SCHEMA_FLOOR})"
|
|
187
|
+
elif [ "$EXISTING_VERSION" -lt "$SCHEMA_FLOOR" ]; then
|
|
188
|
+
# DB por debajo del piso: ya no soportamos upgrade in-place desde la
|
|
189
|
+
# cadena histórica v1..v17. Fallamos claro (no en silencio).
|
|
190
|
+
echo "[bootstrap] ERROR: DB at schema_version=${EXISTING_VERSION} is below the supported floor v${SCHEMA_FLOOR}." >&2
|
|
191
|
+
echo "[bootstrap] In-place upgrade from pre-v${SCHEMA_FLOOR} databases is no longer supported." >&2
|
|
192
|
+
echo "[bootstrap] Recreate the DB: back up any data you need, delete ${GAIA_DB}, then re-run \`gaia install\`." >&2
|
|
193
|
+
exit 1
|
|
194
|
+
else
|
|
195
|
+
# DB en o por encima del piso: nada que sembrar aquí. Section 3c decide
|
|
196
|
+
# si hay migraciones forward pendientes hacia EXPECTED_SCHEMA_VERSION.
|
|
197
|
+
echo "[bootstrap] schema_version at v${EXISTING_VERSION} (>= floor v${SCHEMA_FLOOR}); no baseline seed needed"
|
|
198
|
+
fi
|
|
173
199
|
|
|
174
|
-
# === Section 3c: Apply pending
|
|
200
|
+
# === Section 3c: Apply pending forward migrations (floor+1 .. EXPECTED) ===
|
|
175
201
|
#
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# BEGIN/COMMIT con guard de pre-condición para soportar fresh installs donde
|
|
180
|
-
# schema.sql ya creó la tabla en estado target.
|
|
202
|
+
# Modelo FLOOR forward-only. La cadena histórica v1..v17 fue eliminada; el
|
|
203
|
+
# baseline es el FLOOR (Section 3b). Esta sección aplica SÓLO migraciones
|
|
204
|
+
# forward que se agreguen en el futuro, una por bump:
|
|
181
205
|
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
#
|
|
206
|
+
# scripts/migrations/v{N-1}_to_v{N}.sql (N > SCHEMA_FLOOR)
|
|
207
|
+
#
|
|
208
|
+
# Convención forward-only (ver scripts/migrations/README.md):
|
|
209
|
+
# - El baseline es la versión actual (FLOOR). schema.sql produce esa forma.
|
|
210
|
+
# - Cada bump futuro agrega EXACTAMENTE un v{N-1}_to_v{N}.sql y sube
|
|
211
|
+
# EXPECTED_SCHEMA_VERSION en doctor.py en el mismo commit.
|
|
212
|
+
# - Para una DB en el FLOOR, esa migración corre directo (la DB está en el
|
|
213
|
+
# estado source de la migración). No se necesitan variantes _fresh: un
|
|
214
|
+
# fresh install ya está en EXPECTED tras schema.sql, así que el loop no
|
|
215
|
+
# entra (CURRENT == EXPECTED). El guard-probe por-versión del modelo viejo
|
|
216
|
+
# desaparece junto con la cadena histórica.
|
|
217
|
+
#
|
|
218
|
+
# Cada migración corre en su propia transacción BEGIN/COMMIT. Si falla, abort
|
|
219
|
+
# -- el ledger NO avanza y el próximo bootstrap retry ve la misma pendiente.
|
|
190
220
|
#
|
|
191
221
|
# EXPECTED_SCHEMA_VERSION se lee dinámicamente de doctor.py para mantener una
|
|
192
222
|
# sola fuente de verdad. test_schema_version_lockstep garantiza que el número
|
|
193
|
-
# en doctor.py concuerda con las migraciones disponibles
|
|
223
|
+
# en doctor.py concuerda con las migraciones disponibles (== FLOOR cuando no
|
|
224
|
+
# hay migraciones forward todavía).
|
|
194
225
|
|
|
195
226
|
DOCTOR_PY="${SCRIPT_DIR}/../bin/cli/doctor.py"
|
|
196
227
|
if [ ! -f "$DOCTOR_PY" ]; then
|
|
@@ -215,6 +246,12 @@ echo "[bootstrap] schema_version: current=${CURRENT_VERSION}, expected=${EXPECTE
|
|
|
215
246
|
MIG_DIR="${SCRIPT_DIR}/migrations"
|
|
216
247
|
|
|
217
248
|
if [ "$CURRENT_VERSION" -lt "$EXPECTED_VERSION" ]; then
|
|
249
|
+
# Forward-only loop. Reaches here only when a FUTURE migration has been
|
|
250
|
+
# added (EXPECTED_SCHEMA_VERSION > FLOOR) and the live DB is behind it.
|
|
251
|
+
# On a fresh install the DB is already at EXPECTED (schema.sql produced the
|
|
252
|
+
# FLOOR == EXPECTED shape when no forward migrations exist), so this branch
|
|
253
|
+
# is skipped entirely. Any DB below the FLOOR was already rejected in
|
|
254
|
+
# Section 3b, so CURRENT_VERSION here is always >= FLOOR.
|
|
218
255
|
for N in $(seq $((CURRENT_VERSION + 1)) "$EXPECTED_VERSION"); do
|
|
219
256
|
PREV=$((N - 1))
|
|
220
257
|
MIG_FILE="${MIG_DIR}/v${PREV}_to_v${N}.sql"
|
|
@@ -222,424 +259,35 @@ if [ "$CURRENT_VERSION" -lt "$EXPECTED_VERSION" ]; then
|
|
|
222
259
|
if [ ! -f "$MIG_FILE" ]; then
|
|
223
260
|
echo "[bootstrap] ERROR: missing migration file ${MIG_FILE}" >&2
|
|
224
261
|
echo "[bootstrap] Cannot advance from v${PREV} to v${N}. The ledger will remain at v${CURRENT_VERSION}." >&2
|
|
262
|
+
echo "[bootstrap] When bumping EXPECTED_SCHEMA_VERSION to v${N}, add scripts/migrations/v${PREV}_to_v${N}.sql in the same commit." >&2
|
|
225
263
|
exit 1
|
|
226
264
|
fi
|
|
227
265
|
|
|
228
|
-
#
|
|
229
|
-
#
|
|
230
|
-
#
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
ALREADY_AT_TARGET=0
|
|
239
|
-
OVERRIDE_MIG_FILE=""
|
|
240
|
-
case "$N" in
|
|
241
|
-
2)
|
|
242
|
-
# v1 -> v2: widen memory.type CHECK. Target state contains 'atom'.
|
|
243
|
-
MEMORY_DDL="$(sqlite3 "$GAIA_DB" "SELECT sql FROM sqlite_master WHERE type='table' AND name='memory';")"
|
|
244
|
-
if [[ "$MEMORY_DDL" == *"'atom'"* ]]; then
|
|
245
|
-
ALREADY_AT_TARGET=1
|
|
246
|
-
fi
|
|
247
|
-
;;
|
|
248
|
-
3)
|
|
249
|
-
# v2 -> v3: rename context_contracts -> project_context_contracts
|
|
250
|
-
# and add agent_contract_permissions. Three entry states:
|
|
251
|
-
# state 1 (only old): rename via v2_to_v3.sql (the default file).
|
|
252
|
-
# state 2 (only new + perms exist): "at target", stamp ledger.
|
|
253
|
-
# state 3 (both tables): copy rows + drop old via v2_to_v3_merge.sql.
|
|
254
|
-
#
|
|
255
|
-
# The detection order is deliberate: we check for the legacy
|
|
256
|
-
# table first because its presence is the disqualifying signal
|
|
257
|
-
# for "already at target", regardless of what else exists.
|
|
258
|
-
HAS_OLD="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='context_contracts';")"
|
|
259
|
-
HAS_NEW="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='project_context_contracts';")"
|
|
260
|
-
HAS_PERMS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='agent_contract_permissions';")"
|
|
261
|
-
|
|
262
|
-
if [ -z "$HAS_OLD" ] && [ "$HAS_NEW" = "project_context_contracts" ] && [ "$HAS_PERMS" = "agent_contract_permissions" ]; then
|
|
263
|
-
# State 2: only new tables exist, fully migrated.
|
|
264
|
-
ALREADY_AT_TARGET=1
|
|
265
|
-
elif [ "$HAS_OLD" = "context_contracts" ] && [ "$HAS_NEW" = "project_context_contracts" ]; then
|
|
266
|
-
# State 3: both tables exist -- run the merge variant.
|
|
267
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v2_to_v3_merge.sql"
|
|
268
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
269
|
-
echo "[bootstrap] ERROR: state-3 merge script missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
270
|
-
exit 1
|
|
271
|
-
fi
|
|
272
|
-
fi
|
|
273
|
-
# Otherwise: state 1 (only old) -- fall through to default rename script.
|
|
274
|
-
;;
|
|
275
|
-
4)
|
|
276
|
-
# v3 -> v4: add memory.class + memory.status columns plus the
|
|
277
|
-
# memory_links table. Target state contains the `class` column
|
|
278
|
-
# on the memory table. We probe pragma_table_info; presence of
|
|
279
|
-
# 'class' is the fingerprint of v4 target state.
|
|
280
|
-
#
|
|
281
|
-
# Note: idx_memory_class_status is intentionally NOT declared
|
|
282
|
-
# in schema.sql -- it references columns that ALTER TABLE adds
|
|
283
|
-
# later, and CREATE INDEX in schema.sql would parse-fail on
|
|
284
|
-
# v3 DBs. On fresh-install (ALREADY_AT_TARGET=1) we run the
|
|
285
|
-
# migration script anyway because its statements are all
|
|
286
|
-
# idempotent (`IF NOT EXISTS`) and the only operation that is
|
|
287
|
-
# NOT a no-op on fresh install is the index creation.
|
|
288
|
-
MEMORY_HAS_CLASS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('memory') WHERE name='class';")"
|
|
289
|
-
MEMORY_LINKS_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='memory_links';")"
|
|
290
|
-
if [ "$MEMORY_HAS_CLASS" = "class" ] && [ "$MEMORY_LINKS_EXISTS" = "memory_links" ]; then
|
|
291
|
-
# Fresh install: schema.sql created the v4 columns and
|
|
292
|
-
# memory_links table. Run the migration anyway -- the
|
|
293
|
-
# ALTER TABLE statements need to be skipped because the
|
|
294
|
-
# columns already exist. We branch to a fresh-install
|
|
295
|
-
# variant that ONLY creates the index.
|
|
296
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v3_to_v4_fresh.sql"
|
|
297
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
298
|
-
echo "[bootstrap] ERROR: v3->v4 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
299
|
-
exit 1
|
|
300
|
-
fi
|
|
301
|
-
fi
|
|
302
|
-
# Otherwise: existing v3 DB -- fall through to default v3_to_v4.sql.
|
|
303
|
-
;;
|
|
304
|
-
5)
|
|
305
|
-
# v4 -> v5: add acceptance_criteria.status + milestones.status.
|
|
306
|
-
# Target state: acceptance_criteria has 'status' column.
|
|
307
|
-
AC_HAS_STATUS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('acceptance_criteria') WHERE name='status';")"
|
|
308
|
-
MS_HAS_STATUS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('milestones') WHERE name='status';")"
|
|
309
|
-
if [ "$AC_HAS_STATUS" = "status" ] && [ "$MS_HAS_STATUS" = "status" ]; then
|
|
310
|
-
# Fresh install: schema.sql already created v5 columns.
|
|
311
|
-
# Run the fresh-install variant that ONLY creates the indexes.
|
|
312
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v4_to_v5_fresh.sql"
|
|
313
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
314
|
-
echo "[bootstrap] ERROR: v4->v5 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
315
|
-
exit 1
|
|
316
|
-
fi
|
|
317
|
-
fi
|
|
318
|
-
# Otherwise: existing v4 DB -- fall through to default v4_to_v5.sql.
|
|
319
|
-
;;
|
|
320
|
-
6)
|
|
321
|
-
# v5 -> v6: add evidence table (three-tier storage model).
|
|
322
|
-
# Target state: evidence table exists.
|
|
323
|
-
EVIDENCE_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='evidence';")"
|
|
324
|
-
if [ "$EVIDENCE_EXISTS" = "evidence" ]; then
|
|
325
|
-
# Fresh install: schema.sql already created the evidence table.
|
|
326
|
-
# Run the fresh-install variant that ONLY creates the indexes.
|
|
327
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v5_to_v6_fresh.sql"
|
|
328
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
329
|
-
echo "[bootstrap] ERROR: v5->v6 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
330
|
-
exit 1
|
|
331
|
-
fi
|
|
332
|
-
fi
|
|
333
|
-
# Otherwise: existing v5 DB -- fall through to default v5_to_v6.sql.
|
|
334
|
-
;;
|
|
335
|
-
7)
|
|
336
|
-
# v6 -> v7: add workspaces.last_scan_at column (agent-contract-handoff M1).
|
|
337
|
-
# Target state: workspaces table has a 'last_scan_at' column.
|
|
338
|
-
WS_HAS_LAST_SCAN="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('workspaces') WHERE name='last_scan_at';")"
|
|
339
|
-
if [ "$WS_HAS_LAST_SCAN" = "last_scan_at" ]; then
|
|
340
|
-
# Fresh install: schema.sql already created the column.
|
|
341
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
342
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v6_to_v7_fresh.sql"
|
|
343
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
344
|
-
echo "[bootstrap] ERROR: v6->v7 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
345
|
-
exit 1
|
|
346
|
-
fi
|
|
347
|
-
fi
|
|
348
|
-
# Otherwise: existing v6 DB -- fall through to default v6_to_v7.sql.
|
|
349
|
-
;;
|
|
350
|
-
8)
|
|
351
|
-
# v7 -> v8: add approval_grants table (agent-contract-handoff M3).
|
|
352
|
-
# Target state: approval_grants table exists.
|
|
353
|
-
GRANTS_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='approval_grants';")"
|
|
354
|
-
if [ "$GRANTS_EXISTS" = "approval_grants" ]; then
|
|
355
|
-
# Fresh install: schema.sql already created the approval_grants table.
|
|
356
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
357
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v7_to_v8_fresh.sql"
|
|
358
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
359
|
-
echo "[bootstrap] ERROR: v7->v8 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
360
|
-
exit 1
|
|
361
|
-
fi
|
|
362
|
-
fi
|
|
363
|
-
# Otherwise: existing v7 DB -- fall through to default v7_to_v8.sql.
|
|
364
|
-
;;
|
|
365
|
-
9)
|
|
366
|
-
# v8 -> v9: add agent_contract_handoffs, agent_contract_handoff_approvals,
|
|
367
|
-
# project_context_contracts_history tables + trg_pcc_history trigger
|
|
368
|
-
# (agent-contract-handoff M4: handoff persistence).
|
|
369
|
-
# Target state: agent_contract_handoffs table exists.
|
|
370
|
-
HANDOFFS_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='agent_contract_handoffs';")"
|
|
371
|
-
if [ "$HANDOFFS_EXISTS" = "agent_contract_handoffs" ]; then
|
|
372
|
-
# Fresh install: schema.sql already created all v9 tables and trigger.
|
|
373
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
374
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v8_to_v9_fresh.sql"
|
|
375
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
376
|
-
echo "[bootstrap] ERROR: v8->v9 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
377
|
-
exit 1
|
|
378
|
-
fi
|
|
379
|
-
fi
|
|
380
|
-
# Otherwise: existing v8 DB -- fall through to default v8_to_v9.sql.
|
|
381
|
-
;;
|
|
382
|
-
10)
|
|
383
|
-
# v9 -> v10: add episodes.tier column + idx_episodes_tier + idx_episodes_tier_outcome
|
|
384
|
-
# + episode_anomalies table + its 3 indexes
|
|
385
|
-
# (episodic-workflow-to-db AC-3: migration apply).
|
|
386
|
-
#
|
|
387
|
-
# Target state fingerprint: episodes.tier column exists.
|
|
388
|
-
# We use PRAGMA table_info to check for the tier column.
|
|
389
|
-
# This is the correct fingerprint because:
|
|
390
|
-
# - Fresh install: schema.sql creates episodes WITH tier -> tier exists
|
|
391
|
-
# - Existing v9 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
392
|
-
# -> tier does NOT exist -> falls through to the full migration
|
|
393
|
-
# Note: episode_anomalies table is NOT a valid fingerprint because
|
|
394
|
-
# schema.sql creates it via CREATE TABLE IF NOT EXISTS even on existing DBs.
|
|
395
|
-
TIER_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('episodes') WHERE name='tier';")"
|
|
396
|
-
if [ "$TIER_EXISTS" = "tier" ]; then
|
|
397
|
-
# Fresh install: schema.sql already created episodes with tier column.
|
|
398
|
-
# Run the fresh-install variant (creates tier indexes) to stamp the ledger.
|
|
399
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v9_to_v10_fresh.sql"
|
|
400
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
401
|
-
echo "[bootstrap] ERROR: v9->v10 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
402
|
-
exit 1
|
|
403
|
-
fi
|
|
404
|
-
fi
|
|
405
|
-
# Otherwise: existing v9 DB -- fall through to default v9_to_v10.sql.
|
|
406
|
-
;;
|
|
407
|
-
11)
|
|
408
|
-
# v10 -> v11: memory.class NOT NULL + CHECK(anchor|thread|log)
|
|
409
|
-
# + trg_pcc_history trigger column fix (contract_key->contract_name,
|
|
410
|
-
# payload_json->payload). Closes ledger task #6.
|
|
411
|
-
#
|
|
412
|
-
# Target state fingerprint: memory.class column is NOT NULL.
|
|
413
|
-
# We query pragma_table_info and check the notnull flag (column 3 in
|
|
414
|
-
# the pragma output: 0=nullable, 1=NOT NULL). A fresh install creates
|
|
415
|
-
# memory with NOT NULL class -> notnull=1. An existing v10 DB has
|
|
416
|
-
# class as nullable -> notnull=0 -> falls through to the full migration.
|
|
417
|
-
# Correct fingerprint because:
|
|
418
|
-
# - Fresh install (schema.sql creates memory with NOT NULL class): notnull=1
|
|
419
|
-
# - Existing v10 DB (CREATE TABLE IF NOT EXISTS is a no-op): notnull=0
|
|
420
|
-
MEMORY_CLASS_NOTNULL="$(sqlite3 "$GAIA_DB" "SELECT \"notnull\" FROM pragma_table_info('memory') WHERE name='class';")"
|
|
421
|
-
if [ "$MEMORY_CLASS_NOTNULL" = "1" ]; then
|
|
422
|
-
# Fresh install: schema.sql already created memory with NOT NULL class.
|
|
423
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
424
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v10_to_v11_fresh.sql"
|
|
425
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
426
|
-
echo "[bootstrap] ERROR: v10->v11 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
427
|
-
exit 1
|
|
428
|
-
fi
|
|
429
|
-
fi
|
|
430
|
-
# Otherwise: existing v10 DB -- fall through to default v10_to_v11.sql.
|
|
431
|
-
;;
|
|
432
|
-
12)
|
|
433
|
-
# v11 -> v12: add approvals + approval_events tables + three hash-chain triggers
|
|
434
|
-
# (approval-model-redesign M1: user-in-loop, fingerprint-bound, hash-chained).
|
|
435
|
-
#
|
|
436
|
-
# Target state fingerprint: approvals table exists.
|
|
437
|
-
# We probe sqlite_master for the table name.
|
|
438
|
-
# This is the correct fingerprint because:
|
|
439
|
-
# - Fresh install: schema.sql creates approvals table -> it exists
|
|
440
|
-
# - Existing v11 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
441
|
-
# -> approvals does NOT exist -> falls through to the full migration
|
|
442
|
-
# Note: approval_events triggers require the gaia_sha256 scalar function
|
|
443
|
-
# to be registered on the connection before any INSERT fires them.
|
|
444
|
-
# bootstrap_database.sh uses sqlite3 CLI which does NOT register Python
|
|
445
|
-
# functions; the trigger DDL is stored but can only fire via gaia.store.
|
|
446
|
-
# The migration SQL itself only defines the DDL (no INSERTs into
|
|
447
|
-
# approval_events), so the migration applies cleanly via sqlite3 CLI.
|
|
448
|
-
APPROVALS_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='approvals';")"
|
|
449
|
-
if [ "$APPROVALS_EXISTS" = "approvals" ]; then
|
|
450
|
-
# Fresh install: schema.sql already created the approvals table.
|
|
451
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
452
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v11_to_v12_fresh.sql"
|
|
453
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
454
|
-
echo "[bootstrap] ERROR: v11->v12 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
455
|
-
exit 1
|
|
456
|
-
fi
|
|
457
|
-
fi
|
|
458
|
-
# Otherwise: existing v11 DB -- fall through to default v11_to_v12.sql.
|
|
459
|
-
;;
|
|
460
|
-
13)
|
|
461
|
-
# v12 -> v13: add group_name column to projects table
|
|
462
|
-
# (gaia-scan-overhaul: workspace->group->repo model, AC-2).
|
|
463
|
-
#
|
|
464
|
-
# Target state fingerprint: projects.group_name column exists.
|
|
465
|
-
# We probe pragma_table_info for the column name.
|
|
466
|
-
# This is the correct fingerprint because:
|
|
467
|
-
# - Fresh install: schema.sql creates projects WITH group_name -> it exists
|
|
468
|
-
# - Existing v12 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
469
|
-
# -> group_name does NOT exist -> falls through to the full migration
|
|
470
|
-
GROUP_NAME_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('projects') WHERE name='group_name';")"
|
|
471
|
-
if [ "$GROUP_NAME_EXISTS" = "group_name" ]; then
|
|
472
|
-
# Fresh install: schema.sql already created projects with group_name column.
|
|
473
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
474
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v12_to_v13_fresh.sql"
|
|
475
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
476
|
-
echo "[bootstrap] ERROR: v12->v13 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
477
|
-
exit 1
|
|
478
|
-
fi
|
|
479
|
-
fi
|
|
480
|
-
# Otherwise: existing v12 DB -- fall through to default v12_to_v13.sql.
|
|
481
|
-
;;
|
|
482
|
-
14)
|
|
483
|
-
# v13 -> v14: add path column to projects table
|
|
484
|
-
# (gaia-scan-overhaul: findability, project -> path + workspace).
|
|
485
|
-
#
|
|
486
|
-
# Target state fingerprint: projects.path column exists.
|
|
487
|
-
# We probe pragma_table_info for the column name.
|
|
488
|
-
# This is the correct fingerprint because:
|
|
489
|
-
# - Fresh install: schema.sql creates projects WITH path -> it exists
|
|
490
|
-
# - Existing v13 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
491
|
-
# -> path does NOT exist -> falls through to the full migration
|
|
492
|
-
PATH_EXISTS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('projects') WHERE name='path';")"
|
|
493
|
-
if [ "$PATH_EXISTS" = "path" ]; then
|
|
494
|
-
# Fresh install: schema.sql already created projects with path column.
|
|
495
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
496
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v13_to_v14_fresh.sql"
|
|
497
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
498
|
-
echo "[bootstrap] ERROR: v13->v14 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
499
|
-
exit 1
|
|
500
|
-
fi
|
|
501
|
-
fi
|
|
502
|
-
# Otherwise: existing v13 DB -- fall through to default v13_to_v14.sql.
|
|
503
|
-
;;
|
|
504
|
-
15)
|
|
505
|
-
# v14 -> v15: rename the per-project child-table FK column
|
|
506
|
-
# repo -> project on apps, libraries, services, features,
|
|
507
|
-
# tf_modules, tf_live, releases, workloads, clusters_defined
|
|
508
|
-
# (substrate rename catch-up; closes "no such column: project").
|
|
509
|
-
#
|
|
510
|
-
# Target state fingerprint: apps.project column exists.
|
|
511
|
-
# We probe pragma_table_info for the column name on `apps`
|
|
512
|
-
# (representative of all nine child tables, which are renamed
|
|
513
|
-
# together in the same migration).
|
|
514
|
-
# This is the correct fingerprint because:
|
|
515
|
-
# - Fresh install: schema.sql creates apps WITH `project` -> it exists
|
|
516
|
-
# - Existing v14 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
517
|
-
# so apps still has the legacy `repo` column -> `project` does
|
|
518
|
-
# NOT exist -> falls through to the full rename migration.
|
|
519
|
-
APPS_HAS_PROJECT="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('apps') WHERE name='project';")"
|
|
520
|
-
if [ "$APPS_HAS_PROJECT" = "project" ]; then
|
|
521
|
-
# Fresh install: schema.sql already created child tables with
|
|
522
|
-
# the `project` column. Run the fresh-install variant (no-op
|
|
523
|
-
# SELECT) to stamp the ledger without attempting the rename.
|
|
524
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v14_to_v15_fresh.sql"
|
|
525
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
526
|
-
echo "[bootstrap] ERROR: v14->v15 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
527
|
-
exit 1
|
|
528
|
-
fi
|
|
529
|
-
fi
|
|
530
|
-
# Otherwise: existing v14 DB -- fall through to default v14_to_v15.sql.
|
|
531
|
-
;;
|
|
532
|
-
16)
|
|
533
|
-
# v15 -> v16: add status + missing_since columns to projects table
|
|
534
|
-
# (gaia-scan-overhaul: soft-delete support for missing projects).
|
|
535
|
-
#
|
|
536
|
-
# Target state fingerprint: projects.status column exists.
|
|
537
|
-
# We probe pragma_table_info for the column name.
|
|
538
|
-
# This is the correct fingerprint because:
|
|
539
|
-
# - Fresh install: schema.sql creates projects WITH status -> it exists
|
|
540
|
-
# - Existing v15 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
541
|
-
# -> status does NOT exist -> falls through to the full migration
|
|
542
|
-
PROJECTS_HAS_STATUS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('projects') WHERE name='status';")"
|
|
543
|
-
if [ "$PROJECTS_HAS_STATUS" = "status" ]; then
|
|
544
|
-
# Fresh install: schema.sql already created projects with status column.
|
|
545
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
546
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v15_to_v16_fresh.sql"
|
|
547
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
548
|
-
echo "[bootstrap] ERROR: v15->v16 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
549
|
-
exit 1
|
|
550
|
-
fi
|
|
551
|
-
fi
|
|
552
|
-
# Otherwise: existing v15 DB -- fall through to default v15_to_v16.sql.
|
|
553
|
-
;;
|
|
554
|
-
17)
|
|
555
|
-
# v16 -> v17: add status + missing_since columns to workspaces
|
|
556
|
-
# table (DEMOTE case: soft-delete support for demoted workspaces
|
|
557
|
-
# whose Gaia install footprint disappeared).
|
|
558
|
-
#
|
|
559
|
-
# Target state fingerprint: workspaces.status column exists.
|
|
560
|
-
# We probe pragma_table_info for the column name.
|
|
561
|
-
# This is the correct fingerprint because:
|
|
562
|
-
# - Fresh install: schema.sql creates workspaces WITH status -> it exists
|
|
563
|
-
# - Existing v16 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
564
|
-
# -> status does NOT exist -> falls through to the full migration
|
|
565
|
-
WORKSPACES_HAS_STATUS="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('workspaces') WHERE name='status';")"
|
|
566
|
-
if [ "$WORKSPACES_HAS_STATUS" = "status" ]; then
|
|
567
|
-
# Fresh install: schema.sql already created workspaces with status column.
|
|
568
|
-
# Run the fresh-install variant (no-op SELECT) to stamp the ledger.
|
|
569
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v16_to_v17_fresh.sql"
|
|
570
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
571
|
-
echo "[bootstrap] ERROR: v16->v17 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
572
|
-
exit 1
|
|
573
|
-
fi
|
|
574
|
-
fi
|
|
575
|
-
# Otherwise: existing v16 DB -- fall through to default v16_to_v17.sql.
|
|
576
|
-
;;
|
|
577
|
-
18)
|
|
578
|
-
# v17 -> v18: add project_identity column + partial unique index
|
|
579
|
-
# to projects (stable, vantage-independent project identity that
|
|
580
|
-
# collapses the same physical repo scanned from different roots
|
|
581
|
-
# into one row).
|
|
582
|
-
#
|
|
583
|
-
# Target state fingerprint: projects.project_identity column exists.
|
|
584
|
-
# We probe pragma_table_info for the column name.
|
|
585
|
-
# This is the correct fingerprint because:
|
|
586
|
-
# - Fresh install: schema.sql creates projects WITH project_identity -> it exists
|
|
587
|
-
# - Existing v17 DB: schema.sql's CREATE TABLE IF NOT EXISTS is a no-op
|
|
588
|
-
# -> project_identity does NOT exist -> falls through to the full migration
|
|
589
|
-
PROJECTS_HAS_IDENTITY="$(sqlite3 "$GAIA_DB" "SELECT name FROM pragma_table_info('projects') WHERE name='project_identity';")"
|
|
590
|
-
if [ "$PROJECTS_HAS_IDENTITY" = "project_identity" ]; then
|
|
591
|
-
# Fresh install: schema.sql already created projects with the
|
|
592
|
-
# project_identity column. Run the fresh-install variant
|
|
593
|
-
# (no-op SELECT) to stamp the ledger.
|
|
594
|
-
OVERRIDE_MIG_FILE="${MIG_DIR}/v17_to_v18_fresh.sql"
|
|
595
|
-
if [ ! -f "$OVERRIDE_MIG_FILE" ]; then
|
|
596
|
-
echo "[bootstrap] ERROR: v17->v18 fresh-install variant missing at ${OVERRIDE_MIG_FILE}" >&2
|
|
597
|
-
exit 1
|
|
598
|
-
fi
|
|
599
|
-
fi
|
|
600
|
-
# Otherwise: existing v17 DB -- fall through to default v17_to_v18.sql.
|
|
601
|
-
;;
|
|
602
|
-
*)
|
|
603
|
-
# Future migrations: each new N must add a case here with a
|
|
604
|
-
# fingerprint of the post-migration state.
|
|
605
|
-
echo "[bootstrap] ERROR: no guard probe registered for v${PREV}->v${N}." >&2
|
|
606
|
-
echo "[bootstrap] Add a case to Section 3c when introducing migration v${N}." >&2
|
|
607
|
-
exit 1
|
|
608
|
-
;;
|
|
609
|
-
esac
|
|
610
|
-
|
|
611
|
-
# Resolve which file actually runs: per-state override or default.
|
|
612
|
-
EFFECTIVE_MIG_FILE="${OVERRIDE_MIG_FILE:-$MIG_FILE}"
|
|
613
|
-
|
|
614
|
-
if [ "$ALREADY_AT_TARGET" = "1" ]; then
|
|
615
|
-
echo "[bootstrap] migration v${PREV}->v${N}: live DDL already at target (fresh install), stamping ledger only"
|
|
616
|
-
sqlite3 "$GAIA_DB" <<EOF
|
|
617
|
-
INSERT OR IGNORE INTO schema_version (version, applied_at, description)
|
|
618
|
-
VALUES (${N}, '${NOW_UTC}', 'auto-stamped: schema.sql created table at v${N} state');
|
|
619
|
-
EOF
|
|
620
|
-
else
|
|
621
|
-
echo "[bootstrap] migration v${PREV}->v${N}: applying ${EFFECTIVE_MIG_FILE}"
|
|
622
|
-
# Wrap the migration in an explicit transaction. The migration SQL
|
|
623
|
-
# itself does NOT contain BEGIN/COMMIT so we control atomicity here.
|
|
624
|
-
# Errors abort the script via set -e + sqlite3 exit code.
|
|
625
|
-
MIG_SQL="$(cat "$EFFECTIVE_MIG_FILE")"
|
|
626
|
-
if ! sqlite3 "$GAIA_DB" <<EOF
|
|
266
|
+
# Forward-only: a DB at the FLOOR (or any version below N) is in the
|
|
267
|
+
# source state of this migration, so we apply it directly inside an
|
|
268
|
+
# explicit transaction. No per-version guard probe and no _fresh
|
|
269
|
+
# variant are needed -- the historical "schema.sql already created the
|
|
270
|
+
# target table" case only existed because the baseline was v1 and the
|
|
271
|
+
# whole chain was walked on every fresh install. Under the FLOOR model
|
|
272
|
+
# a fresh install is already at EXPECTED, so it never enters this loop.
|
|
273
|
+
echo "[bootstrap] migration v${PREV}->v${N}: applying ${MIG_FILE}"
|
|
274
|
+
MIG_SQL="$(cat "$MIG_FILE")"
|
|
275
|
+
if ! sqlite3 "$GAIA_DB" <<EOF
|
|
627
276
|
BEGIN;
|
|
628
277
|
${MIG_SQL}
|
|
629
278
|
COMMIT;
|
|
630
279
|
EOF
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
280
|
+
then
|
|
281
|
+
echo "[bootstrap] ERROR: migration v${PREV}->v${N} failed. Transaction rolled back." >&2
|
|
282
|
+
echo "[bootstrap] schema_version ledger remains at v${CURRENT_VERSION} -- not stamping v${N}." >&2
|
|
283
|
+
exit 1
|
|
284
|
+
fi
|
|
285
|
+
echo "[bootstrap] migration v${PREV}->v${N}: applied successfully"
|
|
286
|
+
MIG_DESC="applied migration $(basename "$MIG_FILE")"
|
|
287
|
+
sqlite3 "$GAIA_DB" <<EOF
|
|
639
288
|
INSERT OR IGNORE INTO schema_version (version, applied_at, description)
|
|
640
289
|
VALUES (${N}, '${NOW_UTC}', '${MIG_DESC}');
|
|
641
290
|
EOF
|
|
642
|
-
fi
|
|
643
291
|
done
|
|
644
292
|
else
|
|
645
293
|
echo "[bootstrap] schema_version up-to-date (no migrations pending)"
|
|
@@ -831,12 +479,13 @@ else
|
|
|
831
479
|
fi
|
|
832
480
|
|
|
833
481
|
# Check 5: schema_version. La tabla se crea en schema.sql y la Section 3b
|
|
834
|
-
#
|
|
482
|
+
# sella la fila baseline en el FLOOR (v${SCHEMA_FLOOR}). Verificamos que
|
|
483
|
+
# MAX(version) >= FLOOR -- por debajo del piso ya habríamos abortado en 3b.
|
|
835
484
|
SCHEMA_VER="$(sqlite3 "$GAIA_DB" "SELECT COALESCE(MAX(version), 0) FROM schema_version;")"
|
|
836
|
-
if [ "$SCHEMA_VER" -ge
|
|
837
|
-
echo "[bootstrap] check: schema_version >=
|
|
485
|
+
if [ "$SCHEMA_VER" -ge "$SCHEMA_FLOOR" ]; then
|
|
486
|
+
echo "[bootstrap] check: schema_version >= floor v${SCHEMA_FLOOR} (got ${SCHEMA_VER}) -- PASS"
|
|
838
487
|
else
|
|
839
|
-
echo "[bootstrap] check: schema_version >=
|
|
488
|
+
echo "[bootstrap] check: schema_version >= floor v${SCHEMA_FLOOR} (got ${SCHEMA_VER}) -- FAIL"
|
|
840
489
|
ALL_OK=0
|
|
841
490
|
fi
|
|
842
491
|
|