Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
# OpenTelemetry Instrumentation
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the OpenTelemetry instruments used by `@suaveplan/ecs`. There are two metrics — `ecs.entity.lifecycle_total` (counter) and `ecs.world.execute_duration_ms` (histogram) — plus the helper functions `recordLifecycle` and `recordExecuteDuration` that the world calls from its mutation paths. Instruments are bound to a single meter (`@suaveplan/ecs`) resolved through the global `MeterProvider` at module load.
When no SDK is registered (e.g. plain production deploys without an OTel collector), the OTel API returns a no-op meter and recording is free. When tests register an in-memory `MeterProvider` (`tests/setup/polyfills.ts`), the same instruments emit real data points readable through the test exporter.
## Features
- Single `Counter` (`ecs.entity.lifecycle_total`) keyed by `op ∈ {spawn, despawn}`.
- Single `Histogram` (`ecs.world.execute_duration_ms`) in milliseconds.
- Stable meter name `@suaveplan/ecs` for filtering in dashboards.
- Helper functions wrap `.add` / `.record` so call sites stay terse.
- No SDK dependency at runtime — `@opentelemetry/api` is the only import.
## Usage: Basic Example
```ts
import { recordLifecycle, recordExecuteDuration } from "@suaveplan/ecs";
recordLifecycle("spawn");
recordExecuteDuration(0.42);
```
## Usage: Advanced Example
```ts
import { metrics } from "@opentelemetry/api";
import { MeterProvider, PeriodicExportingMetricReader, InMemoryMetricExporter, AggregationTemporality } from "@opentelemetry/sdk-metrics";
import { createWorld } from "@suaveplan/ecs";
const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 60_000 });
metrics.setGlobalMeterProvider(new MeterProvider({ readers: [reader] }));
const world = createWorld();
world.spawn();
world.execute(0.016);
// later
const snapshots = await /* meterProvider */;
// Inspect the spawn / despawn counter and the execute duration histogram.
```
## API Reference
| Export | Description |
|---|---|
| `entityLifecycleCounter` | Raw `Counter` instrument. Attribute `op ∈ {spawn, despawn}`. |
| `executeDurationHistogram` | Raw `Histogram` instrument; unit `"ms"`. |
| `recordLifecycle(op)` | Increment the counter for a spawn or despawn. |
| `recordExecuteDuration(durationMs)` | Record a single execute-tick duration. |
## Implementation Notes
- The meter is resolved at module load via `metrics.getMeter("@suaveplan/ecs")`. The OTel API guarantees a stable meter reference: when a real SDK is later registered, *previously created* instruments continue to emit through the new provider. This is the documented "no-op-then-bind" pattern.
- The histogram unit is `"ms"`, matching `performance.now()`. The world records the wall-clock difference between the start and end of `execute(dt)`.
- Counter attributes are keyed by `op`, not by code-path, so dashboards can sum spawn + despawn as a single series or split per-op trivially.
- Tests should reset the in-memory exporter between cases (`testInMemoryMetricExporter.reset()`) to avoid cross-test bleed; the package's `world.spec-conformance.test.ts` does this in an `afterEach` hook.
- No spans are created here — the histogram is sufficient for measuring execute duration, and span-creation overhead would dominate the metric it's meant to observe. If consumers want per-system spans, they can wrap `execute` in their own tracer.