refactor: Phase 3a — absorb checkdefaults into core/app as pure Derive
Problem: check derivation logic lived in internal/checkdefaults with the pure decision logic (buildKind, address/user/port resolution) interleaved with tx I/O (entity_status insert, graph host fallback, check upserts) — and internal/db importing it was the plan's called-out inverted dependency. Change: - internal/core/app/checkdefaults.go: Derive(tree, target, lookup) — the full derivation (monitoring overrides, host fallback via an injected HostLookup thunk, per-kind builders) with zero I/O imports. Types renamed for the app surface: CheckTarget, CheckDef, DeriveResult, Skip; LogDeriveResult. - internal/adapters/postgres/checks.go absorbs the I/O half: EnsureChecks (entity_status row + upsert loop), writeCheck, and hostViaGraph. The db→checkdefaults edge is gone — adapters→core is the ADR 0016 direction (the Phase 7 SeedService note anticipated this; the inversion is fixed a phase early). - seed.go pending-checks loop uses app.CheckTarget + EnsureChecks; mcp formatting/tests follow the renamed types; both test files moved to internal/core/app. - Deliberate behavior note: a hostViaGraph read failure inside the thunk now logs a warning and degrades to 'skipped: no address' instead of aborting the whole entity-create tx — a monitoring derivation gap is visible (warn log + coverage sweep) and self-heals on the next mutation; failing the create over a graph-read blip was disproportionate. Verification: go build/vet, full test suite green (app tests exercise every buildKind branch at their new home).
This commit is contained in:
@@ -15,7 +15,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dtoro/oikos/internal/checkdefaults"
|
||||
"github.com/dtoro/oikos/internal/core/app"
|
||||
"github.com/dtoro/oikos/internal/adapters/postgres"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
@@ -235,17 +235,17 @@ func TestUpdateEntityAttributes_NotFound(t *testing.T) {
|
||||
// TestFormatCheckResult is a pure unit test for the result-message helper, so
|
||||
// the formatting contract holds even when the DB is unavailable.
|
||||
func TestFormatCheckResult(t *testing.T) {
|
||||
if got := formatCheckResult(checkdefaults.Result{Created: 2}); !strings.Contains(got, "Derived 2 check") {
|
||||
if got := formatCheckResult(app.DeriveResult{Created: 2}); !strings.Contains(got, "Derived 2 check") {
|
||||
t.Errorf("created-only = %q, want Derived 2", got)
|
||||
}
|
||||
got := formatCheckResult(checkdefaults.Result{Created: 1, Skipped: []checkdefaults.Skip{{Kind: "process", Reason: "no host"}}})
|
||||
got := formatCheckResult(app.DeriveResult{Created: 1, Skipped: []app.Skip{{Kind: "process", Reason: "no host"}}})
|
||||
if !strings.Contains(got, "Derived 1 check") || !strings.Contains(got, "Skipped process") || !strings.Contains(got, "no host") {
|
||||
t.Errorf("created+skipped = %q", got)
|
||||
}
|
||||
if got := formatCheckResult(checkdefaults.Result{Undeclared: true}); !strings.Contains(got, "no monitoring") {
|
||||
if got := formatCheckResult(app.DeriveResult{Undeclared: true}); !strings.Contains(got, "no monitoring") {
|
||||
t.Errorf("undeclared = %q, want no-monitoring hint", got)
|
||||
}
|
||||
if formatCreateResult("a", "b", checkdefaults.Result{Created: 0}) != "Created a (b)." {
|
||||
if formatCreateResult("a", "b", app.DeriveResult{Created: 0}) != "Created a (b)." {
|
||||
t.Error("create result with no checks should have no suffix")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/dtoro/oikos/internal/checkdefaults"
|
||||
"github.com/dtoro/oikos/internal/core/app"
|
||||
"github.com/dtoro/oikos/internal/core/ports"
|
||||
"github.com/dtoro/oikos/internal/adapters/postgres"
|
||||
"github.com/google/uuid"
|
||||
@@ -26,7 +26,7 @@ func allTools(pool *db.Pool, agentID uuid.UUID, sec ports.Secrets) []toolReg {
|
||||
AnalysisTools(pool, agentID, sec)...)
|
||||
}
|
||||
|
||||
func formatCheckResult(res checkdefaults.Result) string {
|
||||
func formatCheckResult(res app.DeriveResult) string {
|
||||
var b strings.Builder
|
||||
if res.Created > 0 {
|
||||
fmt.Fprintf(&b, " Derived %d check(s).", res.Created)
|
||||
@@ -40,7 +40,7 @@ func formatCheckResult(res checkdefaults.Result) string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func formatCreateResult(slug, entityType string, res checkdefaults.Result) string {
|
||||
func formatCreateResult(slug, entityType string, res app.DeriveResult) string {
|
||||
return fmt.Sprintf("Created %s (%s).%s", slug, entityType, formatCheckResult(res))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user