@mikeargento/bitgraph-audit 0.8.0 → 0.10.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 (51) hide show
  1. package/README.md +8 -2
  2. package/dist/audit.d.ts +9 -6
  3. package/dist/audit.d.ts.map +1 -1
  4. package/dist/audit.js +34 -8
  5. package/dist/audit.js.map +1 -1
  6. package/dist/ceilings.d.ts.map +1 -1
  7. package/dist/ceilings.js +1 -0
  8. package/dist/ceilings.js.map +1 -1
  9. package/dist/cli.js +109 -21
  10. package/dist/cli.js.map +1 -1
  11. package/dist/exports.d.ts +39 -0
  12. package/dist/exports.d.ts.map +1 -0
  13. package/dist/exports.js +374 -0
  14. package/dist/exports.js.map +1 -0
  15. package/dist/floors.d.ts +23 -0
  16. package/dist/floors.d.ts.map +1 -0
  17. package/dist/floors.js +203 -0
  18. package/dist/floors.js.map +1 -0
  19. package/dist/index.d.ts +6 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +5 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/ingest.d.ts +2 -0
  24. package/dist/ingest.d.ts.map +1 -1
  25. package/dist/ingest.js +193 -19
  26. package/dist/ingest.js.map +1 -1
  27. package/dist/report-json.d.ts.map +1 -1
  28. package/dist/report-json.js +30 -0
  29. package/dist/report-json.js.map +1 -1
  30. package/dist/report-md.d.ts.map +1 -1
  31. package/dist/report-md.js +315 -25
  32. package/dist/report-md.js.map +1 -1
  33. package/dist/temporal.d.ts +12 -0
  34. package/dist/temporal.d.ts.map +1 -1
  35. package/dist/temporal.js +245 -41
  36. package/dist/temporal.js.map +1 -1
  37. package/dist/types.d.ts +348 -7
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +3 -2
  40. package/src/__tests__/base-floor.test.ts +405 -0
  41. package/src/audit.ts +36 -8
  42. package/src/ceilings.ts +1 -0
  43. package/src/cli.ts +117 -22
  44. package/src/exports.ts +482 -0
  45. package/src/floors.ts +242 -0
  46. package/src/index.ts +20 -0
  47. package/src/ingest.ts +207 -18
  48. package/src/report-json.ts +30 -0
  49. package/src/report-md.ts +353 -29
  50. package/src/temporal.ts +279 -48
  51. package/src/types.ts +341 -6
package/src/types.ts CHANGED
@@ -123,6 +123,13 @@ export type AnomalyCode =
123
123
  | "attestation-measurement-mismatch"
124
124
  /** A validated attestation document's user_data is not bound to this proof's canonical proof hash. */
125
125
  | "attestation-user-data-mismatch"
126
+ // --- Exports (bitgraph-export/1) ---
127
+ /** A file declares format "bitgraph-export/1" but lacks an export's structure (a proof object and tree.rootDocument). Not checked; fails the audit (exit bit 1). */
128
+ | "export-malformed"
129
+ /** A file declares a bitgraph-export format other than "bitgraph-export/1". Not checked; fails the audit (exit bit 1), as an unsupported proof version does. */
130
+ | "export-unsupported-format"
131
+ /** A file opens an export object but is larger than the audit's cap for one export's JSON (IngestLimits.maxExportJsonBytes). Not checked; fails the audit (exit bit 1). */
132
+ | "export-too-large"
126
133
  | (string & {});
127
134
 
128
135
  /**
@@ -335,6 +342,19 @@ export interface AnchorWitnessFile {
335
342
  witness: Record<string, unknown>;
336
343
  }
337
344
 
345
+ /**
346
+ * A floor header file (bitgraph-floor-header/1):
347
+ * { version, chain: "base", evmChainId: 8453, blockNumber, blockHash, blockTimestamp, header }
348
+ * where header is the block's RLP as 0x hex. Only the header bytes are
349
+ * evidence: they are checked by keccak-256 against the floor a proof signs,
350
+ * and the other fields are a convenience for readers.
351
+ */
352
+ export interface FloorHeaderFile {
353
+ path: string;
354
+ fileSha256Hex: string;
355
+ json: Record<string, unknown>;
356
+ }
357
+
338
358
  // ---------------------------------------------------------------------------
339
359
  // Manifest
340
360
  // ---------------------------------------------------------------------------
