coverage

package
v0.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package coverage is the fleet coverage read model (#413, epic #405): a tenant-scoped PROJECTION over agents, work orders and the asset model that answers, for each (asset, capability), what the coverage verdict is — with unknown/stale/refused/unauthorized/agent-missing kept as distinct states (domain/fleetcoverage) rather than collapsed into "clean". It owns no table. A summary that does not reconcile with its detail is the exact failure this exists to prevent, so the summary is computed from the same rows and a test asserts they reconcile.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentLister

type AgentLister interface {
	ListAgents(ctx context.Context, tenantID shared.ID) ([]*fleetagent.Agent, error)
}

Narrow consumer-side read ports; the memory/Postgres stores satisfy these.

type AgentRow

type AgentRow struct {
	ID           string                    `json:"id"`
	Name         string                    `json:"name"`
	Platform     string                    `json:"platform"`
	Version      string                    `json:"agent_version"`
	Health       fleetcoverage.AgentHealth `json:"state"`
	LastSeen     time.Time                 `json:"last_seen"`
	Capabilities []string                  `json:"capabilities"`
	CurrentWork  int                       `json:"current_work"`
}

AgentRow is one row of the agent-health view.

type AssetLister

type AssetLister interface {
	ListAssets(ctx context.Context, tenantID shared.ID) ([]*asset.Asset, error)
}

Narrow consumer-side read ports; the memory/Postgres stores satisfy these.

type CoverageRow

type CoverageRow struct {
	AssetID    string                `json:"asset_id"`
	Capability string                `json:"capability"`
	Verdict    fleetcoverage.Verdict `json:"verdict"`
	Detail     string                `json:"detail,omitempty"`
	LastRun    time.Time             `json:"last_run"`
	AgentID    string                `json:"agent_id,omitempty"`
}

CoverageRow is one (asset, capability) coverage verdict.

type OrderBrief

type OrderBrief struct {
	ID         string          `json:"id"`
	Capability string          `json:"capability"`
	AssetID    string          `json:"asset_id"`
	State      workorder.State `json:"state"`
	UpdatedAt  time.Time       `json:"updated_at"`
}

OrderBrief is a work order summarised for the agent-detail view.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service computes the coverage read model.

func NewService

func NewService(agents AgentLister, orders WorkOrderLister, assets AssetLister, clock ports.Clock, staleAfter, freshTarget time.Duration) (*Service, error)

NewService validates its dependencies. staleAfter/freshTarget <= 0 disable the respective check.

func (*Service) AgentDetail

func (s *Service) AgentDetail(ctx context.Context, tenantID, agentID shared.ID) (AgentRow, []OrderBrief, error)

AgentDetail returns one agent's health row plus its recent work orders (most recent first). shared.ErrNotFound if the agent does not exist for the tenant.

func (*Service) Agents

func (s *Service) Agents(ctx context.Context, tenantID shared.ID, stateFilter fleetcoverage.AgentHealth) ([]AgentRow, error)

Agents returns the agent-health rows, optionally filtered to a single health state ("" = all).

func (*Service) Coverage

func (s *Service) Coverage(ctx context.Context, tenantID shared.ID) ([]CoverageRow, error)

Coverage returns one row per (asset, capability) that the fleet has attempted (a work order exists), with the resolved verdict. Rows are deterministically ordered.

func (*Service) Summary

func (s *Service) Summary(ctx context.Context, tenantID shared.ID) (Summary, error)

Summary computes the fleet summary from the SAME projection rows, so it reconciles with the detail by construction (RowsByVerdict sums to len(Coverage rows)).

type Summary

type Summary struct {
	AgentsByState       map[fleetcoverage.AgentHealth]int `json:"agents_by_state"`
	RowsByVerdict       map[fleetcoverage.Verdict]int     `json:"rows_by_verdict"`
	OldestPerCapability map[string]time.Time              `json:"oldest_per_capability"`
	AssetsWithoutAgent  int                               `json:"assets_without_agent"`
}

Summary is the fleet coverage summary; AssetsByVerdict counts coverage ROWS per verdict and MUST sum to the number of coverage rows (reconciliation).

type WorkOrderLister

type WorkOrderLister interface {
	ListByTenant(ctx context.Context, tenantID shared.ID) ([]*workorder.WorkOrder, error)
}

Narrow consumer-side read ports; the memory/Postgres stores satisfy these.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL