@zanii/blackbox 0.21.0 → 0.21.2

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.
@@ -103,4 +103,4 @@ export declare function verifyRegression(events: Ev[]): Finding[];
103
103
  /** Stage 2 R4, judged at close: a run labelled (or claimed) a success that its own record contradicts:
104
104
  * a check's last result failed, or the last tool call failed with nothing succeeding after it. */
105
105
  export declare function falseSuccess(events: Ev[], now: number): Finding[];
106
- export { type Growth, growth, isoWeek, type Lessons, lessons, POWER_KINDS, promptChanged, SELF_CHANGE_KINDS, selfChanges, systemPromptHash, toolsHash, } from "./learning.ts";
106
+ export { type Growth, growth, isoWeek, type Lessons, lessons, POWER_KINDS, promptChanged, SELF_CHANGE_KINDS, selfChanges, successRange, systemPromptHash, toolsHash, } from "./learning.ts";
@@ -586,4 +586,4 @@ export function falseSuccess(events, now) {
586
586
  : "The agent claimed it was done, but its last tool call failed and nothing succeeded after it.");
587
587
  return [];
588
588
  }
589
- export { growth, isoWeek, lessons, POWER_KINDS, promptChanged, SELF_CHANGE_KINDS, selfChanges, systemPromptHash, toolsHash, } from "./learning.js";
589
+ export { growth, isoWeek, lessons, POWER_KINDS, promptChanged, SELF_CHANGE_KINDS, selfChanges, successRange, systemPromptHash, toolsHash, } from "./learning.js";
@@ -86,6 +86,10 @@ export interface Growth {
86
86
  spend_per_run_micro_usd: number;
87
87
  human_steps: number;
88
88
  declared: boolean;
89
+ success_low_ppm: number;
90
+ success_high_ppm: number;
91
+ vs_previous: "better" | "worse" | "unclear" | null;
92
+ certificate: string | null;
89
93
  }>;
90
94
  versions_total: number;
91
95
  learned: Array<{
@@ -98,9 +102,15 @@ export interface Growth {
98
102
  corrected: number;
99
103
  unknown: number;
100
104
  checked: boolean;
105
+ certificate: string | null;
101
106
  }>;
102
107
  hints: string[];
103
108
  }
109
+ /**
110
+ * spec/fleet.md §9: the 95% Wilson interval of `s` successes in `n` runs, in ppm (low rounded down,
111
+ * high up). The same IEEE operations in the same order in both SDKs, so the digits agree.
112
+ */
113
+ export declare function successRange(s: number, n: number): [number, number];
104
114
  /**
105
115
  * spec/fleet.md §9: how one agent (its label) grows, from its closed sessions' summaries, newest
106
116
  * first. Autonomy per ISO week (a run done alone is a success with no human step, shown next to the
@@ -219,6 +219,24 @@ export function isoWeek(ts) {
219
219
  return `${year}-W${String(week).padStart(2, "0")}`;
220
220
  }
221
221
  const ppm = (n, d) => (d ? Math.floor((n * 1_000_000) / d) : 0);
222
+ /**
223
+ * spec/fleet.md §9: the 95% Wilson interval of `s` successes in `n` runs, in ppm (low rounded down,
224
+ * high up). The same IEEE operations in the same order in both SDKs, so the digits agree.
225
+ */
226
+ export function successRange(s, n) {
227
+ if (!n)
228
+ return [0, 1_000_000];
229
+ const z = 1.96;
230
+ const z2 = z * z;
231
+ const p = s / n;
232
+ const denom = 1 + z2 / n;
233
+ const centre = (p + z2 / (2 * n)) / denom;
234
+ const half = (z * Math.sqrt((p * (1 - p)) / n + z2 / (4 * n * n))) / denom;
235
+ return [
236
+ Math.max(0, Math.floor((centre - half) * 1_000_000)),
237
+ Math.min(1_000_000, Math.ceil((centre + half) * 1_000_000)),
238
+ ];
239
+ }
222
240
  const VERSIONS = 20;
223
241
  const LEARNED = 50;
