Files
pulse/internal/api/resources_compat.go
T
rcourtman 39f988b220 Remove AI Discovery
AI Discovery ran a separate model-backed service scanner beside Patrol
and the Assistant: its own store, scheduler, model route, API, tool and
drawer UI. No telemetry counter ever measured its use (the telemetry
discovery_enabled flag OR'd it with network subnet discovery), the
maintainer judged it a flop, and the context it produced is already
available to the models through pulse_query, pulse_read and the
unified-resource context sections.

This deletes internal/servicediscovery, internal/ai/infradiscovery, the
pulse_discovery tool, the /api/discovery routes, the mock Discovery
fixtures, the Discovery tabs in the resource, guest, node and Docker host
drawers, the identified-service cards, readiness badges, provenance
markers, suggested web-interface URLs, the Workloads AI Context column,
the chat "Discovery is off" hint and the AI Service Context settings page.
The old settings route redirects to Assistant settings. The model-bound
sanitizer allow-list existed only to pass Discovery context through, so it
goes too, along with the CopyableCodeRow primitive that only the
Discovery tab used.

Network subnet discovery (/api/discover, the Infrastructure discovery
settings) and the discoveryTarget agent coordinates are separate features
and stay. Stored discovery_enabled, discovery_interval_hours and
discovery_model AI settings are ignored on load; the settings API decoder
is lenient, so older frontends saving those fields still succeed.
2026-10-11 22:20:25 +01:00

148 lines
5.2 KiB
Go

package api
import (
"net/http"
"strings"
"github.com/rcourtman/pulse-go-rewrite/internal/actionlifecycle"
"github.com/rcourtman/pulse-go-rewrite/internal/api/resourceapi"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
unified "github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
"github.com/rcourtman/pulse-go-rewrite/pkg/auth"
)
// ResourceHandlers preserves the established router and extension surface
// while composing the resource-query service with API-owned action mutations.
// QueryService owns resource registry construction, durable resource storage,
// filtering, projections, and read handlers. The fields below remain here
// because action lifecycle and operator-state mutations are separate domains.
type ResourceHandlers struct {
resourceapi.QueryService
cfg *config.Config
tenantStateProvider TenantStateProvider
actionExecutor ActionExecutor
actionCompleted func(unified.ActionAuditRecord)
actionTransition func(orgID string, record unified.ActionAuditRecord)
policyAdmission *actionlifecycle.PolicyAdmissionCoordinator
actionEmergencyStop func(orgID string) (bool, error)
actionDecisionAuthorizer actionlifecycle.DecisionAuthorizer
actionExecutionAuthorizer actionlifecycle.ExecutionAuthorizer
actionRefreshPlanner actionlifecycle.RefreshPlanner
operatorStateChanged func(orgID, resourceID string)
}
type SupplementalRecordsProvider = resourceapi.SupplementalRecordsProvider
type TenantSupplementalRecordsProvider = resourceapi.TenantSupplementalRecordsProvider
type SupplementalSnapshotSourceOwner = resourceapi.SupplementalSnapshotSourceOwner
type TenantSupplementalSnapshotSourceOwner = resourceapi.TenantSupplementalSnapshotSourceOwner
type ResourcesResponse = resourceapi.ResourcesResponse
type ResourcesMeta = resourceapi.ResourcesMeta
type StorageSummaryResponse = resourceapi.StorageSummaryResponse
type StorageSummaryIncident = resourceapi.StorageSummaryIncident
type StorageIncidentsResponse = resourceapi.StorageIncidentsResponse
type StorageIncidentSection = resourceapi.StorageIncidentSection
func EmptyResourcesResponse() ResourcesResponse { return resourceapi.EmptyResourcesResponse() }
func EmptyStorageSummaryResponse() StorageSummaryResponse {
return resourceapi.EmptyStorageSummaryResponse()
}
func EmptyStorageIncidentsResponse() StorageIncidentsResponse {
return resourceapi.EmptyStorageIncidentsResponse()
}
// NewResourceHandlers builds the compatibility composition used by Router.
func NewResourceHandlers(cfg *config.Config) *ResourceHandlers {
return &ResourceHandlers{
QueryService: *resourceapi.NewQueryService(cfg),
cfg: cfg,
policyAdmission: &actionlifecycle.PolicyAdmissionCoordinator{},
}
}
func (h *ResourceHandlers) ensureQueryService() *resourceapi.QueryService {
return &h.QueryService
}
func (h *ResourceHandlers) SetStateProvider(provider SnapshotProvider) {
h.ensureQueryService().SetStateProvider(provider)
}
func (h *ResourceHandlers) SetTenantStateProvider(provider TenantStateProvider) {
h.tenantStateProvider = provider
h.ensureQueryService().SetTenantStateProvider(provider)
}
func (h *ResourceHandlers) SetActionExecutor(executor ActionExecutor) {
h.actionExecutor = executor
checker, _ := executor.(actionlifecycle.AvailabilityChecker)
h.ensureQueryService().SetActionAvailabilityChecker(checker)
}
func (h *ResourceHandlers) SetActionEmergencyStopChecker(checker func(orgID string) (bool, error)) {
h.actionEmergencyStop = checker
}
func (h *ResourceHandlers) SetActionAuthorizers(decision actionlifecycle.DecisionAuthorizer, execution actionlifecycle.ExecutionAuthorizer) {
h.actionDecisionAuthorizer = decision
h.actionExecutionAuthorizer = execution
}
func (h *ResourceHandlers) SetActionRefreshPlanner(planner actionlifecycle.RefreshPlanner) {
h.actionRefreshPlanner = planner
}
func (h *ResourceHandlers) SetActionCompletedPublisher(publisher func(unified.ActionAuditRecord)) {
h.actionCompleted = publisher
}
func (h *ResourceHandlers) SetActionTransitionPublisher(publisher func(orgID string, record unified.ActionAuditRecord)) {
h.actionTransition = publisher
}
func (h *ResourceHandlers) SetOperatorStateChanged(callback func(orgID, resourceID string)) {
h.operatorStateChanged = callback
}
func (h *ResourceHandlers) buildRegistry(orgID string) (*unified.ResourceRegistry, error) {
return h.ensureQueryService().BuildRegistry(orgID)
}
func (h *ResourceHandlers) getStore(orgID string) (unified.ResourceStore, error) {
return h.ensureQueryService().Store(orgID)
}
func (h *ResourceHandlers) invalidateCache(orgID string) {
h.ensureQueryService().InvalidateCache(orgID)
}
func (h *ResourceHandlers) CloseTenantStore(orgID string) error {
if h == nil {
return nil
}
return h.QueryService.CloseTenantStore(orgID)
}
func (h *ResourceHandlers) CloseStores() error {
if h == nil {
return nil
}
return h.QueryService.CloseStores()
}
// firstNonEmptyTrimmed is retained for non-resource connection projections.
func firstNonEmptyTrimmed(values ...string) string {
for _, value := range values {
if trimmed := strings.TrimSpace(value); trimmed != "" {
return trimmed
}
}
return ""
}
func getUserID(r *http.Request) string {
return auth.GetUser(r.Context())
}