Layer E + G. Role TOML gains extends/relaxes for parent-role composition; agent spawn gets self-describing DNA identity alongside UUID. Role expression: - _roles/*.toml gain optional `extends = "<parent>"` + `relaxes = [...]` - compose.rs + verify.rs delegate to new role::resolve_role() with recursive extends-chain resolution + cycle detection - explorer.toml: 28→18 LOC (extends read-only) - edit-shared.toml: 31→23 LOC (extends edit-local, relaxes scope::files-whitelist for task-param override) DNA identity: - new dna.rs (159 LOC) — compose/render/parse round-trip - AgentInvocation carries dna field (prepare.rs) - Format: <role>::<caps-bitmap>::<sha4-scope>::<sha4-body>-<hex4-nonce> - ≤ 80 chars total, greppable, parseable - 11 capability codes in CAP_CODES table: NG, FW, FD, CP, CG, TG, ND, RF, SG, DT, BA kei-ledger schema v2: - ADD COLUMN dna TEXT + prefix index - `kei-ledger fork --dna <string>` optional flag - AgentRow.dna: Option<String> - Backward compat: schema migration detects + applies on open Docs: AGENT-SUBSTRATE-SCHEMA.md Layer E + Layer G sections + CAP_CODES table. New deps: sha2 (workspace), rand 0.8. Tests: kei-agent-runtime 50 (was 41, +9: 4 role + 5 DNA), kei-ledger 10 (was 9, +1 DNA roundtrip). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
1.8 KiB
Rust
53 lines
1.8 KiB
Rust
//! SQL schema for the agent ledger.
|
|
//!
|
|
//! Constructor Pattern: one cube = schema DDL + migration runner.
|
|
//! Single source of truth for table shape. Any structural change MUST
|
|
//! bump the migration list below; existing rows are preserved.
|
|
|
|
use rusqlite::{Connection, Result};
|
|
|
|
/// Ordered migrations. Index = schema version. Never reorder; append only.
|
|
pub const MIGRATIONS: &[&str] = &[
|
|
// v1 — initial schema (RULE 0.12, 2026-04-21)
|
|
"CREATE TABLE IF NOT EXISTS agents (
|
|
id TEXT PRIMARY KEY,
|
|
branch TEXT NOT NULL,
|
|
parent_branch TEXT,
|
|
spec_sha TEXT NOT NULL,
|
|
status TEXT NOT NULL CHECK (status IN ('running','done','failed','merged','rejected')),
|
|
started_ts INTEGER NOT NULL,
|
|
finished_ts INTEGER,
|
|
summary TEXT,
|
|
worktree_path TEXT
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_parent ON agents(parent_branch);
|
|
CREATE INDEX IF NOT EXISTS idx_status ON agents(status);",
|
|
// v2 — Layer G DNA identity column + prefix index (2026-04-23)
|
|
"ALTER TABLE agents ADD COLUMN dna TEXT;
|
|
CREATE INDEX IF NOT EXISTS idx_agents_dna_prefix ON agents(substr(dna, 1, 30));",
|
|
];
|
|
|
|
/// Apply all pending migrations. Stores current version in pragma user_version.
|
|
pub fn migrate(conn: &Connection) -> Result<()> {
|
|
let current: i64 = conn
|
|
.query_row("PRAGMA user_version", [], |r| r.get(0))
|
|
.unwrap_or(0);
|
|
for (i, sql) in MIGRATIONS.iter().enumerate() {
|
|
let target = (i + 1) as i64;
|
|
if current < target {
|
|
conn.execute_batch(sql)?;
|
|
conn.pragma_update(None, "user_version", target)?;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Six required artefacts per agent (RULE 0.12 §completion bundle).
|
|
pub const REQUIRED_ARTEFACTS: &[&str] = &[
|
|
"spec.md",
|
|
"plan.md",
|
|
"progress.json",
|
|
"chatlog.md",
|
|
"handoffs.md",
|
|
"review.md",
|
|
];
|