224
242
  /**
@@ -269,6 +287,10 @@ export function growth(summaries, label, options = {}) {
269
287
  .map((ss) => {
270
288
  const v = ss[0]?.version;
271
289
  const starts = ss.map((s) => s.started_at).sort();
290
+ const wins = ss.filter((s) => s.outcome === "success").length;
291
+ const [low, high] = successRange(wins, ss.length);
292
+ // the newest run's certificate first: ss is newest first
293
+ const cert = ss.flatMap((s) => (s.self_changes ?? []).map((c) => c.certificate)).find(Boolean) ?? null;
272
294
  return {
273
295
  id: v.id,
274
296
  prompt: v.prompt,
@@ -278,16 +300,27 @@ export function growth(summaries, label, options = {}) {
278
300
  sessions: ss.length,
279
301
  first_seen: starts[0],
280
302
  last_seen: starts[starts.length - 1],
281
- success_ppm: ppm(ss.filter((s) => s.outcome === "success").length, ss.length),
303
+ success_ppm: ppm(wins, ss.length),
282
304
  spend_per_run_micro_usd: Math.floor(ss.reduce((n, s) => n + s.spend_micro_usd, 0) / ss.length),
283
305
  human_steps: ss.reduce((n, s) => n + (s.human_steps ?? 0), 0),
284
306
  declared: ss.some((s) => (s.self_changes?.length ?? 0) > 0),
307
+ success_low_ppm: low,
308
+ success_high_ppm: high,
309
+ vs_previous: null,
310
+ certificate: cert,
285
311
  };
286
312
  })
287
313
  .sort((a, b) => a.first_seen < b.first_seen ? -1 : a.first_seen > b.first_seen ? 1 : a.id < b.id ? -1 : 1);
288
314
  for (let i = 1; i < all.length; i++) {
289
315
  const [p, v] = [all[i - 1], all[i]];
290
316
  v.changed = ["prompt", "tools", "model"].filter((k) => p[k] !== v[k]);
317
+ // only a difference outside both ranges counts: two runs each tell nothing
318
+ v.vs_previous =
319
+ v.success_low_ppm > p.success_high_ppm
320
+ ? "better"
321
+ : v.success_high_ppm < p.success_low_ppm
322
+ ? "worse"
323
+ : "unclear";
291
324
  }
292
325
  const decided = new Map();
293
326
  for (const s of runs)
@@ -312,6 +345,7 @@ export function growth(summaries, label, options = {}) {
312
345
  corrected,
313
346
  unknown,
314
347
  checked: found.length > 0 && unknown === 0,
348
+ certificate: c.certificate ?? null,
315
349
  });
316
350
  }
317
351
  const hints = [];
@@ -17,6 +17,9 @@ export interface ModelPrice {
17
17
  /** Audio in and out (else `input` / `output`). */
18
18
  input_audio?: number;
19
19
  output_audio?: number;
20
+ /** Image tokens in and out (else `input` / `output`): OpenAI's and Gemini's image models. */
21
+ input_image?: number;
22
+ output_image?: number;
20
23
  /** µUSD per 1,000 web-search requests (Anthropic's server tool); absent: not priced. */
21
24
  web_search_per_1k?: number;
22
25
  /** Prices once the call's prompt is over `above` tokens (Gemini's >200k tier), highest first. */
@@ -56,6 +59,8 @@ export interface Tokens {
56
59
  cache_write_1h?: number;
57
60
  input_audio?: number;
58
61
  output_audio?: number;
62
+ input_image?: number;
63
+ output_image?: number;
59
64
  }
