package db import ( "database/sql" "time" ) // StrainMemoryRecord is one AI surgical replay outcome for strain learning. type StrainMemoryRecord struct { ID int64 `json:"id"` AgentID string `json:"agent_id"` SessionID string `json:"session_id"` FailedTier string `json:"failed_tier"` Strain string `json:"strain"` FixType string `json:"fix_type"` FixArgs string `json:"fix_args"` Outcome string `json:"outcome"` Timestamp string `json:"ts"` } func (d *Database) ensureStrainMemoryTable() error { _, err := d.Exec(`CREATE TABLE IF NOT EXISTS strain_memory ( id INTEGER PRIMARY KEY AUTOINCREMENT, agent_id TEXT NOT NULL, session_id TEXT NOT NULL DEFAULT '', failed_tier TEXT NOT NULL DEFAULT '', strain TEXT NOT NULL DEFAULT '', fix_type TEXT NOT NULL DEFAULT '', fix_args TEXT NOT NULL DEFAULT '', outcome TEXT NOT NULL DEFAULT '', ts DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP )`) if err != nil { return err } _, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_strain_memory_agent ON strain_memory(agent_id)`) _, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_strain_memory_strain ON strain_memory(strain)`) _, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_strain_memory_ts ON strain_memory(ts)`) return nil } // InsertStrainMemory records a surgical replay fix and its dispatch outcome. func (d *Database) InsertStrainMemory(agentID, sessionID, failedTier, strain, fixType, fixArgs, outcome string) error { _, err := d.Exec( `INSERT INTO strain_memory (agent_id, session_id, failed_tier, strain, fix_type, fix_args, outcome) VALUES (?, ?, ?, ?, ?, ?, ?)`, agentID, sessionID, failedTier, strain, fixType, fixArgs, outcome, ) return err } // ListStrainMemory returns recent strain memory rows, optionally filtered by agent. func (d *Database) ListStrainMemory(agentID string, limit int) ([]StrainMemoryRecord, error) { if limit <= 0 { limit = 50 } var rows *sql.Rows var err error if agentID != "" { rows, err = d.Query( `SELECT id, agent_id, session_id, failed_tier, strain, fix_type, fix_args, outcome, ts FROM strain_memory WHERE agent_id = ? ORDER BY id DESC LIMIT ?`, agentID, limit, ) } else { rows, err = d.Query( `SELECT id, agent_id, session_id, failed_tier, strain, fix_type, fix_args, outcome, ts FROM strain_memory ORDER BY id DESC LIMIT ?`, limit, ) } if err != nil { return nil, err } defer rows.Close() var out []StrainMemoryRecord for rows.Next() { var rec StrainMemoryRecord var ts time.Time if err := rows.Scan(&rec.ID, &rec.AgentID, &rec.SessionID, &rec.FailedTier, &rec.Strain, &rec.FixType, &rec.FixArgs, &rec.Outcome, &ts); err != nil { return nil, err } rec.Timestamp = ts.UTC().Format(time.RFC3339) out = append(out, rec) } return out, rows.Err() }