Finding 3 of REVIEW-2026-07-30.md. target_entity_id was accepted as any
non-empty string; the engine only compared it against a pinned TargetEntityID,
which is empty for every registered capability. Spec §4.3: "Hexis never
accepts a free-text target. Ever."
Targets are now checked in order: ent_ shape (free, never touches the
network), pinned target, existence in Nexus, entity still active, and a match
against the capability's TargetTypes. Validation runs before a confirmation is
consumed, so a bad target cannot burn one, and at confirmation-mint time too,
since a confirmation binds a target.
Two deliberate calls:
Nexus unreachable fails closed (503, ErrTargetUnverifiable). Failing open
would reinstate exactly this hole the moment Nexus blips, and hand it to
anyone able to degrade Nexus. Hexis holds no entity table, so "unreachable"
and "I cannot tell if this target is real" are the same statement. The cost is
that executes now require Nexus liveness; the lookup is bounded at 5s so a
hung Nexus fails fast rather than consuming the capability timeout.
An empty TargetTypes means no type constraint, not a bypass — the entity must
still exist, be canonical and be active. Rejecting empty outright would
disable 16 of the 19 registered capabilities, since only the docker.* entries
declare a target type.
The spec's stronger blessing guard is not implementable: Nexus has no blessing
concept at all. This is the achievable guard, and strictly weaker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uea55zaiWuEByEDC4UBSdd
Findings 1 and 2 of REVIEW-2026-07-30.md, which must land together: every
workspace capability registered with enabled=false, so the only working
provider could never execute. Fixing that alone would have turned a dead
execution path into a reachable one on an unauthenticated port.
Auth: a shared bearer token (HEXIS_API_TOKEN) is now required on the whole
/api/v1/ surface, compared with crypto/subtle.ConstantTimeCompare. /health
and /ready stay open for probes. It fails closed twice over — hexisd refuses
to start with an empty token, and the middleware returns 503 rather than ever
serving unauthenticated.
Guards: `enabled` and `requires_confirmation` are no longer readable from the
request body at all. Previously the handler derived the correct §4.3 default
and then let the caller override it, which is worse than no guard because it
reads as enforced. Both are now derived from the risk tier by shared helpers
in domain, used by the HTTP and provider registration paths alike;
unrecognised tiers fail closed to requiring confirmation.
BuildCapabilities sets Enabled, RequiresConfirmation and TimeoutSeconds
explicitly, and hexisd reconciles drifted rows on startup instead of skipping
any capability whose ID already exists — without that, allowlist edits never
reach an existing database.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uea55zaiWuEByEDC4UBSdd
resolve_target previously returned a hardcoded "requires_nexus_resolution"
placeholder; it now calls Nexus's /api/v1/resolve via a new minimal
internal/nexusclient, configurable with -nexus (default localhost:8987).
/api/v1/changes ignored the since query param and always returned from
sequence 0 (`since = 0` regardless of what was parsed) — fixed to actually
parse and use it, so change-cursor polling works.
The MCP hexis.execute tool only forwarded capability_id/target_entity_id/
arguments/idempotency_key, silently dropping entity_version, requested_by,
origin, correlation_id, causation_id, resolution_evidence, and
confirmation_id even though the native HTTP API and domain.ExecuteRequest
already supported all of them — MCP callers now get full parity.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ghELqYhZNLub2TXGMazqA
Go daemon (hexisd/hexisctl) implementing capability registry, guarded
execution (confirmations, blessed-entity checks), systemd/workspace-mcp
providers per ECOSYSTEM-SPEC.md. Snapshotting existing working state
before further development.