@zanii/blackbox 0.21.2 → 0.23.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 (95) hide show
  1. package/README.md +1 -0
  2. package/dist/actions/index.d.ts +29 -0
  3. package/dist/actions/index.js +114 -0
  4. package/dist/admission/index.d.ts +30 -0
  5. package/dist/admission/index.js +106 -0
  6. package/dist/analysis/accepted.d.ts +26 -0
  7. package/dist/analysis/accepted.js +61 -0
  8. package/dist/analysis/detectors.js +12 -9
  9. package/dist/analysis/faults.js +71 -0
  10. package/dist/analysis/grounding.js +5 -9
  11. package/dist/analysis/guard.d.ts +72 -0
  12. package/dist/analysis/guard.js +240 -0
  13. package/dist/analysis/hallucination.js +2 -2
  14. package/dist/analysis/index.d.ts +21 -1
  15. package/dist/analysis/index.js +101 -19
  16. package/dist/analysis/injection.d.ts +2 -1
  17. package/dist/analysis/injection.js +16 -16
  18. package/dist/analysis/landing.js +60 -14
  19. package/dist/analysis/plan-checks.d.ts +55 -0
  20. package/dist/analysis/plan-checks.js +748 -0
  21. package/dist/analysis/taxonomy.js +1 -0
  22. package/dist/analysis/waste.js +2 -3
  23. package/dist/approvals/index.d.ts +12 -3
  24. package/dist/approvals/index.js +36 -10
  25. package/dist/authority/index.js +3 -3
  26. package/dist/aviation/index.d.ts +422 -0
  27. package/dist/aviation/index.js +1014 -0
  28. package/dist/aviation/qrh.d.ts +4 -0
  29. package/dist/aviation/qrh.js +171 -0
  30. package/dist/budgets/index.d.ts +63 -0
  31. package/dist/budgets/index.js +161 -0
  32. package/dist/cli.js +199 -24
  33. package/dist/compliance/index.d.ts +2 -0
  34. package/dist/compliance/index.js +26 -2
  35. package/dist/cost/batch.d.ts +26 -0
  36. package/dist/cost/batch.js +173 -0
  37. package/dist/cost/index.d.ts +21 -0
  38. package/dist/cost/index.js +115 -30
  39. package/dist/cv/index.js +1 -1
  40. package/dist/duty/index.js +2 -1
  41. package/dist/evals/index.d.ts +233 -0
  42. package/dist/evals/index.js +488 -0
  43. package/dist/evidence/index.d.ts +9 -0
  44. package/dist/evidence/index.js +50 -0
  45. package/dist/federation/index.d.ts +9 -0
  46. package/dist/federation/index.js +8 -1
  47. package/dist/finance/index.js +3 -4
  48. package/dist/fleet/index.d.ts +25 -0
  49. package/dist/fleet/index.js +57 -17
  50. package/dist/fleet/insights.js +4 -1
  51. package/dist/health/index.js +2 -2
  52. package/dist/hooks/ai-sdk.d.ts +17 -19
  53. package/dist/hooks/ai-sdk.js +13 -7
  54. package/dist/hooks/index.d.ts +1 -0
  55. package/dist/hooks/index.js +1 -0
  56. package/dist/hooks/mastra.d.ts +26 -0
  57. package/dist/hooks/mastra.js +63 -0
  58. package/dist/index.d.ts +24 -9
  59. package/dist/index.js +25 -9
  60. package/dist/mcp-requests/index.d.ts +26 -0
  61. package/dist/mcp-requests/index.js +154 -0
  62. package/dist/mcp-server/index.d.ts +12 -0
  63. package/dist/mcp-server/index.js +84 -2
  64. package/dist/mcp-wrap/index.js +8 -4
  65. package/dist/otlp/index.d.ts +155 -0
  66. package/dist/otlp/index.js +468 -0
  67. package/dist/otlp/protobuf.d.ts +7 -0
  68. package/dist/otlp/protobuf.js +314 -0
  69. package/dist/packs/index.d.ts +2 -0
  70. package/dist/packs/index.js +5 -1
  71. package/dist/pdf/arabic.d.ts +45 -0
  72. package/dist/pdf/arabic.js +373 -0
  73. package/dist/pdf/index.d.ts +77 -0
  74. package/dist/pdf/index.js +673 -0
  75. package/dist/policy/index.d.ts +0 -4
  76. package/dist/policy/index.js +13 -5
  77. package/dist/realtime/index.d.ts +33 -0
  78. package/dist/realtime/index.js +204 -0
  79. package/dist/reconcile/record.d.ts +14 -0
  80. package/dist/reconcile/record.js +161 -66
  81. package/dist/session/index.d.ts +43 -0
  82. package/dist/session/index.js +83 -0
  83. package/dist/undo/index.js +3 -3
  84. package/dist/verify/anchor.d.ts +5 -1
  85. package/dist/verify/anchor.js +13 -4
  86. package/dist/verify/chain.d.ts +4 -0
  87. package/dist/verify/chain.js +4 -3
  88. package/dist/verify/envelope.d.ts +1 -1
  89. package/dist/verify/envelope.js +5 -0
  90. package/dist/version.d.ts +1 -1
  91. package/dist/version.js +1 -1
  92. package/dist/walls/index.js +2 -2
  93. package/dist/warehouse/index.d.ts +62 -0
  94. package/dist/warehouse/index.js +142 -0
  95. package/package.json +6 -3