@@ -406,8 +426,12 @@ export interface IngestCounts {
406
426
  artifacts: number;
407
427
  /** Anchor witness files. */
408
428
  witnesses: number;
429
+ /** Floor header files (bitgraph-floor-header/1). Absent when there are none. */
430
+ floorHeaders?: number;
409
431
  /** Ceiling files (bitgraph-ceiling/1) and ceiling status notes (bitgraph-ceiling-status/1). */
410
432
  ceilings?: number;
433
+ /** Export-shaped files (format "bitgraph-export/..."), checked or rejected. */
434
+ exports?: number;
411
435
  /** Container entries skipped for unsafe paths. */
412
436
  skippedUnsafePaths: number;
413
437
  }
@@ -437,6 +461,14 @@ export interface IngestLimits {
437
461
  * declaring a larger size aborts ingest before any allocation.
438
462
  */
439
463
  maxMetadataEntryBytes: number;
464
+ /**
465
+ * Ceiling on one export's JSON (bitgraph-export/1), for every container,
466
+ * directories included. Other JSON candidates stop at 8 MiB; an entry that
467
+ * opens an export object may run to this size (the owner's export of a
468
+ * large tree lists every leaf). A larger export is reported
469
+ * (export-too-large) and not checked. Default 192 MiB.
470
+ */
471
+ maxExportJsonBytes?: number;
440
472
  }
441
473
 
442
474
  /**
@@ -469,10 +501,21 @@ export interface IngestResult {
469
501
  artifacts: ArtifactRecord[];
470
502
  /** Anchor witness files in observation order. */
471
503
  witnesses: AnchorWitnessFile[];
504
+ /**
505
+ * Floor header files (bitgraph-floor-header/1): the header of a Base block
506
+ * a proof signs as its floor, the way the carrier/3 unpacker writes it.
507
+ * Evidence, never artifacts. Optional so older embedders' IngestResults still type.
508
+ */
509
+ floorHeaders?: FloorHeaderFile[];
472
510
  /** Ceiling files (bitgraph-ceiling/1) in observation order. Optional so older embedders' IngestResults still type. */
473
511
  ceilings?: CeilingFile[];
474
512
  /** Ceiling status notes (bitgraph-ceiling-status/1): a package saying why a ceiling is absent. */
475
513
  ceilingStatuses?: CeilingFile[];
514
+ /**
515
+ * Export-shaped files (format "bitgraph-export/..."), in observation order.
516
+ * Evidence, never artifacts. Optional so older embedders' IngestResults still type.
517
+ */
518
+ exports?: ExportFile[];
476
519
  /** Present when a root manifest.json entry existed. */
477
520
  manifest?: ManifestReport;
478
521
 
