Files
hexis/internal/domain/capability.go
T
kami 9e6b995538 Remove dead code and three tests that assert nothing
Finding 5 and the "remove" list of REVIEW-2026-07-30.md.

The tests were prose, not verification. TestContract_ChangesSinceAlwaysZero
documented a bug commit 74b19e0 had already fixed and could only t.Logf.
TestContract_TimeoutGoroutineNotCancelled was a bare t.Log, and is now
falsified by the preceding commit anyway.
TestContract_DestructiveCapabilityDisabledByDefault re-implemented
`risk != "destructive"` inside the test and asserted on its own local
variable — it would have passed if the handler were deleted. The real
derivation is now domain.EnabledForRisk and is tested against production code.

Also removed: the systemd provider (no systemctl in the distroless image and
nothing ever registered it), Server.ListenUnix, Registry.List,
DiscoveredTools, Capability.IsDestructive, the ExecutionDenied status,
EventCapabilityUnavailable, ResolveRequest/ResolveResult (superseded by
nexusclient), Engine.emitEvent, and eight unused Err values.

Three items on the review's list were kept, having turned out to be wrong:
ifString is still used by BuildCapabilities; EventExecutionDenied is asserted
on by a real test; and schema_migrations was NOT dropped. migrate() applies
migrations by slice index and writes user_version = index + 1, so removing an
element renumbers every later migration and any database past that point would
permanently skip one it had not yet applied. The live database is far behind
HEAD, so that is a data hazard rather than a cleanup. The CREATE TABLE is now
a no-op holding its slot, with a comment saying why the slot must stay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uea55zaiWuEByEDC4UBSdd
2026-07-30 23:40:04 +04:00

133 lines
5.8 KiB
Go

package domain
import "time"
type ExecuteRequest struct {
CapabilityID string `json:"capability_id"`
TargetEntityID string `json:"target_entity_id"`
EntityVersion int64 `json:"entity_version,omitempty"`
Arguments map[string]any `json:"arguments,omitempty"`
RequestedBy map[string]string `json:"requested_by,omitempty"`
Origin map[string]string `json:"origin,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
CorrelationID string `json:"correlation_id,omitempty"`
CausationID string `json:"causation_id,omitempty"`
ResolutionEvidence []map[string]any `json:"resolution_evidence,omitempty"`
ConfirmationID string `json:"confirmation_id,omitempty"`
}
type Capability struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
TargetTypes []string `json:"target_types"`
TargetEntityID string `json:"target_entity_id,omitempty"`
Provider string `json:"provider"`
Operation string `json:"operation"`
Risk string `json:"risk,omitempty"`
ReadOnly bool `json:"read_only"`
ExpectedSideEffects string `json:"expected_side_effects,omitempty"`
RequiresConfirmation bool `json:"requires_confirmation"`
Enabled bool `json:"enabled"`
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
Attributes map[string]any `json:"attributes,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Version int64 `json:"version"`
}
// Risk tiers. ECOSYSTEM-SPEC.md §4.1 names read/low/protected/destructive; the
// workspace allowlist additionally uses medium/high, which map onto the same
// two guard decisions below.
const (
RiskRead = "read"
RiskLow = "low"
RiskMedium = "medium"
RiskProtected = "protected"
RiskHigh = "high"
RiskDestructive = "destructive"
)
// DefaultCapabilityTimeoutSeconds is the per-capability wall-clock timeout
// applied when a registration does not specify one (ECOSYSTEM-SPEC.md §4.3).
const DefaultCapabilityTimeoutSeconds = 30
// EnabledForRisk reports the server-derived `enabled` value for a risk tier.
// Destructive capabilities are disabled by default and must be turned on
// explicitly out of band (ECOSYSTEM-SPEC.md §4.3). This is never overridable
// by an API caller.
func EnabledForRisk(risk string) bool {
return risk != RiskDestructive
}
// RequiresConfirmationForRisk reports the server-derived
// `requires_confirmation` value for a risk tier. Only genuinely read-only and
// low-risk tiers skip confirmation; unrecognised tiers fail closed.
func RequiresConfirmationForRisk(risk string) bool {
switch risk {
case "", RiskRead, RiskLow:
return false
default:
return true
}
}
type ExecutionStatus string
const (
ExecutionStarted ExecutionStatus = "started"
ExecutionSucceeded ExecutionStatus = "succeeded"
ExecutionFailed ExecutionStatus = "failed"
// ExecutionUnknown marks a wall-clock timeout: the executor may or may not
// have completed the side effect. Never retried automatically.
ExecutionUnknown ExecutionStatus = "unknown"
)
type Execution struct {
// Seq is the storage-assigned, monotonically increasing insertion
// sequence. It is the pagination cursor for GET /api/v1/executions and
// mirrors Event.Sequence on GET /api/v1/changes: pass the last Seq you saw
// back as `since` and the server returns strictly greater rows. Only
// populated by list reads; single-execution reads leave it zero.
Seq int64 `json:"seq,omitempty"`
ID string `json:"id"`
CapabilityID string `json:"capability_id"`
CapabilityVersion int64 `json:"capability_version,omitempty"`
TargetEntityID string `json:"target_entity_id"`
EntityVersion int64 `json:"entity_version,omitempty"`
Arguments map[string]any `json:"arguments,omitempty"`
RequestedBy map[string]string `json:"requested_by,omitempty"`
Origin map[string]string `json:"origin,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
ConfirmationID string `json:"confirmation_id,omitempty"`
Status ExecutionStatus `json:"status"`
Result map[string]any `json:"result,omitempty"`
Error string `json:"error,omitempty"`
ResolutionEvidence []map[string]any `json:"resolution_evidence,omitempty"`
CorrelationID string `json:"correlation_id,omitempty"`
CausationID string `json:"causation_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type HexisEventType string
const (
EventCapabilityRegistered HexisEventType = "hexis.capability.registered"
EventExecutionStarted HexisEventType = "hexis.execution.started"
EventExecutionSucceeded HexisEventType = "hexis.execution.succeeded"
EventExecutionFailed HexisEventType = "hexis.execution.failed"
EventExecutionDenied HexisEventType = "hexis.execution.denied"
)
type Event struct {
ID string `json:"id"`
Sequence int64 `json:"sequence"`
Type HexisEventType `json:"type"`
Timestamp time.Time `json:"timestamp"`
Actor string `json:"actor,omitempty"`
CorrelationID string `json:"correlation_id,omitempty"`
CausationID string `json:"causation_id,omitempty"`
Payload map[string]any `json:"payload,omitempty"`
}