60
65
  export interface CallCost {
61
66
  seq: number;
@@ -74,6 +79,8 @@ export interface CallCost {
74
79
  /** spec/cost.md §1a: the uplift applied, when one matched. */
75
80
  uplift_percent?: number;
76
81
  source?: "reported";
82
+ /** The answer carried no usage (`usage_missing`): unpriced, never counted as free. */
83
+ no_usage?: true;
77
84
  }
78
85
  export interface CostReport {
79
86
  v: 1;
@@ -2,12 +2,20 @@
2
2
  // Mirrors sdks/python/src/zanii_blackbox/cost.py.
3
3
  import { createHash } from "node:crypto";
4
4
  const CLASSES = ["input", "output", "cache_read", "cache_write"];
5
- const EXTRA = ["cache_write_1h", "input_audio", "output_audio"];
5
+ const EXTRA = [
6
+ "cache_write_1h",
7
+ "input_audio",
8
+ "output_audio",
9
+ "input_image",
10
+ "output_image",
11
+ ];
6
12
  const OPTIONAL_PRICES = [
7
13
  "context_window",
8
14
  "cache_write_1h",
9
15
  "input_audio",
10
16
  "output_audio",
17
+ "input_image",
18
+ "output_image",
11
19
  "web_search_per_1k",
12
20
  ];
13
21
  /** Parses and checks a price table; its sha256 is of the exact file bytes. */
@@ -99,12 +107,20 @@ export function tokensOf(usage) {
99
107
  const cached = n("cachedContentTokenCount");
100
108
  const audioIn = n("promptTokensDetails_AUDIO");
101
109
  const audioOut = n("candidatesTokensDetails_AUDIO");
110
+ const imageIn = n("promptTokensDetails_IMAGE");
111
+ const imageOut = n("candidatesTokensDetails_IMAGE");
102
112
  return extras({
103
- input: Math.max(0, n("promptTokenCount") - cached - audioIn) + n("toolUsePromptTokenCount"),
104
- output: Math.max(0, n("candidatesTokenCount") - audioOut) + n("thoughtsTokenCount"),
113
+ input: Math.max(0, n("promptTokenCount") - cached - audioIn - imageIn) +
114
+ n("toolUsePromptTokenCount"),
115
+ output: Math.max(0, n("candidatesTokenCount") - audioOut - imageOut) + n("thoughtsTokenCount"),
105
116
  cache_read: cached,
106
117
  cache_write: 0,
107
- }, { input_audio: audioIn, output_audio: audioOut });
118
+ }, {
119
+ input_audio: audioIn,
120
+ output_audio: audioOut,
121
+ input_image: imageIn,
122
+ output_image: imageOut,
123
+ });
108
124
  }
109
125
  if ("inputTokens" in usage)
110
126
  // Bedrock Converse (spec/providers.md §5)
@@ -130,18 +146,28 @@ export function tokensOf(usage) {
130
146
  // Anthropic's cache names are its own: they win over the Responses shape, since Anthropic also
131
147
  // sends output_tokens_details (thinking_tokens) since Claude Sonnet 5
132
148
  const anthropicCache = "cache_read_input_tokens" in usage || "cache_creation_input_tokens" in usage;
149
+ // OpenAI's transcriptions write input_token_details (singular); its images, image_tokens
133
150
  if (!anthropicCache &&
134
- Object.keys(usage).some((k) => k.startsWith("input_tokens_details_") || k.startsWith("output_tokens_details_"))) {
151
+ Object.keys(usage).some((k) => k.startsWith("input_tokens_details_") ||
152
+ k.startsWith("output_tokens_details_") ||
153
+ k.startsWith("input_token_details_"))) {
135
154
  const cached = n("input_tokens_details_cached_tokens");
136
155
  const written = n("input_tokens_details_cache_write_tokens");
137
- const audioIn = n("input_tokens_details_audio_tokens");
156
+ const audioIn = n("input_tokens_details_audio_tokens") + n("input_token_details_audio_tokens");
138
157
  const audioOut = n("output_tokens_details_audio_tokens");
158
+ const imageIn = n("input_tokens_details_image_tokens");
159
+ const imageOut = n("output_tokens_details_image_tokens");
139
160
  return extras({
140
- input: Math.max(0, n("input_tokens") - cached - written - audioIn),
141
- output: Math.max(0, n("output_tokens") - audioOut),
161
+ input: Math.max(0, n("input_tokens") - cached - written - audioIn - imageIn),
162
+ output: Math.max(0, n("output_tokens") - audioOut - imageOut),
142
163
  cache_read: cached,
143
164
  cache_write: written,
144
- }, { input_audio: audioIn, output_audio: audioOut });
165
+ }, {
166
+ input_audio: audioIn,
167
+ output_audio: audioOut,
168
+ input_image: imageIn,
169
+ output_image: imageOut,
170
+ });
145
171
  }
146
172
  // Anthropic: cache_creation_input_tokens is both lifetimes; the 1-hour part is priced apart
147
173
  const hour = n("cache_creation_ephemeral_1h_input_tokens");
@@ -167,7 +193,12 @@ export function requestsOf(usage) {
167
193
  }
168
194
  /** A call's prompt, in tokens: what a context tier is decided on. */
