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.
- package/dist/agents/agent-output-schema.d.ts +2 -2
- package/dist/cli/{config-doctor-n3hatm9d.js → config-doctor-vyx82nx2.js} +2 -2
- package/dist/cli/{core-jpjk2qvt.js → core-6w5sd5bc.js} +1 -1
- package/dist/cli/{curation-policy-c4g08bg1.js → curation-policy-8tvs4pa0.js} +7 -6
- package/dist/cli/{curator-jc5cc980.js → curator-43xqs75k.js} +25 -25
- package/dist/cli/{curator-llm-factory-atfnhbn6.js → curator-llm-factory-8nywfdsh.js} +25 -25
- package/dist/cli/{evidence-summary-service-nse06dqr.js → evidence-summary-service-85gw9p2m.js} +7 -7
- package/dist/cli/{gate-evidence-kdygjr56.js → gate-evidence-s2kytsrj.js} +4 -4
- package/dist/cli/{guardrail-explain-v6f8efve.js → guardrail-explain-8kkqz8tx.js} +26 -26
- package/dist/cli/{guardrail-log-0mrq14g9.js → guardrail-log-e2v9qw71.js} +3 -3
- package/dist/cli/{hive-promoter-wyejhz8b.js → hive-promoter-jt9ky0hn.js} +25 -25
- package/dist/cli/{index-45y0y3xh.js → index-1zrb3vt2.js} +7 -7
- package/dist/cli/{index-d2sf9an1.js → index-5r6kkhd7.js} +4 -4
- package/dist/cli/{index-ne28wyyc.js → index-5wjw05dy.js} +2 -2
- package/dist/cli/{index-84se71v1.js → index-72wzb81c.js} +3 -3
- package/dist/cli/{index-7t3vjw5e.js → index-877ah4kx.js} +1 -1
- package/dist/cli/{index-tncy55bp.js → index-8ehyt3rx.js} +1 -1
- package/dist/cli/{index-j7ja83v5.js → index-91kk2e9j.js} +1 -1
- package/dist/cli/{index-hbzh7yyz.js → index-92v63zzr.js} +55 -55
- package/dist/cli/{index-bqan4y2y.js → index-aze9n64z.js} +2 -2
- package/dist/cli/{index-tr0ctbhq.js → index-d00q9kpq.js} +5 -5
- package/dist/cli/{index-akc6rp3x.js → index-d0nhz96c.js} +2 -2
- package/dist/cli/{index-hh34tyv7.js → index-dxatvs3f.js} +1 -1
- package/dist/cli/{index-yj61bped.js → index-f24r6yqk.js} +3 -3
- package/dist/cli/{index-qhbr4h5n.js → index-fgkhpdc6.js} +6 -6
- package/dist/cli/{index-w6j1n5az.js → index-gv00q5gc.js} +1 -1
- package/dist/cli/index-h5sbn1zr.js +1670 -0
- package/dist/cli/{index-xvcctb2t.js → index-j2ghsdzz.js} +27 -27
- package/dist/cli/{index-f5qs217h.js → index-j6ewv2pe.js} +1 -1
- package/dist/cli/{index-nfm9f10v.js → index-k3mezk96.js} +1 -1
- package/dist/cli/{index-6kd0ezgd.js → index-mg26zd8x.js} +2 -2
- package/dist/cli/{index-eeb35dnx.js → index-mwdzkr6k.js} +3 -2
- package/dist/cli/{index-b3jfcptk.js → index-n3h6rmbe.js} +1 -1
- package/dist/cli/{index-vm05set2.js → index-p124rnwb.js} +4 -4
- package/dist/cli/{index-pyz1p8qv.js → index-pcwjz5de.js} +1 -1
- package/dist/cli/{index-kym0cctr.js → index-qy3rgmkc.js} +1 -1
- package/dist/cli/{index-d61h3f3h.js → index-s3j9fsab.js} +2 -2
- package/dist/cli/{index-zzhyws9g.js → index-vft1pg34.js} +1 -1
- package/dist/cli/{index-8f4346kf.js → index-wg98bsxz.js} +2 -2
- package/dist/cli/{index-xp2pfbpq.js → index-y25nsyaq.js} +1 -1
- package/dist/cli/index.js +25 -25
- package/dist/cli/{knowledge-escalator-2xe8z24p.js → knowledge-escalator-9k0kbx6b.js} +8 -7
- package/dist/cli/{knowledge-events-wecrshsx.js → knowledge-events-8nz3sa2d.js} +6 -5
- package/dist/cli/{knowledge-link-zr40rnwr.js → knowledge-link-t94b79qe.js} +5 -4
- package/dist/cli/{knowledge-store-9f74whxw.js → knowledge-store-esghe3f9.js} +6 -5
- package/dist/cli/{knowledge-validator-4ng7x9dr.js → knowledge-validator-bjxag1jp.js} +9 -8
- package/dist/cli/{pending-delegations-0h5b18p7.js → pending-delegations-kshh66s2.js} +3 -3
- package/dist/cli/{pr-subscriptions-jn0h047q.js → pr-subscriptions-5fpzz4f3.js} +3 -3
- package/dist/cli/{runner-deeswadt.js → runner-d820ws7y.js} +5 -5
- package/dist/cli/{scan-cursor-yzj9n225.js → scan-cursor-t212v00f.js} +7 -6
- package/dist/cli/{schema-cr1nr1w0.js → schema-11gyrec3.js} +1 -1
- package/dist/cli/{scope-persistence-5xc9ntdh.js → scope-persistence-sjz200dt.js} +4 -4
- package/dist/cli/{skill-generator-ybncj9et.js → skill-generator-a07hpmw6.js} +10 -9
- package/dist/cli/{telemetry-6678gya0.js → telemetry-h7h7f0ez.js} +2 -1
- package/dist/cli/{worktree-collision-ownership-wt7cc850.js → worktree-collision-ownership-xzwab4xt.js} +3 -3
- package/dist/config/constants.d.ts +1 -1
- package/dist/config/evidence-schema.d.ts +103 -103
- package/dist/config/plan-schema.d.ts +10 -10
- package/dist/config/schema.d.ts +8 -8
- package/dist/consensus/contracts.d.ts +3 -3
- package/dist/hooks/hive-promoter.d.ts +1 -1
- package/dist/index.js +72 -72
- package/dist/observability/catalog.d.ts +84 -0
- package/dist/observability/envelope.d.ts +401 -0
- package/dist/observability/ids.d.ts +97 -0
- package/dist/observability/index.d.ts +58 -0
- package/dist/observability/legacy.d.ts +68 -0
- package/dist/observability/observe.d.ts +112 -0
- package/dist/observability/otel-mapping.d.ts +48 -0
- package/dist/observability/relationships.d.ts +44 -0
- package/dist/observability/sampling.d.ts +77 -0
- package/dist/summaries/schema.d.ts +2 -2
- package/dist/telemetry.d.ts +4 -1
- package/package.json +3 -2
- package/dist/cli/index-cze4bq1x.js +0 -358
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy telemetry adapter (issue #2029 item 4 / AC2).
|
|
3
|
+
*
|
|
4
|
+
* Its real production input is the untyped `data: Record<string, unknown>` that
|
|
5
|
+
* `src/telemetry.ts:emit()` receives from 40+ call sites: caller-ordered,
|
|
6
|
+
* unversioned, with extra and missing fields. That is legacy-shaped input by
|
|
7
|
+
* definition, and adapting it is this module's genuine job.
|
|
8
|
+
*
|
|
9
|
+
* Two hard constraints govern every function here:
|
|
10
|
+
* 1. **Never throw.** `emit()` documents a never-throw guarantee
|
|
11
|
+
* (`src/telemetry.ts:266,294`) and `src/telemetry.test.ts:137-162`
|
|
12
|
+
* exercises circular objects, functions, `Symbol`s and `BigInt`s.
|
|
13
|
+
* 2. **Never deep-traverse, clone, or serialize the payload.** Only
|
|
14
|
+
* `Object.keys` (shallow) and own-key reads. See `LegacyProjectionSchema`
|
|
15
|
+
* for why `raw` must stay an alias.
|
|
16
|
+
*
|
|
17
|
+
* Import rules: no filesystem, network, subprocess, or OTel SDK.
|
|
18
|
+
*/
|
|
19
|
+
import type { LegacyProjection, Outcome, WorkflowIds } from './envelope.js';
|
|
20
|
+
/** The store these payloads are written to. */
|
|
21
|
+
export declare const LEGACY_TELEMETRY_SOURCE_STORE = ".swarm/telemetry.jsonl";
|
|
22
|
+
/** Marker recorded in `legacy.unknown` when the payload is not an object. */
|
|
23
|
+
export declare const NON_OBJECT_PAYLOAD_MARKER = "<non-object-payload>";
|
|
24
|
+
/**
|
|
25
|
+
* Marker recorded when the payload resisted shallow introspection — a Proxy
|
|
26
|
+
* whose `ownKeys` trap throws, or a throwing getter. The payload is still kept
|
|
27
|
+
* by reference; only our description of it is degraded.
|
|
28
|
+
*/
|
|
29
|
+
export declare const INTROSPECTION_FAILED_MARKER = "<payload-introspection-failed>";
|
|
30
|
+
/**
|
|
31
|
+
* The adapter rules, stated as a checkable list.
|
|
32
|
+
*
|
|
33
|
+
* These are the item-4 rules of issue #2029. They are exported as data (not
|
|
34
|
+
* prose in a doc file) so the static contract check and the unit tests can
|
|
35
|
+
* assert against the same statement of intent the implementation follows.
|
|
36
|
+
*/
|
|
37
|
+
export declare const LEGACY_ADAPTER_RULES: readonly string[];
|
|
38
|
+
/**
|
|
39
|
+
* Payload keys each producer is known to emit.
|
|
40
|
+
*
|
|
41
|
+
* Derived from the emit call sites in source, NOT from captured output: a key
|
|
42
|
+
* whose value is `undefined` is elided by `JSON.stringify`, so a captured line
|
|
43
|
+
* under-reports the producer's key set. Listing those keys here is precisely
|
|
44
|
+
* what makes `legacy.unknown` non-vacuous — `delegation_end` naming `model`,
|
|
45
|
+
* `gate` and `retry_index` lets the adapter say "the producer did not know
|
|
46
|
+
* these" instead of silently omitting them.
|
|
47
|
+
*/
|
|
48
|
+
export declare const KNOWN_TELEMETRY_KEYS: Readonly<Record<string, readonly string[]>>;
|
|
49
|
+
export declare function adaptLegacyTelemetryPayload(kind: string, data: unknown, knownKeys: readonly string[]): LegacyProjection;
|
|
50
|
+
/**
|
|
51
|
+
* Extract recognized correlation IDs from a legacy payload.
|
|
52
|
+
*
|
|
53
|
+
* Shallow, never throws, and NEVER synthesizes: an ID that is absent, empty, or
|
|
54
|
+
* of the wrong type stays `undefined`. Only the mappings a producer actually
|
|
55
|
+
* populates are implemented — `sessionId` to `hostSessionId`, `taskId`, `phase`
|
|
56
|
+
* to `phaseId`, `laneId`, `batchId`. The remaining eight recognized IDs have no
|
|
57
|
+
* current producer, and inventing an extraction for them would manufacture
|
|
58
|
+
* exactly the joins issue #2029 item 2 forbids.
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractWorkflowIds(data: unknown): WorkflowIds;
|
|
61
|
+
/**
|
|
62
|
+
* Extract terminal disposition from a legacy payload.
|
|
63
|
+
*
|
|
64
|
+
* Shallow and never throws. `durationMs` is deliberately never populated: no
|
|
65
|
+
* current producer reports a duration, and deriving one would fabricate a
|
|
66
|
+
* measurement.
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractOutcome(data: unknown): Outcome;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation construction and the legacy line projection (issue #2029).
|
|
3
|
+
*
|
|
4
|
+
* Import rules: no filesystem, network, subprocess, or OTel SDK. Everything here
|
|
5
|
+
* is synchronous and allocation-only.
|
|
6
|
+
*
|
|
7
|
+
* ## Module state
|
|
8
|
+
*
|
|
9
|
+
* Four process-scoped variables. None is session-keyed, so AGENTS.md invariant 8
|
|
10
|
+
* (session-scoped state must be keyed by `sessionID` and bounded) does not
|
|
11
|
+
* apply: `_provenance` and `_lineage` are single small frozen-by-convention
|
|
12
|
+
* records describing THIS process, `_sampleRate` is a scalar, and
|
|
13
|
+
* `_writerSequence` is a scalar counter. None of them grows with session count,
|
|
14
|
+
* so there is nothing to evict. All four have a reset seam
|
|
15
|
+
* ({@link resetObservabilityForTesting}) so no test's assertions become order
|
|
16
|
+
* dependent.
|
|
17
|
+
*/
|
|
18
|
+
import { type ObservabilityEvent, type Provenance } from './envelope.js';
|
|
19
|
+
/** Violation code stamped on a fallback event. */
|
|
20
|
+
export declare const OBSERVATION_BUILD_FAILED = "observation_build_failed";
|
|
21
|
+
/** Input to {@link initObservability}. */
|
|
22
|
+
export interface InitObservabilityInput {
|
|
23
|
+
/** Absolute project root. Pseudonymized, never stored. */
|
|
24
|
+
directory?: string;
|
|
25
|
+
/** Cohort label (e.g. a swarm id). Pseudonymized together with `directory`. */
|
|
26
|
+
cohortLabel?: string;
|
|
27
|
+
/** Worktree identity. Pseudonymized, never stored. */
|
|
28
|
+
worktreeId?: string;
|
|
29
|
+
provenance?: Provenance;
|
|
30
|
+
sampleRate?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Install process provenance and lineage.
|
|
34
|
+
*
|
|
35
|
+
* Performs ZERO I/O — it hashes strings the caller already holds. That matters
|
|
36
|
+
* for AGENTS.md invariant 1: this runs on the plugin init path, and init-path
|
|
37
|
+
* work must be fast, bounded and side-effect-minimal.
|
|
38
|
+
*
|
|
39
|
+
* Lineage refs are computed ONCE here and reused by every subsequent
|
|
40
|
+
* observation. Computing them per-emit would put three SHA-256 digests on the
|
|
41
|
+
* hot path for values that never change within a process.
|
|
42
|
+
*
|
|
43
|
+
* NEVER THROWS. The whole body is guarded: a failure here must not prevent the
|
|
44
|
+
* plugin manifest from being returned (invariant 1, fail-open).
|
|
45
|
+
*/
|
|
46
|
+
export declare function initObservability(input: InitObservabilityInput): void;
|
|
47
|
+
/**
|
|
48
|
+
* Build the canonical observation for one emit.
|
|
49
|
+
*
|
|
50
|
+
* **NEVER THROWS.** Not on a circular object, not on a function / `Symbol` /
|
|
51
|
+
* `BigInt` payload, not on an unknown kind, not on `null` or `undefined` data.
|
|
52
|
+
* It never calls `JSON.stringify`, never clones, and never deep-traverses
|
|
53
|
+
* `data` — `src/telemetry.test.ts:137-162` emits exactly those payloads and
|
|
54
|
+
* asserts `emit()` does not throw, and `src/telemetry.ts:266` documents the
|
|
55
|
+
* never-throw guarantee. If anything inside fails, a minimal valid event is
|
|
56
|
+
* returned carrying `relationshipViolations: ['observation_build_failed']`.
|
|
57
|
+
*
|
|
58
|
+
* An UNCATALOGUED kind is classified (`category: 'unrecognized'`), never
|
|
59
|
+
* dropped. Preventing new unrecognized kinds is the static contract check's job,
|
|
60
|
+
* not a runtime drop.
|
|
61
|
+
*
|
|
62
|
+
* `occurredAt` is set equal to `observedAt`. That is a recorded finding, not an
|
|
63
|
+
* invention: no current producer supplies a distinct time at which the described
|
|
64
|
+
* thing happened, so claiming one would fabricate precision the source does not
|
|
65
|
+
* have.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createObservation(kind: string, data: unknown): ObservabilityEvent;
|
|
68
|
+
/**
|
|
69
|
+
* Project a canonical event onto the legacy `.swarm/telemetry.jsonl` record.
|
|
70
|
+
*
|
|
71
|
+
* ## This projection is LOSSY and LEGACY-PINNED
|
|
72
|
+
*
|
|
73
|
+
* The envelope's non-legacy fields — `eventId`, `trace` (`traceId`, `spanId`,
|
|
74
|
+
* `parentSpanId`, `links`), `lineage`, `provenance`, `policy`, `writerSequence`,
|
|
75
|
+
* `schemaVersion` and `relationshipViolations` — are **currently DISCARDED**.
|
|
76
|
+
* Nothing in this change consumes them; their consumer lands in **#2047**. That
|
|
77
|
+
* is stated here rather than buried: a reader of this function must not conclude
|
|
78
|
+
* the written line is the canonical record. It is not.
|
|
79
|
+
*
|
|
80
|
+
* ## Byte-for-byte preservation
|
|
81
|
+
*
|
|
82
|
+
* The caller's object is spread **LAST**, exactly as the pre-change inline line
|
|
83
|
+
* construction in `src/telemetry.ts` `emit()` did. Three properties depend on
|
|
84
|
+
* that ordering, and all three are observable in
|
|
85
|
+
* `tests/fixtures/observability/telemetry-lines-golden.json` (issue #2029 item
|
|
86
|
+
* 5 arm (a) — "preserve the existing output"):
|
|
87
|
+
*
|
|
88
|
+
* 1. **Caller key order** is preserved after `timestamp` and `event`.
|
|
89
|
+
* 2. **Caller key collisions win on value.** `conflict-resolution.ts:55-66`
|
|
90
|
+
* supplies its own `timestamp` and `type`; the caller's `timestamp` value
|
|
91
|
+
* overwrites the envelope's while the key keeps position 1.
|
|
92
|
+
* 3. **`undefined`-key elision** is unchanged, because the caller's own object
|
|
93
|
+
* is spread rather than a reconstruction of it.
|
|
94
|
+
*
|
|
95
|
+
* `timestamp` is taken from `event.observedAt` — a real, load-bearing data
|
|
96
|
+
* dependency on the canonical event, which is why this composition is not the
|
|
97
|
+
* identity function on the emit path.
|
|
98
|
+
*
|
|
99
|
+
* A non-object, `null`, or array payload yields just `{ timestamp, event }`,
|
|
100
|
+
* matching what `JSON.stringify({ timestamp, event, ...data })` produces for
|
|
101
|
+
* those inputs.
|
|
102
|
+
*/
|
|
103
|
+
export declare function toLegacyTelemetryLine(event: ObservabilityEvent): Record<string, unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* Reset all four module-scoped variables.
|
|
106
|
+
*
|
|
107
|
+
* Called alongside `resetTelemetryForTesting` so no test's assertions become
|
|
108
|
+
* dependent on how many events an earlier test emitted.
|
|
109
|
+
*
|
|
110
|
+
* @internal - For testing only
|
|
111
|
+
*/
|
|
112
|
+
export declare function resetObservabilityForTesting(): void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External-convention attribute mappings (issue #2029 item 6).
|
|
3
|
+
*
|
|
4
|
+
* These are INERT LOOKUP TABLES. There is no OpenTelemetry SDK dependency, no
|
|
5
|
+
* exporter, and no runtime consumer in this change: the tables are consumed as
|
|
6
|
+
* data by the static contract check (which asserts every catalog entry records a
|
|
7
|
+
* mapping decision) and by `docs/observability-event-contract.md`. The runtime
|
|
8
|
+
* consumer lands in #2049.
|
|
9
|
+
*
|
|
10
|
+
* Import rules: no filesystem, network, subprocess, or OTel SDK.
|
|
11
|
+
*/
|
|
12
|
+
import type { OtelMappingKind } from './catalog.js';
|
|
13
|
+
/**
|
|
14
|
+
* OpenTelemetry semantic-convention generation these GenAI attribute names track.
|
|
15
|
+
*
|
|
16
|
+
* Pinned SEPARATELY from `OBSERVABILITY_SCHEMA_VERSION`. That separation is the
|
|
17
|
+
* whole point of issue #2029 item 6: the GenAI conventions are an external,
|
|
18
|
+
* still-unstable vocabulary. If they were versioned together, an upstream rename
|
|
19
|
+
* would force a bump of the internal envelope version and every consumer would
|
|
20
|
+
* be told the domain shape changed when nothing about the domain changed.
|
|
21
|
+
* External convention churn must never change internal domain state.
|
|
22
|
+
*/
|
|
23
|
+
export declare const OTEL_GENAI_MAPPING_VERSION = "1.29.0";
|
|
24
|
+
/**
|
|
25
|
+
* OpenInference specification generation these attribute names track. Pinned
|
|
26
|
+
* separately from both {@link OTEL_GENAI_MAPPING_VERSION} and
|
|
27
|
+
* `OBSERVABILITY_SCHEMA_VERSION`, for the same reason.
|
|
28
|
+
*/
|
|
29
|
+
export declare const OPENINFERENCE_MAPPING_VERSION = "0.1.14";
|
|
30
|
+
/**
|
|
31
|
+
* Internal envelope path to OTel GenAI attribute name.
|
|
32
|
+
*
|
|
33
|
+
* Keys are dotted paths into `ObservabilityEvent`. `legacy.raw.*` paths reach
|
|
34
|
+
* into the aliased producer payload, which is where token counts and the
|
|
35
|
+
* resolved model live today.
|
|
36
|
+
*/
|
|
37
|
+
export declare const OTEL_GENAI_ATTRIBUTES: Readonly<Record<string, string>>;
|
|
38
|
+
/** Internal envelope path to OpenInference attribute name. */
|
|
39
|
+
export declare const OPENINFERENCE_ATTRIBUTES: Readonly<Record<string, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the attribute table a catalog entry projects onto.
|
|
42
|
+
*
|
|
43
|
+
* `'none'` is a real, recorded decision — "this kind has no external
|
|
44
|
+
* equivalent" — not a missing value. It returns an empty table, never
|
|
45
|
+
* `undefined`, so a consumer never has to distinguish "no mapping" from "not
|
|
46
|
+
* asked".
|
|
47
|
+
*/
|
|
48
|
+
export declare function mappingForEntry(mapping: OtelMappingKind): Readonly<Record<string, string>>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ObservabilityEvent } from './envelope.js';
|
|
2
|
+
/** Verdict from {@link validateEventRelationships}. */
|
|
3
|
+
export type RelationshipValidationResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
violations: string[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Stable violation codes.
|
|
11
|
+
*
|
|
12
|
+
* Codes are machine-readable and must not be renamed once emitted — they are the
|
|
13
|
+
* join key a downstream consumer will group on. The suffix after `:` is the
|
|
14
|
+
* offending identifier or link index.
|
|
15
|
+
*/
|
|
16
|
+
export declare const RELATIONSHIP_VIOLATION_CODES: Readonly<{
|
|
17
|
+
unknownKind: "unknown_kind";
|
|
18
|
+
requiredWorkflowIdMissing: "required_workflow_id_missing";
|
|
19
|
+
forbiddenWorkflowIdPresent: "forbidden_workflow_id_present";
|
|
20
|
+
parentSpanNotAllowed: "parent_span_not_allowed";
|
|
21
|
+
parentSpanMissing: "parent_span_missing";
|
|
22
|
+
malformedParentSpanId: "malformed_parent_span_id";
|
|
23
|
+
linksNotAllowed: "links_not_allowed";
|
|
24
|
+
malformedLinkTraceId: "malformed_link_trace_id";
|
|
25
|
+
malformedLinkSpanId: "malformed_link_span_id";
|
|
26
|
+
validationFailed: "relationship_validation_failed";
|
|
27
|
+
}>;
|
|
28
|
+
/**
|
|
29
|
+
* Validate an event against its catalogued relationship rules.
|
|
30
|
+
*
|
|
31
|
+
* Checks, in order:
|
|
32
|
+
* (a) the kind is catalogued;
|
|
33
|
+
* (b) every `requiredWorkflowIds` entry is present;
|
|
34
|
+
* (c) no `forbiddenWorkflowIds` entry is present (a present one means an ID
|
|
35
|
+
* was manufactured upstream — issue #2029 item 2);
|
|
36
|
+
* (d) a parent span is absent when the kind does not take one;
|
|
37
|
+
* (e) a parent span is present when the kind requires one;
|
|
38
|
+
* (f) a present parent span is a well-formed W3C span id;
|
|
39
|
+
* (g) links are absent when the kind does not allow them;
|
|
40
|
+
* (h) every link carries a well-formed trace/span id pair.
|
|
41
|
+
*
|
|
42
|
+
* @returns `{ ok: true }` or `{ ok: false, violations }`. Never throws.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateEventRelationships(event: ObservabilityEvent): RelationshipValidationResult;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sampling and metric-cardinality policy (issue #2029).
|
|
3
|
+
*
|
|
4
|
+
* Import rules: no filesystem, network, subprocess, or OTel SDK.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Default sample rate.
|
|
8
|
+
*
|
|
9
|
+
* `1` = sample everything. This PR introduces no dropping: a drop that no
|
|
10
|
+
* consumer can see is exactly the silent data loss the issue names, and the
|
|
11
|
+
* consumer that would make a drop observable lands in #2047.
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEFAULT_SAMPLE_RATE = 1;
|
|
14
|
+
/**
|
|
15
|
+
* Decide whether a trace is sampled.
|
|
16
|
+
*
|
|
17
|
+
* **Deterministic by construction.** The decision is a pure function of the
|
|
18
|
+
* trace id and the rate: the LAST 8 hex characters of the trace id are read as
|
|
19
|
+
* an unsigned integer and compared against `rate * 0xffffffff`. The same trace
|
|
20
|
+
* therefore samples identically in every process, on every host, and across
|
|
21
|
+
* restarts — no shared state, no RNG, no coordination. That is what makes a
|
|
22
|
+
* sampled distributed trace complete rather than a set of disconnected
|
|
23
|
+
* fragments, and it is why the decision is not `Math.random()`.
|
|
24
|
+
*
|
|
25
|
+
* **CAVEAT — that property is currently VACUOUS in this system, and saying so
|
|
26
|
+
* is the point.** `createObservation` mints a FRESH `traceId` per event, with
|
|
27
|
+
* `links: []` and no `parentSpanId`, so every event today is its own
|
|
28
|
+
* single-span trace. At a rate below 1 the decision is therefore independent
|
|
29
|
+
* PER EVENT, not per logical trace: a "trace" never spans two events, so
|
|
30
|
+
* nothing can be kept whole or torn apart. Trace continuation — propagating one
|
|
31
|
+
* trace id across the events that belong together — is #2047's work, and only
|
|
32
|
+
* then does trace-coherent sampling become a real property rather than a
|
|
33
|
+
* latent one. Nothing is dropped today regardless: {@link DEFAULT_SAMPLE_RATE}
|
|
34
|
+
* is `1`.
|
|
35
|
+
*
|
|
36
|
+
* **Fail-open.** Every unusable input returns `true`. Dropping an event because
|
|
37
|
+
* an id was malformed would lose data silently, which is the failure mode this
|
|
38
|
+
* contract exists to prevent. A non-finite rate also fails open, for the same
|
|
39
|
+
* reason: `NaN` would otherwise fall through both bounds and make every
|
|
40
|
+
* comparison `false`, silently dropping everything.
|
|
41
|
+
*
|
|
42
|
+
* @param traceId - 32 lowercase hex characters.
|
|
43
|
+
* @param rate - `>= 1` samples everything, `<= 0` samples nothing.
|
|
44
|
+
*/
|
|
45
|
+
export declare function shouldSample(traceId: string, rate: number): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* The only labels permitted on a metric.
|
|
48
|
+
*
|
|
49
|
+
* Every member is bounded: a small, enumerable set of values that cannot grow
|
|
50
|
+
* with traffic. The rule this enforces, from issue #2029: **IDs, paths, users,
|
|
51
|
+
* tasks, and repositories belong in traces and logs, not metric labels.** A
|
|
52
|
+
* single unbounded label multiplies the time-series count by its cardinality and
|
|
53
|
+
* takes a metrics backend down; the trace already carries that detail, keyed to
|
|
54
|
+
* the same event.
|
|
55
|
+
*/
|
|
56
|
+
export declare const METRIC_LABEL_ALLOWLIST: readonly string[];
|
|
57
|
+
/** Verdict from {@link assertBoundedCardinality}. */
|
|
58
|
+
export type CardinalityResult = {
|
|
59
|
+
ok: true;
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
violations: string[];
|
|
63
|
+
};
|
|
64
|
+
/** Stable violation codes, suffixed with the offending label. */
|
|
65
|
+
export declare const CARDINALITY_VIOLATION_CODES: Readonly<{
|
|
66
|
+
notAllowlisted: "label_not_allowlisted";
|
|
67
|
+
highCardinalityShape: "high_cardinality_label_shape";
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Check a metric's label set against the allowlist and against high-cardinality
|
|
71
|
+
* shapes.
|
|
72
|
+
*
|
|
73
|
+
* RETURNS a verdict; never throws. A label can produce both codes — the shape
|
|
74
|
+
* check runs independently of the allowlist check so that a newly-allowlisted
|
|
75
|
+
* label with an unbounded shape is still reported.
|
|
76
|
+
*/
|
|
77
|
+
export declare function assertBoundedCardinality(labels: readonly string[]): CardinalityResult;
|
|
@@ -95,10 +95,10 @@ export declare const PhaseArchitectureSummarySchema: z.ZodObject<{
|
|
|
95
95
|
export type PhaseArchitectureSummary = z.infer<typeof PhaseArchitectureSummarySchema>;
|
|
96
96
|
export declare const SupervisorFindingSchema: z.ZodObject<{
|
|
97
97
|
severity: z.ZodEnum<{
|
|
98
|
+
critical: "critical";
|
|
98
99
|
low: "low";
|
|
99
100
|
medium: "medium";
|
|
100
101
|
high: "high";
|
|
101
|
-
critical: "critical";
|
|
102
102
|
}>;
|
|
103
103
|
category: z.ZodString;
|
|
104
104
|
agents: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
@@ -135,10 +135,10 @@ export declare const ArchitectureSupervisorReportSchema: z.ZodObject<{
|
|
|
135
135
|
}>;
|
|
136
136
|
findings: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
137
137
|
severity: z.ZodEnum<{
|
|
138
|
+
critical: "critical";
|
|
138
139
|
low: "low";
|
|
139
140
|
medium: "medium";
|
|
140
141
|
high: "high";
|
|
141
|
-
critical: "critical";
|
|
142
142
|
}>;
|
|
143
143
|
category: z.ZodString;
|
|
144
144
|
agents: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createObservation, toLegacyTelemetryLine } from './observability/index.js';
|
|
1
2
|
import type { DelegationCostFields } from './services/cost-accounting.js';
|
|
2
3
|
export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'gate_parse_error' | 'reviewer_gate_decision' | 'phase_changed' | 'budget_updated' | 'model_fallback' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'no_op_strong_warning' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected' | 'evidence_lock_acquired' | 'evidence_lock_contended' | 'evidence_lock_stale_recovered' | 'plan_ledger_cas_retry' | 'plan_md_write_failed' | 'snapshot_failed' | 'gate_denial_loop'
|
|
3
4
|
/**
|
|
@@ -25,7 +26,7 @@ export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activa
|
|
|
25
26
|
* `prm_hard_stop` TRIGGER emitted by `src/prm/escalation.ts`. A trigger with
|
|
26
27
|
* no matching delivery means the containment never reached the agent.
|
|
27
28
|
*/
|
|
28
|
-
| 'prm_hard_stop_delivered';
|
|
29
|
+
| 'prm_hard_stop_delivered' | 'agent_conflict_detected';
|
|
29
30
|
/** Stable classification for how a reviewer-gate decision was established. */
|
|
30
31
|
export type ReviewerGateEvidenceKind = 'genuine' | 'fallback' | 'data_quality' | 'block';
|
|
31
32
|
/**
|
|
@@ -157,4 +158,6 @@ export declare const _internals: {
|
|
|
157
158
|
emit: typeof emit;
|
|
158
159
|
rotateTelemetryIfNeeded: typeof rotateTelemetryIfNeeded;
|
|
159
160
|
heartbeatListenerCount: () => number;
|
|
161
|
+
createObservation: typeof createObservation;
|
|
162
|
+
toLegacyTelemetryLine: typeof toLegacyTelemetryLine;
|
|
160
163
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.137.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -104,7 +104,8 @@
|
|
|
104
104
|
"prepare": "bun run build",
|
|
105
105
|
"repro:704": "node scripts/repro-704.mjs",
|
|
106
106
|
"repro:1144": "bun scripts/repro-1144.mjs",
|
|
107
|
-
"repro:1873": "bun build scripts/repro-1873-entry.ts --outdir dist-build-test/repro-1873 --target node --format esm && node scripts/repro-1873.mjs"
|
|
107
|
+
"repro:1873": "bun build scripts/repro-1873-entry.ts --outdir dist-build-test/repro-1873 --target node --format esm && node scripts/repro-1873.mjs",
|
|
108
|
+
"check:events": "bun run scripts/check-event-contract.ts"
|
|
108
109
|
},
|
|
109
110
|
"dependencies": {
|
|
110
111
|
"@opencode-ai/plugin": "^1.18.3",
|