@@ -646,9 +689,13 @@ export interface EpochAnchorBound {
646
689
  * anchor evidence. "not-before": they came after it. Always one-sided.
647
690
  */
648
691
  kind: "not-after" | "not-before";
649
- /** Canonical hash of the anchor proof providing the bound. */
692
+ /** Canonical hash of the anchor proof providing the bound (for a Base floor, the proof that signs it). */
650
693
  anchorProofHash: string;
651
- /** Ethereum block number parsed from the signed anchor title URL (decimal string). */
694
+ /** Absent for an anchor bound; "signed-floor" when the representative bound is a Base floor a proof signs. */
695
+ source?: "signed-floor";
696
+ /** Absent for Ethereum; "base" when the representative bound is a Base block. */
697
+ chain?: "base";
698
+ /** Block number (decimal string): the anchored Ethereum block, or the Base floor block. */
652
699
  blockNumber?: string;
653
700
  /** Ethereum block hash from the signed attribution message. */
654
701
  blockHash?: string;
@@ -1050,8 +1097,17 @@ export interface AnchorWitnessAnalysis {
1050
1097
  * "counter-order" only the commit counters order them. This relies on
1051
1098
  * the authority's per-chain counter discipline rather
1052
1099
  * than verifiable hash links, and is marked weaker.
1100
+ * "signed-floor" the bounded proof itself signs the floor block
1101
+ * (commit.slotFloor, a Base block, enclave v10). Nothing
1102
+ * stands between the proof and the block: it is the
1103
+ * proof's own signed field. Not weaker.
1104
+ *
1105
+ * A Base floor bound reaches other proofs only the way an anchor bound
1106
+ * does: through a verified hash-link path ("chain-link") or by counter
1107
+ * order ("counter-order"), and only as a NOT-BEFORE. A floor never yields a
1108
+ * not-after: a later proof's floor block can predate this proof.
1053
1109
  */
1054
- export type BoundEvidence = "chain-link" | "counter-order";
1110
+ export type BoundEvidence = "chain-link" | "counter-order" | "signed-floor";
1055
1111
 
1056
1112
  /**
1057
1113
  * One one-sided temporal bound on a segment, derived from a verified
@@ -1081,7 +1137,27 @@ export type BoundEvidence = "chain-link" | "counter-order";
1081
1137
  */
1082
1138
  export interface SegmentBound {
1083
1139
  kind: "not-before" | "not-after";
1140
+ /**
1141
+ * The proof that supplies the bound: the anchor proof, or for a Base floor
1142
+ * (source "signed-floor") the proof that signs the floor block.
1143
+ */
1084
1144
  anchorProofHash: string;
1145
+ /**
1146
+ * Absent for an anchor bound (an Ethereum anchor proof with a verified
1147
+ * witness, every bound before enclave v10). "signed-floor": the Base block a
1148
+ * proof signs as commit.slotFloor (enclave v10). Always a not-before.
1149
+ */
1150
+ source?: "signed-floor";
1151
+ /** Absent for Ethereum (every anchor bound); "base" for a Base floor. */
1152
+ chain?: "base";
1153
+ /**
1154
+ * Base floors only: where the block time comes from. "header": a header in
1155
+ * the bundle hashes to the signed block and carries the signed number and
1156
+ * time. "signed": no header for the block is in the bundle; the time is the
1157
+ * one the proof signs (on Base mainnet's schedule for its number), and
1158
+ * confirming the block needs a Base lookup.
1159
+ */
1160
+ timeSource?: "header" | "signed";
1085
1161
  /** Block number confirmed by the verified witness header (decimal string). */
1086
1162
  blockNumber?: string;
1087
1163
  /** Locally recomputed block hash (0x + 64 lowercase hex). */
@@ -1175,6 +1251,52 @@ export interface AnchorOrderedPair {
1175
1251
  note: string;
1176
1252
  }
1177
1253
 
1254
+ /**
1255
+ * A Base floor one proof signs (commit.slotFloor, enclave v10), as the
1256
+ * temporal pass read it. Listed only for Base floors: an Ethereum floor
1257
+ * (commit.slotAnchor) is read through the anchor proofs, as before.
1258
+ */
1259
+ export interface SignedFloorRecord {
1260
+ proofHash: string;
1261
+ chain: "base";
1262
+ blockNumber: number;
1263
+ /** 0x-prefixed lowercase hex, as signed. */
1264
+ blockHash: string;
1265
+ /** Unix seconds, as signed. */
1266
+ blockTimestamp: number;
1267
+ /** "checked": a header in the bundle hashes to the signed block (headerPath names it). "not-carried": none is here. */
1268
+ header: "checked" | "not-carried";
1269
+ /** Bundle path of the header that was checked (a floor header file, a ceiling file or an export). */
1270
+ headerPath?: string;
1271
+ /** "not-before": the floor bounds the proof. "withheld": it does not, for withheldReason. */
1272
+ bound: "not-before" | "withheld";
1273
+ withheldReason?: string;
1274
+ }
1275
+
1276
+ /** Problem codes of the floor stage. Every one sets exit bit 2. */
1277
+ export type FloorProblemCode =
1278
+ /** The proof signs two floors (commit.slotAnchor and commit.slotFloor): ambiguous, bounds nothing. */
1279
+ | "floor-ambiguous"
1280
+ /** commit.slotFloor does not name Base mainnet, or lacks a 32-byte hash, a number or a time. */
1281
+ | "floor-malformed"
1282
+ /** The signed Base floor time is not Base mainnet's schedule for the signed block number. */
1283
+ | "floor-off-schedule"
1284
+ /** A floor header file names a block a proof signs, and does not match it (hash, number, time or chain). */
1285
+ | "floor-header-mismatch"
1286
+ /** A floor header file is unreadable or not a Base header. */
1287
+ | "floor-header-malformed"
1288
+ /** A floor header file hashes to a block no proof in the bundle signs as its floor. */
1289
+ | "floor-header-unmatched";
1290
+
1291
+ export interface FloorProblem {
1292
+ code: FloorProblemCode;
1293
+ /** The proof concerned, when there is one. */
1294
+ proofHash?: string;
1295
+ /** The bundle path concerned (a proof file or a floor header file). */
1296
+ path?: string;
1297
+ message: string;
1298
+ }
1299
+
1178
1300
  /** Output of the temporal bounds pass. */
1179
1301
  export interface TemporalAnalysis {
1180
1302
  /** Per-partition segments with their bounds, deterministically ordered. */
@@ -1185,6 +1307,10 @@ export interface TemporalAnalysis {
1185
1307
  verifiedAnchorProofHashes: string[];
1186
1308
  /** Identified anchors with no verified witness: they still establish causal order, but confer no wall-clock evidence. Sorted. */
1187
1309
  unverifiedAnchorProofHashes: string[];
1310
+ /** Base floors the proofs sign (enclave v10), in observation order. Absent when no proof signs one. */
1311
+ signedFloors?: SignedFloorRecord[];
1312
+ /** Floor problems (exit bit 2). Absent when there are none. */
1313
+ floorProblems?: FloorProblem[];
1188
1314
  }
1189
1315
 
1190
1316
  // ---------------------------------------------------------------------------
@@ -1314,6 +1440,8 @@ export interface AuditOptions {
1314
1440
  trustedRootCaDer?: Uint8Array;
1315
1441
  /** Ceilings in time: the declared writer, the chain, and an optional Base RPC for the one online check. */
1316
1442
  ceilings?: import("./ceilings.js").CeilingAuditOptions;
1443
+ /** Exports (bitgraph-export/1): extra spec hashes, PCR0 pins, and optional lookups for embedders that allow network. */
1444
+ exports?: import("./exports.js").ExportAuditOptions;
1317
1445
  }
1318
1446
 
1319
1447
  /**
@@ -1351,9 +1479,11 @@ export interface CeilingCheck {
1351
1479
  */
1352
1480
  status: "verified" | "failed" | "pending" | "unmatched";
1353
1481
  reason?: string;
1354
- /** One line for people, e.g. "Ceiling: Base block N at hh:mm:ss UTC, settled on Ethereum." */
1482
+ /** One line for people, e.g. "Ceiling: included in Base block N at hh:mm:ss UTC. ..."; it never claims settlement the file does not prove. */
1355
1483
  label?: string;
1356
1484
  window?: {
1485
+ /** "base" when the floor block (the one the proof signs) is a Base block; absent for Ethereum or no floor. */
1486
+ floorChain?: "base";
1357
1487
  floorBlock: number | null;
1358
1488
  floorTime: number | null;
1359
1489
  ceilingChainId: number;
@@ -1406,6 +1536,166 @@ export interface CeilingAnalysis {
1406
1536
  statuses: Array<{ path: string; status: string; note: string }>;
1407
1537
  }
1408
1538
 
1539
+ // ---------------------------------------------------------------------------
1540
+ // Exports (bitgraph-export/1)
1541
+ // ---------------------------------------------------------------------------
1542
+
1543
+ /**
1544
+ * An export-shaped file as found in the bundle: a JSON object whose format
1545
+ * field starts with "bitgraph-export/". Found by structure, never by name.
1546
+ * Evidence, never an artifact.
1547
+ */
1548
+ export interface ExportFile {
1549
+ path: string;
1550
+ fileSha256Hex: string;
1551
+ /** The format the file declares. */
1552
+ format: string;
1553
+ /**
1554
+ * ok: a bitgraph-export/1 document (bitgraph-verify's parseExport accepts it).
1555
+ * malformed: declares bitgraph-export/1 but lacks a proof object or tree.rootDocument.
1556
+ * unsupported-format: declares another bitgraph-export version.
1557
+ * too-large: opens an export object but is larger than the audit's export JSON cap; not parsed (json is empty).
1558
+ */
1559
+ status: "ok" | "malformed" | "unsupported-format" | "too-large";
1560
+ json: Record<string, unknown>;
1561
+ /** Canonical hash of the proof the export carries, when that proof joined the proof analysis (a proof-shaped bitgraph/1 object). */
1562
+ proofHash?: string;
1563
+ }
1564
+
1565
+ /** One claim exactly as bitgraph-verify's verifyExport states it. */
1566
+ export interface ExportClaimRecord {
1567
+ /** Stable id, dotted: "proof.signature", "tree.member", "bytes.floor", "ceiling.base", "confirmed.floor" ... */
1568
+ id: string;
1569
+ name: string;
1570
+ result: "TRUE" | "FALSE" | "UNDETERMINED" | "NOT_CARRIED";
1571
+ /** What the result rests on (the primitive or the evidence), empty when nothing was checked. */
1572
+ restsOn: string;
1573
+ detail: string;
1574
+ /** offline: recomputed from the bytes in hand. confirmed: from the caller's own chain lookups (never made by the CLI). */
1575
+ level: "offline" | "confirmed";
1576
+ }
1577
+
1578
+ /** The three time claims as verifyExport establishes them. Never merged; a null field was not established. */
1579
+ export interface ExportTimes {
1580
+ /**
1581
+ * The committed bytes were finished after this block (the proof's signed
1582
+ * floor block, its header checked by hash), on its chain: chain absent is
1583
+ * Ethereum (an anchor floor, commit.slotAnchor), "base" a Base floor
1584
+ * (commit.slotFloor, enclave v10). Absent rather than "ethereum" so reports
1585
+ * on older exports stay byte-identical.
1586
+ */
1587
+ floor: { chain?: "base"; blockNumber: number; blockHash: string; blockTimestamp: number } | null;
1588
+ /** The record existed by this Base block, at its time. Provisional until the block is checked against Base (offline, always provisional). */
1589
+ ceilingBase: { blockNumber: number; blockHash: string; blockTimestamp: number; provisional: boolean } | null;
1590
+ /** The record existed by this Ethereum block (through Base's output root; needs no trust in Base). */
1591
+ ceilingEthereum: { blockNumber: number; blockHash: string; blockTimestamp: number } | null;
1592
+ }
1593
+
1594
+ /** A file in the bundle that an export covers, matched by SHA-256 against a leaf's digests. */
1595
+ export interface ExportCoveredFile {
1596
+ /** SHA-256 of the file, lowercase hex. */
1597
+ sha256Hex: string;
1598
+ /** Every bundle path holding these bytes. */
1599
+ paths: string[];
1600
+ byteLength: number;
1601
+ /** The leaf it matched, in tree order: the first leaf whose committed or original digest is the file's, as verifyExport picks it. */
1602
+ leafIndex: number | null;
1603
+ /** That leaf's placement: "as-is", "trailer/1", "container/1" or "container/2". */
1604
+ placement: string | null;
1605
+ /**
1606
+ * committed-bytes: the file is the leaf's committed bytes (its artifact digest).
1607
+ * original: the file is the original the committed bytes were made from (its origin digest).
1608
+ * as-is: the leaf records the file exactly as it is (the two digests are the same).
1609
+ */
1610
+ matchedAs: "committed-bytes" | "original" | "as-is";
1611
+ /** The name an owner's export lists for that leaf. Unsigned and informational. */
1612
+ nameInExport?: string;
1613
+ }
1614
+
1615
+ /** A claim of one run that is not common to every run of its export, with its place in verifyExport's order. */
1616
+ export interface ExportOwnClaim extends ExportClaimRecord {
1617
+ /** Index of this claim in the run's whole claim list, in verifyExport's order. */
1618
+ position: number;
1619
+ }
1620
+
1621
+ /**
1622
+ * One verifyExport run: with one covered file, or once without a file when
1623
+ * the bundle holds none. The run's whole claim list, in verifyExport's
1624
+ * order, is the export's common claims (ExportCheck.claims) with this run's
1625
+ * own claims put back at their positions: exportRunClaims(check, run).
1626
+ * verifyExport's reasons are that list's FALSE and UNDETERMINED claims, and
1627
+ * its time claims are the export's (ExportCheck.times): they do not depend
1628
+ * on the file.
1629
+ */
1630
+ export interface ExportRun {
1631
+ /** The covered file this run checked; null for the run without a file. */
1632
+ file: ExportCoveredFile | null;
1633
+ /** verifyExport's verdict over its offline claims. */
1634
+ verdict: "TRUE" | "FALSE" | "UNDETERMINED";
1635
+ /** This run's claims that differ from the export's common claims (in practice the ones about its file: tree.member, bytes.member, bytes.floor). */
1636
+ claims: ExportOwnClaim[];
1637
+ /** The member the run established (index, count, placement, digests), when it did. */
1638
+ member: { index: number; count: number; placement: string; artifactHex: string; originHex: string } | null;
1639
+ /**
1640
+ * What the floor covers for this run's file, read from its claims: content
1641
+ * (the committed bytes carry the commitment, so they were finished after the
1642
+ * floor block; an original inside them is not dated by it), record (an as-is
1643
+ * leaf: the record was made after the floor block, the bytes themselves are
1644
+ * not dated), or null (the file was not established as a member, or no file
1645
+ * was checked).
1646
+ */
1647
+ floorCovers: "content" | "record" | null;
1648
+ /** verifyExport's plain-language reading, written from its claims. */
1649
+ reading: string;
1650
+ }
1651
+
1652
+ /** One export file, checked. */
1653
+ export interface ExportCheck {
1654
+ path: string;
1655
+ fileSha256Hex: string;
1656
+ format: string;
1657
+ /** checked: verifyExport ran. malformed / unsupported-format / too-large: rejected at ingest, not checked (exit bit 1). */
1658
+ status: "checked" | "malformed" | "unsupported-format" | "too-large";
1659
+ /** Why the file was not checked. */
1660
+ reason?: string;
1661
+ /** member: carries one member's evidence (tree.member). owner: carries the whole list (tree.leaves). root-only: neither. */
1662
+ kind?: "member" | "owner" | "root-only";
1663
+ /** Canonical hash of the export's proof, which also appears in the proof analysis. */
1664
+ proofHash?: string;
1665
+ /**
1666
+ * The audit's judgment of the export: FALSE when any run's verdict is FALSE
1667
+ * or any claim of any run is FALSE (a confirmed claim included, from an
1668
+ * embedder's lookup); else UNDETERMINED when any run is; else TRUE. A FALSE
1669
+ * export fails the audit (exit bit 1), as a bad proof does.
1670
+ */
1671
+ verdict: "TRUE" | "FALSE" | "UNDETERMINED";
1672
+ /** Ids of the claims that are FALSE in any run, in first-seen order. */
1673
+ failedClaims: string[];
1674
+ /** The three time claims, never merged. They do not depend on the file, so every run states the same; read from the first. */
1675
+ times: ExportTimes;
1676
+ /** The claims every run states alike (same id, result, level, restsOn and detail), in verifyExport's order. With one run, all of its claims. */
1677
+ claims: ExportClaimRecord[];
1678
+ /** Files in the bundle this export covers, sorted by first path. */
1679
+ files: ExportCoveredFile[];
1680
+ /** One run per covered file (in the order of files), or one run without a file when the bundle holds none. */
1681
+ runs: ExportRun[];
1682
+ /**
1683
+ * How the per-file runs of an owner's export were made. as-given: verifyExport
1684
+ * on the export itself, once per file. member-from-list: the owner's list was
1685
+ * checked once (claim tree.leaves TRUE), then each file's member evidence was
1686
+ * derived from it exactly as verifyExport derives it, verifyExport ran on that
1687
+ * member form, and the list claim was put back in its place; the runs equal
1688
+ * the as-given runs, without rebuilding the whole tree once per file.
1689
+ */
1690
+ runMode?: "as-given" | "member-from-list";
1691
+ /** Covered files not checked one by one: only when an owner's list fails and the per-file budget ran out, or a file could not be re-read. */
1692
+ unchecked?: Array<{ file: ExportCoveredFile; reason: string }>;
1693
+ }
1694
+
1695
+ export interface ExportAnalysis {
1696
+ checks: ExportCheck[];
1697
+ }
1698
+
1409
1699
  export interface AuditResult {
1410
1700
  runMetadata: AuditRunMetadata;
1411
1701
  ingest: IngestResult;
@@ -1419,6 +1709,8 @@ export interface AuditResult {
1419
1709
  attestations: AttestationAnalysis;
1420
1710
  /** Ceilings in time on Base. Absent from results made before this stage existed. */
1421
1711
  ceilings?: CeilingAnalysis;
1712
+ /** Exports (bitgraph-export/1), each checked with verifyExport per covered file. Absent from results made before this stage existed. */
1713
+ exports?: ExportAnalysis;
1422
1714
  }
1423
1715
 
1424
1716
  /**
@@ -1426,7 +1718,13 @@ export interface AuditResult {
1426
1718
  *
1427
1719
  * bit 1 (value 1): verification failures. Set when any proof's canonical
1428
1720
  * checks failed at either tier, or any proof-shaped input was rejected
1429
- * as an unsupported version. artifact-unavailable is NOT a failure: a
1721
+ * as an unsupported version, or any export (bitgraph-export/1) has a
1722
+ * FALSE claim (its verdict is FALSE), or an export-shaped file was
1723
+ * rejected as malformed or of an unsupported format. An export's
1724
+ * attestation claims are part of its verdict: an export is checked as
1725
+ * one self-contained object, as a carrier is. NOT_CARRIED claims (a
1726
+ * pending ceiling, the covered file absent) never fail an export.
1727
+ * artifact-unavailable is NOT a failure: a
1430
1728
  * proof without artifact bytes passes or fails on its bytes-free checks
1431
1729
  * alone, unless a supplied trust policy makes those checks fail (for
1432
1730
  * example requireSlot), in which case its status is "failed" and it
@@ -1440,7 +1738,9 @@ export interface AuditResult {
1440
1738
  * witness failed its offline verification (a witness-* code: RLP or
1441
1739
  * header malformation, block-hash mismatch, digest-binding mismatch,
1442
1740
  * block-number mismatch, an invalid candidate anchor, or an unmatched
1443
- * witness). Benign findings are reported but never set exit bits: ingest
1741
+ * witness), or any floor problem (a floor-* code: a proof signing two
1742
+ * floors, a malformed or off-schedule Base floor, a floor header that
1743
+ * contradicts the signed floor or matches none). Benign findings are reported but never set exit bits: ingest
1444
1744
  * advisories (duplicate copies, manifest advisories, unsafe paths,
1445
1745
  * embedded proofHash mismatches) and informational anchor findings
1446
1746
  * (anchor-metadata-disagreement, anchor-metadata-only-claim,
@@ -1615,6 +1915,35 @@ export interface ReportSummary {
1615
1915
  segmentsLowerBounded: number;
1616
1916
  segmentsUpperBounded: number;
1617
1917
  segmentsUnanchored: number;
1918
+ /**
1919
+ * Base floors (enclave v10), as counts. Present only when a proof signs a
1920
+ * Base floor or a floor problem was found, so older reports are unchanged.
1921
+ */
1922
+ baseFloors?: {
1923
+ /** Proofs that sign a Base floor (commit.slotFloor). */
1924
+ signed: number;
1925
+ /** Of those, floors that bound their proof not-before. */
1926
+ bounding: number;
1927
+ /** Of those, floors whose header the bundle carries, checked against the signed block. */
1928
+ headersChecked: number;
1929
+ /** Floors not used as a bound (see SignedFloorRecord.withheldReason). */
1930
+ withheld: number;
1931
+ /** Floor problems (exit bit 2). */
1932
+ problems: number;
1933
+ };
1934
+ };
1935
+ /** Exports (bitgraph-export/1), as counts. Present only when the bundle carries export-shaped files. */
1936
+ exports?: {
1937
+ /** Export-shaped files found. */
1938
+ files: number;
1939
+ /** Exports checked, by the audit's verdict. */
1940
+ verdictTrue: number;
1941
+ verdictFalse: number;
1942
+ verdictUndetermined: number;
1943
+ /** Export-shaped files rejected (malformed or an unsupported format). */
1944
+ rejected: number;
1945
+ /** verifyExport runs made with a covered file from the bundle. */
1946
+ coveredFilesChecked: number;
1618
1947
  };
1619
1948
  exit: ExitFlags;
1620
1949
  }
@@ -1662,6 +1991,8 @@ export interface AuditJsonReport {
1662
1991
  };
1663
1992
  /** Ceilings in time on Base (bitgraph-ceiling/1). Absent when the bundle carries none. */
1664
1993
  ceilings?: import("./types.js").CeilingAnalysis;
1994
+ /** Exports (bitgraph-export/1), one entry per export file in observation order. Absent when the bundle carries none. */
1995
+ exports?: ExportAnalysis;
1665
1996
  attestations: {
1666
1997
  records: ProofAttestationRecord[];
1667
1998
  counts: AttestationAnalysis["counts"];
@@ -1677,6 +2008,10 @@ export interface AuditJsonReport {
1677
2008
  segments: TemporalSegment[];
1678
2009
  verifiedAnchorProofHashes: string[];
1679
2010
  unverifiedAnchorProofHashes: string[];
2011
+ /** Base floors the proofs sign (enclave v10). Absent when there are none. */
2012
+ signedFloors?: SignedFloorRecord[];
2013
+ /** Floor problems (exit bit 2). Absent when there are none. */
2014
+ floorProblems?: FloorProblem[];
1680
2015
  };
1681
2016
  summary: ReportSummary;
1682
2017
  }