4.5 KiB
Why
Section 4 of the test-suite audit (/mnt/s/web/genesis/docs/superpowers/specs/2026-04-25-test-suite-audit.md) flags that observability of the test suite itself is absent: every @suaveplan/* package ships OTel instrumentation via @opentelemetry/api, but there is no fixture that exercises the export path end-to-end and no runner hook that turns each it/test into a span. Today CI can only assert "no SDK registered = no-op"; there is no way to verify that a counter, histogram, or span actually reaches a collector when one is registered. Section 1 of the same audit lists the OpenTelemetry collector as a critical missing service-fixture (alongside OIDC, Mongo, Kafka/NATS).
This change closes both gaps in a single capability: a @suaveplan/testing-integration-otel-collector plugin (a ServiceFixture for otel/opentelemetry-collector-contrib) plus a normative requirement on the testing capability that the runner SHALL emit a span per test, an event per assertion failure, and an event per fixture lifecycle transition when an OTLP endpoint is configured. Failed-test span trees are serialised to playwright-report/traces/ and uploaded to a configured Garage S3 sink — directly addressing audit §4 ("Trace-on-failure exists locally but is not exported anywhere").
What Changes
New plugin package — @suaveplan/testing-integration-otel-collector
- Lives at
packages/testing/testing-integration-otel-collector(mirrors thetesting-integration-*plugin convention fromCLAUDE.md). - Implements the
ServiceFixture<TConfig>interface from@suaveplan/testing-integrationwith imageotel/opentelemetry-collector-contribpinned to a specific minor (digest-pin tracked intasks.md). - Env-bridge:
OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL(http/protobufdefault,grpcopt-in), optionalOTEL_EXPORTER_OTLP_HEADERS. - HTTP healthcheck on
:13133/health/status(port configurable; default timeout 60 s). - Config object
{ receivers: ('otlp-grpc' | 'otlp-http')[]; exporters: ('logging' | 'memory' | 'jaeger' | 'file')[]; configFile?: string }— when noconfigFileis provided the plugin synthesises a minimalotelcol-config.yamlfrom the receivers/exporters lists. - Public helper
getSpans({ filter })queries the in-memory exporter (when configured) and returnsReadableSpan[]for assertion in tests. - Errors prefixed
INTEGRATION.OTEL_COLLECTOR.*; injectablecontainerFactoryandfetchFnfor unit-testability of the fixture itself.
Test-execution OTel export — addition to the testing capability
When OTEL_EXPORTER_OTLP_ENDPOINT is set the test runner SHALL emit one span per it/test (name, status, attributes={ suite, file, retry }), one event per assertion failure (exception.type, exception.message, exception.stacktrace), and one event per fixture lifecycle transition (setup-start, setup-end, teardown-start, teardown-end). Implementation hooks ship at @suaveplan/testing/reporters/otel for both vitest and bun-test. Failed tests serialise their full span tree to playwright-report/traces/<spec>.json and (when TESTING_TRACE_SINK_URL is set) upload that file to the configured Garage S3 bucket.
Capabilities
New Capabilities
testing-integration-otel-collector— aServiceFixturefor the OpenTelemetry collector (image policy, env-bridge, health-check contract, config shape, span-query helper, error code prefix).
Modified Capabilities
testing— adds the Test-execution OTel export requirement (runner emits spans/events for tests and fixture lifecycle, trace-on-failure serialised and uploaded).
Impact
- Affected code: new package at
/mnt/s/web/genesis/packages/testing/testing-integration-otel-collector/**; new reporters at/mnt/s/web/genesis/packages/testing/testing/src/reporters/otel/**. - Affected consumers: every
@suaveplan/*test suite gains span export when the env var is set; zero behaviour change when unset. - Catalog additions (root
package.json): none —@opentelemetry/sdk-node,@opentelemetry/sdk-trace-node, and@opentelemetry/exporter-trace-otlp-httpare added undercatalogs.observabilityonly if not already pinned by@suaveplan/opentelemetry. - Pre-publish gate: plugin package must hit 100% Istanbul coverage (per
openspec/AGENTS.md§7) and pass the standardlint typecheck testsuite before publish. - Cross-cutting: the
testingspec gains a new requirement; folding on archive will append it toopenspec/specs/testing/spec.md.