← Ledger


title: Phase 7b (stratt slice) close — console emits agent.registered for STRATT date: 2026-06-29 status: Accepted phase: 7b (stratt slice) predecessor: docs/decisions/2026-06-29-phase-7b-sniffer-close.md spec: docs/specs/2026-06-29-agent-registration-v1.md plan: docs/plans/2026-06-29-phase-7b-stratt.md

Phase 7b stratt-slice close

Shipped

Locked decisions

1. Lifecycle: agent.registered only

STRATT's routes are registry list/read + one upload. Only the upload maps to a lifecycle event: doctrine entries ARE the agents; upload = registration. Alternatives rejected at plan approval:

Consumer-side dedup is idempotent on agent_id body — re-upload of the same doctrine is a no-op at the projection layer.

2. agent_id = <workspace>-stratt-<doctrine.id>

One agent per doctrine entry. Doctrine id comes from the filename slug in console/src/lib/stratt/registry.ts:163; source-prefixed on collision (e.g. stratt:council). agent_id normalizes any [^a-z0-9-] char to - (dots from foo.bar, colons from stratt:council) to keep the spec regex ^[a-z][a-z0-9-]*-stratt-[a-z0-9-]+$ satisfied. Alternative (coarse <workspace>-stratt-doctrine id per workspace) rejected: hides doctrine identity from the hatch projection.

3. Capabilities: fixed ["stratt.serve_doctrine"]

Doctrine capabilities field in the parsed markdown is a string[] of nouns (frontend, theming, nextjs). The spec's AgentCapabilityVerbSchema regex ^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$ requires <namespace>.<action> verb form; nouns like frontend fail. Registering them prefixed as stratt.frontend was rejected — the noun-per-doctrine mixing would poison the CAPABILITIES column with per-doctrine tags. Fixed verb keeps the registry projection scannable. Doctrine's parsed capability nouns still ride through additively via .passthrough() if future consumers want them.

4. Subsystem assignment: SS-04 WORKSPACE

STRATT registry lifts under SS-04 for the agent projection, mirroring sniffer/council placement. Not yet a discrete SS# in the CLAUDE.md subsystems table; a future SS# split-out would be additive at the projection layer.

5. Header gate consistent with prior slices

x-rocky-workspace required for emission. No header → no agent identity → no event. Existing role-gate (operator/admin) + upload semantics unchanged.

6. Failure paths emit nothing

Deferred

Council-entry agent.registered

No POST surface exists for council upload; existing councils are read-only from vendor/stratt/ or the live STRATT_HQ_PATH checkout. Retroactive registration is explicitly forbidden by the predecessor decision's forward-only projection policy. Councils will land in a future slice if a write surface is added.

agent.revoked on doctrine delete

No delete route exists in /api/stratt/doctrines. When one lands, agent.revoked fires symmetrically.

Polar entitlement check at registration time

tier_floor: "solo" + seats_required: 0 → no-op for this slice. Real check waits for Phase 7c.

Airlock agent.approve verb

approval.required: false. Doctrine upload is operator-curated; no per-upload approval gate. First approval.required: true candidate remains hearth driver (per producer-order from 2026-06-29-agentic-layer-projection.md).

Doctrine-parsed capabilities into capabilities

Doctrine markdown carries a capabilities row (nouns like frontend, theming). Not projected as agent capabilities in v1 because they fail the verb regex. Future v1.x consumers can read them additively from the .passthrough() fields; no schema change required to expose.

Carry-forward to remaining 7b producers

Registered-only lifecycle establishes the projection shape for registry-CRUD producers: identity carriers (registry entries) emit agent.registered on write; no invoked/completed since there is no invocation surface. This is distinct from the sync-producer pattern (RELAY/SNIFFER: triple per request) and the async split-emit pattern (RALPH: submit/cancel/terminal).

Remaining 7b producer: hearth driver (Go producer in hearth/, cross-submodule). Async — reverts to the RALPH split-emit shape (submit + terminal). Then 7b-ralph-2 (terminal observer) and 7c (hatch consumer + Polar RATE column).

Acceptance verified

Sources