phase 1: Go foundation — module, migrations, domain, seed ingest

Core deliverables:
- Go module github.com/dtoro/oikos (Go 1.26.3)
- cmd/oikos: single binary with role subcommands (migrate, seed, export)
- 6 SQL migrations: ontology meta-schema, entity instances (UUID+slug,
  blast_radius recursive function), operations (signals/checks/approvals),
  cognition (classifications/executions/feedback/patterns/skills), policy,
  observability (TimescaleDB hypertables + CAGGs + retention)
- Domain layer: entity, signal, execution, classification, pattern, skill,
  approval, check types + 11 sentinel errors + lifecycle state machines
- DB layer: pgx pool, SQL splitter (handles 94436 and -- comments), migration
  runner, seed ingest (ontology+inventory+policy) with content-hash dedup
- Config: env-based with defaults, secrets redaction
- Observability: slog JSON logger with debug mode
- Infrastructure: Makefile, docker-compose.yml, multi-stage Dockerfile
  (distroless, CGO_ENABLED=0)

Verified end-to-end against timescale/timescaledb:2.17.2-pg16:
- 6 migrations applied (65 SQL statements)
- Seeds ingested: 6 lifecycles, 59 entity types, 46 relationship types,
  111 entities, 144 relationships, 4 risk classes, 27 approval rules,
  9 autonomy settings
- Idempotent: second seed run is a no-op (content hash matches)

Bugs fixed during implementation:
- TimescaleDB CAGGs can't run in a transaction -> splitSQL() executes
  statements individually
- Semicolons in -- comments treated as separators -> comment handling
- YAML keys source/target didn't match code's source_type/target_type
- yaml.Marshal produced YAML for JSONB columns -> json.Marshal
This commit is contained in:
2026-07-07 01:07:26 +02:00
parent 55710bd254
commit aa2ca0ae6f
23 changed files with 1964 additions and 0 deletions

110
internal/domain/approval.go Normal file
View File

@@ -0,0 +1,110 @@
package domain
import "time"
// Approval is a short-TTL signed grant for a gated action.
type Approval struct {
EntityID UUID
SubjectEntityID UUID
Action string
RiskClass string
Kind string
Payload map[string]any
Status string
TokenHash string
ExpiresAt time.Time
DecidedAt *time.Time
DecidedBy UUID
CreatedAt time.Time
}
// Approval statuses.
const (
ApprovalPending = "pending"
ApprovalApproved = "approved"
ApprovalDenied = "denied"
ApprovalExpired = "expired"
ApprovalRevoked = "revoked"
)
// Approval kinds.
const (
ApprovalKindExecution = "execution"
ApprovalKindPolicyChange = "policy-change"
ApprovalKindPatternActivation = "pattern-activation"
)
// CheckDef defines a probe (R3-7: probes as data, not code).
type CheckDef struct {
EntityID UUID
TargetID UUID
TargetType string
Kind string
Config map[string]any
IntervalS int
TimeoutS int
Zone string
Enabled bool
UpdatedAt time.Time
}
// Check kinds.
const (
CheckHTTP = "http"
CheckTCP = "tcp"
CheckDisk = "disk"
CheckCertExpiry = "cert-expiry"
CheckDrift = "drift"
CheckSSHScript = "ssh-script"
)
// EntityStatus is the current health of an entity (R3-6: replaces state_snapshots).
type EntityStatus struct {
EntityID UUID
Health string
LastCheckAt *time.Time
Details map[string]any
UpdatedAt time.Time
}
// Health values.
const (
HealthHealthy = "healthy"
HealthDegraded = "degraded"
HealthDown = "down"
HealthUnknown = "unknown"
)
// RiskClass is the four-level safety model.
type RiskClass struct {
Name string
Description string
ApprovalRequired string
AutonomyAllowed bool
}
// Risk class names.
const (
RiskReadOnly = "read_only"
RiskReversibleLow = "reversible_low"
RiskConfigMutation = "config_mutation"
RiskDestructive = "destructive"
)
// ApprovalRule maps (entity_type, action) → risk_class + autonomy.
type ApprovalRule struct {
ID UUID
EntityType string
Action string
RiskClass string
AutonomyLevel string
ScopeEntity UUID
Version int
}
// Autonomy levels.
const (
AutonomyAuto = "auto"
AutonomyEscalate = "escalate"
AutonomyNever = "never"
)