@@ -55,6 +55,7 @@ export const TAXONOMY = {
55
55
  TOKEN_MISUSE: { owasp: ["ASI03"], atlas: ["AML.T0091.000", "AML.T0086"] },
56
56
  TOOL_CHANGED: { owasp: ["ASI04"], atlas: ["AML.T0110.002"] },
57
57
  TOOL_DRIFTED: { owasp: ["ASI04"], atlas: ["AML.T0110.002"] },
58
+ ELICITATION_SECRET: { owasp: ["ASI03"], atlas: ["AML.T0057"] },
58
59
  PROMPT_INJECTION: { owasp: ["ASI01"], atlas: ["AML.T0051"] },
59
60
  PROMPT_CHANGED: { owasp: ["ASI04"] },
60
61
  SELF_CHANGE_UNAPPROVED: { owasp: ["ASI10"] },
@@ -1,15 +1,14 @@
1
1
  // The waste ledger (spec/cost.md §5): which paid model calls were wasted, and why.
2
2
  // Mirrors analysis/waste.py.
3
3
  import { sessionCost, toAedFils } from "../cost/index.js";
4
- import { callsOf } from "../reconcile/record.js";
4
+ import { callsOf, envelopesOf } from "../reconcile/record.js";
5
5
  import { toolCallsOf } from "./detectors.js";
6
6
  export const OUTCOMES = ["success", "failure", "abandoned"];
7
7
  export function waste(lines, bodies, prices) {
8
8
  const cost = sessionCost(lines, prices);
9
9
  const status = new Map();
10
10
  let outcome = null;
11
- for (const line of lines) {
12
- const e = JSON.parse(line);
11
+ for (const e of envelopesOf(lines)) {
13
12
  if (e.kind === "llm.response" && typeof e.meta.status === "number")
14
13
  status.set(e.seq, e.meta.status);
15
14
  else if (e.kind === "llm.incomplete")
@@ -21,14 +21,23 @@ export declare function approvalFindings(lines: readonly string[]): ApprovalFind
21
21
  export declare function approvalConfirmation(lines: readonly string[], approvalId: string, gateway: {
22
22
  did: string;
23
23
  privateKey: Uint8Array;
24
- }): {
24
+ }): ApprovalConfirmation | {
25
+ error: "not_found" | "not_approved";
26
+ };
27
+ /** spec/anchoring.md §15: `approvalConfirmation` with a key held outside the process. */
28
+ export declare function approvalConfirmationWith(lines: readonly string[], approvalId: string, gateway: {
29
+ did: string;
30
+ sign: (message: Uint8Array) => Promise<Uint8Array>;
31
+ }): Promise<ApprovalConfirmation | {
32
+ error: "not_found" | "not_approved";
33
+ }>;
34
+ type ApprovalConfirmation = {
25
35
  confirmation: ReturnType<typeof createConfirmation>;
26
36
  decision_seq: number;
27
37
  action_seq: number;
28
38
  by: unknown;
29
39
  person?: unknown;
30
- } | {
31
- error: "not_found" | "not_approved";
32
40
  };
33
41
  /** spec/approvals.md §8: Zanii's check of an action_confirmation (the DID it names signed it). */
34
42
  export declare const verifyConfirmation: (c: unknown) => boolean;
43
+ export {};
@@ -1,7 +1,8 @@
1
1
  // The two-person rule (spec/approvals.md): what the approval decisions say. Pure; mirrors
2
2
  // sdks/python/src/zanii_blackbox/approvals.py; pinned by spec/vectors/approvals.json.
3
3
  import { createHash } from "node:crypto";
4
- import { createConfirmation, verifyConfirmation as zaniiVerifyConfirmation } from "@zanii/core";
4
+ import { canonicalBytes, createConfirmation, verifyConfirmation as zaniiVerifyConfirmation, } from "@zanii/core";
5
+ import { envelopesOf } from "../reconcile/record.js";
5
6
  import { canonical } from "../reconcile/shared.js";
6
7
  import { hashLine } from "../verify/envelope.js";
7
8
  /** spec/approvals.md §2: what an approval's arguments are, `sha256:<hex>` of their canonical JSON
@@ -14,8 +15,7 @@ export function argsHash(args) {
14
15
  /** spec/approvals.md §3: a refused action (advisory), and one nobody confirmed in time (warning). */
15
16
  export function approvalFindings(lines) {
16
17
  const out = [];
17
- for (const line of lines) {
18
- const e = JSON.parse(line);
18
+ for (const e of envelopesOf(lines)) {
19
19
  if (e.kind !== "control" || e.meta.action !== "approval")
20
20
  continue;
21
21
  const id = typeof e.meta.approval_id === "string" ? e.meta.approval_id : "";
@@ -42,7 +42,31 @@ export function approvalFindings(lines) {
42
42
  * decision's time. Deterministic. `error` when there is no approve decision.
43
43
  */
44
44
  export function approvalConfirmation(lines, approvalId, gateway) {
45
- const events = lines.map((l) => JSON.parse(l));
45
+ const found = approvedAction(lines, approvalId);
46
+ if ("error" in found)
47
+ return found;
48
+ const { actionHash, confirmedAt, rest } = found;
49
+ const confirmation = createConfirmation({ ownerId: gateway.did, actionHash, confirmedAt }, gateway.privateKey);
50
+ return { confirmation, ...rest };
51
+ }
52
+ /** spec/anchoring.md §15: `approvalConfirmation` with a key held outside the process. */
53
+ export async function approvalConfirmationWith(lines, approvalId, gateway) {
54
+ const found = approvedAction(lines, approvalId);
55
+ if ("error" in found)
56
+ return found;
57
+ const unsigned = {
58
+ v: 1,
59
+ type: "action_confirmation",
60
+ owner_id: gateway.did,
61
+ action_hash: found.actionHash,
62
+ confirmed_at: found.confirmedAt,
63
+ };
64
+ const sig = `ed25519:${Buffer.from(await gateway.sign(canonicalBytes(unsigned))).toString("hex")}`;
65
+ return { confirmation: { ...unsigned, sig }, ...found.rest };
66
+ }
67
+ /** The approved event's hash, the decision's time, and the rest of the answer. */
68
+ function approvedAction(lines, approvalId) {
69
+ const events = envelopesOf(lines);
46
70
  const decision = events.find((e) => e.kind === "control" && e.meta.action === "approval" && e.meta.approval_id === approvalId);
47
71
  if (!decision)
48
72
  return { error: "not_found" };
@@ -55,13 +79,15 @@ export function approvalConfirmation(lines, approvalId, gateway) {
55
79
  const line = lines[actionSeq];
56
80
  if (line === undefined)
57
81
  return { error: "not_found" };
58
- const confirmation = createConfirmation({ ownerId: gateway.did, actionHash: hashLine(line), confirmedAt: decision.ts }, gateway.privateKey);
59
82
  return {
60
- confirmation,
61
- decision_seq: decision.seq,
62
- action_seq: actionSeq,
63
- by: decision.meta.by,
64
- ...(decision.meta.person !== undefined ? { person: decision.meta.person } : {}),
83
+ actionHash: hashLine(line),
84
+ confirmedAt: decision.ts,
85
+ rest: {
86
+ decision_seq: decision.seq,
87
+ action_seq: actionSeq,
88
+ by: decision.meta.by,
89
+ ...(decision.meta.person !== undefined ? { person: decision.meta.person } : {}),
90
+ },
65
91
  };
66
92
  }
67
93
  /** spec/approvals.md §8: Zanii's check of an action_confirmation (the DID it names signed it). */
@@ -1,5 +1,6 @@
1
1
  // Who had the controls (spec/authority.md): the authority timeline, and automation surprise.
2
2
  // Pure; mirrors sdks/python/src/zanii_blackbox/authority.py; pinned by spec/vectors/authority.json.
3
+ import { envelopesOf } from "../reconcile/record.js";
3
4
  const MODES = new Set(["agent", "supervised", "human"]);
4
5
  const ADMIN_BLOCKS = new Set(["EMERGENCY", "TAKEOVER"]);
5
6
  /** The mode an event sets, or null for one that doesn't change who is flying (spec §2). */
@@ -28,8 +29,7 @@ function change(e) {
28
29
  /** spec/authority.md §3: who was flying, span by span, oldest first. */
29
30
  export function authorityTimeline(lines) {
30
31
  const spans = [];
31
- for (const line of lines) {
32
- const e = JSON.parse(line);
32
+ for (const e of envelopesOf(lines)) {
33
33
  const c = change(e);
34
34
  const current = spans.at(-1);
35
35
  if (!c || current?.mode === c.mode)
@@ -49,7 +49,7 @@ export function authorityAt(lines, seq) {
49
49
  }
50
50
  /** spec/authority.md §4: the agent acted in a `human` span before it knew the mode had changed. */
51
51
  export function automationSurprise(lines) {
52
- const events = lines.map((l) => JSON.parse(l));
52
+ const events = envelopesOf(lines);
53
53
  const out = [];
54
54
  for (const span of authorityTimeline(lines)) {
55
55
  if (span.mode !== "human")
@@ -0,0 +1,422 @@
1
+ import type { Finding } from "../analysis/index.ts";
2
+ import { type LoadedPrices } from "../cost/index.ts";
3
+ import type { Bodies } from "../reconcile/record.ts";
4
+ import { QRH } from "./qrh.ts";
5
+ export { QRH };
6
+ /** A `*` pattern as a whole-name match (spec/policy.md §1's tool patterns). */
7
+ export declare function globMatch(pattern: string, name: string): boolean;
8
+ export type ClearanceMode = "exclusive" | "shared";
9
+ export interface ActiveClearance {
10
+ clearance_id: string;
11
+ session_id: string;
12
+ resource: string;
13
+ mode: ClearanceMode;
14
+ expires_at: string;
15
+ }
16
+ export interface ClearanceDecision {
17
+ decision: "granted" | "hold";
18
+ retry_after_s?: number;
19
+ conflicts: Array<{
20
+ session_id: string;
21
+ mode: ClearanceMode;
22
+ expires_at: string;
23
+ }>;
24
+ advisories: Array<{
25
+ session_id: string;
26
+ action: "hold" | "proceed";
27
+ }>;
28
+ }
29
+ /** spec/aviation.md §1: the gateway's answer to a clearance request. */
30
+ export type ClearanceAnswer = ClearanceDecision & {
31
+ resource: string;
32
+ mode: ClearanceMode;
33
+ clearance_id?: string;
34
+ expires_at?: string;
35
+ };
36
+ /** spec/aviation.md §1: may this session have the resource now? §2: and what each side does. */
37
+ export declare function clearance(active: readonly ActiveClearance[], request: {
38
+ session_id: string;
39
+ resource: string;
40
+ mode: ClearanceMode;
41
+ at: string;
42
+ }): ClearanceDecision;
43
+ /** spec/aviation.md §1: each change made without an exclusive clearance in force for it. */
44
+ export declare function clearanceFindings(lines: readonly string[], bodies: Bodies): Finding[];
45
+ export interface Notam {
46
+ id: string;
47
+ text: string;
48
+ from: string;
49
+ until: string;
50
+ tools: string[];
51
+ providers: string[];
52
+ effect: "inform" | "avoid";
53
+ tenant: string | null;
54
+ created_at: string;
55
+ cancelled_at: string | null;
56
+ }
57
+ /** spec/aviation.md §3: a notice's fields with defaults filled in, or an error message. */
58
+ export declare function checkNotam(input: Record<string, unknown>, now: string): {
59
+ ok: true;
60
+ notam: Pick<Notam, "text" | "from" | "until" | "tools" | "providers" | "effect">;
61
+ } | {
62
+ ok: false;
63
+ error: string;
64
+ };
65
+ /** spec/aviation.md §3: the notices in force at `at` for a tenant, by `from` then `id`. */
66
+ export declare function notamsInForce(notams: readonly Notam[], at: string, tenant: string | null): Notam[];
67
+ /** spec/aviation.md §3: the first event each `avoid` notice in force covers. */
68
+ export declare function notamFindings(lines: readonly string[], notams: readonly Notam[]): Finding[];
69
+ /** spec/aviation.md §9: the seq of the session's first `commit_point` SDK event, or null. */
70
+ export declare function commitPointSeq(lines: readonly string[]): number | null;
71
+ /** spec/aviation.md §9: a non-critical finding that comes after the commit point. */
72
+ export declare function pastCommitPoint(lines: readonly string[], finding: {
73
+ severity: string;
74
+ ref: {
75
+ [key: string]: unknown;
76
+ };
77
+ }): boolean;
78
+ export interface EnvelopeLimits {
79
+ v: 1;
80
+ forbidden_tools?: string[];
81
+ max_output_tokens?: number;
82
+ }
83
+ export type EnvelopeChange = {
84
+ field: string;
85
+ from: number;
86
+ to: number;
87
+ } | {
88
+ removed_tool: string;
89
+ };
90
+ /** spec/aviation.md §15: an error message, or null for a valid envelope. */
91
+ export declare function checkEnvelope(doc: unknown): string | null;
92
+ /** spec/aviation.md §15: the request inside the envelope, and what changed; null when nothing did. */
93
+ export declare function shapeRequest(body: unknown, envelope: EnvelopeLimits): {
94
+ body: Record<string, unknown>;
95
+ changes: EnvelopeChange[];
96
+ } | null;
97
+ /** spec/aviation.md §15: each model request the envelope shaped. */
98
+ export declare function envelopeFindings(lines: readonly string[]): Finding[];
99
+ export interface LoadSheet {
100
+ v: 1;
101
+ model: string | null;
102
+ parts: {
103
+ system: number;
104
+ tools: number;
105
+ messages: number;
106
+ };
107
+ total_tokens: number;
108
+ max_output_tokens: number | null;
109
+ context_window: number | null;
110
+ context_pct: number | null;
111
+ tools: number;
112
+ expected_micro_usd: number | null;
113
+ budget_micro_usd: number | null;
114
+ overweight: boolean;
115
+ reasons: Array<"context" | "budget">;
116
+ risk: "low" | "medium" | "high";
117
+ }
118
+ /** spec/aviation.md §17: the load sheet of a model request. Pure; an estimate. */
119
+ export declare function loadSheet(body: unknown, options?: {
120
+ prices?: LoadedPrices;
121
+ model?: string;
122
+ budgetMicroUsd?: number;
123
+ }): LoadSheet;
124
+ export declare const LEVELS: readonly ["public", "restricted", "confidential", "secret"];
125
+ export type Level = (typeof LEVELS)[number];
126
+ export interface OpSpecs {
127
+ v: 1;
128
+ default_classification?: Level;
129
+ default?: Level;
130
+ environments?: Record<string, Level>;
131
+ providers?: Record<string, Level>;
132
+ tools?: Record<string, Level>;
133
+ }
134
+ export declare const isLevel: (v: unknown) => v is Level;
135
+ /** spec/aviation.md §19: an error message, or null for valid OpSpecs. */
136
+ export declare function checkOpspecs(doc: unknown): string | null;
137
+ /** spec/aviation.md §19: null when approved at this classification, else why not. */
138
+ export declare function opspecsCheck(specs: OpSpecs, classification: Level, item: {
139
+ environment: string;
140
+ } | {
141
+ provider: string;
142
+ } | {
143
+ tool: readonly string[];
144
+ }): {
145
+ reason: "environment" | "provider" | "tool";
146
+ classification: Level;
147
+ max: Level;
148
+ } | null;
149
+ export interface Locator {
150
+ session_id: string | null;
151
+ label: string | null;
152
+ lost_contact: {
153
+ seq: number;
154
+ at: string;
155
+ last_seen: unknown;
156
+ silent_ms: unknown;
157
+ } | null;
158
+ open_actions: Array<{
159
+ seq: number;
160
+ kind: string;
161
+ at: string;
162
+ provider?: string;
163
+ tool?: string;
164
+ }>;
165
+ last_events: Array<{
166
+ seq: number;
167
+ kind: string;
168
+ ts: string;
169
+ }>;
170
+ findings: string[];
171
+ controls: {
172
+ mode: string;
173
+ by: string;
174
+ } | null;
175
+ }
176
+ /** spec/aviation.md §4: the session's last known state, packaged when it goes silent. */
177
+ export declare function locator(lines: readonly string[]): Locator;
178
+ /** spec/aviation.md §4: each loss of contact while an action was open. */
179
+ export declare function locatorFindings(lines: readonly string[]): Finding[];
180
+ export interface ReasoningRequest {
181
+ request_id: string;
182
+ session_id: string;
183
+ reason: string;
184
+ requested_by: Record<string, unknown>;
185
+ requested_at: string;
186
+ decision: "approve" | "reject" | null;
187
+ decided_by: Record<string, unknown> | null;
188
+ decided_at: string | null;
189
+ expires_at: string | null;
190
+ }
191
+ /** spec/aviation.md §5: where an opening request stands at `at`. */
192
+ export declare function reasoningStatus(request: Pick<ReasoningRequest, "decision" | "expires_at">, at: string): "pending" | "open" | "rejected" | "expired";
193
+ /** spec/aviation.md §5: whether two deciders are one person: the same login (iss + sub), or the
194
+ * same name or email (case and surrounding spaces ignored). */
195
+ export declare function samePerson(a: Record<string, unknown>, b: Record<string, unknown>): boolean;
196
+ /** spec/aviation.md §5: an actions page with the reasoning text taken out. */
197
+ export declare function protectReasoning<T extends {
198
+ actions: ReadonlyArray<{
199
+ reasoning: {
200
+ kind: string;
201
+ };
202
+ }>;
203
+ }>(page: T): T;
204
+ export declare const SAFETY_CATEGORIES: readonly ["near_miss", "hazard", "procedure", "tooling", "other"];
205
+ /** spec/aviation.md §6: a person's safety report, checked: the fields, or an error message. */
206
+ export declare function checkSafetyReport(input: Record<string, unknown>): {
207
+ ok: true;
208
+ report: {
209
+ category: (typeof SAFETY_CATEGORIES)[number];
210
+ description: string;
211
+ };
212
+ } | {
213
+ ok: false;
214
+ error: string;
215
+ };
216
+ /** spec/aviation.md §6: report counts by category, only those at least `k` tenants reported. */
217
+ export declare function safetyReportSummary(reports: ReadonlyArray<{
218
+ category: string;
219
+ tenant: string | null;
220
+ }>, k?: number): {
221
+ k: number;
222
+ categories: Array<{
223
+ category: string;
224
+ reports: number;
225
+ tenants: number;
226
+ }>;
227
+ };
228
+ /** spec/aviation.md §6, §10: the agent's own safety reports, maydays and pan-pans. */
229
+ export declare function agentReportFindings(lines: readonly string[]): Finding[];
230
+ export interface Procedure {
231
+ code: string;
232
+ fault: string;
233
+ title: string;
234
+ title_ar: string;
235
+ steps: string[];
236
+ source: "qrh" | "generic";
237
+ }
238
+ /** spec/aviation.md §8: the procedure for a fault code, or the generic one. */
239
+ export declare function procedureFor(code: string): Procedure;
240
+ export interface Hazard {
241
+ id: string;
242
+ title: string;
243
+ likelihood: number;
244
+ severity: number;
245
+ codes: string[];
246
+ mitigations: string[];
247
+ owner: string;
248
+ review_by: string;
249
+ }
250
+ export interface HazardRegister {
251
+ v: 1;
252
+ type: "blackbox.hazard-register";
253
+ hazards: Hazard[];
254
+ }
255
+ /** spec/aviation.md §7: an error message, or null for a valid hazard register. */
256
+ export declare function checkHazardRegister(doc: unknown): string | null;
257
+ /** spec/aviation.md §7: each hazard's risk, and the sessions that show it, highest risk first. */
258
+ export declare function hazardStatus(register: HazardRegister, summaries: ReadonlyArray<{
259
+ started_at: string;
260
+ finding_codes: Record<string, number>;
261
+ }>, today: string): {
262
+ v: 1;
263
+ type: "blackbox.hazard-status";
264
+ register_hash: string;
265
+ hazards: {
266
+ id: string;
267
+ title: string;
268
+ likelihood: number;
269
+ severity: number;
270
+ codes: string[];
271
+ mitigations: string[];
272
+ owner: string;
273
+ review_by: string;
274
+ risk: number;
275
+ band: string;
276
+ review_overdue: boolean;
277
+ sessions: number;
278
+ findings: number;
279
+ last_seen: string | null;
280
+ }[];
281
+ };
282
+ /** spec/aviation.md §11: a configuration's id, the same as a version's (spec/fleet.md §9). */
283
+ export declare function configurationId(prompt: string | null, tools: string | null, model: string | null): string;
284
+ export interface TypeCertificate {
285
+ v: 1;
286
+ type: "blackbox.type-certificate";
287
+ id: string;
288
+ configuration: string;
289
+ label: string;
290
+ model: string;
291
+ prompt: string | null;
292
+ tools: string | null;
293
+ tenant: string | null;
294
+ issued_at: string;
295
+ }
296
+ /** spec/aviation.md §11: a type certificate (unsigned), or an error message. */
297
+ export declare function typeCertificate(input: {
298
+ label: unknown;
299
+ model: unknown;
300
+ prompt: unknown;
301
+ tools: unknown;
302
+ }, tenant: string | null, issuedAt: string): {
303
+ ok: true;
304
+ certificate: TypeCertificate;
305
+ } | {
306
+ ok: false;
307
+ error: string;
308
+ };
309
+ /** spec/aviation.md §11: each configuration a labelled session ran that no certificate covers. */
310
+ export declare function unapprovedModifications(lines: readonly string[], certificates: ReadonlyArray<{
311
+ label: string;
312
+ configuration: string;
313
+ }>): Finding[];
314
+ export interface OperatorFacts {
315
+ packs: string[];
316
+ audit_chain_ok: boolean;
317
+ anchoring: {
318
+ enabled: boolean;
319
+ dead: number;
320
+ };
321
+ incidents_open: number;
322
+ checks_overdue: number | null;
323
+ }
324
+ /** spec/aviation.md §14: the operator's certificate (unsigned) over the facts. */
325
+ export declare function operatorCertificate(facts: OperatorFacts, options: {
326
+ operator: string;
327
+ issuedAt: string;
328
+ days?: number;
329
+ }): {
330
+ v: 1;
331
+ type: "blackbox.operator-certificate";
332
+ operator: string;
333
+ issued_at: string;
334
+ expires_at: string;
335
+ controls: OperatorFacts;
336
+ verdict: "certified" | "not_certified";
337
+ reasons: string[];
338
+ };
339
+ /** spec/aviation.md §14: an operator certificate checked offline, like an accreditation. */
340
+ export declare function checkOperatorCertificate(cert: unknown, options: {
341
+ issuers?: readonly string[];
342
+ now: string;
343
+ }): {
344
+ ok: true;
345
+ } | {
346
+ ok: false;
347
+ reason: string;
348
+ };
349
+ export interface Check {
350
+ id: string;
351
+ label: string;
352
+ kind: "drill" | "scenario";
353
+ every_days: number;
354
+ grace_days?: number;
355
+ }
356
+ export interface CheckStatus {
357
+ id: string;
358
+ label: string;
359
+ kind: "drill" | "scenario";
360
+ every_days: number;
361
+ grace_days: number;
362
+ last_done: string | null;
363
+ due_at: string | null;
364
+ status: "current" | "due" | "overdue";
365
+ }
366
+ /** spec/aviation.md §12: an error message, or null for a valid checks file. */
367
+ export declare function checkChecks(doc: unknown): string | null;
368
+ /** spec/aviation.md §12: each check's last run, due date and status at `now`. */
369
+ export declare function checkStatus(checks: readonly Check[], done: ReadonlyArray<{
370
+ label: string;
371
+ kind: string;
372
+ at: string;
373
+ }>, now: string): CheckStatus[];
374
+ /** spec/aviation.md §12: an overdue check of the session's label, flagged at pre-flight. */
375
+ export declare function checkFindings(lines: readonly string[], statuses: readonly CheckStatus[]): Finding[];
376
+ export interface Currency {
377
+ label: string;
378
+ model: string;
379
+ last_flown: string | null;
380
+ current: boolean;
381
+ }
382
+ /** spec/aviation.md §13: whether each airworthy rating is still current. */
383
+ export declare function ratingCurrency(ratings: ReadonlyArray<{
384
+ label: string;
385
+ model: string;
386
+ verdict: string;
387
+ }>, items: ReadonlyArray<{
388
+ summary: {
389
+ label: string | null;
390
+ started_at: string;
391
+ closed: boolean;
392
+ };
393
+ models: readonly string[];
394
+ }>, options: {
395
+ days: number;
396
+ now: string;
397
+ }): Currency[];
398
+ /** spec/aviation.md §13: each model the session uses whose rating for its label has lapsed. */
399
+ export declare function ratingLapsed(lines: readonly string[], prices: LoadedPrices, currency: readonly Currency[], severity?: "advisory" | "warning"): Finding[];
400
+ export interface ApproverStat {
401
+ approver: string;
402
+ decisions: number;
403
+ approved: number;
404
+ rejected: number;
405
+ approve_ppm: number;
406
+ median_ms: number | null;
407
+ fast: number;
408
+ fast_ppm: number;
409
+ rubber_stamp: boolean;
410
+ }
411
+ /** spec/aviation.md §18: each approver's decisions, speed and whether they rubber-stamp. */
412
+ export declare function approverStats(records: ReadonlyArray<readonly string[]>, options?: {
413
+ fastMs?: number;
414
+ minDecisions?: number;
415
+ rubberStampPpm?: number;
416
+ }): {
417
+ approvers: ApproverStat[];
418
+ };
419
+ /** spec/aviation.md §18: once per rubber-stamping approver who decided in this session. */
420
+ export declare function approverFatigueFindings(lines: readonly string[], stats: {
421
+ approvers: readonly ApproverStat[];
422
+ }): Finding[];