normalizeEffects classifies a run's security-relevant events into normalized RuntimeEffects and attributes each to an agent. Attribution has two tiers, most precise first: (1) the command-match agent_syscall edge (a specific sub-agent's tool call caused this syscall); (2) the event's own tool_call -
(db *sql.DB, runID string, eng security.Engine)
| 163 | // honesty contract: an effect we cannot tie to captured intent is a gap, not a |
| 164 | // rogue action. |
| 165 | func normalizeEffects(db *sql.DB, runID string, eng security.Engine) ([]RuntimeEffect, error) { |
| 166 | // tool_call -> agent |
| 167 | agentOf := map[string]string{} |
| 168 | arows, err := db.Query(`SELECT id, agent_id FROM tool_calls WHERE run_id = ? AND agent_id != ''`, runID) |
| 169 | if err != nil { |
| 170 | return nil, err |
| 171 | } |
| 172 | for arows.Next() { |
| 173 | var id, agent string |
| 174 | if err := arows.Scan(&id, &agent); err != nil { |
| 175 | arows.Close() |
| 176 | return nil, err |
| 177 | } |
| 178 | agentOf[id] = agent |
| 179 | } |
| 180 | arows.Close() |
| 181 | |
| 182 | // Refinement: command-match attribution (agent_syscall edge: tool_call -> |
| 183 | // runtime_event/<eventID>) overrides the coarse tool_call join when present. |
| 184 | refinedAgent := map[string]string{} |
| 185 | refinedToolCall := map[string]string{} |
| 186 | erows, err := db.Query(`SELECT from_id, to_id FROM graph_edges |
| 187 | WHERE run_id = ? AND edge_type = 'agent_syscall'`, runID) |
| 188 | if err != nil { |
| 189 | return nil, err |
| 190 | } |
| 191 | for erows.Next() { |
| 192 | var from, to string |
| 193 | if err := erows.Scan(&from, &to); err != nil { |
| 194 | erows.Close() |
| 195 | return nil, err |
| 196 | } |
| 197 | eid := strings.TrimPrefix(to, "runtime_event/") |
| 198 | if a := agentOf[from]; a != "" { |
| 199 | refinedAgent[eid] = a |
| 200 | refinedToolCall[eid] = from |
| 201 | } |
| 202 | } |
| 203 | erows.Close() |
| 204 | |
| 205 | windows := loadToolCallWindows(db, runID) |
| 206 | |
| 207 | placeholders := strings.TrimSuffix(strings.Repeat("?,", len(effectEventTypes)), ",") |
| 208 | args := []any{runID} |
| 209 | for _, t := range effectEventTypes { |
| 210 | args = append(args, t) |
| 211 | } |
| 212 | rows, err := db.Query(`SELECT id, event_type, COALESCE(tool_call_id,''), payload, correlation_confidence, created_at |
| 213 | FROM events WHERE run_id = ? AND event_type IN (`+placeholders+`)`, args...) |
| 214 | if err != nil { |
| 215 | return nil, err |
| 216 | } |
| 217 | defer rows.Close() |
| 218 | var out []RuntimeEffect |
| 219 | for rows.Next() { |
| 220 | var id, etype, toolCall, payload, createdAt string |
| 221 | var conf float64 |
| 222 | if err := rows.Scan(&id, &etype, &toolCall, &payload, &conf, &createdAt); err != nil { |
no test coverage detected