@jaguilar87/gaia 5.0.4 → 5.0.6
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 +65 -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 +2 -2
- 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
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
-- Migration v2 -> v3 (merge path).
|
|
2
|
-
--
|
|
3
|
-
-- Runs when the guard probe in bootstrap_database.sh detects "state 3" --
|
|
4
|
-
-- both `context_contracts` (legacy v2 table) AND `project_context_contracts`
|
|
5
|
-
-- (new v3 table) exist. This happens when an earlier bootstrap under v3
|
|
6
|
-
-- code applied schema.sql (which created the new table with IF NOT EXISTS)
|
|
7
|
-
-- but the old table was never dropped because schema.sql no longer declares
|
|
8
|
-
-- it and IF NOT EXISTS only creates -- it never drops.
|
|
9
|
-
--
|
|
10
|
-
-- See v2_to_v3.sql for the rename path (state 1) and for the full discussion
|
|
11
|
-
-- of the three entry states.
|
|
12
|
-
--
|
|
13
|
-
-- Strategy
|
|
14
|
-
-- --------
|
|
15
|
-
-- The new table is created in v3 shape (column `contract_name`), the old
|
|
16
|
-
-- table is in v2 shape (column `section_name`). The two columns are
|
|
17
|
-
-- semantically identical, so we copy rows with column aliasing:
|
|
18
|
-
--
|
|
19
|
-
-- INSERT INTO project_context_contracts (workspace, contract_name, ...)
|
|
20
|
-
-- SELECT workspace, section_name, ...
|
|
21
|
-
-- FROM context_contracts
|
|
22
|
-
-- WHERE (workspace, section_name) NOT IN (
|
|
23
|
-
-- SELECT workspace, contract_name FROM project_context_contracts
|
|
24
|
-
-- );
|
|
25
|
-
--
|
|
26
|
-
-- The NOT IN guard makes the copy idempotent: rows that were already
|
|
27
|
-
-- migrated by a prior partial run are skipped instead of duplicating PK
|
|
28
|
-
-- conflicts. Once the copy is complete and verified, the legacy table is
|
|
29
|
-
-- dropped along with its index.
|
|
30
|
-
--
|
|
31
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. If
|
|
32
|
-
-- the copy or the drop fails, the transaction rolls back, the ledger is
|
|
33
|
-
-- NOT stamped, and the next bootstrap retry observes state 3 again.
|
|
34
|
-
|
|
35
|
-
-- 1. Copy rows from the legacy table into the new one, skipping any whose
|
|
36
|
-
-- primary key already exists in the new table.
|
|
37
|
-
INSERT INTO project_context_contracts (workspace, contract_name, payload, metadata, updated_at)
|
|
38
|
-
SELECT workspace, section_name, payload, metadata, updated_at
|
|
39
|
-
FROM context_contracts
|
|
40
|
-
WHERE (workspace, section_name) NOT IN (
|
|
41
|
-
SELECT workspace, contract_name FROM project_context_contracts
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
-- 2. Drop the legacy index explicitly. SQLite drops indexes with their
|
|
45
|
-
-- table on DROP TABLE, but being explicit catches the case where the
|
|
46
|
-
-- index was created standalone or renamed without us noticing.
|
|
47
|
-
DROP INDEX IF EXISTS idx_context_contracts_workspace;
|
|
48
|
-
|
|
49
|
-
-- 3. Drop the legacy table. Its rows have already been copied above.
|
|
50
|
-
DROP TABLE context_contracts;
|
|
51
|
-
|
|
52
|
-
-- 4. Ensure the new index exists with the canonical name (in case an
|
|
53
|
-
-- earlier partial run created the table but not its index).
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_project_context_contracts_workspace
|
|
55
|
-
ON project_context_contracts(workspace);
|
|
56
|
-
|
|
57
|
-
-- 5. Permissions table + index. IF NOT EXISTS makes this safe whether
|
|
58
|
-
-- schema.sql already created them in a previous bootstrap or not.
|
|
59
|
-
CREATE TABLE IF NOT EXISTS agent_contract_permissions (
|
|
60
|
-
agent_name TEXT NOT NULL,
|
|
61
|
-
contract_name TEXT NOT NULL,
|
|
62
|
-
can_read INTEGER NOT NULL DEFAULT 0,
|
|
63
|
-
can_write INTEGER NOT NULL DEFAULT 0,
|
|
64
|
-
cloud_scope TEXT,
|
|
65
|
-
PRIMARY KEY (agent_name, contract_name, cloud_scope)
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
CREATE INDEX IF NOT EXISTS idx_agent_contract_perms_agent
|
|
69
|
-
ON agent_contract_permissions(agent_name);
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
-- Migration v3 -> v4 (memory model: class + status + memory_links).
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v3 schema had:
|
|
6
|
-
-- memory(workspace, name, type, description, body, origin_session_id, updated_at)
|
|
7
|
-
-- PK: (workspace, name)
|
|
8
|
-
-- type CHECK constraint: ('project','user','feedback','atom','decision','negative')
|
|
9
|
-
--
|
|
10
|
-
-- v4 schema adds two ortogonal axes to the memory model:
|
|
11
|
-
-- * class -- semantic role (anchor | thread | log), nullable for legacy rows.
|
|
12
|
-
-- * status -- lifecycle for class=thread (open | carry_forward | graduated | closed).
|
|
13
|
-
--
|
|
14
|
-
-- Plus a new table:
|
|
15
|
-
-- memory_links(workspace, src_name, dst_name, kind, created_at)
|
|
16
|
-
-- PK: (workspace, src_name, dst_name, kind)
|
|
17
|
-
-- kind CHECK: ('relates_to','supersedes','derived_from','graduated_to')
|
|
18
|
-
--
|
|
19
|
-
-- Design decision: NO CHECK constraint on memory.class / memory.status
|
|
20
|
-
-- ---------------------------------------------------------------------
|
|
21
|
-
-- SQLite's ALTER TABLE ADD COLUMN cannot attach a CHECK that depends on
|
|
22
|
-
-- the new column's enum values. The standard workaround is a full table
|
|
23
|
-
-- rebuild (CREATE new, INSERT SELECT, DROP old, RENAME), which would:
|
|
24
|
-
-- 1. Force re-creation of memory_fts triggers (drift risk on live DBs).
|
|
25
|
-
-- 2. Move all existing memory rows through a copy step, complicating the
|
|
26
|
-
-- AC-2 contract that "the 36 me-workspace rows survive intact" with
|
|
27
|
-
-- byte-identical bodies.
|
|
28
|
-
-- 3. Add complexity disproportionate to the gain -- the writer layer
|
|
29
|
-
-- validates the enum on every upsert in T3 anyway.
|
|
30
|
-
--
|
|
31
|
-
-- Therefore: schema declares class/status as plain TEXT nullable columns.
|
|
32
|
-
-- Enum enforcement is the writer's job (gaia/store/writer.py, T3).
|
|
33
|
-
-- memory_links.kind keeps its CHECK because it is a brand-new table with
|
|
34
|
-
-- no rebuild cost.
|
|
35
|
-
--
|
|
36
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT. A
|
|
37
|
-
-- failure mid-flight rolls back to v3 state and the ledger row is NOT
|
|
38
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
39
|
-
|
|
40
|
-
-- 1. Add the two nullable columns to memory. Existing rows get NULL,
|
|
41
|
-
-- which is the documented "legacy row" state and is what T8/T9 will
|
|
42
|
-
-- reclassify interactively.
|
|
43
|
-
ALTER TABLE memory ADD COLUMN class TEXT;
|
|
44
|
-
ALTER TABLE memory ADD COLUMN status TEXT;
|
|
45
|
-
|
|
46
|
-
-- 2. Index on (workspace, class, status) -- supports the injector path
|
|
47
|
-
-- that picks class=thread/status=carry_forward first.
|
|
48
|
-
CREATE INDEX IF NOT EXISTS idx_memory_class_status
|
|
49
|
-
ON memory(workspace, class, status);
|
|
50
|
-
|
|
51
|
-
-- 3. New table memory_links + indexes. IF NOT EXISTS makes the script
|
|
52
|
-
-- idempotent if a partial earlier attempt already created them.
|
|
53
|
-
CREATE TABLE IF NOT EXISTS memory_links (
|
|
54
|
-
workspace TEXT NOT NULL,
|
|
55
|
-
src_name TEXT NOT NULL,
|
|
56
|
-
dst_name TEXT NOT NULL,
|
|
57
|
-
kind TEXT NOT NULL CHECK (kind IN ('relates_to', 'supersedes', 'derived_from', 'graduated_to')),
|
|
58
|
-
created_at TEXT,
|
|
59
|
-
PRIMARY KEY (workspace, src_name, dst_name, kind),
|
|
60
|
-
FOREIGN KEY (workspace) REFERENCES workspaces(name) ON DELETE CASCADE
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
CREATE INDEX IF NOT EXISTS memory_links_src
|
|
64
|
-
ON memory_links(workspace, src_name);
|
|
65
|
-
|
|
66
|
-
CREATE INDEX IF NOT EXISTS idx_memory_links_dst_kind
|
|
67
|
-
ON memory_links(workspace, dst_name, kind);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
-- v3 -> v4 fresh-install variant.
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh Section 3c case 4 when the live DDL is
|
|
4
|
-
-- already at the v4 target state (memory.class column present, memory_links
|
|
5
|
-
-- table present). This happens on a clean install where schema.sql already
|
|
6
|
-
-- created the v4 column layout and the memory_links table.
|
|
7
|
-
--
|
|
8
|
-
-- The default v3_to_v4.sql cannot run here because ALTER TABLE ADD COLUMN
|
|
9
|
-
-- fails when the column already exists. This variant carries only the DDL
|
|
10
|
-
-- that schema.sql cannot declare safely:
|
|
11
|
-
-- * idx_memory_class_status -- references columns added at ALTER time,
|
|
12
|
-
-- so schema.sql cannot pre-declare it (the replay on v3 DBs would parse-
|
|
13
|
-
-- fail before the migration ran).
|
|
14
|
-
--
|
|
15
|
-
-- Everything else (memory_links table, memory_links indexes) is declared in
|
|
16
|
-
-- schema.sql and is therefore already present on a fresh install. CREATE
|
|
17
|
-
-- INDEX IF NOT EXISTS makes this script safe to re-run.
|
|
18
|
-
|
|
19
|
-
CREATE INDEX IF NOT EXISTS idx_memory_class_status
|
|
20
|
-
ON memory(workspace, class, status);
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
-- Migration v4 -> v5 (state-machine completion: status columns on AC + milestones).
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v4 schema has:
|
|
6
|
-
-- acceptance_criteria(id, brief_id, ac_id, description, evidence_type,
|
|
7
|
-
-- evidence_shape, artifact_path)
|
|
8
|
-
-- milestones(id, brief_id, order_num, name, description)
|
|
9
|
-
--
|
|
10
|
-
-- v5 schema adds a status lifecycle column to both tables:
|
|
11
|
-
-- * acceptance_criteria.status -- lifecycle (pending | done | blocked)
|
|
12
|
-
-- * milestones.status -- lifecycle (pending | done | blocked)
|
|
13
|
-
--
|
|
14
|
-
-- Design decision: CHECK constraint inline on ADD COLUMN
|
|
15
|
-
-- -------------------------------------------------------
|
|
16
|
-
-- SQLite >= 3.37 supports ADD COLUMN with NOT NULL + DEFAULT + CHECK in a
|
|
17
|
-
-- single statement without a full table rebuild. The bootstrap environment
|
|
18
|
-
-- is confirmed at SQLite 3.45.1, so this is safe.
|
|
19
|
-
--
|
|
20
|
-
-- The enum values are intentionally small: pending (default), done (AC
|
|
21
|
-
-- satisfied / milestone reached), blocked (cannot progress, needs action).
|
|
22
|
-
-- They mirror the task lifecycle (pending|done|skipped) but substitute
|
|
23
|
-
-- 'blocked' for 'skipped' to distinguish an actively-stuck entity from one
|
|
24
|
-
-- that was explicitly bypassed.
|
|
25
|
-
--
|
|
26
|
-
-- D2 (backfill): explicit UPDATE after ALTER ensures pre-existing rows
|
|
27
|
-
-- carry 'pending'. The NOT NULL DEFAULT 'pending' covers new rows; the
|
|
28
|
-
-- UPDATE covers rows inserted before this migration.
|
|
29
|
-
--
|
|
30
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
31
|
-
-- A failure mid-flight rolls back to v4 state and the ledger row is NOT
|
|
32
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
33
|
-
|
|
34
|
-
-- 1. Add status column to acceptance_criteria.
|
|
35
|
-
ALTER TABLE acceptance_criteria
|
|
36
|
-
ADD COLUMN status TEXT NOT NULL DEFAULT 'pending'
|
|
37
|
-
CHECK (status IN ('pending', 'done', 'blocked'));
|
|
38
|
-
|
|
39
|
-
-- 2. Backfill existing AC rows (D2: explicit UPDATE, all rows -> 'pending').
|
|
40
|
-
UPDATE acceptance_criteria SET status = 'pending' WHERE status IS NULL;
|
|
41
|
-
|
|
42
|
-
-- 3. Add status column to milestones.
|
|
43
|
-
ALTER TABLE milestones
|
|
44
|
-
ADD COLUMN status TEXT NOT NULL DEFAULT 'pending'
|
|
45
|
-
CHECK (status IN ('pending', 'done', 'blocked'));
|
|
46
|
-
|
|
47
|
-
-- 4. Backfill existing milestone rows (D2).
|
|
48
|
-
UPDATE milestones SET status = 'pending' WHERE status IS NULL;
|
|
49
|
-
|
|
50
|
-
-- 5. Indexes to support brief-scoped status queries efficiently.
|
|
51
|
-
CREATE INDEX IF NOT EXISTS idx_ac_brief_status
|
|
52
|
-
ON acceptance_criteria(brief_id, status);
|
|
53
|
-
|
|
54
|
-
CREATE INDEX IF NOT EXISTS idx_milestones_brief_status
|
|
55
|
-
ON milestones(brief_id, status);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
-- v4 -> v5 fresh-install variant.
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh Section 3c case 5 when the live DDL is
|
|
4
|
-
-- already at the v5 target state (acceptance_criteria.status column present,
|
|
5
|
-
-- milestones.status column present). This happens on a clean install where
|
|
6
|
-
-- schema.sql already created the v5 column layout.
|
|
7
|
-
--
|
|
8
|
-
-- The default v4_to_v5.sql cannot run here because ALTER TABLE ADD COLUMN
|
|
9
|
-
-- fails when the column already exists. This variant carries only the DDL
|
|
10
|
-
-- that schema.sql cannot declare safely:
|
|
11
|
-
-- * idx_ac_brief_status -- index on acceptance_criteria(brief_id, status)
|
|
12
|
-
-- * idx_milestones_brief_status -- index on milestones(brief_id, status)
|
|
13
|
-
--
|
|
14
|
-
-- Both indexes are CREATE INDEX IF NOT EXISTS, making this script safe to re-run.
|
|
15
|
-
|
|
16
|
-
CREATE INDEX IF NOT EXISTS idx_ac_brief_status
|
|
17
|
-
ON acceptance_criteria(brief_id, status);
|
|
18
|
-
|
|
19
|
-
CREATE INDEX IF NOT EXISTS idx_milestones_brief_status
|
|
20
|
-
ON milestones(brief_id, status);
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
-- Migration v5 -> v6 (evidence three-tier storage: dedicated evidence table).
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v5 schema has:
|
|
6
|
-
-- acceptance_criteria(id, brief_id, ac_id, description, evidence_type,
|
|
7
|
-
-- evidence_shape, artifact_path, status)
|
|
8
|
-
-- milestones(id, brief_id, order_num, name, description, status)
|
|
9
|
-
--
|
|
10
|
-
-- v6 schema adds the evidence table for structured per-AC evidence storage.
|
|
11
|
-
-- Each row is one evidence artifact tied to a brief_id + ac_id pair.
|
|
12
|
-
-- Two storage modes:
|
|
13
|
-
-- inline: text IS NOT NULL, artifact_path IS NULL (payload <= 4096 bytes)
|
|
14
|
-
-- blob: text IS NULL, artifact_path IS NOT NULL (payload on filesystem)
|
|
15
|
-
--
|
|
16
|
-
-- Design decision: independent migration version
|
|
17
|
-
-- ------------------------------------------------
|
|
18
|
-
-- Evidence is an independent feature (Plan B). Extending v4_to_v5 with this
|
|
19
|
-
-- DDL would have conflated two unrelated concerns in one migration version.
|
|
20
|
-
-- The override decision (D4 of Plan A) establishes that each independent
|
|
21
|
-
-- feature gets its own migration version -- evidence belongs in v6.
|
|
22
|
-
--
|
|
23
|
-
-- brief_id FK CASCADE ensures cleanup when a brief is deleted.
|
|
24
|
-
-- type CHECK enforces the evidence taxonomy at the DB layer (new table,
|
|
25
|
-
-- no rebuild penalty unlike the memory.class situation).
|
|
26
|
-
--
|
|
27
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
28
|
-
-- A failure mid-flight rolls back to v5 state and the ledger row is NOT
|
|
29
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
30
|
-
|
|
31
|
-
-- 1. Create the evidence table.
|
|
32
|
-
CREATE TABLE IF NOT EXISTS evidence (
|
|
33
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
|
-
brief_id INTEGER NOT NULL,
|
|
35
|
-
ac_id TEXT NOT NULL,
|
|
36
|
-
task_id TEXT,
|
|
37
|
-
type TEXT NOT NULL CHECK (type IN ('text', 'file', 'command_output', 'url', 'screenshot')),
|
|
38
|
-
text TEXT,
|
|
39
|
-
artifact_path TEXT,
|
|
40
|
-
size_bytes INTEGER,
|
|
41
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
42
|
-
created_by_agent TEXT,
|
|
43
|
-
FOREIGN KEY (brief_id) REFERENCES briefs(id) ON DELETE CASCADE
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
-- 2. Indexes to support brief-scoped and AC-scoped evidence queries.
|
|
47
|
-
CREATE INDEX IF NOT EXISTS idx_evidence_brief ON evidence(brief_id);
|
|
48
|
-
CREATE INDEX IF NOT EXISTS idx_evidence_ac ON evidence(brief_id, ac_id);
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
-- v5 -> v6 fresh-install variant.
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh Section 3c case 6 when the live DDL is
|
|
4
|
-
-- already at the v6 target state (evidence table present). This happens on
|
|
5
|
-
-- a clean install where schema.sql already created the evidence table.
|
|
6
|
-
--
|
|
7
|
-
-- The default v5_to_v6.sql cannot run here because CREATE TABLE IF NOT EXISTS
|
|
8
|
-
-- is a no-op when the table already exists, but the indexes must still be
|
|
9
|
-
-- stamped. This variant carries only the DDL that schema.sql cannot declare
|
|
10
|
-
-- safely for older DBs:
|
|
11
|
-
-- * idx_evidence_brief -- index on evidence(brief_id)
|
|
12
|
-
-- * idx_evidence_ac -- index on evidence(brief_id, ac_id)
|
|
13
|
-
--
|
|
14
|
-
-- Both indexes are CREATE INDEX IF NOT EXISTS, making this script safe to re-run.
|
|
15
|
-
|
|
16
|
-
CREATE INDEX IF NOT EXISTS idx_evidence_brief ON evidence(brief_id);
|
|
17
|
-
CREATE INDEX IF NOT EXISTS idx_evidence_ac ON evidence(brief_id, ac_id);
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
-- Migration v6 -> v7 (agent-contract-handoff M1: workspaces.last_scan_at)
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v6 schema has:
|
|
6
|
-
-- workspaces(name, identity, created_at)
|
|
7
|
-
--
|
|
8
|
-
-- v7 adds last_scan_at (ISO8601 TEXT, nullable) to workspaces.
|
|
9
|
-
-- NULL means "never scanned via gaia scan" -- not 'pending'.
|
|
10
|
-
-- The column is written by bin/cli/scan.py after a successful scan run.
|
|
11
|
-
--
|
|
12
|
-
-- Design decision: independent migration version
|
|
13
|
-
-- -----------------------------------------------
|
|
14
|
-
-- workspaces.last_scan_at is the first column added to workspaces.
|
|
15
|
-
-- It belongs in v7, owned by the agent-contract-handoff brief (M1).
|
|
16
|
-
-- M3 and M4 will add further columns in later v7 sub-tasks of the
|
|
17
|
-
-- same migration file (both will extend this file in their dispatches).
|
|
18
|
-
--
|
|
19
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
20
|
-
-- A failure mid-flight rolls back to v6 state and the ledger row is NOT
|
|
21
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
22
|
-
|
|
23
|
-
-- 1. Add last_scan_at column to workspaces.
|
|
24
|
-
-- SQLite ALTER TABLE ADD COLUMN is safe for nullable columns.
|
|
25
|
-
ALTER TABLE workspaces ADD COLUMN last_scan_at TEXT;
|
|
26
|
-
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
-- Migration v6 -> v7 fresh-install variant (agent-contract-handoff M1)
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh when the live DB already has last_scan_at
|
|
4
|
-
-- (i.e. schema.sql ran first on a clean install and created workspaces with
|
|
5
|
-
-- the v7 column already present). This variant is a no-op -- it only exists
|
|
6
|
-
-- so the bootstrap guard-probe branch can select it and stamp the ledger.
|
|
7
|
-
--
|
|
8
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
9
|
-
-- No DDL is executed; the COMMIT is harmless.
|
|
10
|
-
|
|
11
|
-
-- No-op: column already exists on fresh install (schema.sql created it).
|
|
12
|
-
-- This variant only exists to stamp the ledger without applying DDL.
|
|
13
|
-
SELECT 1;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
-- Migration v7 -> v8 (agent-contract-handoff M3: approval_grants table)
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v7 schema has:
|
|
6
|
-
-- workspaces(name, identity, created_at, last_scan_at)
|
|
7
|
-
--
|
|
8
|
-
-- v8 adds the approval_grants table for DB-backed T3 command approval storage.
|
|
9
|
-
-- This replaces the filesystem JSON approval store (.claude/cache/approvals/).
|
|
10
|
-
-- Per D5 / D10: no TTL column (enforced at query time via created_at + 10 min);
|
|
11
|
-
-- byte-for-byte command match; each command_set item is single-use.
|
|
12
|
-
--
|
|
13
|
-
-- Design decision: v8 bump (option a)
|
|
14
|
-
-- ------------------------------------
|
|
15
|
-
-- The approval_grants table was previously appended to v6_to_v7.sql as a
|
|
16
|
-
-- supplemental idempotent block. That approach conflated two unrelated
|
|
17
|
-
-- concerns in one migration version. v8 is the correct version for M3:
|
|
18
|
-
-- each independent feature gets its own migration version (precedent from
|
|
19
|
-
-- v5->v6 evidence table decision). The M3 appended block has been removed
|
|
20
|
-
-- from v6_to_v7.sql and moved here.
|
|
21
|
-
--
|
|
22
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
23
|
-
-- A failure mid-flight rolls back to v7 state and the ledger row is NOT
|
|
24
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
25
|
-
|
|
26
|
-
-- 1. Create the approval_grants table.
|
|
27
|
-
CREATE TABLE IF NOT EXISTS approval_grants (
|
|
28
|
-
approval_id TEXT PRIMARY KEY, -- nonce, e.g. 32-char hex
|
|
29
|
-
agent_id TEXT, -- agent that initiated the request
|
|
30
|
-
session_id TEXT, -- CLAUDE_SESSION_ID at grant time
|
|
31
|
-
command_set_json TEXT NOT NULL, -- JSON array of {command, rationale}
|
|
32
|
-
scope TEXT NOT NULL DEFAULT 'COMMAND_SET', -- grant scope type
|
|
33
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
34
|
-
expires_at TEXT, -- ISO8601 or NULL (TTL enforced at query time)
|
|
35
|
-
status TEXT NOT NULL DEFAULT 'PENDING', -- PENDING|CONSUMED|REVOKED|EXPIRED
|
|
36
|
-
consumed_indexes_json TEXT, -- JSON array of consumed command_set indexes
|
|
37
|
-
consumed_at TEXT, -- ISO8601 when all items consumed
|
|
38
|
-
revoked_at TEXT -- ISO8601 when explicitly revoked
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
-- 2. Indexes to support agent- and session-scoped approval queries.
|
|
42
|
-
CREATE INDEX IF NOT EXISTS idx_approval_grants_agent ON approval_grants(agent_id);
|
|
43
|
-
CREATE INDEX IF NOT EXISTS idx_approval_grants_session ON approval_grants(session_id);
|
|
44
|
-
CREATE INDEX IF NOT EXISTS idx_approval_grants_status ON approval_grants(status);
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
-- Migration v7 -> v8 fresh-install variant (agent-contract-handoff M3)
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh when the live DB already has the approval_grants
|
|
4
|
-
-- table (i.e. schema.sql ran first on a clean install and created the table
|
|
5
|
-
-- in v8 target state already present). This variant is a no-op -- it only
|
|
6
|
-
-- exists so the bootstrap guard-probe branch can select it and stamp the ledger.
|
|
7
|
-
--
|
|
8
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
9
|
-
-- No DDL is executed; the COMMIT is harmless.
|
|
10
|
-
|
|
11
|
-
-- No-op: approval_grants table already exists on fresh install (schema.sql created it).
|
|
12
|
-
-- The indexes are also created by schema.sql on fresh install.
|
|
13
|
-
-- This variant only exists to stamp the ledger without applying DDL.
|
|
14
|
-
SELECT 1;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
-- Migration v8 -> v9 (agent-contract-handoff M4: handoff persistence)
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v8 schema has:
|
|
6
|
-
-- approval_grants(approval_id, agent_id, session_id, command_set_json, ...)
|
|
7
|
-
--
|
|
8
|
-
-- v9 adds:
|
|
9
|
-
-- agent_contract_handoffs -- persisted SubagentStop contract envelopes
|
|
10
|
-
-- agent_contract_handoff_approvals -- approval decisions linked to handoffs
|
|
11
|
-
-- project_context_contracts_history -- audit trail for PCC mutations
|
|
12
|
-
-- trg_pcc_history -- AFTER UPDATE trigger on project_context_contracts
|
|
13
|
-
--
|
|
14
|
-
-- Design decisions
|
|
15
|
-
-- ----------------
|
|
16
|
-
-- * brief_id is NULLABLE -- subagents that return without a brief context
|
|
17
|
-
-- still get a handoff row. EXTENSION_POINT for state-machine-completion:
|
|
18
|
-
-- downstream briefs can query WHERE brief_id = <N> to verify completion
|
|
19
|
-
-- invariants across the handoff record.
|
|
20
|
-
-- * agent_contract_handoff_approvals CASCADE-deletes when the handoff row
|
|
21
|
-
-- is removed. approval_id FK references approval_grants for audit integrity.
|
|
22
|
-
-- * project_context_contracts_history captures before/after payloads at the
|
|
23
|
-
-- SQL layer -- no Python path can bypass the trigger.
|
|
24
|
-
--
|
|
25
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
26
|
-
-- A failure mid-flight rolls back to v8 state; the ledger row is NOT
|
|
27
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
28
|
-
|
|
29
|
-
-- 1. Create the agent_contract_handoffs table.
|
|
30
|
-
CREATE TABLE IF NOT EXISTS agent_contract_handoffs (
|
|
31
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
|
-
agent_id TEXT NOT NULL, -- e.g. "a1b2c3d4e5"
|
|
33
|
-
session_id TEXT, -- CLAUDE_SESSION_ID at SubagentStop time
|
|
34
|
-
workspace TEXT NOT NULL, -- FK -> workspaces.name
|
|
35
|
-
brief_id INTEGER, -- NULLABLE FK -> briefs.id; EXTENSION_POINT
|
|
36
|
-
task_status TEXT NOT NULL, -- resolved plan_status from contract envelope
|
|
37
|
-
raw_handoff_json TEXT NOT NULL, -- full contract envelope serialized
|
|
38
|
-
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
39
|
-
FOREIGN KEY (workspace) REFERENCES workspaces(name),
|
|
40
|
-
FOREIGN KEY (brief_id) REFERENCES briefs(id)
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_workspace ON agent_contract_handoffs(workspace);
|
|
44
|
-
CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_brief ON agent_contract_handoffs(brief_id);
|
|
45
|
-
CREATE INDEX IF NOT EXISTS idx_agent_contract_handoffs_session ON agent_contract_handoffs(session_id);
|
|
46
|
-
|
|
47
|
-
-- 2. Create the agent_contract_handoff_approvals table.
|
|
48
|
-
CREATE TABLE IF NOT EXISTS agent_contract_handoff_approvals (
|
|
49
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
50
|
-
handoff_id INTEGER NOT NULL, -- FK -> agent_contract_handoffs.id
|
|
51
|
-
approval_id TEXT NOT NULL, -- FK -> approval_grants.approval_id
|
|
52
|
-
decision TEXT NOT NULL CHECK (decision IN ('APPROVED', 'REJECTED', 'EXPIRED', 'REVOKED')),
|
|
53
|
-
decided_at TEXT NOT NULL,
|
|
54
|
-
FOREIGN KEY (handoff_id) REFERENCES agent_contract_handoffs(id) ON DELETE CASCADE,
|
|
55
|
-
FOREIGN KEY (approval_id) REFERENCES approval_grants(approval_id)
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
CREATE INDEX IF NOT EXISTS idx_agent_contract_handoff_approvals_handoff ON agent_contract_handoff_approvals(handoff_id);
|
|
59
|
-
|
|
60
|
-
-- 3. Create the project_context_contracts_history table.
|
|
61
|
-
CREATE TABLE IF NOT EXISTS project_context_contracts_history (
|
|
62
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
63
|
-
contract_key TEXT NOT NULL, -- project_context_contracts.contract_key
|
|
64
|
-
workspace TEXT NOT NULL, -- FK -> workspaces.name
|
|
65
|
-
before_payload_json TEXT, -- NULL on first insert (no prior value)
|
|
66
|
-
after_payload_json TEXT NOT NULL, -- new payload value
|
|
67
|
-
changed_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
68
|
-
changed_by_agent TEXT, -- optional: GAIA_DISPATCH_AGENT at write time
|
|
69
|
-
FOREIGN KEY (workspace) REFERENCES workspaces(name)
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
CREATE INDEX IF NOT EXISTS idx_pcc_history_contract ON project_context_contracts_history(contract_key);
|
|
73
|
-
|
|
74
|
-
-- 4. Create the AFTER UPDATE trigger on project_context_contracts.
|
|
75
|
-
CREATE TRIGGER IF NOT EXISTS trg_pcc_history
|
|
76
|
-
AFTER UPDATE ON project_context_contracts
|
|
77
|
-
BEGIN
|
|
78
|
-
INSERT INTO project_context_contracts_history (
|
|
79
|
-
contract_key, workspace, before_payload_json, after_payload_json, changed_at
|
|
80
|
-
) VALUES (
|
|
81
|
-
OLD.contract_key,
|
|
82
|
-
OLD.workspace,
|
|
83
|
-
OLD.payload_json,
|
|
84
|
-
NEW.payload_json,
|
|
85
|
-
strftime('%Y-%m-%dT%H:%M:%SZ', 'now')
|
|
86
|
-
);
|
|
87
|
-
END;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
-- Migration v8 -> v9 fresh-install variant (agent-contract-handoff M4)
|
|
2
|
-
--
|
|
3
|
-
-- Used by bootstrap_database.sh when the live DB already has the
|
|
4
|
-
-- agent_contract_handoffs table (i.e. schema.sql ran first on a clean
|
|
5
|
-
-- install and created the tables in v9 target state).
|
|
6
|
-
--
|
|
7
|
-
-- This variant is a no-op -- it only exists so the bootstrap guard-probe
|
|
8
|
-
-- branch can select it and stamp the ledger without applying DDL.
|
|
9
|
-
--
|
|
10
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
11
|
-
-- No DDL is executed; the COMMIT is harmless.
|
|
12
|
-
|
|
13
|
-
-- No-op: all v9 tables and trigger already exist on fresh install (schema.sql).
|
|
14
|
-
-- This variant only exists to stamp the ledger.
|
|
15
|
-
SELECT 1;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
-- Migration v9 -> v10 (episodic-workflow-to-db: episodes workspace canonical)
|
|
2
|
-
--
|
|
3
|
-
-- Background
|
|
4
|
-
-- ----------
|
|
5
|
-
-- v9 schema has the episodes table with these columns:
|
|
6
|
-
-- episode_id, workspace, timestamp, session_id, task_id, agent,
|
|
7
|
-
-- type, title, prompt, enriched_prompt, wf_prompt, clarifications,
|
|
8
|
-
-- keywords, tags, commands_executed, context_metrics, relevance_score,
|
|
9
|
-
-- outcome, duration_seconds, exit_code, plan_status, output_length,
|
|
10
|
-
-- output_tokens_approx
|
|
11
|
-
--
|
|
12
|
-
-- v10 adds:
|
|
13
|
-
-- episodes.tier -- security tier (T0/T1/T2/T3), promoted from context_metrics blob
|
|
14
|
-
-- episode_anomalies -- structured anomaly records extracted from context_metrics blob
|
|
15
|
-
--
|
|
16
|
-
-- Design decisions
|
|
17
|
-
-- ----------------
|
|
18
|
-
-- D1: tier -> top-level column (not blob)
|
|
19
|
-
-- Rationale: tier is a single short TEXT value (T0/T1/T2/T3) with a clear
|
|
20
|
-
-- compliance query pattern: "COUNT(*) WHERE tier='T3' AND outcome='partial'".
|
|
21
|
-
-- Keeping it in the context_metrics JSON blob would require a full-table
|
|
22
|
-
-- JSON parse for every compliance query. With 10,000+ rows in workspace 'me'
|
|
23
|
-
-- alone, this is a significant performance cost. A column + index reduces
|
|
24
|
-
-- that to a B-tree lookup. The schema cost is one ALTER TABLE + one index.
|
|
25
|
-
-- Alternative considered: keep in blob. Rejected because the query pattern
|
|
26
|
-
-- is both real (used by context_injector.py anomaly surfacing) and frequent
|
|
27
|
-
-- (every compliance dashboard query). No reason to pay JSON parsing overhead
|
|
28
|
-
-- when the data is a four-value enum.
|
|
29
|
-
--
|
|
30
|
-
-- D2: episode_anomalies -> separate table (not blob)
|
|
31
|
-
-- Rationale: anomalies have a stable schema {type, severity, message} per
|
|
32
|
-
-- object. The query "all anomalies of type X in the last 7 days" is a real
|
|
33
|
-
-- operational need -- context_injector.py currently reads anomalies.jsonl
|
|
34
|
-
-- to surface critical anomalies in orchestrator context. That reader must
|
|
35
|
-
-- be ported post-migration. A separate table with a type index enables
|
|
36
|
-
-- `SELECT * FROM episode_anomalies JOIN episodes ON ... WHERE type=? AND
|
|
37
|
-
-- episodes.timestamp > ?` without JSON parsing any rows. With anomalies
|
|
38
|
-
-- present in a large fraction of episodes (4 anomalies in the 12 observed
|
|
39
|
-
-- sessions), the cardinality justifies a separate table. The anomalies[]
|
|
40
|
-
-- array is still preserved inside context_metrics for backward compatibility
|
|
41
|
-
-- with any reader that parses the full blob -- the table is an additional
|
|
42
|
-
-- queryable index, not a replacement.
|
|
43
|
-
-- Alternative considered: keep in context_metrics blob. Rejected because
|
|
44
|
-
-- the type-filtered cross-episode query has no efficient implementation
|
|
45
|
-
-- without the table. GROUP BY type reports are otherwise O(N) full scans
|
|
46
|
-
-- with JSON parsing per row.
|
|
47
|
-
--
|
|
48
|
-
-- Column notes
|
|
49
|
-
-- ------------
|
|
50
|
-
-- episodes.workspace: already present in the v9 schema; NO ALTER TABLE needed.
|
|
51
|
-
-- Live DB confirmed: workspace column exists and has data ('me', 'bildwiz',
|
|
52
|
-
-- 'nfi'). The default 'me' for legacy rows is unnecessary -- workspace is
|
|
53
|
-
-- already populated. This step is a no-op in terms of DDL.
|
|
54
|
-
--
|
|
55
|
-
-- Atomicity: bootstrap_database.sh wraps this script in BEGIN/COMMIT.
|
|
56
|
-
-- A failure mid-flight rolls back to v9 state; the ledger row is NOT
|
|
57
|
-
-- inserted, so the next bootstrap retry sees the same pending migration.
|
|
58
|
-
-- Closes AC-2 of brief episodic-workflow-to-db (brief_id=72).
|
|
59
|
-
|
|
60
|
-
-- Step 1: Add tier column to episodes.
|
|
61
|
-
-- SQLite does not support CHECK constraints in ALTER TABLE ADD COLUMN without
|
|
62
|
-
-- a DEFAULT, so the CHECK is omitted here; validation is enforced at the
|
|
63
|
-
-- application layer (episodic.py / workflow_recorder.py writers).
|
|
64
|
-
ALTER TABLE episodes ADD COLUMN tier TEXT;
|
|
65
|
-
|
|
66
|
-
-- Step 2: Index tier for compliance queries.
|
|
67
|
-
CREATE INDEX IF NOT EXISTS idx_episodes_tier ON episodes(tier);
|
|
68
|
-
|
|
69
|
-
-- Step 3: Compound index for the primary compliance query pattern:
|
|
70
|
-
-- "T3 operations with non-COMPLETE outcomes in time window".
|
|
71
|
-
CREATE INDEX IF NOT EXISTS idx_episodes_tier_outcome ON episodes(tier, outcome);
|
|
72
|
-
|
|
73
|
-
-- Step 4: Create episode_anomalies table.
|
|
74
|
-
-- Each row is one anomaly record extracted from an episode's context_metrics
|
|
75
|
-
-- blob. The payload column holds the full original JSON object for forward
|
|
76
|
-
-- compatibility (additional keys in future anomaly schemas are preserved).
|
|
77
|
-
CREATE TABLE IF NOT EXISTS episode_anomalies (
|
|
78
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
79
|
-
episode_id TEXT NOT NULL, -- FK -> episodes.episode_id
|
|
80
|
-
workspace TEXT NOT NULL, -- denormalized for partition queries without JOIN
|
|
81
|
-
timestamp TEXT NOT NULL, -- denormalized from parent episode for time-range queries
|
|
82
|
-
type TEXT NOT NULL, -- e.g. "investigation_skip", "no_tool_use"
|
|
83
|
-
severity TEXT, -- e.g. "warning", "error", "info"
|
|
84
|
-
message TEXT, -- human-readable description
|
|
85
|
-
payload TEXT, -- full JSON object (forward-compat for extra keys)
|
|
86
|
-
FOREIGN KEY (episode_id) REFERENCES episodes(episode_id) ON DELETE CASCADE
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
-- Step 5: Indexes on episode_anomalies.
|
|
90
|
-
-- Primary query patterns:
|
|
91
|
-
-- (a) All anomalies of type X: WHERE type = ?
|
|
92
|
-
-- (b) Cross-episode anomaly report in time window: WHERE type = ? AND timestamp > ?
|
|
93
|
-
-- (c) Anomalies for a specific episode: WHERE episode_id = ?
|
|
94
|
-
-- (d) Workspace-scoped anomaly dashboard: WHERE workspace = ? AND timestamp > ?
|
|
95
|
-
CREATE INDEX IF NOT EXISTS idx_episode_anomalies_type ON episode_anomalies(type);
|
|
96
|
-
CREATE INDEX IF NOT EXISTS idx_episode_anomalies_workspace ON episode_anomalies(workspace, timestamp DESC);
|
|
97
|
-
CREATE INDEX IF NOT EXISTS idx_episode_anomalies_episode ON episode_anomalies(episode_id);
|
|
98
|
-
|
|
99
|
-
-- Step 6: Bump schema_version to 10.
|
|
100
|
-
INSERT OR IGNORE INTO schema_version (version, applied_at, description)
|
|
101
|
-
VALUES (10, strftime('%Y-%m-%dT%H:%M:%SZ', 'now'),
|
|
102
|
-
'episodes.tier column + idx + episode_anomalies table (brief episodic-workflow-to-db AC-2)');
|
|
103
|
-
|
|
104
|
-
-- Verification queries (run after applying):
|
|
105
|
-
-- SELECT MAX(version) FROM schema_version; -- expect: 10
|
|
106
|
-
-- PRAGMA table_info(episodes); -- expect: tier column present (after output_tokens_approx)
|
|
107
|
-
-- SELECT * FROM sqlite_master WHERE type='index' AND name LIKE 'idx_episodes_tier%'; -- expect: 2 rows
|
|
108
|
-
-- PRAGMA table_info(episode_anomalies); -- expect: 7 columns
|
|
109
|
-
-- SELECT COUNT(*) FROM episode_anomalies; -- expect: 0 (populated by T3 migration task)
|