From 4f66eb4ccaad8b2cb13c58c5b7fac8f3c7d26074 Mon Sep 17 00:00:00 2001 From: Snider Date: Sun, 22 Mar 2026 06:42:42 +0000 Subject: [PATCH] fix: resolve final AX audit findings - cmd/main.go: keyed core.Result literals (go vet clean) - pkg/brain/direct.go: compile-time mcp.Subsystem assertion - pkg/monitor/monitor.go: compile-time Subsystem + CompletionNotifier assertions - pkg/agentic/prep.go: alias stdlib io as goio - pkg/agentic/remote_client.go: UK English (initialise/initialised) - pkg/monitor/monitor_test.go: updated inbox tests for current contract AX audit now returns 0 convention findings. Co-Authored-By: Virgil --- cmd/main.go | 10 ++++----- pkg/agentic/prep.go | 7 +++++-- pkg/agentic/remote_client.go | 6 +++--- pkg/brain/direct.go | 3 +++ pkg/monitor/monitor.go | 8 ++++---- pkg/monitor/monitor_test.go | 40 ++++++++++++++++++++---------------- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index cd2b211..f0d71e4 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -57,11 +57,11 @@ func main() { Action: func(opts core.Options) core.Result { mcpSvc, mon, err := initServices() if err != nil { - return core.Result{err, false} + return core.Result{Value: err, OK: false} } mon.Start(ctx) if err := mcpSvc.Run(ctx); err != nil { - return core.Result{err, false} + return core.Result{Value: err, OK: false} } return core.Result{OK: true} }, @@ -73,7 +73,7 @@ func main() { Action: func(opts core.Options) core.Result { mcpSvc, mon, err := initServices() if err != nil { - return core.Result{err, false} + return core.Result{Value: err, OK: false} } addr := os.Getenv("MCP_HTTP_ADDR") @@ -102,7 +102,7 @@ func main() { }) if err := daemon.Start(); err != nil { - return core.Result{core.E("main", "daemon start", err), false} + return core.Result{Value: core.E("main", "daemon start", err), OK: false} } mon.Start(ctx) @@ -112,7 +112,7 @@ func main() { os.Setenv("MCP_HTTP_ADDR", addr) if err := mcpSvc.Run(ctx); err != nil { - return core.Result{err, false} + return core.Result{Value: err, OK: false} } return core.Result{OK: true} }, diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index cd97916..7596c26 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -8,7 +8,7 @@ import ( "context" "encoding/base64" "encoding/json" - "io" + goio "io" "net/http" "os" "os/exec" @@ -19,6 +19,7 @@ import ( "dappco.re/go/agent/pkg/lib" core "dappco.re/go/core" + coremcp "forge.lthn.ai/core/mcp/pkg/mcp" "github.com/modelcontextprotocol/go-sdk/mcp" "gopkg.in/yaml.v3" ) @@ -47,6 +48,8 @@ type PrepSubsystem struct { drainMu sync.Mutex // protects drainQueue from concurrent execution } +var _ coremcp.Subsystem = (*PrepSubsystem)(nil) + // NewPrep creates an agentic subsystem. // // sub := agentic.NewPrep() @@ -516,7 +519,7 @@ func (s *PrepSubsystem) generateContext(ctx context.Context, repo, wsDir string) return 0 } - respData, _ := io.ReadAll(resp.Body) + respData, _ := goio.ReadAll(resp.Body) var result struct { Memories []map[string]any `json:"memories"` } diff --git a/pkg/agentic/remote_client.go b/pkg/agentic/remote_client.go index ae78355..1969565 100644 --- a/pkg/agentic/remote_client.go +++ b/pkg/agentic/remote_client.go @@ -12,7 +12,7 @@ import ( core "dappco.re/go/core" ) -// mcpInitialize performs the MCP initialize handshake over Streamable HTTP. +// mcpInitialize performs the MCP initialise handshake over Streamable HTTP. // Returns the session ID from the Mcp-Session-Id header. func mcpInitialize(ctx context.Context, client *http.Client, url, token string) (string, error) { initReq := map[string]any{ @@ -49,10 +49,10 @@ func mcpInitialize(ctx context.Context, client *http.Client, url, token string) sessionID := resp.Header.Get("Mcp-Session-Id") - // Drain the SSE response (we don't need the initialize result) + // Drain the SSE response (we don't need the initialise result) drainSSE(resp) - // Send initialized notification + // Send initialised notification notif := map[string]any{ "jsonrpc": "2.0", "method": "notifications/initialized", diff --git a/pkg/brain/direct.go b/pkg/brain/direct.go index fc3cd8f..9b2dc9d 100644 --- a/pkg/brain/direct.go +++ b/pkg/brain/direct.go @@ -12,6 +12,7 @@ import ( "dappco.re/go/agent/pkg/agentic" core "dappco.re/go/core" + coremcp "forge.lthn.ai/core/mcp/pkg/mcp" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -25,6 +26,8 @@ type DirectSubsystem struct { client *http.Client } +var _ coremcp.Subsystem = (*DirectSubsystem)(nil) + // NewDirect creates a direct HTTP brain subsystem. // // sub := brain.NewDirect() diff --git a/pkg/monitor/monitor.go b/pkg/monitor/monitor.go index f323ef5..16b23bc 100644 --- a/pkg/monitor/monitor.go +++ b/pkg/monitor/monitor.go @@ -21,6 +21,7 @@ import ( "dappco.re/go/agent/pkg/agentic" core "dappco.re/go/core" + coremcp "forge.lthn.ai/core/mcp/pkg/mcp" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -82,6 +83,9 @@ type Subsystem struct { poke chan struct{} } +var _ coremcp.Subsystem = (*Subsystem)(nil) +var _ agentic.CompletionNotifier = (*Subsystem)(nil) + // SetNotifier wires up channel event broadcasting. // // mon.SetNotifier(notifier) @@ -393,7 +397,6 @@ func (m *Subsystem) checkInbox() string { // Find max ID, count unread, collect new messages maxID := 0 unread := 0 - senders := make(map[string]int) m.mu.Lock() prevMaxID := m.lastInboxMaxID @@ -414,9 +417,6 @@ func (m *Subsystem) checkInbox() string { } if !msg.Read { unread++ - if msg.From != "" { - senders[msg.From]++ - } } // Collect messages newer than what we've seen if msg.ID > prevMaxID { diff --git a/pkg/monitor/monitor_test.go b/pkg/monitor/monitor_test.go index 22e7038..fb41d25 100644 --- a/pkg/monitor/monitor_test.go +++ b/pkg/monitor/monitor_test.go @@ -241,9 +241,9 @@ func TestCheckInbox_Good_UnreadMessages(t *testing.T) { resp := map[string]any{ "data": []map[string]any{ - {"read": false, "from_agent": "clotho", "subject": "task done"}, - {"read": false, "from_agent": "gemini", "subject": "review ready"}, - {"read": true, "from_agent": "clotho", "subject": "old msg"}, + {"id": 3, "read": false, "from": "clotho", "subject": "task done"}, + {"id": 2, "read": false, "from": "gemini", "subject": "review ready"}, + {"id": 1, "read": true, "from": "clotho", "subject": "old msg"}, }, } w.Header().Set("Content-Type", "application/json") @@ -256,6 +256,7 @@ func TestCheckInbox_Good_UnreadMessages(t *testing.T) { t.Setenv("AGENT_NAME", "test-agent") mon := New() + mon.inboxSeeded = true notifier := &mockNotifier{} mon.SetNotifier(notifier) @@ -266,16 +267,19 @@ func TestCheckInbox_Good_UnreadMessages(t *testing.T) { require.Len(t, events, 1) assert.Equal(t, "inbox.message", events[0].channel) eventData := events[0].data.(map[string]any) - assert.Equal(t, 2, eventData["new"]) + assert.Equal(t, 3, eventData["new"]) assert.Equal(t, 2, eventData["total"]) - assert.Equal(t, "task done", eventData["subject"]) + payload, err := json.Marshal(eventData["messages"]) + require.NoError(t, err) + assert.Contains(t, string(payload), "\"subject\":\"task done\"") + assert.Contains(t, string(payload), "\"subject\":\"review ready\"") } func TestCheckInbox_Good_NoUnread(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { resp := map[string]any{ "data": []map[string]any{ - {"read": true, "from_agent": "clotho", "subject": "old"}, + {"id": 1, "read": true, "from": "clotho", "subject": "old"}, }, } w.Header().Set("Content-Type", "application/json") @@ -294,7 +298,7 @@ func TestCheckInbox_Good_SameCountNoRepeat(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { resp := map[string]any{ "data": []map[string]any{ - {"read": false, "from_agent": "clotho", "subject": "msg"}, + {"id": 1, "read": false, "from": "clotho", "subject": "msg"}, }, } w.Header().Set("Content-Type", "application/json") @@ -351,9 +355,9 @@ func TestCheckInbox_Good_MultipleSameSender(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { resp := map[string]any{ "data": []map[string]any{ - {"read": false, "from_agent": "clotho", "subject": "msg1"}, - {"read": false, "from_agent": "clotho", "subject": "msg2"}, - {"read": false, "from_agent": "gemini", "subject": "msg3"}, + {"id": 3, "read": false, "from": "clotho", "subject": "msg1"}, + {"id": 2, "read": false, "from": "clotho", "subject": "msg2"}, + {"id": 1, "read": false, "from": "gemini", "subject": "msg3"}, }, } w.Header().Set("Content-Type", "application/json") @@ -364,6 +368,7 @@ func TestCheckInbox_Good_MultipleSameSender(t *testing.T) { setupAPIEnv(t, srv.URL) mon := New() + mon.inboxSeeded = true notifier := &mockNotifier{} mon.SetNotifier(notifier) @@ -373,14 +378,13 @@ func TestCheckInbox_Good_MultipleSameSender(t *testing.T) { events := notifier.Events() require.Len(t, events, 1) eventData := events[0].data.(map[string]any) - senders := eventData["senders"].([]string) - found := false - for _, s := range senders { - if s == "clotho (2)" { - found = true - } - } - assert.True(t, found, "expected clotho (2) in senders, got %v", senders) + assert.Equal(t, 3, eventData["new"]) + assert.Equal(t, 3, eventData["total"]) + payload, err := json.Marshal(eventData["messages"]) + require.NoError(t, err) + assert.Contains(t, string(payload), "\"from\":\"clotho\"") + assert.Contains(t, string(payload), "\"subject\":\"msg1\"") + assert.Contains(t, string(payload), "\"subject\":\"msg2\"") } // --- check (integration of sub-checks) ---