{"_id":"@adhd/sox-telemetry","_rev":"5-46f6c01a6a170ea9e0287240549626c5","name":"@adhd/sox-telemetry","dist-tags":{"latest":"0.3.2"},"versions":{"0.2.0":{"name":"@adhd/sox-telemetry","version":"0.2.0","license":"MIT","_id":"@adhd/sox-telemetry@0.2.0","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"278f3796d9e9599b085ab0bce0932743fff2696a","tarball":"https://registry.npmjs.org/@adhd/sox-telemetry/-/sox-telemetry-0.2.0.tgz","fileCount":30,"integrity":"sha512-r9t4dwqtt4g300hQkeA59mJW7qZF8IUTN9dNa5nVC9ryAs9NHZPcuN68hpDn4uRii0l56CXsVR5cxV0N+Vd2Hw==","signatures":[{"sig":"MEUCICdpRouqV1KaGgNkpsFaUKBx8WIE8t+acTC0/QEZ6NXTAiEAji44gsujfu5cVta0+g2OAe77C4yc2XntQTh1S3T4TM4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":139875},"main":"./dist/index.js","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"87f04f7c23a8b340ce4417b3e848d1c22ecc8ac0","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_npmVersion":"11.6.2","description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ulid":"^2.3.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/context-async-hooks":"^2.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sox-telemetry_0.2.0_1785892023828_0.3174855028133057","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@adhd/sox-telemetry","version":"0.2.1","license":"MIT","_id":"@adhd/sox-telemetry@0.2.1","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"dist":{"shasum":"9d592306e06a7ba67f288b86ac1ba514ca7fca9a","tarball":"https://registry.npmjs.org/@adhd/sox-telemetry/-/sox-telemetry-0.2.1.tgz","fileCount":30,"integrity":"sha512-joPql1U0Ua5xyOPeZiuktfn0pAHOrApZLrDVK5yT8P9FEv9ePdUTYKuDOSAh36E1BBHPGS1QIKNiWpmk8sIUEQ==","signatures":[{"sig":"MEUCIQD9wqVRgMd0vGisIH+aQPzLSlk2g0J6JLMshThgITLyTQIgA93xHLrq6v0yx9rgerX3ObQGR3x8ZepB+2doQtK4Ogg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":147714},"main":"./dist/index.js","_from":"file:adhd-sox-telemetry-0.2.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./package.json":"./package.json"},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/6a31e35cdf354d0410a4fdf1fccc913d/adhd-sox-telemetry-0.2.1.tgz","_integrity":"sha512-joPql1U0Ua5xyOPeZiuktfn0pAHOrApZLrDVK5yT8P9FEv9ePdUTYKuDOSAh36E1BBHPGS1QIKNiWpmk8sIUEQ==","_npmVersion":"11.6.2","description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ulid":"^2.3.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/context-async-hooks":"^2.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sox-telemetry_0.2.1_1787113047661_0.08453443646249847","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@adhd/sox-telemetry","version":"0.3.0","keywords":["telemetry","tracing","metrics","otel","typescript"],"license":"MIT","_id":"@adhd/sox-telemetry@0.3.0","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"homepage":"https://github.com/PseudoSky/adhd","bugs":{"url":"https://github.com/PseudoSky/adhd/issues"},"dist":{"shasum":"cd098c4f849fd5377369cba34ad90fae4e014f69","tarball":"https://registry.npmjs.org/@adhd/sox-telemetry/-/sox-telemetry-0.3.0.tgz","fileCount":36,"integrity":"sha512-i+VANrQKQgpZxxpDF/JiG+1jBEpEp8qKYetwQPZARIaTvkNjwNdXlnU21qSlPqsxj59afLGmxWvulpcp7DZv/g==","signatures":[{"sig":"MEUCIQCwvrf2d66KFT4NVOIjpqErhxeIxShQM0kHGZF/9z09wgIgW8p2e0mavveuL8f2YJA96zP9ni5i+vL1JVKDzLMiNHE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD5V5JE/oop46MwOCZ8WjFmQQglIhiWFvvfIvuVmcAFHAIhAPA9G/+0evGRSc/VdqnoPGgE+2PCb8Rw1osq1BBS4P2n","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":188091},"main":"./dist/index.js","_from":"file:adhd-sox-telemetry-0.3.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./package.json":"./package.json"},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/0635900ca1890eb5b6c94404841583b4/adhd-sox-telemetry-0.3.0.tgz","_integrity":"sha512-i+VANrQKQgpZxxpDF/JiG+1jBEpEp8qKYetwQPZARIaTvkNjwNdXlnU21qSlPqsxj59afLGmxWvulpcp7DZv/g==","repository":{"url":"git+https://github.com/PseudoSky/adhd.git","type":"git"},"_npmVersion":"11.6.2","description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ulid":"^2.3.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/context-async-hooks":"^2.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sox-telemetry_0.3.0_1788566548674_0.2865320651598262","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@adhd/sox-telemetry","version":"0.3.1","keywords":["telemetry","tracing","metrics","otel","typescript"],"license":"MIT","_id":"@adhd/sox-telemetry@0.3.1","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"homepage":"https://github.com/PseudoSky/adhd","bugs":{"url":"https://github.com/PseudoSky/adhd/issues"},"dist":{"shasum":"2b68603c733f28a870312a4cdbe1b7161309616d","tarball":"https://registry.npmjs.org/@adhd/sox-telemetry/-/sox-telemetry-0.3.1.tgz","fileCount":36,"integrity":"sha512-YHKgl+KIaYzLDrIhjPWKuL96hV8KGeaml1zvb+LkTbZLbiKcjDXlS6K/5IAq4Oy50YUYm2BO+AMR+Z5ggzapvQ==","signatures":[{"sig":"MEUCIEjDVocSaQJxInvi3kHxz/kDy58wZDg1e2wjR7KtZIMNAiEA+SEV5pMqMeOHdRrmZ0Rn6ocY04KlJnq4AWjHgLLFwpE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCFHHIQex1w+wPP/henX+1kIvF6tdpLFzTkPZ2c8r7AKgIhANS/DlHVnJjPze3N6EHZgj+DeNfkaMhpi0pcJ4M7lE4/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":193898},"main":"./dist/index.js","_from":"file:adhd-sox-telemetry-0.3.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./package.json":"./package.json"},"_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/5c38352df01a85725d60ee23d84cec52/adhd-sox-telemetry-0.3.1.tgz","_integrity":"sha512-YHKgl+KIaYzLDrIhjPWKuL96hV8KGeaml1zvb+LkTbZLbiKcjDXlS6K/5IAq4Oy50YUYm2BO+AMR+Z5ggzapvQ==","repository":{"url":"git+https://github.com/PseudoSky/adhd.git","type":"git"},"_npmVersion":"11.6.2","description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ulid":"^2.3.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/context-async-hooks":"^2.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sox-telemetry_0.3.1_1790105635299_0.2608371290815028","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"_id":"@adhd/sox-telemetry@0.3.2","bugs":{"url":"https://github.com/PseudoSky/adhd/issues"},"dist":{"shasum":"b01d03ce05010f1f5c7382ec56f973e3a8ebfca3","tarball":"https://registry.npmjs.org/@adhd/sox-telemetry/-/sox-telemetry-0.3.2.tgz","fileCount":36,"integrity":"sha512-tJaQtJaHHaYw9KLpKQEJAfEzadh6dBm6ZZeVmr1XwJIKvp4Nu87cTvljHY75ZNFGVmg6SyFBy8SnmaACDCbvZg==","signatures":[{"sig":"MEUCIQDnT/hOqpCXPvGcTgP/vuEzv9mUp3gSK6xrVLjdKmXWyAIgJ76F7uzNb61GXbnWZJUbOQW5vGv+9FLPPeKZqqT7Fp4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAlCIA6b8+SjdFAPg1Z/OG20f8AhNesuA9iIwa8Whev/AiEA3B46CFPt2jbAoImx35BM/wcgW9DvfN4vhDoi+TKuvGw="}],"unpackedSize":196780},"main":"./dist/index.js","name":"@adhd/sox-telemetry","_from":"file:adhd-sox-telemetry-0.3.2.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./package.json":"./package.json"},"license":"MIT","version":"0.3.2","_npmUser":{"name":"pseudosky","email":"skywinston.sk@gmail.com"},"homepage":"https://github.com/PseudoSky/adhd","keywords":["telemetry","tracing","metrics","otel","typescript"],"_resolved":"/private/var/folders/yg/cfczgtx54bzfh74lx2_mv0z80000gp/T/9eb78bf91bdf4bfeac5471e4fac0dc13/adhd-sox-telemetry-0.3.2.tgz","_integrity":"sha512-tJaQtJaHHaYw9KLpKQEJAfEzadh6dBm6ZZeVmr1XwJIKvp4Nu87cTvljHY75ZNFGVmg6SyFBy8SnmaACDCbvZg==","repository":{"url":"git+https://github.com/PseudoSky/adhd.git","type":"git"},"_npmVersion":"11.6.2","description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","directories":{},"maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"_nodeVersion":"24.11.1","dependencies":{"ulid":"^2.3.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/context-async-hooks":"^2.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sox-telemetry_0.3.2_1790391246843_0.710226427008499"}}},"time":{"created":"2026-08-05T01:07:03.600Z","modified":"2026-09-26T02:54:07.119Z","0.2.0":"2026-08-05T01:07:03.990Z","0.2.1":"2026-08-19T04:17:27.820Z","0.3.0":"2026-09-05T00:02:28.768Z","0.3.1":"2026-09-22T19:33:55.393Z","0.3.2":"2026-09-26T02:54:06.937Z"},"bugs":{"url":"https://github.com/PseudoSky/adhd/issues"},"license":"MIT","homepage":"https://github.com/PseudoSky/adhd","keywords":["telemetry","tracing","metrics","otel","typescript"],"repository":{"url":"git+https://github.com/PseudoSky/adhd.git","type":"git"},"description":"Shared tracing/metrics substrate (BL-351): OTel API facade, durable JSONL sink, wait/work primitive, stage self-check. The only package permitted to import @opentelemetry/*.","maintainers":[{"name":"pseudosky","email":"skywinston.sk@gmail.com"}],"readme":"# @adhd/sox-telemetry\n\nA shared tracing/metrics substrate: a durable JSONL log sink, a `log`/`withTimedEvent` API that\nmakes hangs visible (the \"start\" line lands before the work even begins, so a process that never\nreturns is already on disk), a stage catalog for measuring wait-vs-work on contended resources, a\nself-check surface you can poll instead of grepping logs, and an opt-in bridge to the real\nOpenTelemetry SDK. It is the one place in a codebase that should own `@opentelemetry/*` — every\nother package can log/trace through this facade without paying the SDK's load cost unless\n`initTelemetry({ otel: true })` actually asks for it.\n\n```bash\npnpm add @adhd/sox-telemetry\n```\n\n## Quick start\n\n```typescript\nimport { initTelemetry, log, withTimedEvent } from '@adhd/sox-telemetry';\n\nconst handle = initTelemetry({\n  service: 'my-service',\n  role: 'live-service', // required, closed union: 'live-service' | 'test' | 'cli' | 'harness'\n  logDir: './logs',      // defaults to ~/.adhd/sox-ecosystem/<service>/logs\n});\n\nlog.info('startup.begin', { pid: process.pid });\n\nawait withTimedEvent('db.migrate', { table: 'users' }, async () => {\n  // ... do the work; a \"db.migrate.start\" line is already durable on disk\n  // before this callback even runs, so a hang here is visible immediately.\n});\n\nconsole.log('records are landing in', handle.currentLogFilePath());\nawait handle.flush();\nhandle.close();\n```\n\nEvery record — from `log.*`, from `withTimedEvent`, from a stage, from an OTel span — carries\n`service`, `role`, `trace_id`, `pid`, `ts` (ISO-8601), and `level`, stamped once by `initTelemetry`\nrather than per call site. Calling any emitter before `initTelemetry()` is safe: it falls back to a\n`service: 'unlabeled'`, no-op sink rather than throwing, and prints one stderr warning on first use\nso an unwired composition root doesn't fail silently forever.\n\n## API reference\n\n### Initialization\n\n```typescript\nfunction initTelemetry(opts: InitTelemetryOptions): TelemetryHandle;\n\ninterface InitTelemetryOptions {\n  service: string;\n  role: Role;                    // 'live-service' | 'test' | 'cli' | 'harness' — required\n  logSink?: LogSink;              // 'file' (default) | 'stderr' | 'none' — never 'stdout'\n  logDir?: string;                 // default: ~/.adhd/sox-ecosystem/<service>/logs\n  maxBytes?: number;                // size-based log rotation threshold\n  maxFiles?: number;                 // rotated files retained\n  durable?: boolean;                  // writeSync durability, default true\n  otel?: boolean;                       // bring up the real OTel SDK; default on for\n                                         // 'live-service'/'cli', off for 'test'/'harness'\n  snapshotEveryRecords?: number;         // activity-triggered metrics snapshot cadence, default 1000\n}\n\ninterface TelemetryHandle {\n  readonly service: string;\n  readonly role: Role;\n  currentLogFilePath(): string | null; // null means \"no file sink configured\" — the only meaning it has\n  flush(): Promise<void>;              // await any buffered writes\n  otelReady(): Promise<void>;          // resolves once OTel bring-up settles; never rejects\n  close(): void;\n}\n\nfunction currentRuntimeState(): Readonly<{ service: string; role: Role; logSink: LogSink }>;\n\n/** Resolve the role a composition root should actually pass to initTelemetry(),\n *  correcting a structural default toward 'harness' when an out-of-process\n *  integration harness set SOX_TELEMETRY_HARNESS=1 on this process's env. */\nfunction resolveProcessRole(structuralDefault: Role): Role;\n```\n\n### Logging\n\n```typescript\ninterface LogFields { [key: string]: unknown; }\n\nconst log: {\n  debug: (event: string, fields?: LogFields) => void;\n  info: (event: string, fields?: LogFields) => void;\n  warn: (event: string, fields?: LogFields) => void;\n  error: (event: string, fields?: LogFields) => void;\n};\n\n/** Truncate a value for safe, size-bounded logging (SQL text, error messages). */\nfunction truncateForLog(s: string, maxLen?: number): string; // default maxLen 500\n\n/** Log `<event>.start` immediately, run fn, then log `.finish`/`.error` with\n *  an elapsed duration_ms. The start line reaches the sink before fn even runs. */\nfunction withTimedEvent<T>(event: string, fields: LogFields, fn: () => Promise<T>): Promise<T>;\n\n/** Wrap every named method of obj so it emits withTimedEvent automatically,\n *  bound to the real target — `this` inside a wrapped method is never a Proxy. */\nfunction instrumentBoundary<T extends object>(\n  obj: T,\n  opts: { component: string; methods: readonly (keyof T & string)[] },\n): T;\n```\n\n```typescript\nimport { instrumentBoundary } from '@adhd/sox-telemetry';\n\nconst store = instrumentBoundary(rawStore, { component: 'user-store', methods: ['get', 'put'] });\n// store.get(...) / store.put(...) now emit user-store.get.start/finish/error automatically;\n// every other method on rawStore passes through untouched.\n```\n\n### Stages — measuring wait vs. work on a contended resource\n\n```typescript\ninterface StageDeclaration { paths: readonly string[]; }\ntype StageMap = Record<string, StageDeclaration>;\n\nfunction declareStages<T extends StageMap>(pkg: string, stages: T): StageCatalog<T>;\n\nclass StageCatalog<T extends StageMap> {\n  withContendedStage<K extends keyof T & string, R>(\n    stage: K,\n    stagePath: T[K]['paths'][number],\n    admit: () => Promise<void>,\n    work: () => Promise<R>,\n  ): Promise<R>;\n}\n```\n\nDeclaring a stage's code paths up front makes an unwired sibling path a visible finding in\n`telemetrySelfCheck()` (`paths_with_zero_samples`) instead of a metric that silently never fires:\n\n```typescript\nimport { declareStages } from '@adhd/sox-telemetry';\n\nconst stages = declareStages('embed-service', {\n  embed: { paths: ['write', 'heal'] as const },\n});\n\nawait stages.withContendedStage(\n  'embed',\n  'write',\n  async () => { /* acquire a slot/lock — this is the \"wait\" phase */ },\n  async () => { /* do the embedding work — this is the \"work\" phase */ return 'ok'; },\n);\n```\n\n### Self-check\n\n```typescript\nfunction telemetrySelfCheck(): TelemetrySelfCheck;\n\ninterface TelemetrySelfCheck {\n  window: 'since process start';\n  role: Role;\n  stages_declared: number;\n  stages_with_zero_samples: string[];\n  paths_with_zero_samples: string[];\n  stages: StageSelfCheck[];\n  children: ChildrenTelemetrySelfCheck;\n  otel: { state: 'disabled' | 'pending' | 'ready' | 'failed'; spans_enabled: boolean };\n  metric_persistence: { written: number; records_since: number; every_records: number; file: string | null };\n}\n```\n\nA process's own health is a pull, not a log-scrape: `telemetrySelfCheck()` reports whether every\ndeclared stage/path has ever produced a sample, whether spawned children ever initialized telemetry,\nand whether the OTel SDK actually came up — each field distinguishes \"never happened\" from \"not\nasked for\" rather than collapsing both into silence.\n\n### Spans and metrics (OpenTelemetry, opt-in)\n\n```typescript\nfunction withSpan<R>(name: string, attrs: OtelAttributes, fn: (span: OtelSpanHandle) => Promise<R>): Promise<R>;\nfunction otelReady(): Promise<void>;\nfunction snapshotMetrics(reason: 'activity' | 'pull' | 'shutdown' | 'interval'): Promise<void>;\n\ninterface OtelSpanHandle {\n  setAttributes(attrs: OtelAttributes): void;\n  recordError(err: unknown): void;\n}\n```\n\n```typescript\nimport { withSpan } from '@adhd/sox-telemetry';\n\nawait withSpan('checkout.process', { orderId }, async (span) => {\n  span.setAttributes({ itemCount: items.length });\n  // ... do the work; span.recordError(err) on catch if you want it on the span\n});\n```\n\nWhen `initTelemetry({ otel: true })` hasn't been called (or hasn't finished — the SDK loads via a\ndynamic import so it settles a few ms after `initTelemetry` returns), `withSpan` is `fn` plus one\nno-op object — the same call site works whether or not anything is actually collecting spans.\n\n### Trace-id propagation\n\n```typescript\nfunction newTraceId(): string;                       // ulid — sortable, monotonic within a process\nfunction currentTraceId(): string | undefined;\nfunction traceIdOrNew(): string;\nfunction withTrace<T>(traceId: string, fn: () => T): T;\nfunction runWithNewTrace<T>(fn: (traceId: string) => T): T;\n```\n\n```typescript\nimport { runWithNewTrace, log } from '@adhd/sox-telemetry';\n\nrunWithNewTrace((traceId) => {\n  log.info('request.start', { traceId }); // every nested telemetry call in this\n  // continuation (sync or awaited-async) shares the same active trace id.\n});\n```\n\n### The durable sink\n\n```typescript\nclass DurableJsonlSink {\n  constructor(opts: JsonlSinkOptions);\n  currentPath(): string;\n  plannedPath(): string;\n  reconfigure(opts: JsonlSinkOptions): void;\n  flush(): Promise<void>;\n  write(line: string): void;\n  close(): void;\n}\n\ninterface JsonlSinkOptions {\n  dir: string;\n  component: string;      // file-name prefix; role-qualify with '.', e.g. 'my-svc.live', not '-'\n  maxBytes?: number;       // default 20 MB rotation threshold\n  maxFiles?: number;       // default 7 retained\n  durable?: boolean;       // writeSync (true, default) vs. a fire-and-forget stream\n}\n```\n\n`initTelemetry` constructs one of these for you; reach for `DurableJsonlSink` directly only if you\nneed a second, independently-rotated JSONL stream outside the main telemetry record flow. Writes are\nsynchronous (`durable: true`) by default because a fire-and-forget stream loses buffered records on\na hard kill — `write()` returning means the line is already on disk.\n\n### Child processes and worker threads\n\n```typescript\nconst SOX_TELEMETRY_INIT: string; // env var name a parent writes and a child reads\n\nfunction forkChild(modulePath: string, telemetry: InitTelemetryOptions, forkOpts?: ForkOptions): ChildProcess;\nfunction spawnWorker(workerPath: string, telemetry: InitTelemetryOptions, workerOpts?: WorkerOptions): Worker;\nfunction bootstrapChildTelemetry(defaults: InitTelemetryOptions): TelemetryHandle;\nfunction childTelemetrySnapshot(): ChildTelemetrySnapshot;\n\ninterface ChildTelemetrySnapshot {\n  service: string;\n  role: Role;\n  logSink: LogSink;\n  filePath: string | null; // null iff logSink !== 'file'\n  pid: number;\n}\n```\n\n`initTelemetry()` only initializes the calling process's own state — a `node:child_process.fork`'d\nchild or a `worker_threads.Worker` starts with fresh, uninitialized telemetry unless the parent uses\n`forkChild`/`spawnWorker` (which inject `SOX_TELEMETRY_INIT` into the child's env) and the child\ncalls `bootstrapChildTelemetry` at its own entrypoint:\n\n```typescript\n// parent.ts\nimport { forkChild } from '@adhd/sox-telemetry';\nconst child = forkChild('./worker.js', { service: 'my-service', role: 'live-service' });\n\n// worker.js — the child's own composition root\nimport { bootstrapChildTelemetry } from '@adhd/sox-telemetry';\nbootstrapChildTelemetry({ service: 'my-service-worker', role: 'live-service' });\n```\n\nA child that never calls `bootstrapChildTelemetry` shows up as `unacked` in the parent's\n`telemetrySelfCheck().children` rather than silently vanishing.\n\n## Gotchas\n\n- `role` is required and has no default — pass whichever of `'live-service' | 'test' | 'cli' |\n  'harness'` genuinely describes this process. There is no `'stdout'` `LogSink`: writing telemetry\n  to stdout is not offered as an option, because a stray stdout write can corrupt a process's own\n  JSON-RPC/stdio protocol channel.\n- `otel: true` costs real time and memory to bring up (SDK trace/metrics providers +\n  context-manager); it defaults on for `'live-service'`/`'cli'` and off for `'test'`/`'harness'` for\n  that reason. Pass it explicitly to opt a test in.\n- `currentLogFilePath()` and `metric_persistence.file` return `null` for \"no file sink configured\"\n  and a real path otherwise (even before the first write lands) — never `''`. Treat `null` and a\n  string as the only two states.\n- `otelReady()` never rejects, even if OTel bring-up failed — a failed bring-up is reported through\n  `telemetrySelfCheck().otel.state` (`'failed'`) instead, because telemetry must not be able to\n  prevent the service it's observing from starting.\n- `DurableJsonlSink` never throws on a write fault (disk full, fd revoked, directory unwritable) —\n  it drops the record silently rather than propagating, because a logging fault must never break or\n  slow the operation it is observing.\n","readmeFilename":"README.md"}