169
195
  export function promptTokens(t) {
170
- return t.input + t.cache_read + t.cache_write + (t.cache_write_1h ?? 0) + (t.input_audio ?? 0);
196
+ return (t.input +
197
+ t.cache_read +
198
+ t.cache_write +
199
+ (t.cache_write_1h ?? 0) +
200
+ (t.input_audio ?? 0) +
201
+ (t.input_image ?? 0));
171
202
  }
172
203
  /** The prices a call pays: a context tier when its prompt is over one, then its service tier. */
173
204
  export function effectivePrice(price, tokens, serviceTier) {
@@ -203,6 +234,8 @@ export function callMicroUsd(tokens, price, requests) {
203
234
  sum += (tokens.cache_write_1h ?? 0) * (price.cache_write_1h ?? price.cache_write);
204
235
  sum += (tokens.input_audio ?? 0) * (price.input_audio ?? price.input);
205
236
  sum += (tokens.output_audio ?? 0) * (price.output_audio ?? price.output);
237
+ sum += (tokens.input_image ?? 0) * (price.input_image ?? price.input);
238
+ sum += (tokens.output_image ?? 0) * (price.output_image ?? price.output);
206
239
  sum += (requests?.web_search ?? 0) * (price.web_search_per_1k ?? 0) * 1000;
207
240
  if (!Number.isSafeInteger(sum))
208
241
  throw new RangeError("cost overflow: tokens × price beyond 2^53");
@@ -288,9 +321,19 @@ export function sessionCost(lines, prices) {
288
321
  if (replayed.has(e.meta.request_seq))
289
322
  continue;
290
323
  const usage = e.meta.usage;
291
- if (typeof usage !== "object" || usage === null)
292
- continue;
293
324
  const model = typeof e.meta.model === "string" ? e.meta.model : null;
325
+ if (typeof usage !== "object" || usage === null) {
326
+ // an answer that said nothing of what it cost is unpriced, never silently free
327
+ if (e.meta.usage_missing === true)
328
+ calls.push({
329
+ seq: e.seq,
330
+ model,
331
+ tokens: { input: 0, output: 0, cache_read: 0, cache_write: 0 },
332
+ micro_usd: null,
333
+ no_usage: true,
334
+ });
335
+ continue;
336
+ }
294
337
  const priced = priceCall({
295
338
  model,
296
339
  usage: usage,
@@ -53,9 +53,14 @@ export interface SelfChangeEntry {
53
53
  kind: string;
54
54
  approval_id: string | null;
55
55
  taught_by: string[];
56
+ /** A Zanii Evolve certificate's digest behind the change, when the agent names one */
57
+ certificate?: string;
56
58
  }
57
59
  /** An approval id: what a lesson may point at, and nothing else (spec/fleet.md §9). */
58
60
  export declare const APPROVAL_ID: RegExp;
61
+ /** spec/fleet.md §9: a Zanii Evolve certificate's digest (`sha256:` + 64 hex, or the 64 hex its
62
+ * certificate carries), as `sha256:<hex>`; null for anything else. */
63
+ export declare function certificateOf(v: unknown): string | null;
59
64
  /** spec/fleet.md §9: the approval ids a self-change names as what taught it, at most 20. */
60
65
  export declare function taughtBy(v: unknown): string[];
61
66
  export declare function sessionSummary(lines: readonly string[], bodies: Bodies, prices: LoadedPrices): Summary;
@@ -12,6 +12,14 @@ import { callsOf } from "../reconcile/record.js";
12
12
  import { canonical } from "../reconcile/shared.js";
13
13
  /** An approval id: what a lesson may point at, and nothing else (spec/fleet.md §9). */
14
14
  export const APPROVAL_ID = /^apr_[0-9a-f]{18}$/;
15
+ /** spec/fleet.md §9: a Zanii Evolve certificate's digest (`sha256:` + 64 hex, or the 64 hex its
16
+ * certificate carries), as `sha256:<hex>`; null for anything else. */
17
+ export function certificateOf(v) {
18
+ if (typeof v !== "string")
19
+ return null;
20
+ const m = /^(?:sha256:)?([0-9a-f]{64})$/.exec(v);
21
+ return m ? `sha256:${m[1]}` : null;
22
+ }
15
23
  /** spec/fleet.md §9: the approval ids a self-change names as what taught it, at most 20. */
16
24
  export function taughtBy(v) {
17
25
  if (!Array.isArray(v))
@@ -127,6 +135,9 @@ export function sessionSummary(lines, bodies, prices) {
127
135
  kind: typeof d.kind === "string" && d.kind ? d.kind : "other",
128
136
  approval_id: typeof d.approval_id === "string" ? d.approval_id : null,
129
137
  taught_by: taughtBy(d.taught_by),
138
+ ...(certificateOf(d.certificate)
139
+ ? { certificate: certificateOf(d.certificate) }
140
+ : {}),
130
141
  };
131
142
  });
132
143
  const version = versionOf(events);
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { A2A_STREAMING, type AgentCardReport, a2aMethod, a2aRequestMeta, a2aResp
2
2
  export { causality, memoryXray } from "./agents/index.ts";
3
3
  export { type DetectorOptions, detectors, fingerprint } from "./analysis/detectors.ts";
4
4
  export { FAULTS, type Fault, faultOf } from "./analysis/faults.ts";
5
- export { type Accuracy, type AnalyzeOptions, type AnswerClaims, analyze, answerClaims, answerCredential, answerRisk, answersOf, answerText, type ClaimEntry, type ClaimVerdict, type CriterionResult, canonicalNumber, checkAgainstPacks, checkFlightPlan, checkpointReplay, detectorAccuracy, dualWitness, Evidence, eventsOf, type Fact, type Finding as AnalysisFinding, factsIn, findingKey, type GroundedClaim, groundingFindings, groundingRequest, growth, HOLD_TRIGGERS, identifiersIn, isoWeek, judgeFindings, judgeRequest, type Label as AccuracyLabel, type Landing, landing, lessons, loadReferencePacks, modelGroundingFindings, normaliseValue, OUTCOMES, type Outcome, type OutcomeRollup, packsFor, parseGroundingAnswer, parseJudgeAnswer, promptChanged, type ReferenceFact, type ReferencePack, type ReferenceVerdict, referenceContext, rollup, type Severity, schemaProblem, secretSent, selfChanges, systemPromptHash, toolDrifted, toolHallucinations, toolsHash, userDownvotes, verifyAnswerCredential, type WasteReason, type WasteReport, waste, wilsonLow, } from "./analysis/index.ts";
5
+ export { type Accuracy, type AnalyzeOptions, type AnswerClaims, analyze, answerClaims, answerCredential, answerRisk, answersOf, answerText, type ClaimEntry, type ClaimVerdict, type CriterionResult, canonicalNumber, checkAgainstPacks, checkFlightPlan, checkpointReplay, detectorAccuracy, dualWitness, Evidence, eventsOf, type Fact, type Finding as AnalysisFinding, factsIn, findingKey, type GroundedClaim, groundingFindings, groundingRequest, growth, HOLD_TRIGGERS, identifiersIn, isoWeek, judgeFindings, judgeRequest, type Label as AccuracyLabel, type Landing, landing, lessons, loadReferencePacks, modelGroundingFindings, normaliseValue, OUTCOMES, type Outcome, type OutcomeRollup, packsFor, parseGroundingAnswer, parseJudgeAnswer, promptChanged, type ReferenceFact, type ReferencePack, type ReferenceVerdict, referenceContext, rollup, type Severity, schemaProblem, secretSent, selfChanges, successRange, systemPromptHash, toolDrifted, toolHallucinations, toolsHash, userDownvotes, verifyAnswerCredential, type WasteReason, type WasteReport, waste, wilsonLow, } from "./analysis/index.ts";
6
6
  export { injectionFindings, injectionRule } from "./analysis/injection.ts";
7
7
  export { MITRE_ATLAS, OWASP_ASI, TAXONOMY, type Taxonomy, taxonomyOf, } from "./analysis/taxonomy.ts";
8
8
  export { type ApprovalFinding, approvalConfirmation, approvalFindings, argsHash, verifyConfirmation, } from "./approvals/index.ts";
@@ -30,7 +30,7 @@ export { openSegments, type SealedSegment } from "./encryption/index.ts";
30
30
  export { type EvidencePack, type EvidencePackOptions, evidencePack, renderEvidencePack, } from "./evidence/index.ts";
31
31
  export { buildEquivocationProof, compareViews, cosignLedgerSth, verifyEquivocationProof, verifyLedgerCosignature, } from "./federation/index.ts";
32
32
  export { buildOwnerAttestation, buildPayment, CURRENCIES, FTA_WALL_ID, financeFindings, formatMoney, ftaPayload, parseMoney, paymentsOf, screenCounterparty, screeningPayload, verifyOwnerAttestation, verifyOwnerBinding, } from "./finance/index.ts";
33
- export { APPROVAL_ID, aggregateFindings, airworthiness, type Collision, collisions, didFromSeed, type FindingGroup, incidentReport, logbook, type Summary, sessionSummary, signatureOf, signatures, signCertificate, taughtBy, verifyCertificate, } from "./fleet/index.ts";
33
+ export { APPROVAL_ID, aggregateFindings, airworthiness, type Collision, certificateOf, collisions, didFromSeed, type FindingGroup, incidentReport, logbook, type Summary, sessionSummary, signatureOf, signatures, signCertificate, taughtBy, verifyCertificate, } from "./fleet/index.ts";
34
34
  export { copilotContext, copilotPrompt, type Insights, insights, parseCopilotAnswer, } from "./fleet/insights.ts";
35
35
  export { type AppealItem, type AppealPack, appealPack, decisionPayload, GOV_DECISION_KINDS, renderAppealPack, ruleConsistency, signSubjectClaim, subjectTag, verifyDecision, verifyFactors, verifySubjectClaim, } from "./gov/index.ts";
36
36
  export { accessPayload, breakGlass, checkEpisodeTag, clinicianConfirmation, type EpisodeItem, episodeSeed, episodesPack, episodeTag, healthFindings, protocolTrail, recommendationHash, recommendationPayload, verifyCommitment, verifyHealthSignature, } from "./health/index.ts";
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { A2A_STREAMING, a2aMethod, a2aRequestMeta, a2aResponseMeta, a2aRestMetho
4
4
  export { causality, memoryXray } from "./agents/index.js";
5
5
  export { detectors, fingerprint } from "./analysis/detectors.js";
6
6
  export { FAULTS, faultOf } from "./analysis/faults.js";
7
- export { analyze, answerClaims, answerCredential, answerRisk, answersOf, answerText, canonicalNumber, checkAgainstPacks, checkFlightPlan, checkpointReplay, detectorAccuracy, dualWitness, Evidence, eventsOf, factsIn, findingKey, groundingFindings, groundingRequest, growth, HOLD_TRIGGERS, identifiersIn, isoWeek, judgeFindings, judgeRequest, landing, lessons, loadReferencePacks, modelGroundingFindings, normaliseValue, OUTCOMES, packsFor, parseGroundingAnswer, parseJudgeAnswer, promptChanged, referenceContext, rollup, schemaProblem, secretSent, selfChanges, systemPromptHash, toolDrifted, toolHallucinations, toolsHash, userDownvotes, verifyAnswerCredential, waste, wilsonLow, } from "./analysis/index.js";
7
+ export { analyze, answerClaims, answerCredential, answerRisk, answersOf, answerText, canonicalNumber, checkAgainstPacks, checkFlightPlan, checkpointReplay, detectorAccuracy, dualWitness, Evidence, eventsOf, factsIn, findingKey, groundingFindings, groundingRequest, growth, HOLD_TRIGGERS, identifiersIn, isoWeek, judgeFindings, judgeRequest, landing, lessons, loadReferencePacks, modelGroundingFindings, normaliseValue, OUTCOMES, packsFor, parseGroundingAnswer, parseJudgeAnswer, promptChanged, referenceContext, rollup, schemaProblem, secretSent, selfChanges, successRange, systemPromptHash, toolDrifted, toolHallucinations, toolsHash, userDownvotes, verifyAnswerCredential, waste, wilsonLow, } from "./analysis/index.js";
8
8
  export { injectionFindings, injectionRule } from "./analysis/injection.js";
9
9
  export { MITRE_ATLAS, OWASP_ASI, TAXONOMY, taxonomyOf, } from "./analysis/taxonomy.js";
10
10
  export { approvalConfirmation, approvalFindings, argsHash, verifyConfirmation, } from "./approvals/index.js";
@@ -32,7 +32,7 @@ export { openSegments } from "./encryption/index.js";
32
32
  export { evidencePack, renderEvidencePack, } from "./evidence/index.js";
33
33
  export { buildEquivocationProof, compareViews, cosignLedgerSth, verifyEquivocationProof, verifyLedgerCosignature, } from "./federation/index.js";
34
34
  export { buildOwnerAttestation, buildPayment, CURRENCIES, FTA_WALL_ID, financeFindings, formatMoney, ftaPayload, parseMoney, paymentsOf, screenCounterparty, screeningPayload, verifyOwnerAttestation, verifyOwnerBinding, } from "./finance/index.js";
35
- export { APPROVAL_ID, aggregateFindings, airworthiness, collisions, didFromSeed, incidentReport, logbook, sessionSummary, signatureOf, signatures, signCertificate, taughtBy, verifyCertificate, } from "./fleet/index.js";
35
+ export { APPROVAL_ID, aggregateFindings, airworthiness, certificateOf, collisions, didFromSeed, incidentReport, logbook, sessionSummary, signatureOf, signatures, signCertificate, taughtBy, verifyCertificate, } from "./fleet/index.js";
36
36
  export { copilotContext, copilotPrompt, insights, parseCopilotAnswer, } from "./fleet/insights.js";
37
37
  export { appealPack, decisionPayload, GOV_DECISION_KINDS, renderAppealPack, ruleConsistency, signSubjectClaim, subjectTag, verifyDecision, verifyFactors, verifySubjectClaim, } from "./gov/index.js";
38
38
  export { accessPayload, breakGlass, checkEpisodeTag, clinicianConfirmation, episodeSeed, episodesPack, episodeTag, healthFindings, protocolTrail, recommendationHash, recommendationPayload, verifyCommitment, verifyHealthSignature, } from "./health/index.js";
@@ -390,6 +390,8 @@ export declare class BlackboxSession {
390
390
  approvalId?: string;
391
391
  /** The approvals (ids) that taught it this, and nothing else: never content (fleet.md §9). */
392
392
  taughtBy?: readonly string[];
393
+ /** A Zanii Evolve certificate's digest behind the change (spec/fleet.md §9). */
394
+ certificate?: string;
393
395
  }): void;
394
396
  /** spec/findings.md §13.1: what in an answer (the latest, or the one at `seq`) would hold it,
395
397
  * for an app that streams the answer by itself: `{seq, risks, hold}`. `hold` says whether the
@@ -10,7 +10,7 @@ import { SELF_CHANGE_KINDS } from "../analysis/learning.js";
10
10
  import { argsHash } from "../approvals/index.js";
11
11
  import { attest, isReadOnly, parseCommand } from "../attest/index.js";
12
12
  import { buildPayment, ftaPayload, screeningPayload, } from "../finance/index.js";
13
- import { taughtBy } from "../fleet/index.js";
13
+ import { certificateOf, taughtBy } from "../fleet/index.js";
14
14
  import { decisionPayload } from "../gov/index.js";
15
15
  import { accessPayload, checkEpisodeTag, recommendationPayload, verifyHealthSignature, } from "../health/index.js";
16
16
  import { memoryEntry } from "../memory/index.js";
@@ -635,6 +635,9 @@ export class BlackboxSession {
635
635
  ...(options.reason ? { reason: options.reason.slice(0, 500) } : {}),
636
636
  ...(options.approvalId ? { approval_id: options.approvalId.slice(0, 128) } : {}),
637
637
  ...(taught.length ? { taught_by: taught } : {}),
638
+ ...(certificateOf(options.certificate)
639
+ ? { certificate: certificateOf(options.certificate) }
640
+ : {}),
638
641
  });
639
642
  }
640
643
  /** spec/findings.md §13.1: what in an answer (the latest, or the one at `seq`) would hold it,
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.21.0";
1
+ export declare const VERSION = "0.21.2";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // The SDK version, on its own so the CLI can print it without loading the whole SDK.
2
- export const VERSION = "0.21.0";
2
+ export const VERSION = "0.21.2";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zanii/blackbox",
3
3
  "license": "Apache-2.0",
4
- "version": "0.21.0",
4
+ "version": "0.21.2",
5
5
  "description": "The flight recorder for AI agents: sessions, a zero-loss spool, framework hooks, approvals, and offline verification of the gateway's hash-chained record.",
6
6
  "keywords": [
7
7
  "ai-agents",