@capxul/observability 4.20.0-beta.4 → 4.20.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,8 +11,101 @@ Activity action events accept the implemented `unresolved` Payment status in
11
11
  committed filters and export filters. The event records the selected status;
12
12
  it does not infer settlement from an unresolved result.
13
13
 
14
+ ## Where things live
15
+
16
+ `src/index.ts` is the package door (`@capxul/observability`) and re-exports the
17
+ folders below. `src/engineering.ts` is the engineering subpath
18
+ (`@capxul/observability/engineering`): it builds the engineering telemetry Layer
19
+ from `engineering/` and `engineering-delivery.ts`.
20
+
21
+ | Folder | Owns |
22
+ | -------------- | --------------------------------------------------------------------------------------------------------------- |
23
+ | `catalog/` | Event names, journeys, the required envelope, bounded value schemas, every event's schema, CLI vocabularies. |
24
+ | `events/` | Event schemas by domain: identity, onboarding, organizations, money, chain, indexing, workflows, activity, CLI. |
25
+ | `operations/` | Operation names by concept group, composed with the protocol's rows in `operations.ts`. |
26
+ | `telemetry/` | The track handler, redaction before an event leaves the process, and in-process adapters. |
27
+ | `browser/` | Browser PostHog setup, event sanitizing and captured-network masking. |
28
+ | `engineering/` | Engineering logs, metrics and traces: configuration, serialization and the tracer. |
29
+ | `delivery/` | One CLI invocation's engineering delivery: admission, budget, records and export requests. |
30
+
31
+ `packages/tools/src/modules/lint/internal/telemetry-spine/` reads the catalog across `catalog/`,
32
+ `events/`, `telemetry/` and `browser/`, and treats every one of those files as
33
+ naming events rather than producing them.
34
+
35
+ ```text
36
+ src/
37
+ ├── devtools.ts
38
+ ├── engineering-delivery.ts
39
+ ├── engineering.ts
40
+ ├── index.ts
41
+ ├── operations.ts
42
+ ├── telemetry-port.ts
43
+ ├── __tests__/
44
+ │ ├── engineering-delivery.test.ts
45
+ │ ├── devtools.test.ts
46
+ │ ├── engineering.test.ts
47
+ │ ├── operations.test.ts
48
+ │ ├── posthog-browser-privacy.test.ts
49
+ │ └── telemetry.test.ts
50
+ ├── browser/
51
+ │ ├── analytics.ts
52
+ │ ├── network.ts
53
+ │ └── sanitize.ts
54
+ ├── catalog/
55
+ │ ├── cli.ts
56
+ │ ├── envelope.ts
57
+ │ ├── events.ts
58
+ │ ├── journeys.ts
59
+ │ ├── schemas.ts
60
+ │ └── values.ts
61
+ ├── delivery/
62
+ │ ├── admission.ts
63
+ │ ├── budget.ts
64
+ │ ├── records.ts
65
+ │ └── requests.ts
66
+ ├── engineering/
67
+ │ ├── config.ts
68
+ │ ├── logs.ts
69
+ │ ├── metric-points.ts
70
+ │ ├── minimal.ts
71
+ │ ├── serialization.ts
72
+ │ └── tracer.ts
73
+ ├── events/
74
+ │ ├── activity.ts
75
+ │ ├── chain.ts
76
+ │ ├── cli.ts
77
+ │ ├── identity.ts
78
+ │ ├── indexing.ts
79
+ │ ├── money.ts
80
+ │ ├── onboarding.ts
81
+ │ ├── organizations.ts
82
+ │ └── workflows.ts
83
+ ├── operations/
84
+ │ ├── money.ts
85
+ │ ├── organizations.ts
86
+ │ ├── people.ts
87
+ │ ├── platform.ts
88
+ │ └── tree.ts
89
+ └── telemetry/
90
+ ├── adapters.ts
91
+ ├── redaction.ts
92
+ └── track.ts
93
+ ```
94
+
14
95
  ## The required envelope (ADR-0020 A1 amendment)
