(db *sql.DB, runID string, diffs []IntentRuntimeDiff)
| 365 | } |
| 366 | |
| 367 | func persistDiffs(db *sql.DB, runID string, diffs []IntentRuntimeDiff) error { |
| 368 | tx, err := db.Begin() |
| 369 | if err != nil { |
| 370 | return err |
| 371 | } |
| 372 | defer tx.Rollback() |
| 373 | if _, err := tx.Exec(`DELETE FROM intent_diffs WHERE run_id = ?`, runID); err != nil { |
| 374 | return err |
| 375 | } |
| 376 | if _, err := tx.Exec(`DELETE FROM graph_edges WHERE run_id = ? AND edge_type IN (?, ?)`, |
| 377 | runID, edgeIntentContract, edgeIntentEffect); err != nil { |
| 378 | return err |
| 379 | } |
| 380 | now := time.Now().UTC().Format(time.RFC3339Nano) |
| 381 | seq := 0 |
| 382 | for _, d := range diffs { |
| 383 | declared, _ := json.Marshal(d.Declared) |
| 384 | forbidden, _ := json.Marshal(d.Forbidden) |
| 385 | observed, _ := json.Marshal(d.Observed) |
| 386 | if _, err := tx.Exec(`INSERT INTO intent_diffs |
| 387 | (id, run_id, agent_id, tool_call_id, contract_kind, operation, target, status, finding, confidence, |
| 388 | declared_effects, forbidden_effects, observed_effects, mismatch_reason, source, created_at) |
| 389 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, |
| 390 | d.ID, runID, d.AgentID, d.ToolCallID, d.ContractKind, d.Operation, d.Target, d.Status, d.Finding, d.Confidence, |
| 391 | string(declared), string(forbidden), string(observed), d.MismatchReason, d.Source, now); err != nil { |
| 392 | return err |
| 393 | } |
| 394 | // Wire the diff into the graph: scope -> diff node, and diff node -> each |
| 395 | // observed runtime event. Endpoints are not checked by graph verify, so |
| 396 | // these new edge types are safe to add. |
| 397 | scope := "agent/" + d.AgentID |
| 398 | if d.ToolCallID != "" { |
| 399 | scope = d.ToolCallID |
| 400 | } |
| 401 | if err := insertEdge(tx, runID, scope, d.ID, edgeIntentContract, now, &seq); err != nil { |
| 402 | return err |
| 403 | } |
| 404 | for _, eid := range d.EventIDs { |
| 405 | if err := insertEdge(tx, runID, d.ID, "runtime_event/"+eid, edgeIntentEffect, now, &seq); err != nil { |
| 406 | return err |
| 407 | } |
| 408 | } |
| 409 | } |
| 410 | return tx.Commit() |
| 411 | } |
| 412 | |
| 413 | // insertEdge writes a graph edge with a per-persist monotonic id, so the primary |
| 414 | // key can never collide within a run's diff materialization. |
no test coverage detected