Files
pulse/internal/telemetry/pulse_intelligence_evidence.go
T
rcourtman 3ffd622de0 feat(settings): make the external-agent (MCP) connector setup findable in sidebar search
Production telemetry showed 1,437 installs on the external-agent surface but
only 2 on the Pulse MCP adapter. Live verification proved the pulse_mcp
telemetry surface attribution is honest (adapter tools/call records
surface=pulse_mcp; header-less calls record agent_api), so the gap is real -
but the funnel comparison is also misleading: agent_api counts any scoped
API-token REST consumer (scripts, dashboards polling /api/config/nodes or
/api/ai/patrol/findings), not BYO AI agents. Recorded that interpretation
constraint on PulseIntelligenceExternalAgentEvidence.

The genuine product gap: the in-app connector setup (Settings -> Pulse
Intelligence -> Assistant -> External agents) was invisible to sidebar search.
Searching 'mcp', 'claude', 'opencode', or 'connector' returned 'No settings
found' because search matched only nav labels and header descriptions.

- Add search-only keywords to SettingsNavItem and match them in
  filteredTabGroups; the Assistant item now carries mcp / model context
  protocol / external agent(s) / claude / opencode / connector / pulse-mcp.
- Name external agent (MCP) connectors in the Assistant header description
  (EN/DE/ES kept in sync), so the page header states what the page contains.
- Pin the search behavior with parameterized useSettingsAccess tests plus a
  settingsArchitecture source proof; record the keyword channel in the
  frontend-primitives contract (obligation 41) and the product-copy allowance
  in the security-privacy i18n extension point.
2026-07-17 23:43:05 +01:00

162 lines
5.4 KiB
Go

package telemetry
import (
"strings"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
)
// PulseIntelligenceAIUsageEvidence is the content-free subset of AI usage
// history used to prove Pulse Intelligence loop collaboration.
type PulseIntelligenceAIUsageEvidence struct {
AssistantAICalls int
AssistantContextAICalls int
AssistantToolCalls int
PatrolAICalls int
}
// PulseIntelligenceAIUsageEvidenceFromHistory projects AI usage history into
// the same content-free Pulse Intelligence evidence used by telemetry and the
// agent operations-loop status endpoint.
func PulseIntelligenceAIUsageEvidenceFromHistory(history *config.AIUsageHistoryData, since time.Time) PulseIntelligenceAIUsageEvidence {
var evidence PulseIntelligenceAIUsageEvidence
if history == nil {
return evidence
}
for _, event := range history.Events {
if event.Timestamp.IsZero() || event.Timestamp.Before(since) {
continue
}
switch strings.ToLower(strings.TrimSpace(event.UseCase)) {
case "chat":
evidence.AssistantAICalls++
if PulseIntelligenceAssistantContextEvent(event) {
evidence.AssistantContextAICalls++
}
if event.ToolCallCount > 0 {
evidence.AssistantToolCalls += event.ToolCallCount
}
case "patrol":
evidence.PatrolAICalls++
}
}
return evidence
}
// PulseIntelligenceAssistantContextEvent reports whether a chat usage event
// carried governed context. It deliberately ignores prompt text and responses.
func PulseIntelligenceAssistantContextEvent(event config.AIUsageEventRecord) bool {
return strings.TrimSpace(event.ContextScope) != "" ||
strings.TrimSpace(event.TargetType) != "" ||
strings.TrimSpace(event.TargetID) != "" ||
strings.TrimSpace(event.FindingID) != ""
}
// PulseIntelligenceExternalAgentEvidence is the content-free subset of
// authenticated agent/MCP route activity used to prove external collaboration.
//
// Interpretation constraint: the agent_api surface counts any suitably scoped
// API-token request to manifest-listed routes — including plain REST consumers
// like scripts and dashboards hitting GET /api/config/nodes or
// /api/ai/patrol/findings — so Used does NOT imply a BYO AI agent. Only
// MCPAdapterUsed (the pulse_mcp surface header) certainly identifies an MCP
// client. Do not read Used-vs-MCPAdapterUsed as an adoption funnel of the
// same population.
type PulseIntelligenceExternalAgentEvidence struct {
Used bool
MCPAdapterUsed bool
ContextRequests int
EventStreamRequests int
ProvisioningRequests int
OperatorStateRequests int
FindingRequests int
ActionRequests int
}
// CollaborationActive reports whether an external agent or MCP adapter used a
// manifest-published Pulse Intelligence capability in the evidence window.
func (e PulseIntelligenceExternalAgentEvidence) CollaborationActive() bool {
return e.Used ||
e.MCPAdapterUsed ||
e.ContextRequests > 0 ||
e.EventStreamRequests > 0 ||
e.ProvisioningRequests > 0 ||
e.OperatorStateRequests > 0 ||
e.FindingRequests > 0 ||
e.ActionRequests > 0
}
// CollaborationCount returns a coarse activity count for step-level rollups.
func (e PulseIntelligenceExternalAgentEvidence) CollaborationCount() int {
count := e.ContextRequests +
e.EventStreamRequests +
e.ProvisioningRequests +
e.OperatorStateRequests +
e.FindingRequests +
e.ActionRequests
if count > 0 {
return count
}
if e.Used || e.MCPAdapterUsed {
return 1
}
return 0
}
// PulseIntelligenceExternalAgentEvidenceFromHistory projects external-agent
// activity history into content-free collaboration evidence.
func PulseIntelligenceExternalAgentEvidenceFromHistory(history *config.ExternalAgentActivityHistoryData, since time.Time) PulseIntelligenceExternalAgentEvidence {
var evidence PulseIntelligenceExternalAgentEvidence
if history == nil {
return evidence
}
for _, event := range history.Events {
if event.Timestamp.IsZero() || event.Timestamp.Before(since) {
continue
}
if !PulseIntelligenceExternalAgentActivitySurface(event.Surface) {
continue
}
evidence.Used = true
if strings.TrimSpace(event.Surface) == config.ExternalAgentActivitySurfacePulseMCP {
evidence.MCPAdapterUsed = true
}
evidence.ApplyActivity(event.Activity)
}
return evidence
}
// PulseIntelligenceExternalAgentActivitySurface reports whether a persisted
// activity surface is part of the governed external-agent contract.
func PulseIntelligenceExternalAgentActivitySurface(surface string) bool {
switch strings.TrimSpace(surface) {
case config.ExternalAgentActivitySurfaceAgentAPI, config.ExternalAgentActivitySurfacePulseMCP:
return true
default:
return false
}
}
// ApplyActivity increments the matching content-free external-agent activity
// bucket.
func (e *PulseIntelligenceExternalAgentEvidence) ApplyActivity(activity string) {
if e == nil {
return
}
switch strings.TrimSpace(activity) {
case config.ExternalAgentActivityResourceContext, config.ExternalAgentActivityFleetContext:
e.ContextRequests++
case config.ExternalAgentActivityEventStream:
e.EventStreamRequests++
case config.ExternalAgentActivityProvisioning:
e.ProvisioningRequests++
case config.ExternalAgentActivityOperatorState:
e.OperatorStateRequests++
case config.ExternalAgentActivityFindingList, config.ExternalAgentActivityFindingDecision:
e.FindingRequests++
case config.ExternalAgentActivityActionPlan, config.ExternalAgentActivityActionDecision, config.ExternalAgentActivityActionExecute:
e.ActionRequests++
}
}