Files
oikos/internal/observability/record.go
dtoro 4e294b3630
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
0.22.0 — full MCP agent surface: 19 new tools, async run, session reliability
Stage 1 — Foundation:
- Target validation: iptables + systemctl/docker target-type gates
- Async run for long-running commands (sleep/wait/poll loops)
- audit_log.session_id plumbing (SQL, sqlcgen, 18 call sites)

Stage 2 — External agent observe (11 tools):
- get_dashboard_summary, get_ontology, list_checks, list_executions
- get_knowledge_revisions, get_knowledge_duplicates, get_knowledge_orphans
- list_knowledge_tags, list_entity_sessions, find_entities_by
- 3 resource templates: oikos://entity/{slug}, knowledge/{id}, execution/{id}

Stage 3 — Nomos reliability:
- complete_task(success) refused without verification (upgraded from warn)
- sessionHasPlan excludes replaced steps (forces propose_plan after reopen)
- Bash syntax validation in run() (rejects literal \n, flag-space typos)
- Scope gate in SOUL.md (ask before pivoting to unrelated subsystem)

Stage 4 — External agent act (9 mutation tools):
- ack_signal, resolve_signal, mute_signal, cancel_execution
- update_check, delete_knowledge, restore_knowledge
- merge_knowledge, rename_knowledge_tag
2026-08-04 23:51:55 +02:00

67 lines
1.8 KiB
Go

package observability
import (
"context"
"encoding/json"
"github.com/dtoro/oikos/internal/db/sqlcgen"
"github.com/google/uuid"
)
// Audit writes an audit_log entry. Pass a transaction-bound Queries so the
// entry commits or rolls back atomically with the state change it records.
//
// actorLabel is the interim textual actor identity ("operator:dev",
// "agent:mcp") recorded in detail; actor_id (a Person/Agent entity UUID)
// starts being populated when OIDC identity resolution lands.
func Audit(ctx context.Context, q *sqlcgen.Queries, actorType, actorLabel,
action string, entityID *uuid.UUID, method, path, correlationID string,
sessionID *uuid.UUID, detail map[string]any) error {
if detail == nil {
detail = map[string]any{}
}
detail["actor"] = actorLabel
detailJSON, _ := json.Marshal(detail)
var corr *string
if correlationID != "" {
corr = &correlationID
}
return q.InsertAuditEntry(ctx, sqlcgen.InsertAuditEntryParams{
ActorType: actorType,
Action: action,
EntityID: entityID,
Method: &method,
Path: &path,
Detail: detailJSON,
CorrelationID: corr,
SessionID: sessionID,
})
}
// Event emits a structured event in the caller's transaction (SG10). The
// post-commit NOTIFY trigger (migration 008) fans it out to SSE subscribers.
func Event(ctx context.Context, q *sqlcgen.Queries, eventType string,
entityID *uuid.UUID, severity, source string, correlationID string,
data map[string]any) error {
dataJSON, _ := json.Marshal(data)
if data == nil {
dataJSON = []byte("{}")
}
var corr *string
if correlationID != "" {
corr = &correlationID
}
_, err := q.InsertEvent(ctx, sqlcgen.InsertEventParams{
Type: eventType,
EntityID: entityID,
Severity: severity,
Source: source,
Data: dataJSON,
CorrelationID: corr,
})
return err
}