opencode-swarm 7.136.5 → 7.137.0

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.
Files changed (75) hide show
  1. package/dist/agents/agent-output-schema.d.ts +2 -2
  2. package/dist/cli/{config-doctor-n3hatm9d.js → config-doctor-vyx82nx2.js} +2 -2
  3. package/dist/cli/{core-jpjk2qvt.js → core-6w5sd5bc.js} +1 -1
  4. package/dist/cli/{curation-policy-c4g08bg1.js → curation-policy-8tvs4pa0.js} +7 -6
  5. package/dist/cli/{curator-jc5cc980.js → curator-43xqs75k.js} +25 -25
  6. package/dist/cli/{curator-llm-factory-atfnhbn6.js → curator-llm-factory-8nywfdsh.js} +25 -25
  7. package/dist/cli/{evidence-summary-service-nse06dqr.js → evidence-summary-service-85gw9p2m.js} +7 -7
  8. package/dist/cli/{gate-evidence-kdygjr56.js → gate-evidence-s2kytsrj.js} +4 -4
  9. package/dist/cli/{guardrail-explain-v6f8efve.js → guardrail-explain-8kkqz8tx.js} +26 -26
  10. package/dist/cli/{guardrail-log-0mrq14g9.js → guardrail-log-e2v9qw71.js} +3 -3
  11. package/dist/cli/{hive-promoter-wyejhz8b.js → hive-promoter-jt9ky0hn.js} +25 -25
  12. package/dist/cli/{index-45y0y3xh.js → index-1zrb3vt2.js} +7 -7
  13. package/dist/cli/{index-d2sf9an1.js → index-5r6kkhd7.js} +4 -4
  14. package/dist/cli/{index-ne28wyyc.js → index-5wjw05dy.js} +2 -2
  15. package/dist/cli/{index-84se71v1.js → index-72wzb81c.js} +3 -3
  16. package/dist/cli/{index-7t3vjw5e.js → index-877ah4kx.js} +1 -1
  17. package/dist/cli/{index-tncy55bp.js → index-8ehyt3rx.js} +1 -1
  18. package/dist/cli/{index-j7ja83v5.js → index-91kk2e9j.js} +1 -1
  19. package/dist/cli/{index-hbzh7yyz.js → index-92v63zzr.js} +55 -55
  20. package/dist/cli/{index-bqan4y2y.js → index-aze9n64z.js} +2 -2
  21. package/dist/cli/{index-tr0ctbhq.js → index-d00q9kpq.js} +5 -5
  22. package/dist/cli/{index-akc6rp3x.js → index-d0nhz96c.js} +2 -2
  23. package/dist/cli/{index-hh34tyv7.js → index-dxatvs3f.js} +1 -1
  24. package/dist/cli/{index-yj61bped.js → index-f24r6yqk.js} +3 -3
  25. package/dist/cli/{index-qhbr4h5n.js → index-fgkhpdc6.js} +6 -6
  26. package/dist/cli/{index-w6j1n5az.js → index-gv00q5gc.js} +1 -1
  27. package/dist/cli/index-h5sbn1zr.js +1670 -0
  28. package/dist/cli/{index-xvcctb2t.js → index-j2ghsdzz.js} +27 -27
  29. package/dist/cli/{index-f5qs217h.js → index-j6ewv2pe.js} +1 -1
  30. package/dist/cli/{index-nfm9f10v.js → index-k3mezk96.js} +1 -1
  31. package/dist/cli/{index-6kd0ezgd.js → index-mg26zd8x.js} +2 -2
  32. package/dist/cli/{index-eeb35dnx.js → index-mwdzkr6k.js} +3 -2
  33. package/dist/cli/{index-b3jfcptk.js → index-n3h6rmbe.js} +1 -1
  34. package/dist/cli/{index-vm05set2.js → index-p124rnwb.js} +4 -4
  35. package/dist/cli/{index-pyz1p8qv.js → index-pcwjz5de.js} +1 -1
  36. package/dist/cli/{index-kym0cctr.js → index-qy3rgmkc.js} +1 -1
  37. package/dist/cli/{index-d61h3f3h.js → index-s3j9fsab.js} +2 -2
  38. package/dist/cli/{index-zzhyws9g.js → index-vft1pg34.js} +1 -1
  39. package/dist/cli/{index-8f4346kf.js → index-wg98bsxz.js} +2 -2
  40. package/dist/cli/{index-xp2pfbpq.js → index-y25nsyaq.js} +1 -1
  41. package/dist/cli/index.js +25 -25
  42. package/dist/cli/{knowledge-escalator-2xe8z24p.js → knowledge-escalator-9k0kbx6b.js} +8 -7
  43. package/dist/cli/{knowledge-events-wecrshsx.js → knowledge-events-8nz3sa2d.js} +6 -5
  44. package/dist/cli/{knowledge-link-zr40rnwr.js → knowledge-link-t94b79qe.js} +5 -4
  45. package/dist/cli/{knowledge-store-9f74whxw.js → knowledge-store-esghe3f9.js} +6 -5
  46. package/dist/cli/{knowledge-validator-4ng7x9dr.js → knowledge-validator-bjxag1jp.js} +9 -8
  47. package/dist/cli/{pending-delegations-0h5b18p7.js → pending-delegations-kshh66s2.js} +3 -3
  48. package/dist/cli/{pr-subscriptions-jn0h047q.js → pr-subscriptions-5fpzz4f3.js} +3 -3
  49. package/dist/cli/{runner-deeswadt.js → runner-d820ws7y.js} +5 -5
  50. package/dist/cli/{scan-cursor-yzj9n225.js → scan-cursor-t212v00f.js} +7 -6
  51. package/dist/cli/{schema-cr1nr1w0.js → schema-11gyrec3.js} +1 -1
  52. package/dist/cli/{scope-persistence-5xc9ntdh.js → scope-persistence-sjz200dt.js} +4 -4
  53. package/dist/cli/{skill-generator-ybncj9et.js → skill-generator-a07hpmw6.js} +10 -9
  54. package/dist/cli/{telemetry-6678gya0.js → telemetry-h7h7f0ez.js} +2 -1
  55. package/dist/cli/{worktree-collision-ownership-wt7cc850.js → worktree-collision-ownership-xzwab4xt.js} +3 -3
  56. package/dist/config/constants.d.ts +1 -1
  57. package/dist/config/evidence-schema.d.ts +103 -103
  58. package/dist/config/plan-schema.d.ts +10 -10
  59. package/dist/config/schema.d.ts +8 -8
  60. package/dist/consensus/contracts.d.ts +3 -3
  61. package/dist/hooks/hive-promoter.d.ts +1 -1
  62. package/dist/index.js +72 -72
  63. package/dist/observability/catalog.d.ts +84 -0
  64. package/dist/observability/envelope.d.ts +401 -0
  65. package/dist/observability/ids.d.ts +97 -0
  66. package/dist/observability/index.d.ts +58 -0
  67. package/dist/observability/legacy.d.ts +68 -0
  68. package/dist/observability/observe.d.ts +112 -0
  69. package/dist/observability/otel-mapping.d.ts +48 -0
  70. package/dist/observability/relationships.d.ts +44 -0
  71. package/dist/observability/sampling.d.ts +77 -0
  72. package/dist/summaries/schema.d.ts +2 -2
  73. package/dist/telemetry.d.ts +4 -1
  74. package/package.json +3 -2
  75. package/dist/cli/index-cze4bq1x.js +0 -358
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The event catalog (issue #2029).
3
+ *
4
+ * Exactly 39 entries, matching the `TelemetryEvent` union at
5
+ * `src/telemetry.ts:15-86`. Thirty-eight of them predate this change; the 39th is
6
+ * `agent_conflict_detected`, which before this change was emitted in
7
+ * production through a force-cast past the type system before this change
8
+ * (at `src/hooks/conflict-resolution.ts:67-70` in the BASE tree; the replacement typed call is
9
+ * `:73` here) and was absent from the union. That
10
+ * 39th entry is the already-found instance of the defect class this contract
11
+ * exists to close: an event kind can enter the stream with no registration.
12
+ *
13
+ * Every entry names a real producer `file:line`, a retention owner issue at or
14
+ * above #2030 — every entry today cites the #2030-#2051 programme, but only the
15
+ * LOWER bound is enforced, so a successor issue numbered past that window is not
16
+ * forced into a false in-window citation — a privacy class, a doc anchor and a
17
+ * test file. An entry with no
18
+ * live reader declares `consumers: []` AND a `futureOwnerIssue` — an empty
19
+ * consumer list without an owner is a contract violation, not a shrug.
20
+ *
21
+ * Import rules: no filesystem, network, subprocess, or OTel SDK.
22
+ */
23
+ import type { EventCategory, EventSeverity, PrivacyClass, WorkflowIdKey } from './envelope.js';
24
+ /** Which external attribute table, if any, an entry projects onto. */
25
+ export type OtelMappingKind = 'genai' | 'openinference' | 'none';
26
+ /** One catalogued event kind. */
27
+ export interface CatalogEntry {
28
+ /** The wire value written as the `event` field. */
29
+ readonly kind: string;
30
+ readonly category: EventCategory;
31
+ readonly severity: EventSeverity;
32
+ readonly privacyClass: PrivacyClass;
33
+ /** Real `file:line` of the emit call that produces this kind. */
34
+ readonly producer: string;
35
+ /**
36
+ * Real `file:line` of each live reader. Empty is permitted ONLY together
37
+ * with {@link futureOwnerIssue}.
38
+ */
39
+ readonly consumers: readonly string[];
40
+ /** Owner issue for a kind that currently has no reader. */
41
+ readonly futureOwnerIssue?: number;
42
+ /**
43
+ * Owner issue for this kind's retention/lifecycle decision. Must be >= #2030;
44
+ * every entry today names the #2030-#2051 programme, but no upper bound is
45
+ * enforced (see `scripts/check-event-contract.ts`).
46
+ */
47
+ readonly retentionOwnerIssue: number;
48
+ /**
49
+ * Correlation IDs the producer GENUINELY always supplies. Conservative by
50
+ * construction: listing an ID the producer sometimes omits would turn a
51
+ * truthful "absent" into a false violation, and listing one nothing
52
+ * populates would make every event of that kind violate.
53
+ */
54
+ readonly requiredWorkflowIds: readonly WorkflowIdKey[];
55
+ /**
56
+ * Correlation IDs this producer genuinely never holds. Presence of one means
57
+ * an ID was manufactured somewhere upstream to make a join succeed — the
58
+ * exact anti-pattern issue #2029 item 2 forbids.
59
+ */
60
+ readonly forbiddenWorkflowIds: readonly WorkflowIdKey[];
61
+ /**
62
+ * Whether an event of this kind must carry `trace.parentSpanId`.
63
+ *
64
+ * `false` for all 39 entries today, and that is a truthful statement about
65
+ * the current system rather than a placeholder: no producer supplies a
66
+ * parent span, so `createObservation` never sets one. Setting this to `true`
67
+ * for a kind whose producer cannot supply a parent would make every
68
+ * production event of that kind violate.
69
+ */
70
+ readonly requiresParent: boolean;
71
+ /** Whether typed span links are meaningful for this kind. */
72
+ readonly allowsLinks: boolean;
73
+ readonly otelMapping: OtelMappingKind;
74
+ /** Anchor in `docs/observability-event-contract.md`. */
75
+ readonly docAnchor: string;
76
+ /** Test that asserts this entry's completeness. */
77
+ readonly testFile: string;
78
+ }
79
+ /** The catalog, keyed by wire event kind. */
80
+ export declare const EVENT_CATALOG: Readonly<Record<string, CatalogEntry>>;
81
+ /** Every catalogued kind, in declaration order. */
82
+ export declare const CATALOG_KINDS: readonly string[];
83
+ /** Own-property catalog lookup. Returns `undefined` for an unknown kind. */
84
+ export declare function getCatalogEntry(kind: string): CatalogEntry | undefined;
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Canonical observability event envelope (issue #2029).
3
+ *
4
+ * These zod schemas are the contract definition. They are used by tests and by
5
+ * the static contract check — NOT on the `emit()` hot path. `createObservation`
6
+ * constructs a plain object and never calls `.parse()`, because parsing would
7
+ * reallocate the envelope on every emit and, critically, would clone or reject
8
+ * `legacy.raw` (see {@link LegacyProjectionSchema}).
9
+ *
10
+ * Import rules: `zod` only. No filesystem, network, subprocess, or OTel SDK.
11
+ */
12
+ import { z } from 'zod';
13
+ /**
14
+ * Version of the envelope shape itself.
15
+ *
16
+ * Deliberately independent of the OTel GenAI / OpenInference mapping versions in
17
+ * `otel-mapping.ts`: external convention churn must never force a change to
18
+ * internal domain state (issue #2029 item 6).
19
+ */
20
+ export declare const OBSERVABILITY_SCHEMA_VERSION = 1;
21
+ /**
22
+ * Coarse event family. `unrecognized` is reserved for the runtime fail-open
23
+ * path: an event kind absent from `EVENT_CATALOG` is classified, never dropped.
24
+ */
25
+ export declare const EventCategorySchema: z.ZodEnum<{
26
+ lifecycle: "lifecycle";
27
+ delegation: "delegation";
28
+ gate: "gate";
29
+ plan: "plan";
30
+ evidence: "evidence";
31
+ guardrail: "guardrail";
32
+ knowledge: "knowledge";
33
+ cost: "cost";
34
+ prm: "prm";
35
+ conflict: "conflict";
36
+ unrecognized: "unrecognized";
37
+ }>;
38
+ export type EventCategory = z.infer<typeof EventCategorySchema>;
39
+ /** Syslog-shaped severity ladder. */
40
+ export declare const EventSeveritySchema: z.ZodEnum<{
41
+ error: "error";
42
+ debug: "debug";
43
+ info: "info";
44
+ notice: "notice";
45
+ warning: "warning";
46
+ critical: "critical";
47
+ }>;
48
+ export type EventSeverity = z.infer<typeof EventSeveritySchema>;
49
+ /**
50
+ * Handling class for the payload an event carries.
51
+ *
52
+ * - `operational` — counters, enums, durations. No identifiers.
53
+ * - `pseudonymous` — session/task/agent identifiers, but no paths or free text.
54
+ * - `sensitive` — filesystem paths or free-text error strings that can embed
55
+ * a path.
56
+ * - `content` — prompts, responses, documents, tool payloads. No event in
57
+ * the current catalog is `content`; the class exists so a
58
+ * future producer cannot enter the stream unclassified.
59
+ */
60
+ export declare const PrivacyClassSchema: z.ZodEnum<{
61
+ operational: "operational";
62
+ pseudonymous: "pseudonymous";
63
+ sensitive: "sensitive";
64
+ content: "content";
65
+ }>;
66
+ export type PrivacyClass = z.infer<typeof PrivacyClassSchema>;
67
+ /**
68
+ * How much trust the recorded time deserves.
69
+ *
70
+ * - `exact` — the producer supplied the instant the thing happened.
71
+ * - `writer-clock` — the time was read by the writer at record time (this is
72
+ * what every current producer does).
73
+ * - `inferred` — reconstructed from surrounding records.
74
+ * - `unknown` — no defensible statement can be made. NOT a synonym for
75
+ * `writer-clock` (issue #2029 item 4: unknown is not zero).
76
+ */
77
+ export declare const TimingConfidenceSchema: z.ZodEnum<{
78
+ unknown: "unknown";
79
+ exact: "exact";
80
+ "writer-clock": "writer-clock";
81
+ inferred: "inferred";
82
+ }>;
83
+ export type TimingConfidence = z.infer<typeof TimingConfidenceSchema>;
84
+ /**
85
+ * A non-parent relationship to another span.
86
+ *
87
+ * `kind` records WHY the link exists, so a consumer can tell a resumed session
88
+ * apart from a parallel lane apart from a retry — a distinction the issue calls
89
+ * out as unrecoverable once flattened into an untyped parent pointer.
90
+ */
91
+ export declare const SpanLinkSchema: z.ZodObject<{
92
+ traceId: z.ZodString;
93
+ spanId: z.ZodString;
94
+ kind: z.ZodEnum<{
95
+ resume: "resume";
96
+ lane: "lane";
97
+ "cross-process": "cross-process";
98
+ retry: "retry";
99
+ "parent-batch": "parent-batch";
100
+ }>;
101
+ note: z.ZodOptional<z.ZodString>;
102
+ }, z.core.$strip>;
103
+ export type SpanLink = z.infer<typeof SpanLinkSchema>;
104
+ /** W3C-compatible trace context plus typed links. */
105
+ export declare const TraceContextSchema: z.ZodObject<{
106
+ traceId: z.ZodString;
107
+ spanId: z.ZodString;
108
+ parentSpanId: z.ZodOptional<z.ZodString>;
109
+ links: z.ZodArray<z.ZodObject<{
110
+ traceId: z.ZodString;
111
+ spanId: z.ZodString;
112
+ kind: z.ZodEnum<{
113
+ resume: "resume";
114
+ lane: "lane";
115
+ "cross-process": "cross-process";
116
+ retry: "retry";
117
+ "parent-batch": "parent-batch";
118
+ }>;
119
+ note: z.ZodOptional<z.ZodString>;
120
+ }, z.core.$strip>>;
121
+ }, z.core.$strip>;
122
+ export type TraceContext = z.infer<typeof TraceContextSchema>;
123
+ /**
124
+ * The correlation identifiers the contract recognizes.
125
+ *
126
+ * All optional by contract. An ID that the producer does not genuinely hold
127
+ * stays `undefined` — never `''`, never synthesized (issue #2029 item 2: never
128
+ * manufacture an ID to make a join succeed).
129
+ *
130
+ * The enumeration is exhaustive on purpose. A producer that needs a correlation
131
+ * axis not listed here must extend this schema and the catalog together, so a
132
+ * new join key cannot enter the stream unregistered.
133
+ */
134
+ export declare const WorkflowIdsSchema: z.ZodObject<{
135
+ rootConversationId: z.ZodOptional<z.ZodString>;
136
+ hostSessionId: z.ZodOptional<z.ZodString>;
137
+ swarmSessionId: z.ZodOptional<z.ZodString>;
138
+ taskId: z.ZodOptional<z.ZodString>;
139
+ phaseId: z.ZodOptional<z.ZodString>;
140
+ laneId: z.ZodOptional<z.ZodString>;
141
+ batchId: z.ZodOptional<z.ZodString>;
142
+ resultId: z.ZodOptional<z.ZodString>;
143
+ councilRoundId: z.ZodOptional<z.ZodString>;
144
+ backgroundInvocationId: z.ZodOptional<z.ZodString>;
145
+ knowledgeTraceId: z.ZodOptional<z.ZodString>;
146
+ knowledgeEntryId: z.ZodOptional<z.ZodString>;
147
+ prRunId: z.ZodOptional<z.ZodString>;
148
+ }, z.core.$strip>;
149
+ export type WorkflowIds = z.infer<typeof WorkflowIdsSchema>;
150
+ /** Key of a recognized correlation identifier. */
151
+ export type WorkflowIdKey = keyof WorkflowIds;
152
+ /**
153
+ * Pseudonymous lineage refs.
154
+ *
155
+ * Every field is a salted, truncated SHA-256 digest produced by
156
+ * `pseudonymousRef` — never a path, never a label. Absent means "the producer
157
+ * did not hold this", not "empty".
158
+ */
159
+ export declare const LineageSchema: z.ZodObject<{
160
+ projectRef: z.ZodOptional<z.ZodString>;
161
+ cohortRef: z.ZodOptional<z.ZodString>;
162
+ worktreeRef: z.ZodOptional<z.ZodString>;
163
+ }, z.core.$strip>;
164
+ export type Lineage = z.infer<typeof LineageSchema>;
165
+ /**
166
+ * Environment facts about the writer.
167
+ *
168
+ * `gitSha` and `configHash` are deliberately left `undefined` by the current
169
+ * initialization path. This is a decision, not an oversight: obtaining a HEAD
170
+ * SHA would require a THIRD init-path subprocess (`ensureSwarmGitExcluded`
171
+ * already runs `git rev-parse --show-toplevel` and `git rev-parse --git-path
172
+ * info/exclude`, neither of which yields a SHA), and AGENTS.md invariant 1
173
+ * forbids adding unbounded Git work before the plugin manifest returns —
174
+ * "bounded is not free". See fix plan W2.
175
+ *
176
+ * Recording them as explicitly missing rather than as `''` or `'unknown'` is the
177
+ * issue's own item-4 rule ("unknown is not zero") applied to ourselves.
178
+ */
179
+ export declare const ProvenanceSchema: z.ZodObject<{
180
+ pluginVersion: z.ZodOptional<z.ZodString>;
181
+ opencodeVersion: z.ZodOptional<z.ZodString>;
182
+ runtime: z.ZodOptional<z.ZodString>;
183
+ runtimeVersion: z.ZodOptional<z.ZodString>;
184
+ os: z.ZodOptional<z.ZodString>;
185
+ arch: z.ZodOptional<z.ZodString>;
186
+ model: z.ZodOptional<z.ZodString>;
187
+ provider: z.ZodOptional<z.ZodString>;
188
+ gitSha: z.ZodOptional<z.ZodString>;
189
+ configHash: z.ZodOptional<z.ZodString>;
190
+ }, z.core.$strip>;
191
+ export type Provenance = z.infer<typeof ProvenanceSchema>;
192
+ /**
193
+ * Terminal disposition, when the producer reported one.
194
+ *
195
+ * `status` absent means the producer said nothing about success or failure.
196
+ * `'unknown'` means the producer DID report a result the contract cannot map —
197
+ * a different fact, kept distinct on purpose.
198
+ */
199
+ export declare const OutcomeSchema: z.ZodObject<{
200
+ status: z.ZodOptional<z.ZodEnum<{
201
+ unknown: "unknown";
202
+ success: "success";
203
+ failure: "failure";
204
+ partial: "partial";
205
+ }>>;
206
+ reason: z.ZodOptional<z.ZodString>;
207
+ errorName: z.ZodOptional<z.ZodString>;
208
+ errorMessage: z.ZodOptional<z.ZodString>;
209
+ retryIndex: z.ZodOptional<z.ZodNumber>;
210
+ durationMs: z.ZodOptional<z.ZodNumber>;
211
+ }, z.core.$strip>;
212
+ export type Outcome = z.infer<typeof OutcomeSchema>;
213
+ /**
214
+ * Sampling and privacy policy stamped on the event.
215
+ *
216
+ * `sampled: false` plus a `dropReason` is how a drop is made observable. A
217
+ * silently discarded event is exactly the failure the issue names.
218
+ */
219
+ export declare const PolicySchema: z.ZodObject<{
220
+ sampled: z.ZodBoolean;
221
+ sampleRate: z.ZodNumber;
222
+ dropReason: z.ZodOptional<z.ZodString>;
223
+ privacyClass: z.ZodEnum<{
224
+ operational: "operational";
225
+ pseudonymous: "pseudonymous";
226
+ sensitive: "sensitive";
227
+ content: "content";
228
+ }>;
229
+ }, z.core.$strip>;
230
+ export type Policy = z.infer<typeof PolicySchema>;
231
+ /**
232
+ * What the legacy adapter could establish about a pre-contract record.
233
+ *
234
+ * ## `raw` is an ALIAS, not a copy
235
+ *
236
+ * `raw` holds a REFERENCE to the caller's payload object. It is never cloned,
237
+ * never `JSON.stringify`-ed, never deep-traversed, and never passed through
238
+ * `.parse()`. Three properties depend on that:
239
+ *
240
+ * 1. **Key order** — the legacy JSONL line spreads the caller's object last,
241
+ * so caller key order is preserved byte-for-byte.
242
+ * 2. **Key collisions** — a caller that supplies its own `timestamp` (see
243
+ * `src/hooks/conflict-resolution.ts:55-66`) must keep winning on value.
244
+ * 3. **`undefined` elision** — `JSON.stringify` drops `undefined`-valued keys.
245
+ * Any clone or parse step would change which keys survive.
246
+ *
247
+ * It is also a hard safety requirement: `src/telemetry.test.ts:137-162` emits
248
+ * circular objects, functions, `Symbol`s and `BigInt`s and asserts `emit()` does
249
+ * not throw. Cloning or serializing `raw` would throw on those payloads.
250
+ *
251
+ * ## `sourceSchemaVersion: null`
252
+ *
253
+ * `null` means "this store does not version its records — the version is
254
+ * UNKNOWN". It does NOT mean version zero. `.swarm/telemetry.jsonl` carries no
255
+ * version field at all; that absence is itself a finding of issue #2029, and
256
+ * recording it as `0` would fabricate a fact the store never stated.
257
+ */
258
+ export declare const LegacyProjectionSchema: z.ZodObject<{
259
+ sourceStore: z.ZodString;
260
+ sourceSchemaVersion: z.ZodNullable<z.ZodNumber>;
261
+ timingConfidence: z.ZodEnum<{
262
+ unknown: "unknown";
263
+ exact: "exact";
264
+ "writer-clock": "writer-clock";
265
+ inferred: "inferred";
266
+ }>;
267
+ unknown: z.ZodArray<z.ZodString>;
268
+ extra: z.ZodRecord<z.ZodString, z.ZodUnknown>;
269
+ raw: z.ZodUnknown;
270
+ }, z.core.$strip>;
271
+ /**
272
+ * `raw` is required on every projection. zod infers a key typed `unknown` as
273
+ * optional (because `undefined extends unknown`), so the required-ness is
274
+ * restated here rather than weakened in the schema.
275
+ */
276
+ export type LegacyProjection = Omit<z.infer<typeof LegacyProjectionSchema>, 'raw' | 'unknown' | 'extra'> & {
277
+ raw: unknown;
278
+ readonly unknown: readonly string[];
279
+ readonly extra: Readonly<Record<string, unknown>>;
280
+ };
281
+ /** The canonical observability event. */
282
+ export declare const ObservabilityEventSchema: z.ZodObject<{
283
+ schemaVersion: z.ZodNumber;
284
+ eventId: z.ZodString;
285
+ kind: z.ZodString;
286
+ category: z.ZodEnum<{
287
+ lifecycle: "lifecycle";
288
+ delegation: "delegation";
289
+ gate: "gate";
290
+ plan: "plan";
291
+ evidence: "evidence";
292
+ guardrail: "guardrail";
293
+ knowledge: "knowledge";
294
+ cost: "cost";
295
+ prm: "prm";
296
+ conflict: "conflict";
297
+ unrecognized: "unrecognized";
298
+ }>;
299
+ severity: z.ZodEnum<{
300
+ error: "error";
301
+ debug: "debug";
302
+ info: "info";
303
+ notice: "notice";
304
+ warning: "warning";
305
+ critical: "critical";
306
+ }>;
307
+ occurredAt: z.ZodString;
308
+ observedAt: z.ZodString;
309
+ writerSequence: z.ZodNumber;
310
+ trace: z.ZodObject<{
311
+ traceId: z.ZodString;
312
+ spanId: z.ZodString;
313
+ parentSpanId: z.ZodOptional<z.ZodString>;
314
+ links: z.ZodArray<z.ZodObject<{
315
+ traceId: z.ZodString;
316
+ spanId: z.ZodString;
317
+ kind: z.ZodEnum<{
318
+ resume: "resume";
319
+ lane: "lane";
320
+ "cross-process": "cross-process";
321
+ retry: "retry";
322
+ "parent-batch": "parent-batch";
323
+ }>;
324
+ note: z.ZodOptional<z.ZodString>;
325
+ }, z.core.$strip>>;
326
+ }, z.core.$strip>;
327
+ workflow: z.ZodObject<{
328
+ rootConversationId: z.ZodOptional<z.ZodString>;
329
+ hostSessionId: z.ZodOptional<z.ZodString>;
330
+ swarmSessionId: z.ZodOptional<z.ZodString>;
331
+ taskId: z.ZodOptional<z.ZodString>;
332
+ phaseId: z.ZodOptional<z.ZodString>;
333
+ laneId: z.ZodOptional<z.ZodString>;
334
+ batchId: z.ZodOptional<z.ZodString>;
335
+ resultId: z.ZodOptional<z.ZodString>;
336
+ councilRoundId: z.ZodOptional<z.ZodString>;
337
+ backgroundInvocationId: z.ZodOptional<z.ZodString>;
338
+ knowledgeTraceId: z.ZodOptional<z.ZodString>;
339
+ knowledgeEntryId: z.ZodOptional<z.ZodString>;
340
+ prRunId: z.ZodOptional<z.ZodString>;
341
+ }, z.core.$strip>;
342
+ lineage: z.ZodObject<{
343
+ projectRef: z.ZodOptional<z.ZodString>;
344
+ cohortRef: z.ZodOptional<z.ZodString>;
345
+ worktreeRef: z.ZodOptional<z.ZodString>;
346
+ }, z.core.$strip>;
347
+ provenance: z.ZodObject<{
348
+ pluginVersion: z.ZodOptional<z.ZodString>;
349
+ opencodeVersion: z.ZodOptional<z.ZodString>;
350
+ runtime: z.ZodOptional<z.ZodString>;
351
+ runtimeVersion: z.ZodOptional<z.ZodString>;
352
+ os: z.ZodOptional<z.ZodString>;
353
+ arch: z.ZodOptional<z.ZodString>;
354
+ model: z.ZodOptional<z.ZodString>;
355
+ provider: z.ZodOptional<z.ZodString>;
356
+ gitSha: z.ZodOptional<z.ZodString>;
357
+ configHash: z.ZodOptional<z.ZodString>;
358
+ }, z.core.$strip>;
359
+ outcome: z.ZodObject<{
360
+ status: z.ZodOptional<z.ZodEnum<{
361
+ unknown: "unknown";
362
+ success: "success";
363
+ failure: "failure";
364
+ partial: "partial";
365
+ }>>;
366
+ reason: z.ZodOptional<z.ZodString>;
367
+ errorName: z.ZodOptional<z.ZodString>;
368
+ errorMessage: z.ZodOptional<z.ZodString>;
369
+ retryIndex: z.ZodOptional<z.ZodNumber>;
370
+ durationMs: z.ZodOptional<z.ZodNumber>;
371
+ }, z.core.$strip>;
372
+ policy: z.ZodObject<{
373
+ sampled: z.ZodBoolean;
374
+ sampleRate: z.ZodNumber;
375
+ dropReason: z.ZodOptional<z.ZodString>;
376
+ privacyClass: z.ZodEnum<{
377
+ operational: "operational";
378
+ pseudonymous: "pseudonymous";
379
+ sensitive: "sensitive";
380
+ content: "content";
381
+ }>;
382
+ }, z.core.$strip>;
383
+ legacy: z.ZodObject<{
384
+ sourceStore: z.ZodString;
385
+ sourceSchemaVersion: z.ZodNullable<z.ZodNumber>;
386
+ timingConfidence: z.ZodEnum<{
387
+ unknown: "unknown";
388
+ exact: "exact";
389
+ "writer-clock": "writer-clock";
390
+ inferred: "inferred";
391
+ }>;
392
+ unknown: z.ZodArray<z.ZodString>;
393
+ extra: z.ZodRecord<z.ZodString, z.ZodUnknown>;
394
+ raw: z.ZodUnknown;
395
+ }, z.core.$strip>;
396
+ relationshipViolations: z.ZodArray<z.ZodString>;
397
+ }, z.core.$strip>;
398
+ /** See {@link LegacyProjection} for why `legacy` is restated. */
399
+ export type ObservabilityEvent = Omit<z.infer<typeof ObservabilityEventSchema>, 'legacy'> & {
400
+ legacy: LegacyProjection;
401
+ };
@@ -0,0 +1,97 @@
1
+ /** Hex width of a W3C `trace-id`. */
2
+ export declare const TRACE_ID_HEX_LENGTH: number;
3
+ /** Hex width of a W3C span id. */
4
+ export declare const SPAN_ID_HEX_LENGTH: number;
5
+ /**
6
+ * Environment variable that overrides the lineage salt.
7
+ *
8
+ * Deliberately NOT read at module scope: reading `process.env` during module
9
+ * evaluation would make the salt depend on import order and would defeat any
10
+ * test that sets it after import. `resolveLineageSalt()` reads it per call.
11
+ */
12
+ export declare const LINEAGE_SALT_ENV = "SWARM_OBSERVABILITY_LINEAGE_SALT";
13
+ /**
14
+ * Salt used when {@link LINEAGE_SALT_ENV} is unset.
15
+ *
16
+ * A constant default is intentional: lineage refs must be stable for a given
17
+ * path across processes and restarts, otherwise `projectRef` could not correlate
18
+ * two runs of the same project. Operators who want cross-install unlinkability
19
+ * set {@link LINEAGE_SALT_ENV} to a private value.
20
+ */
21
+ export declare const DEFAULT_LINEAGE_SALT = "opencode-swarm/observability/lineage/v1";
22
+ /** Hex characters retained from the SHA-256 digest for a lineage ref. */
23
+ export declare const PSEUDONYMOUS_REF_LENGTH = 16;
24
+ /** A correlated `traceId` + `spanId` pair produced from one CSPRNG call. */
25
+ export interface TraceAndSpanId {
26
+ readonly traceId: string;
27
+ readonly spanId: string;
28
+ }
29
+ /**
30
+ * Generate a W3C-compatible trace id: 32 lowercase hex characters, never
31
+ * all-zero.
32
+ *
33
+ * NAME COLLISION, deliberate to record rather than rename: `newTraceId` in
34
+ * `src/hooks/knowledge-events.ts` has the identical `(): string` signature but
35
+ * a DIFFERENT on-wire shape — a 36-character RFC 4122 UUID, not 32 hex
36
+ * characters. Nothing outside this directory imports this one, and it is no
37
+ * longer re-exported from `src/observability/index.ts`, so the two cannot be
38
+ * confused through the barrel. (`newEventId` is unaffected: both return
39
+ * `randomUUID()`.)
40
+ */
41
+ export declare function newTraceId(): string;
42
+ /**
43
+ * Generate a W3C-compatible span id: 16 lowercase hex characters, never
44
+ * all-zero.
45
+ */
46
+ export declare function newSpanId(): string;
47
+ /** Generate an event id (RFC 4122 UUID v4). */
48
+ export declare function newEventId(): string;
49
+ /**
50
+ * Derive a correlated trace/span pair, consuming 24 bytes from the pool above.
51
+ *
52
+ * This exists for the hot path: `createObservation` runs on every `emit()`, and
53
+ * src/telemetry.ts:315-317 documents that path as deliberately frugal.
54
+ */
55
+ export declare function newTraceAndSpanId(): TraceAndSpanId;
56
+ /**
57
+ * Resolve the lineage salt.
58
+ *
59
+ * Reads {@link LINEAGE_SALT_ENV} at call time (never at module scope) and falls
60
+ * back to {@link DEFAULT_LINEAGE_SALT}. Reading an environment variable is not
61
+ * I/O — no file, socket, or subprocess is touched.
62
+ */
63
+ export declare function resolveLineageSalt(): string;
64
+ /**
65
+ * Produce a pseudonymous reference for an absolute path.
66
+ *
67
+ * `sha256(salt + NUL + absolutePath)`, truncated to 16 hex characters.
68
+ *
69
+ * Properties this guarantees, and why each matters (issue #2029 item 2 / AC3):
70
+ * - The result never CONTAINS or ENCODES the input path. It is a one-way
71
+ * digest, not an encoding.
72
+ * - Two different project paths carrying the SAME cohort label produce
73
+ * DIFFERENT refs, because the path is part of the digest input.
74
+ * - The result is stable for a given (salt, path) pair, so the same project
75
+ * correlates across processes and restarts.
76
+ *
77
+ * What it does NOT guarantee, stated plainly rather than overclaimed: this is a
78
+ * PSEUDONYM, not an anonymous value, and it is not "irreversible" in the sense
79
+ * that matters. With the PUBLIC {@link DEFAULT_LINEAGE_SALT} the digest input is
80
+ * fully known except for the path, and real paths are low entropy, so a holder
81
+ * of an export can CONFIRM a guessed path by re-hashing candidates and matching
82
+ * the ref. Setting {@link LINEAGE_SALT_ENV} to a private per-install value
83
+ * restores guess-resistance and makes refs unlinkable across installs. The
84
+ * algorithm is deliberately left alone here: deriving and persisting a
85
+ * per-install salt needs init-path I/O, which AGENTS.md invariant 1 forbids, so
86
+ * it belongs with #2047.
87
+ *
88
+ * SCOPE of the AC3 claim: `cohortRef` and `worktreeRef` are computed only when a
89
+ * caller supplies `cohortLabel` / `worktreeId` to `initObservability`. The sole
90
+ * production caller (`src/index.ts:732-744`) supplies neither, so both are
91
+ * `undefined` in every real run today; AC3 is asserted at unit level against
92
+ * this API, not against a production emission path.
93
+ *
94
+ * @param absolutePath - Value to pseudonymize. Never stored or echoed.
95
+ * @param salt - Salt from {@link resolveLineageSalt}.
96
+ */
97
+ export declare function pseudonymousRef(absolutePath: string, salt: string): string;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The observability event contract (issue #2029).
3
+ *
4
+ * Reference documentation: `docs/observability-event-contract.md`.
5
+ *
6
+ * ## What this module is
7
+ *
8
+ * A versioned, discriminated, catalogued envelope for every observability record
9
+ * this plugin produces, plus the adapter that projects the existing untyped
10
+ * telemetry payloads onto it. The defect class it closes: *a production
11
+ * telemetry record is written without a versioned, discriminated, catalogued
12
+ * envelope — so a consumer cannot determine producer, schema generation, or
13
+ * unknown-versus-absent, and a new event kind can enter the stream without any
14
+ * registration.*
15
+ *
16
+ * ## The guarantees callers can rely on
17
+ *
18
+ * - **Zero I/O.** No filesystem, network, subprocess, dynamic import, or
19
+ * OpenTelemetry SDK anywhere in this directory. `node:crypto` and `zod` are
20
+ * the only imports. That is what keeps `initObservability` safe on the plugin
21
+ * init path (AGENTS.md invariant 1) and the bundle Node-ESM-portable
22
+ * (invariant 2).
23
+ * - **`createObservation` never throws** — not on a circular object, a
24
+ * function/`Symbol`/`BigInt` payload, an unknown kind, or `null` data. It
25
+ * never serializes, clones, or deep-traverses the payload.
26
+ * - **`legacy.raw` is an ALIAS** to the caller's payload, never a copy. Key
27
+ * order, key collisions and `undefined`-key elision in the written line depend
28
+ * on it.
29
+ * - **Nothing is synthesized.** An identifier the producer does not hold stays
30
+ * `undefined`; an unversioned store records `sourceSchemaVersion: null`
31
+ * (unknown, not zero); an absent field is listed in `legacy.unknown` rather
32
+ * than defaulted.
33
+ * - **Validation returns, never throws.** `validateEventRelationships` and
34
+ * `assertBoundedCardinality` both yield verdicts.
35
+ *
36
+ * ## What it is NOT, stated plainly
37
+ *
38
+ * The envelope is not yet authoritative. `toLegacyTelemetryLine` is a
39
+ * deliberately lossy, legacy-pinned projection: the non-legacy fields
40
+ * (`eventId`, `trace`, `lineage`, `provenance`, `policy`, `writerSequence`,
41
+ * `relationshipViolations`) are currently discarded, and their consumer lands in
42
+ * **#2047**. Consequently `validateEventRelationships` does not bite at runtime
43
+ * today — it bites in unit tests and in the static contract check.
44
+ */
45
+ export type { CatalogEntry, OtelMappingKind } from './catalog.js';
46
+ export { CATALOG_KINDS, EVENT_CATALOG, getCatalogEntry, } from './catalog.js';
47
+ export type { Lineage, ObservabilityEvent, Outcome, Policy, Provenance, } from './envelope.js';
48
+ export { OBSERVABILITY_SCHEMA_VERSION, ObservabilityEventSchema, } from './envelope.js';
49
+ export type { TraceAndSpanId } from './ids.js';
50
+ export { newEventId, newSpanId, pseudonymousRef, SPAN_ID_HEX_LENGTH, TRACE_ID_HEX_LENGTH, } from './ids.js';
51
+ export { adaptLegacyTelemetryPayload, extractOutcome, extractWorkflowIds, KNOWN_TELEMETRY_KEYS, LEGACY_ADAPTER_RULES, NON_OBJECT_PAYLOAD_MARKER, } from './legacy.js';
52
+ export type { InitObservabilityInput } from './observe.js';
53
+ export { createObservation, initObservability, resetObservabilityForTesting, toLegacyTelemetryLine, } from './observe.js';
54
+ export { mappingForEntry, OPENINFERENCE_ATTRIBUTES, OPENINFERENCE_MAPPING_VERSION, OTEL_GENAI_ATTRIBUTES, OTEL_GENAI_MAPPING_VERSION, } from './otel-mapping.js';
55
+ export type { RelationshipValidationResult } from './relationships.js';
56
+ export { RELATIONSHIP_VIOLATION_CODES, validateEventRelationships, } from './relationships.js';
57
+ export type { CardinalityResult } from './sampling.js';
58
+ export { assertBoundedCardinality, METRIC_LABEL_ALLOWLIST, shouldSample, } from './sampling.js';