Add phenotype cloning, failure atlas, AI court session, and clearance L0-L4
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
This commit is contained in:
@@ -14,6 +14,11 @@ type AIDecisionRecord struct {
|
||||
Response string `json:"response"`
|
||||
CommandsExecuted string `json:"commands_executed"`
|
||||
Timestamp string `json:"ts"`
|
||||
|
||||
CourtSession bool `json:"court_session,omitempty"`
|
||||
ProsecutorSnippet string `json:"prosecutor_snippet,omitempty"`
|
||||
DefenderSnippet string `json:"defender_snippet,omitempty"`
|
||||
JudgeVerdict string `json:"judge_verdict,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Database) ensureAIDecisionsTable() error {
|
||||
@@ -30,20 +35,42 @@ func (d *Database) ensureAIDecisionsTable() error {
|
||||
}
|
||||
_, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_ai_decisions_agent ON ai_decisions(agent_id)`)
|
||||
_, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_ai_decisions_ts ON ai_decisions(ts)`)
|
||||
d.ensureAIDecisionsCourtColumns()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) ensureAIDecisionsCourtColumns() {
|
||||
cols := []struct{ name, ddl string }{
|
||||
{"court_session", `ALTER TABLE ai_decisions ADD COLUMN court_session INTEGER NOT NULL DEFAULT 0`},
|
||||
{"prosecutor_snippet", `ALTER TABLE ai_decisions ADD COLUMN prosecutor_snippet TEXT NOT NULL DEFAULT ''`},
|
||||
{"defender_snippet", `ALTER TABLE ai_decisions ADD COLUMN defender_snippet TEXT NOT NULL DEFAULT ''`},
|
||||
{"judge_verdict", `ALTER TABLE ai_decisions ADD COLUMN judge_verdict TEXT NOT NULL DEFAULT ''`},
|
||||
}
|
||||
for _, c := range cols {
|
||||
var n int
|
||||
_ = d.QueryRow(`SELECT COUNT(*) FROM pragma_table_info('ai_decisions') WHERE name = ?`, c.name).Scan(&n)
|
||||
if n == 0 {
|
||||
_, _ = d.Exec(c.ddl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InsertAIDecision logs one fleet AI decision cycle.
|
||||
func (d *Database) InsertAIDecision(agentID, promptHash, response, commandsExecuted string) error {
|
||||
func (d *Database) InsertAIDecision(agentID, promptHash, response, commandsExecuted string, courtSession bool, prosecutorSnippet, defenderSnippet, judgeVerdict string) error {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
if err := d.ensureAIDecisionsTable(); err != nil {
|
||||
return err
|
||||
}
|
||||
courtInt := 0
|
||||
if courtSession {
|
||||
courtInt = 1
|
||||
}
|
||||
_, err := d.Exec(
|
||||
`INSERT INTO ai_decisions (agent_id, prompt_hash, response, commands_executed) VALUES (?, ?, ?, ?)`,
|
||||
agentID, promptHash, response, commandsExecuted,
|
||||
`INSERT INTO ai_decisions (agent_id, prompt_hash, response, commands_executed, court_session, prosecutor_snippet, defender_snippet, judge_verdict)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
agentID, promptHash, response, commandsExecuted, courtInt, prosecutorSnippet, defenderSnippet, judgeVerdict,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -68,13 +95,15 @@ func (d *Database) ListAIDecisions(agentID string, limit int) ([]AIDecisionRecor
|
||||
agentID = strings.TrimSpace(agentID)
|
||||
if agentID != "" {
|
||||
rows, err = d.Query(
|
||||
`SELECT id, agent_id, prompt_hash, response, commands_executed, ts
|
||||
`SELECT id, agent_id, prompt_hash, response, commands_executed, ts,
|
||||
court_session, prosecutor_snippet, defender_snippet, judge_verdict
|
||||
FROM ai_decisions WHERE agent_id = ? ORDER BY id DESC LIMIT ?`,
|
||||
agentID, limit,
|
||||
)
|
||||
} else {
|
||||
rows, err = d.Query(
|
||||
`SELECT id, agent_id, prompt_hash, response, commands_executed, ts
|
||||
`SELECT id, agent_id, prompt_hash, response, commands_executed, ts,
|
||||
court_session, prosecutor_snippet, defender_snippet, judge_verdict
|
||||
FROM ai_decisions ORDER BY id DESC LIMIT ?`,
|
||||
limit,
|
||||
)
|
||||
@@ -88,10 +117,15 @@ func (d *Database) ListAIDecisions(agentID string, limit int) ([]AIDecisionRecor
|
||||
for rows.Next() {
|
||||
var rec AIDecisionRecord
|
||||
var ts string
|
||||
if err := rows.Scan(&rec.ID, &rec.AgentID, &rec.PromptHash, &rec.Response, &rec.CommandsExecuted, &ts); err != nil {
|
||||
var courtInt int
|
||||
if err := rows.Scan(
|
||||
&rec.ID, &rec.AgentID, &rec.PromptHash, &rec.Response, &rec.CommandsExecuted, &ts,
|
||||
&courtInt, &rec.ProsecutorSnippet, &rec.DefenderSnippet, &rec.JudgeVerdict,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rec.Timestamp = ts
|
||||
rec.CourtSession = courtInt != 0
|
||||
out = append(out, rec)
|
||||
}
|
||||
return out, rows.Err()
|
||||
|
||||
65
server/internal/db/atlas.go
Normal file
65
server/internal/db/atlas.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package db
|
||||
|
||||
import "strings"
|
||||
|
||||
// FailureAtlasPattern is one conditioned failure bucket in SQLite.
|
||||
type FailureAtlasPattern struct {
|
||||
FingerprintBucket string
|
||||
Condition string
|
||||
Tier string
|
||||
FailCount int
|
||||
}
|
||||
|
||||
func (d *Database) UpsertFailureAtlasPattern(fingerprintBucket, condition, tier string) error {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
_, err := d.Exec(`
|
||||
INSERT INTO failure_atlas (fingerprint_bucket, condition, tier, fail_count, updated_at)
|
||||
VALUES (?, ?, ?, 1, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(fingerprint_bucket, condition, tier) DO UPDATE SET
|
||||
fail_count = fail_count + 1,
|
||||
updated_at = CURRENT_TIMESTAMP`,
|
||||
fingerprintBucket, condition, tier,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Database) ListFailureAtlasPatterns(fingerprintBucket, goos string) ([]FailureAtlasPattern, error) {
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
out, err := d.queryFailureAtlasPatterns(`fingerprint_bucket = ?`, fingerprintBucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(out) > 0 {
|
||||
return out, nil
|
||||
}
|
||||
if strings.TrimSpace(goos) == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return d.queryFailureAtlasPatterns(`fingerprint_bucket LIKE ?`, strings.ToLower(goos)+"|%")
|
||||
}
|
||||
|
||||
func (d *Database) queryFailureAtlasPatterns(whereClause string, arg interface{}) ([]FailureAtlasPattern, error) {
|
||||
query := `
|
||||
SELECT fingerprint_bucket, condition, tier, fail_count
|
||||
FROM failure_atlas
|
||||
WHERE ` + whereClause + `
|
||||
ORDER BY fail_count DESC, tier ASC`
|
||||
rows, err := d.Query(query, arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []FailureAtlasPattern
|
||||
for rows.Next() {
|
||||
var p FailureAtlasPattern
|
||||
if err := rows.Scan(&p.FingerprintBucket, &p.Condition, &p.Tier, &p.FailCount); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
82
server/internal/db/failure_atlas.go
Normal file
82
server/internal/db/failure_atlas.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FailureAtlasEntry is one tier's aggregated failure rate for a fingerprint bucket.
|
||||
type FailureAtlasEntry struct {
|
||||
Tier string
|
||||
Total int
|
||||
Failures int
|
||||
FailPct float64
|
||||
}
|
||||
|
||||
// FailureAtlasSummary returns a compact prosecutor-ready summary from tier_outcomes.
|
||||
func (d *Database) FailureAtlasSummary(fingerprintKey, goos string) (string, error) {
|
||||
entries, err := d.failureAtlasEntries(fingerprintKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(entries) == 0 && goos != "" {
|
||||
entries, err = d.failureAtlasEntriesLike(goos + "|%")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
return "no fleet failure atlas samples for this fingerprint", nil
|
||||
}
|
||||
parts := make([]string, 0, len(entries))
|
||||
for _, e := range entries {
|
||||
if e.Failures == 0 {
|
||||
continue
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("%s %d/%d failed (%.0f%%)", e.Tier, e.Failures, e.Total, e.FailPct))
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return "fleet atlas shows no tier failures for this fingerprint", nil
|
||||
}
|
||||
return strings.Join(parts, "; "), nil
|
||||
}
|
||||
|
||||
func (d *Database) failureAtlasEntries(fingerprintKey string) ([]FailureAtlasEntry, error) {
|
||||
return d.queryFailureAtlas(`fingerprint_key = ?`, fingerprintKey)
|
||||
}
|
||||
|
||||
func (d *Database) failureAtlasEntriesLike(pattern string) ([]FailureAtlasEntry, error) {
|
||||
return d.queryFailureAtlas(`fingerprint_key LIKE ?`, pattern)
|
||||
}
|
||||
|
||||
func (d *Database) queryFailureAtlas(whereClause string, arg interface{}) ([]FailureAtlasEntry, error) {
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
query := fmt.Sprintf(`
|
||||
SELECT tier,
|
||||
COUNT(*) AS total,
|
||||
SUM(CASE WHEN ok = 0 THEN 1 ELSE 0 END) AS failures
|
||||
FROM tier_outcomes WHERE %s
|
||||
GROUP BY tier
|
||||
HAVING failures > 0
|
||||
ORDER BY failures DESC, total DESC
|
||||
LIMIT 12`, whereClause)
|
||||
rows, err := d.Query(query, arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []FailureAtlasEntry
|
||||
for rows.Next() {
|
||||
var e FailureAtlasEntry
|
||||
if err := rows.Scan(&e.Tier, &e.Total, &e.Failures); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if e.Total > 0 {
|
||||
e.FailPct = 100 * float64(e.Failures) / float64(e.Total)
|
||||
}
|
||||
out = append(out, e)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user