15
96
 
97
+ The `@capxul/observability/devtools` subpath exports `withDevTools(layer, url)` and
98
+ `validateDevToolsUrl(url)` for local Effect inspection. An omitted URL keeps the
99
+ original layer. An explicit local WebSocket URL adds the native Effect 4
100
+ DevTools connection after the host's services and metric registry are built.
101
+ The connection closes with the host scope. Local spans retain their original
102
+ detail; existing remote exporters keep their own privacy policy. The local
103
+ tracer does not mutate the remote exporter's span methods. Its optional protocol
104
+ loads only when enabled. The separate entry stays out of Convex's static runtime graph.
105
+
106
+ See [the development workflow](../../docs/canon/development-and-verification.md#local-effect-devtools)
107
+ for the editor and agent collector commands.
108
+
16
109
  One PostHog project holds every environment, so `capxul_env` — not project
17
110
  isolation — is what keeps a production surface from reading dev traffic. It is
18
111
  REQUIRED on every catalog event, together with `producer`. Call sites do not
@@ -108,3 +201,6 @@ Set `privacy: "minimal"` for hosts that must export only closed operation/error
108
201
  codes, timings, environment, and validated correlation. This opt-in removes
109
202
  free-form logs, provider messages, URLs, bodies, and source paths, including
110
203
  span exception events. Default consumers retain the existing redaction policy.
204
+ `minimalCorrelationId` is that projection's correlation rule: a host that shows
205
+ a correlation id to a person checks it first, so the id it shows is one the
206
+ export carries.
@@ -0,0 +1,7 @@
1
+ import { Layer } from "effect";
2
+ //#region src/devtools.d.ts
3
+ /** Local inspection is an explicit host choice, independent of remote telemetry. */
4
+ export declare function validateDevToolsUrl(value: string): string;
5
+ /** Acquire after the host layer so traces and metrics use the same context. */
6
+ export declare function withDevTools<R, E, I>(layer: Layer.Layer<R, E, I>, url: string | undefined): Layer.Layer<R, E, I>;
7
+ //#endregion
@@ -0,0 +1,72 @@
1
+ import { Effect, Layer, Tracer } from "effect";
2
+ //#region src/devtools.ts
3
+ /** Local inspection is an explicit host choice, independent of remote telemetry. */
4
+ function validateDevToolsUrl(value) {
5
+ const url = new URL(value);
6
+ if (!["ws:", "wss:"].includes(url.protocol) || ![
7
+ "localhost",
8
+ "127.0.0.1",
9
+ "[::1]",
10
+ "host.docker.internal"
11
+ ].includes(url.hostname) || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") throw new TypeError("devToolsUrl must be a local WebSocket URL without credentials");
12
+ return url.href;
13
+ }
14
+ function localSpan(delegate) {
15
+ const attributes = new Map(delegate.attributes);
16
+ let status = delegate.status;
17
+ return {
18
+ _tag: "Span",
19
+ name: delegate.name,
20
+ spanId: delegate.spanId,
21
+ traceId: delegate.traceId,
22
+ parent: delegate.parent,
23
+ annotations: delegate.annotations,
24
+ sampled: delegate.sampled,
25
+ kind: delegate.kind,
26
+ attributes,
27
+ get status() {
28
+ return status;
29
+ },
30
+ get links() {
31
+ return delegate.links;
32
+ },
33
+ attribute(key, value) {
34
+ attributes.set(key, value);
35
+ delegate.attribute(key, value);
36
+ },
37
+ event(name, time, values) {
38
+ delegate.event(name, time, values);
39
+ },
40
+ addLinks(links) {
41
+ delegate.addLinks(links);
42
+ },
43
+ end(endTime, exit) {
44
+ delegate.end(endTime, exit);
45
+ status = {
46
+ _tag: "Ended",
47
+ startTime: status.startTime,
48
+ endTime,
49
+ exit
50
+ };
51
+ }
52
+ };
53
+ }
54
+ /** Acquire after the host layer so traces and metrics use the same context. */
55
+ function withDevTools(layer, url) {
56
+ if (url === void 0) return layer;
57
+ const endpoint = validateDevToolsUrl(url);
58
+ return Layer.unwrap(Effect.promise(async () => {
59
+ const [{ DevToolsClient }, { Socket }] = await Promise.all([import("effect/devtools"), import("effect/socket")]);
60
+ const client = DevToolsClient.layer.pipe(Layer.provide(Socket.layerWebSocket(endpoint)), Layer.provide(Socket.layerWebSocketConstructorGlobal));
61
+ return Layer.effect(Tracer.Tracer, Effect.gen(function* () {
62
+ const delegate = yield* Effect.tracer;
63
+ const mirror = Tracer.make({
64
+ span: (options) => localSpan(delegate.span(options)),
65
+ ...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
66
+ });
67
+ return yield* DevToolsClient.makeTracer.pipe(Effect.provideService(Tracer.Tracer, mirror));
68
+ })).pipe(Layer.provide(client), Layer.provideMerge(layer));
69
+ }));
70
+ }
71
+ //#endregion
72
+ export { validateDevToolsUrl, withDevTools };
@@ -1,12 +1,13 @@
1
- import { Context, Duration, Effect, Layer, Logger, Metric, References, Tracer } from "effect";
2
- import { HttpClient, HttpClientError } from "effect/unstable/http";
3
- import { OtlpExporter, OtlpSerialization } from "effect/unstable/observability";
4
- //#region src/engineering-delivery.d.ts
1
+ import { Context, Duration, Effect, Layer, Logger, Metric, Tracer } from "effect";
2
+ import { HttpClient } from "effect/http";
3
+ import { OtlpExporter } from "effect/observability";
4
+ //#region src/delivery/budget.d.ts
5
5
  /** Fixed admission limits for one CLI invocation and its SDK client. */
6
- declare const CLI_ENGINEERING_LIMITS: Readonly<{
6
+ export declare const CLI_ENGINEERING_LIMITS: Readonly<{
7
7
  records: 80;
8
8
  ordinaryRecords: 64;
9
9
  recordBytes: 16384;
10
+ recordFields: 48;
10
11
  requests: 5;
11
12
  ordinaryRequests: 2;
12
13
  requestBytes: 1572864;
@@ -28,7 +29,7 @@ interface CliEngineeringStats {
28
29
  readonly metricSeries: number;
29
30
  }
30
31
  /** Shared, closure-owned admission state; no queue or mutable counters are exposed. */
31
- declare function makeCliEngineeringBudget(): Readonly<{
32
+ export declare function makeCliEngineeringBudget(): Readonly<{
32
33
  metricRegistry: Map<string, MetricEntry>;
33
34
  emptyMetricRegistry: () => Map<string, MetricEntry>;
34
35
  drop: () => void;
@@ -38,9 +39,9 @@ declare function makeCliEngineeringBudget(): Readonly<{
38
39
  }>;
39
40
  type CliEngineeringBudget = ReturnType<typeof makeCliEngineeringBudget>;
40
41
  //#endregion
41
- //#region src/engineering.d.ts
42
+ //#region src/engineering/config.d.ts
42
43
  type EngineeringProducer = "browser" | "server";
43
- declare const ENGINEERING_CAPXUL_ENVS: readonly ["development", "staging", "production", "local"];
44
+ export declare const ENGINEERING_CAPXUL_ENVS: readonly ["development", "staging", "production", "local"];
44
45
  type EngineeringCapxulEnv = (typeof ENGINEERING_CAPXUL_ENVS)[number];
45
46
  interface EngineeringTelemetryConfig {
46
47
  readonly host: string;
@@ -58,21 +59,35 @@ interface EngineeringTelemetryConfig {
58
59
  /** CLI-only shared admission and transport lifetime. Omission preserves host defaults. */
59
60
  readonly deliveryBudget?: CliEngineeringBudget;
60
61
  }
61
- declare const traceHeaderFilter: (_name: string) => boolean;
62
- declare const postHogOtlpEndpoints: (host: string) => {
62
+ export declare const traceHeaderFilter: (_name: string) => boolean;
63
+ export declare const postHogOtlpEndpoints: (host: string) => {
63
64
  readonly logs: `${string}/i/v1/logs`;
64
65
  readonly traces: `${string}/i/v1/traces`;
65
66
  readonly metrics: `${string}/i/v1/metrics`;
66
67
  };
67
- /** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
68
- declare const makeLeakSafeEngineeringTracer: (delegate: Tracer.Tracer, enabled?: () => boolean) => Tracer.Tracer;
68
+ //#endregion
69
+ //#region src/engineering/logs.d.ts
69
70
  /** Attempt to drain all engineering signals; completion does not prove ingestion. */
70
- declare const flushEngineeringTelemetry: Effect.Effect<void, never, OtlpExporter.Flusher>;
71
+ export declare const flushEngineeringTelemetry: Effect.Effect<void, never, OtlpExporter.Flusher>;
71
72
  declare const EngineeringLog_base: Context.ServiceClass<EngineeringLog, "capxul/EngineeringLog", Logger.Logger<unknown, void>>;
72
73
  declare class EngineeringLog extends EngineeringLog_base {}
73
74
  /** Deliver an owned engineering record without changing the caller's console verbosity. */
74
- declare const logEngineeringInfo: (message: string, attributes: Readonly<Record<string, unknown>>) => Effect.Effect<void, never, EngineeringLog>;
75
+ export declare const logEngineeringInfo: (message: string, attributes: Readonly<Record<string, unknown>>) => Effect.Effect<void, never, never>;
76
+ //#endregion
77
+ //#region src/engineering/tracer.d.ts
78
+ /** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
79
+ export declare const makeLeakSafeEngineeringTracer: (delegate: Tracer.Tracer, enabled?: () => boolean) => Tracer.Tracer;
80
+ //#endregion
81
+ //#region src/engineering/minimal.d.ts
82
+ /**
83
+ * A correlation id the minimal export carries: an identifier with no `/`, not
84
+ * `0x` hex, and unchanged by the secret mask. The CLI quotes a backend
85
+ * correlation id as its `ref` only when it passes, so the ref finds a row.
86
+ */
87
+ export declare const minimalCorrelationId: (value: unknown) => value is string;
88
+ //#endregion
89
+ //#region src/engineering.d.ts
75
90
  /** Shared browser/server OTLP layer. OtlpLogger merges with incumbent loggers once. */
76
- declare const makeEngineeringTelemetryLayer: (config: EngineeringTelemetryConfig) => Layer.Layer<EngineeringLog | OtlpExporter.Flusher, never, never>;
91
+ export declare const makeEngineeringTelemetryLayer: (config: EngineeringTelemetryConfig) => Layer.Layer<EngineeringLog | OtlpExporter.Flusher, never, never>;
77
92
  //#endregion
78
- export { CLI_ENGINEERING_LIMITS, type CliEngineeringBudget, type CliEngineeringStats, ENGINEERING_CAPXUL_ENVS, EngineeringCapxulEnv, EngineeringProducer, EngineeringTelemetryConfig, flushEngineeringTelemetry, logEngineeringInfo, makeCliEngineeringBudget, makeEngineeringTelemetryLayer, makeLeakSafeEngineeringTracer, postHogOtlpEndpoints, traceHeaderFilter };
93
+ export type { CliEngineeringBudget, CliEngineeringStats, EngineeringCapxulEnv, EngineeringProducer, EngineeringTelemetryConfig };