From ring-dev-team
Instruments streaming events in a Go service using lib-streaming: wires catalog, builder, emit, outbox, HTTP manifest, and tests via a 13-gate cycle. Consumes instrumentation-map.json from ring:mapping-streaming-events.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ring-dev-team:instrumenting-streaming-eventsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- User requests streaming instrumentation for a Go service with a validated docs/streaming/instrumentation-map.json from ring:mapping-streaming-events
You orchestrate. Agents implement. NEVER use Edit/Write/Bash on Go source files.
All code changes go through Task(subagent_type="ring:backend-go").
TDD mandatory for all implementation gates (RED → GREEN → REFACTOR).
lib-streaming: producer-only event-emission library. Three-step lifecycle:
streaming.NewCatalog(definitions ...EventDefinition) (Catalog, error) — declare every event up-front (immutable)streaming.NewBuilder().Source(...).Catalog(catalog).Routes(...).Target(...).Logger(...).MetricsFactory(...).Tracer(...).CircuitBreakerManager(...).OutboxRepository(...).Build(ctx) — Builder pattern returns (Emitter, error). There is NO NewProducer constructor; *streaming.Producer is reachable only by type-asserting the Emitter returned from Build(ctx), and only when lifecycle methods (Run, RunContext, RegisterOutboxRelay) are needed.emitter.Emit(ctx, EmitRequest{DefinitionKey, TenantID, Subject, Payload}) from handlers/workersThe Emitter interface has THREE methods — Emit(ctx, EmitRequest) error, Close() error, Healthy(ctx) error. Mocks and adapters MUST implement all three.
Wire format: CloudEvents 1.0 binary mode. Each RouteDefinition picks a transport: Kafka (topic lerian.streaming.<resource>.<event>[.vN]), SQS (queue URL), RabbitMQ (exchange + routing key), EventBridge (bus name), or Custom. Tenant carried on ce-tenantid header for CloudEvents-binary transports.
WebFetch URLs (include in every gate dispatch):
https://raw.githubusercontent.com/LerianStudio/lib-streaming/main/doc.gohttps://raw.githubusercontent.com/LerianStudio/lib-streaming/main/AGENTS.mdhttps://raw.githubusercontent.com/LerianStudio/lib-streaming/main/CHANGELOG.mdThree delivery postures:
| Posture | Direct | Outbox | DLQ | Use when |
|---|---|---|---|---|
| CRITICAL | skip | always | on_routable_failure | Loss is correctness/compliance breach |
| IMPORTANT | direct | fallback_on_circuit_open | on_routable_failure | Direct normally; survives broker outage |
| OBSERVATIONAL | direct | never | never | Analytics-grade; loss acceptable |
| CUSTOM | per-event | per-event | per-event | None of the above fits |
Canonical import paths:
| Alias | Import Path | Purpose |
|---|---|---|
streaming | github.com/LerianStudio/lib-streaming | Producer, Emitter, NewCatalog, EventDefinition |
streamingtest | github.com/LerianStudio/lib-streaming/streamingtest | MockEmitter (test-only) |
outbox | github.com/LerianStudio/lib-commons/v5/commons/outbox | Only when Gate 5 active |
Emitter implementations:
| Implementation | When | Construction |
|---|---|---|
*streaming.Producer (returned as Emitter) | STREAMING_ENABLED=true | streaming.NewBuilder().Catalog(catalog).Source(src).Routes(routes...).Target(target).Logger(log).MetricsFactory(mf).Tracer(tr).Build(ctx) |
| NoopEmitter | STREAMING_ENABLED=false | streaming.NewNoopEmitter() |
*streamingtest.MockEmitter | Tests | streamingtest.NewMockEmitter() |
Service code depends on streaming.Emitter INTERFACE. MUST NOT type-assert to *Producer except in bootstrap to wire Run(launcher) / RunContext(ctx, launcher) / RegisterOutboxRelay(registry). All three implementations satisfy the full three-method interface (Emit, Close, Healthy).
Mandatory agent instruction (include in EVERY dispatch):
WebFetch
https://raw.githubusercontent.com/LerianStudio/lib-streaming/main/doc.goandAGENTS.md.docs/streaming/instrumentation-map.jsonis the canonical contract — every EventDefinition, Emit site, DeliveryPolicy MUST match exactly. Tenant fromtmcore.GetTenantIDContext(ctx)— NEVER hardcode. TDD: RED → GREEN → REFACTOR for every gate.
| Gate | Name | Condition | Agent |
|---|---|---|---|
| 0 | Stack Detection + JSON Validation + Compliance Audit | Always | Orchestrator |
| 1 | Codebase Analysis | Always | ring:codebase-explorer |
| 1.5 | Visual Implementation Preview | Always; user must approve | ring:visualizing |
| 2 | lib-streaming Dependency + Non-Canonical Removal | Skip only if lib-streaming pinned AND zero non-canonical detected | ring:backend-go |
| 3 | Catalog Construction + Builder Bootstrap | Always | ring:backend-go |
| 4 | Emit Instrumentation per Eventable Point | Always | ring:backend-go |
| 5 | Outbox Wiring | Required if any event has outbox != "never" | ring:backend-go |
| 6 | Manifest HTTP Mount | Required unless service has zero HTTP surface | ring:backend-go |
| 7 | Wiring + Lifecycle + Backward Compat | Always — NEVER skippable | ring:backend-go |
| 8 | Tests | Always | ring:backend-go |
| 9 | Code Review | Always | 9 defaults + triggered specialists in parallel |
| 10 | User Validation | Always | User |
| 11 | Activation Guide | Always | Orchestrator |
Gates execute sequentially. Gate 5 skip: only if zero events have outbox != "never". Gate 6 skip: only if service has zero HTTP surface (justify in report).
Orchestrator executes directly. Runs 3 phases:
Phase 1: Stack Detection
grep "lib-streaming" go.mod
grep "lib-commons" go.mod
grep -rn "postgresql\|pgx" internal/ go.mod
grep -rn "outbox" go.mod
grep -rn "fiber\|gin\|echo\|net/http" internal/
# Existing lib-streaming code:
grep -rn "streaming.NewBuilder\|streaming.NewCatalog\|streaming.NewNoopEmitter\|streaming.Emitter\|streaming.Producer" internal/
# Non-canonical (must remove):
grep -rn "sarama\|watermill\|segmentio/kafka-go\|amqp091.Publish\|franz-go" internal/
Phase 2: instrumentation-map.json Validation
Read docs/streaming/instrumentation-map.json
Validate: JSON well-formed, required fields present (service_name, events[])
Each event must have: definition_key, resource, event_type, delivery_policy
delivery_policy must have: direct (bool), outbox (enum), dlq (string)
CRITICAL events must have outbox = "always"
Phase 3: Existing Compliance Audit (if lib-streaming code detected)
streaming.NewBuilder()...Build(ctx) — NOT a hand-rolled NewProducer shim.Catalog(catalog) builder method invoked before .Build(ctx).Source(...), .Routes(...), .Target(...) configured (Builder fails fast on missing required wiring)STREAMING_ENABLED feature flag presentcommons.Launcher.Add (or Run/RunContext) lifecycle wiring; Close() on shutdownHealthy(ctx) wired into readiness probeState: docs/ring:instrumenting-streaming-events/current-cycle.json
Write state after EVERY gate. If write fails → STOP.
{
"service_name": "",
"started_at": "",
"gates_completed": [],
"detected": { "lib_streaming_pinned": false, "has_http": false, "outbox_required": false },
"instrumentation_map_path": "docs/streaming/instrumentation-map.json",
"tasks": []
}
| Severity | Criteria |
|---|---|
| CRITICAL | Builder without .Catalog(); CRITICAL event with outbox=never; manifest unauthenticated; pre-commit emission; service code type-asserting *Producer outside bootstrap |
| HIGH | No Launcher.Add / Run / RunContext; no Close(); Healthy() not wired to readiness; non-canonical code present; STREAMING_ENABLED missing; target name with control chars or >256 bytes |
| MEDIUM | Missing .Logger() / .Tracer() / .MetricsFactory() on Builder; no MockEmitter unit tests; no chaos coverage when outbox required |
| LOW | Documentation gaps, missing comments |
npx claudepluginhub p/lerianstudio-ring-dev-team-dev-teamMaps eventable points in a Lerian Go service for lib-streaming event emission. Produces a PM-validated event catalog and instrumentation-map.json via three-pass discovery (Survey, Slice, Mark).
Adopts or references Lerian's lib-streaming Go library for producer-only event publication (Kafka/SQS/RabbitMQ/EventBridge). Sweep mode detects DIY publishers; Reference mode catalogs the Builder/Emitter/Catalog facade.
Builds event-driven APIs with webhooks, Server-Sent Events, message brokers, event schemas, subscribers, retries, and dead-letter queues.