@tenova/swt3-ai 0.5.5 → 0.5.6

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 (65) hide show
  1. package/README.md +16 -13
  2. package/dist/adapters/a2a.d.ts +26 -0
  3. package/dist/adapters/a2a.d.ts.map +1 -0
  4. package/dist/adapters/a2a.js +86 -0
  5. package/dist/adapters/a2a.js.map +1 -0
  6. package/dist/adapters/crewai.d.ts +26 -0
  7. package/dist/adapters/crewai.d.ts.map +1 -0
  8. package/dist/adapters/crewai.js +78 -0
  9. package/dist/adapters/crewai.js.map +1 -0
  10. package/dist/adapters/foundry.d.ts +26 -0
  11. package/dist/adapters/foundry.d.ts.map +1 -0
  12. package/dist/adapters/foundry.js +118 -0
  13. package/dist/adapters/foundry.js.map +1 -0
  14. package/dist/adapters/google-adk.d.ts +25 -0
  15. package/dist/adapters/google-adk.d.ts.map +1 -0
  16. package/dist/adapters/google-adk.js +81 -0
  17. package/dist/adapters/google-adk.js.map +1 -0
  18. package/dist/chain.d.ts +33 -0
  19. package/dist/chain.d.ts.map +1 -0
  20. package/dist/chain.js +94 -0
  21. package/dist/chain.js.map +1 -0
  22. package/dist/clearing.d.ts +7 -2
  23. package/dist/clearing.d.ts.map +1 -1
  24. package/dist/clearing.js +16 -5
  25. package/dist/clearing.js.map +1 -1
  26. package/dist/cli.d.ts +1 -0
  27. package/dist/cli.d.ts.map +1 -1
  28. package/dist/cli.js +123 -6
  29. package/dist/cli.js.map +1 -1
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +15 -0
  32. package/dist/config.js.map +1 -1
  33. package/dist/demo.d.ts.map +1 -1
  34. package/dist/demo.js +173 -10
  35. package/dist/demo.js.map +1 -1
  36. package/dist/doctor.d.ts +1 -1
  37. package/dist/doctor.d.ts.map +1 -1
  38. package/dist/doctor.js +39 -16
  39. package/dist/doctor.js.map +1 -1
  40. package/dist/index.d.ts +9 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +7 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/procedures.d.ts +20 -0
  45. package/dist/procedures.d.ts.map +1 -0
  46. package/dist/procedures.js +162 -0
  47. package/dist/procedures.js.map +1 -0
  48. package/dist/profile.d.ts +50 -0
  49. package/dist/profile.d.ts.map +1 -0
  50. package/dist/profile.js +109 -0
  51. package/dist/profile.js.map +1 -0
  52. package/dist/trust.d.ts +96 -2
  53. package/dist/trust.d.ts.map +1 -1
  54. package/dist/trust.js +200 -9
  55. package/dist/trust.js.map +1 -1
  56. package/dist/types.d.ts +120 -1
  57. package/dist/types.d.ts.map +1 -1
  58. package/dist/types.js +173 -1
  59. package/dist/types.js.map +1 -1
  60. package/dist/witness.d.ts +547 -0
  61. package/dist/witness.d.ts.map +1 -1
  62. package/dist/witness.js +1557 -202
  63. package/dist/witness.js.map +1 -1
  64. package/package.json +2 -2
  65. package/templates/healthcare-clinical.yaml +4 -0
package/dist/witness.js CHANGED
@@ -34,7 +34,7 @@ import { queryHardware as queryHw, topologyCode as topoCode, queryTPM as queryTp
34
34
  import { queryEnvironment as queryEnv } from "./environment.js";
35
35
  import { TrustRegistry, verifyCredential, signCredential, TRUST_LEVEL_NAMES, } from "./trust.js";
36
36
  import { createVercelOnFinish } from "./adapters/vercel-ai.js";
37
- import { QUANTIZATION_CODES, POLICY_CATEGORIES, BINDING_METHODS, APPROVAL_STATUS, PII_EVENT_TYPES, CONTENT_TYPE_CODES, BASELINE_MODE_CODES } from "./types.js";
37
+ import { QUANTIZATION_CODES, POLICY_CATEGORIES, BINDING_METHODS, APPROVAL_STATUS, PII_EVENT_TYPES, CONTENT_TYPE_CODES, BASELINE_MODE_CODES, LICENSE_TYPE_CODES, SBOM_FORMAT_CODES, REDTEAM_CATEGORY_CODES, CONSENT_BASIS_CODES, DRIFT_TYPE_CODES, LOG_FORMAT_CODES, INCIDENT_TYPE_CODES, BENCHMARK_TYPE_CODES, PERTURBATION_TYPE_CODES, CYBER_FRAMEWORK_CODES, DISCLOSURE_TYPE_CODES, RECIPIENT_TYPE_CODES, DETECTION_METHOD_CODES, PROCESSING_TYPE_CODES, DECISION_TYPE_CODES, REPORTING_STATUS_CODES, SUPPLY_RISK_CODES, PMM_TYPE_CODES, LIFECYCLE_STAGE_CODES, METAGOV_SCOPE_CODES, METAGOV_PERMISSION_CODES, METAGOV_OVERRIDE_REASON_CODES, METAGOV_REVIEW_STATUS_CODES, METAGOV_DIVERGENCE_CODES, DESIGN_DOMAIN_CODES, SIMULATION_TYPE_CODES, APPROVAL_TYPE_CODES, MATERIAL_STANDARD_CODES, CHAIN_STATUS_CODES, RELEASE_TYPE_CODES } from "./types.js";
38
38
  import { loadFullConfig, validatePolicy } from "./config.js";
39
39
  import { MerkleAccumulator } from "./merkle.js";
40
40
  // ── Chain Density Enforcement ──────────────────────────────────────────
@@ -44,6 +44,13 @@ function globToRegex(pattern) {
44
44
  .replace(/\?/g, ".");
45
45
  return new RegExp("^" + escaped + "$");
46
46
  }
47
+ /** Parse first 8 hex chars as int mod 1M, falling back to hash for non-hex input. */
48
+ function safeHexInt(s) {
49
+ const v = parseInt(s.slice(0, 8), 16);
50
+ if (!isNaN(v))
51
+ return v % 1000000;
52
+ return parseInt(sha256Truncated(s, 8), 16) % 1000000;
53
+ }
47
54
  function parseVelocity(spec) {
48
55
  const parts = spec.split("/");
49
56
  const limit = parseInt(parts[0], 10);
@@ -297,6 +304,7 @@ export class Witness {
297
304
  _chainEnforcer;
298
305
  _sentinel;
299
306
  _sentinelDetecting = false;
307
+ _lastKnownGoodVersion = 0;
300
308
  get configHash() {
301
309
  return this._configHash;
302
310
  }
@@ -975,8 +983,9 @@ export class Witness {
975
983
  ? Witness.hashModelFile(weights)
976
984
  : weights;
977
985
  const match = options?.expectedHash ? info.fileHash === options.expectedHash : true;
986
+ const stageCode = options?.lifecycleStage ? (LIFECYCLE_STAGE_CODES[options.lifecycleStage] ?? 0) : 0;
978
987
  const [ts, epoch] = timestampMs();
979
- const fa = 1, fb = match ? 1 : 0, fc = 0;
988
+ const fa = 1, fb = match ? 1 : 0, fc = stageCode;
980
989
  const fp = mintFingerprint(this.config.tenantId, "AI-MDL.5", fa, fb, fc, ts);
981
990
  const payload = {
982
991
  procedure_id: "AI-MDL.5", factor_a: fa, factor_b: fb, factor_c: fc,
@@ -994,6 +1003,8 @@ export class Witness {
994
1003
  ctx.format = info.format;
995
1004
  if (options?.expectedHash)
996
1005
  ctx.expected_hash = options.expectedHash;
1006
+ if (options?.lifecycleStage)
1007
+ ctx.lifecycle_stage = options.lifecycleStage;
997
1008
  payload.ai_context = ctx;
998
1009
  }
999
1010
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1548,206 +1559,338 @@ export class Witness {
1548
1559
  this.buffer.enqueueMany([payload]);
1549
1560
  return payload;
1550
1561
  }
1551
- // ── Chain, Violation, Charter, Registry, Reviewer, Safe State ───
1562
+ // ── License Provenance (AI-LIC.1) ──────────────────────────────
1552
1563
  /**
1553
- * Witness a multi-agent chain handoff (AI-CHAIN.1).
1564
+ * Witness license provenance of a model stack (AI-LIC.1).
1565
+ *
1566
+ * Records the license composition of base models, adapters, and
1567
+ * training data. Detects license drift when components from
1568
+ * different license families are combined.
1569
+ *
1570
+ * @param options.componentsChecked - Number of license components verified.
1571
+ * @param options.allCompliant - True if all components are license-compatible.
1572
+ * @param options.licenseType - Primary license type (permissive, copyleft, proprietary, dual, openmdw, unknown).
1573
+ * @param options.baseModelLicense - SPDX identifier of the base model license.
1574
+ * @param options.adapterLicenses - List of adapter/LoRA license identifiers.
1575
+ * @param options.spdxIds - SPDX identifiers for all components.
1576
+ * @param options.licenseHash - SHA-256 of the full license manifest.
1554
1577
  */
1555
- witnessChainHandoff(depth, targetAgent, options) {
1556
- const accepted = options?.accepted ?? true;
1578
+ witnessLicenseProvenance(options) {
1579
+ const fa = options.componentsChecked;
1580
+ const fb = options.allCompliant ? 1 : 0;
1581
+ const fc = LICENSE_TYPE_CODES[options.licenseType] ?? 5;
1557
1582
  const [ts, epoch] = timestampMs();
1558
- const fa = depth;
1559
- const fb = this.config.cycleId ? 1 : 0;
1560
- const fc = accepted ? 1 : 0;
1561
- const fp = mintFingerprint(this.config.tenantId, "AI-CHAIN.1", fa, fb, fc, ts);
1583
+ const fp = mintFingerprint(this.config.tenantId, "AI-LIC.1", fa, fb, fc, ts);
1562
1584
  const payload = {
1563
- procedure_id: "AI-CHAIN.1", factor_a: fa, factor_b: fb, factor_c: fc,
1585
+ procedure_id: "AI-LIC.1",
1586
+ factor_a: fa, factor_b: fb, factor_c: fc,
1564
1587
  clearing_level: this.config.clearingLevel,
1565
1588
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1566
1589
  };
1567
1590
  if (this.config.clearingLevel <= 1) {
1568
- payload.ai_model_id = targetAgent;
1569
- payload.ai_context = {
1570
- provider: "chain", target_agent: targetAgent, depth, accepted,
1591
+ payload.ai_model_id = `license-${options.licenseType}`;
1592
+ const ctx = {
1593
+ provider: "license-provenance",
1594
+ license_type: options.licenseType,
1571
1595
  };
1596
+ if (options.baseModelLicense)
1597
+ ctx.base_model_license = options.baseModelLicense;
1598
+ if (options.adapterLicenses)
1599
+ ctx.adapter_licenses = options.adapterLicenses;
1600
+ if (options.spdxIds)
1601
+ ctx.spdx_ids = options.spdxIds;
1602
+ if (options.licenseHash)
1603
+ ctx.license_hash = options.licenseHash;
1604
+ payload.ai_context = ctx;
1572
1605
  }
1573
- const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1606
+ const policyHash = this.config.policyVersion
1607
+ ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1574
1608
  this._applyOperationalMetadata(payload, policyHash);
1575
1609
  this.buffer.enqueueMany([payload]);
1576
1610
  return payload;
1577
1611
  }
1612
+ // ── AI Bill of Materials (AI-SBOM.1) ────────────────────────────
1578
1613
  /**
1579
- * Witness a trust-level-aware chain handoff (AI-CHAIN.1 + optional AI-CHAIN.2).
1614
+ * Witness an AI bill of materials snapshot (AI-SBOM.1).
1580
1615
  *
1581
- * Tracks the effective trust level across all agents in the chain.
1582
- * If chainMinTrustLevel is configured and strict mode is active,
1583
- * throws ChainTrustError when the effective level drops below the minimum.
1616
+ * Records the component inventory of an AI system at build or deploy
1617
+ * time, covering models, datasets, infrastructure, and security
1618
+ * posture per G7/CISA "SBOM for AI Minimum Elements" (May 2026).
1584
1619
  *
1585
- * Auto-mints AI-CHAIN.2 (trust degradation) when the effective trust
1586
- * level drops compared to the previous handoff.
1620
+ * @param options.totalComponents - Number of components in the BOM.
1621
+ * @param options.clustersDocumented - G7 clusters documented (0-7).
1622
+ * @param options.format - BOM format (cyclonedx, spdx, custom, unknown).
1623
+ * @param options.bomHash - SHA-256 of the full BOM document.
1624
+ * @param options.version - BOM version string.
1625
+ * @param options.modelCount - Number of AI models in BOM.
1626
+ * @param options.datasetCount - Number of datasets in BOM.
1627
+ * @param options.infrastructureComponents - Number of infra components.
1587
1628
  */
1588
- witnessChainTrustHandoff(targetAgentId, targetTrustLevel, options) {
1589
- const accepted = options?.accepted ?? true;
1590
- const prevEffective = this._chainTrustLevels.length > 0
1591
- ? Math.min(...this._chainTrustLevels)
1592
- : targetTrustLevel;
1593
- this._chainTrustLevels.push(targetTrustLevel);
1594
- const effectiveTrustLevel = Math.min(...this._chainTrustLevels);
1595
- // Enforce minimum if configured
1596
- const minLevel = this.config.chainMinTrustLevel;
1597
- if (minLevel !== undefined && effectiveTrustLevel < minLevel && this._strict) {
1598
- throw new ChainTrustError(effectiveTrustLevel, minLevel);
1599
- }
1629
+ witnessSbom(options) {
1630
+ const fa = options.totalComponents;
1631
+ const fb = options.clustersDocumented;
1632
+ const fc = SBOM_FORMAT_CODES[options.format] ?? 3;
1600
1633
  const [ts, epoch] = timestampMs();
1601
- const fa = this._chainTrustLevels.length;
1602
- const fb = targetTrustLevel;
1603
- const fc = effectiveTrustLevel;
1604
- const fp = mintFingerprint(this.config.tenantId, "AI-CHAIN.1", fa, fb, fc, ts);
1634
+ const fp = mintFingerprint(this.config.tenantId, "AI-SBOM.1", fa, fb, fc, ts);
1605
1635
  const payload = {
1606
- procedure_id: "AI-CHAIN.1", factor_a: fa, factor_b: fb, factor_c: fc,
1636
+ procedure_id: "AI-SBOM.1",
1637
+ factor_a: fa, factor_b: fb, factor_c: fc,
1607
1638
  clearing_level: this.config.clearingLevel,
1608
1639
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1609
1640
  };
1610
1641
  if (this.config.clearingLevel <= 1) {
1611
- payload.ai_model_id = targetAgentId;
1612
- payload.ai_context = {
1613
- provider: "chain-trust",
1614
- target_agent: targetAgentId,
1615
- target_trust_level: targetTrustLevel,
1616
- effective_trust_level: effectiveTrustLevel,
1617
- chain_depth: this._chainTrustLevels.length,
1642
+ payload.ai_model_id = `sbom-${options.format}`;
1643
+ const ctx = {
1644
+ provider: "ai-sbom",
1645
+ bom_hash: options.bomHash,
1646
+ format: options.format,
1618
1647
  };
1648
+ if (options.version)
1649
+ ctx.version = options.version;
1650
+ if (options.modelCount != null)
1651
+ ctx.model_count = options.modelCount;
1652
+ if (options.datasetCount != null)
1653
+ ctx.dataset_count = options.datasetCount;
1654
+ if (options.infrastructureComponents != null)
1655
+ ctx.infrastructure_components = options.infrastructureComponents;
1656
+ payload.ai_context = ctx;
1619
1657
  }
1620
- const cycleId = options?.cycleId ?? this.config.cycleId;
1621
- const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1658
+ const policyHash = this.config.policyVersion
1659
+ ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1622
1660
  this._applyOperationalMetadata(payload, policyHash);
1623
- if (cycleId)
1624
- payload.cycle_id = cycleId;
1625
- const payloads = [payload];
1626
- // Auto-mint AI-CHAIN.2 if trust degraded
1627
- if (this._chainTrustLevels.length > 1 && effectiveTrustLevel < prevEffective) {
1628
- const degradation = extractChainTrustDegradationPayload(this.config.tenantId, prevEffective, effectiveTrustLevel, this.config.clearingLevel, this.config.agentId, this.config.signingKey, this.config.signingKeyId, this.config.signingKeyVersion, cycleId, policyHash, this.config.signingAlgorithm);
1629
- if (this.config.clearingLevel <= 1) {
1630
- degradation.ai_context = {
1631
- provider: "chain-trust-degradation",
1632
- previous_effective: prevEffective,
1633
- new_effective: effectiveTrustLevel,
1634
- target_agent: targetAgentId,
1635
- };
1636
- }
1637
- payloads.push(degradation);
1638
- }
1639
- this.buffer.enqueueMany(payloads);
1661
+ this.buffer.enqueueMany([payload]);
1640
1662
  return payload;
1641
1663
  }
1642
- /** The effective (minimum) trust level across all chain handoffs. Returns 4 if no handoffs yet. */
1643
- get chainEffectiveTrustLevel() {
1644
- return this._chainTrustLevels.length === 0 ? 4 : Math.min(...this._chainTrustLevels);
1645
- }
1646
- /** The trust levels recorded at each chain handoff. */
1647
- get chainTrustLevels() {
1648
- return this._chainTrustLevels;
1649
- }
1664
+ // ── Adversarial Test Campaign (AI-REDTEAM.1) ──────────────────
1650
1665
  /**
1651
- * Witness a policy violation (AI-VIO.1).
1666
+ * Witness an adversarial test campaign (AI-REDTEAM.1).
1667
+ *
1668
+ * Records red team or adversarial testing results, transforming
1669
+ * point-in-time reports into continuous verifiable evidence per
1670
+ * EO 14110, EU AI Act Art. 9(7), and NIST AI 100-2.
1671
+ *
1672
+ * @param options.testsExecuted - Number of attack scenarios run.
1673
+ * @param options.testsPassed - Number of attacks successfully mitigated.
1674
+ * @param options.coverageCategory - Coverage category key (prompt_injection, jailbreak, etc.).
1675
+ * @param options.framework - Testing framework (e.g. "OWASP-LLM-Top10", "NIST-AI-100-2").
1676
+ * @param options.campaignId - Unique identifier for this test campaign.
1677
+ * @param options.modelUnderTest - Model identifier being tested.
1678
+ * @param options.attackTaxonomy - Attack taxonomy version or reference.
1679
+ * @param options.passRate - Computed pass rate (0-1).
1680
+ * @param options.durationSeconds - Campaign duration in seconds.
1652
1681
  */
1653
- witnessViolation(severity, description, options) {
1654
- const autoDetected = options?.autoDetected ?? false;
1655
- const policyCategory = options?.policyCategory ?? "unspecified";
1682
+ witnessRedTeam(options) {
1683
+ const fa = options.testsExecuted;
1684
+ const fb = options.testsPassed;
1685
+ const fc = REDTEAM_CATEGORY_CODES[options.coverageCategory] ?? 10;
1656
1686
  const [ts, epoch] = timestampMs();
1657
- const fa = Math.max(1, Math.min(4, severity));
1658
- const fb = autoDetected ? 1 : 0;
1659
- const fc = POLICY_CATEGORIES[policyCategory] ?? 0;
1660
- const fp = mintFingerprint(this.config.tenantId, "AI-VIO.1", fa, fb, fc, ts);
1687
+ const fp = mintFingerprint(this.config.tenantId, "AI-REDTEAM.1", fa, fb, fc, ts);
1661
1688
  const payload = {
1662
- procedure_id: "AI-VIO.1", factor_a: fa, factor_b: fb, factor_c: fc,
1689
+ procedure_id: "AI-REDTEAM.1",
1690
+ factor_a: fa, factor_b: fb, factor_c: fc,
1663
1691
  clearing_level: this.config.clearingLevel,
1664
1692
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1665
1693
  };
1666
1694
  if (this.config.clearingLevel <= 1) {
1667
- payload.ai_model_id = `violation-sev${fa}`;
1668
- payload.ai_context = {
1669
- provider: "violation", severity: fa, description, auto_detected: autoDetected, policy_category: policyCategory,
1695
+ payload.ai_model_id = `redteam-${options.coverageCategory}`;
1696
+ const ctx = {
1697
+ provider: "red-team",
1698
+ coverage_category: options.coverageCategory,
1670
1699
  };
1700
+ if (options.framework)
1701
+ ctx.framework = options.framework;
1702
+ if (options.campaignId)
1703
+ ctx.campaign_id = options.campaignId;
1704
+ if (options.modelUnderTest)
1705
+ ctx.model_under_test = options.modelUnderTest;
1706
+ if (options.attackTaxonomy)
1707
+ ctx.attack_taxonomy = options.attackTaxonomy;
1708
+ if (options.passRate != null)
1709
+ ctx.pass_rate = options.passRate;
1710
+ if (options.durationSeconds != null)
1711
+ ctx.duration_seconds = options.durationSeconds;
1712
+ payload.ai_context = ctx;
1671
1713
  }
1672
- const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1714
+ const policyHash = this.config.policyVersion
1715
+ ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1673
1716
  this._applyOperationalMetadata(payload, policyHash);
1674
1717
  this.buffer.enqueueMany([payload]);
1675
1718
  return payload;
1676
1719
  }
1720
+ // ── Data Subject Consent (AI-CONSENT.1) ───────────────────────
1677
1721
  /**
1678
- * Witness an agent charter or system prompt hash (AI-CHR.1).
1722
+ * Witness data subject consent documentation (AI-CONSENT.1).
1723
+ *
1724
+ * Records that consent or lawful basis was documented before
1725
+ * processing. Complements CJT fields (which declare legal basis)
1726
+ * by proving consent was actually obtained per GDPR Art. 6/7
1727
+ * and EU AI Act Art. 10.
1728
+ *
1729
+ * @param options.subjectsCovered - Number of data subjects in scope.
1730
+ * @param options.legalBasisType - GDPR lawful basis (consent, contract, legal_obligation, vital_interest, public_task, legitimate_interest).
1731
+ * @param options.withdrawalAvailable - True if withdrawal mechanism exists.
1732
+ * @param options.purpose - Processing purpose description.
1733
+ * @param options.retentionDays - Data retention period in days.
1734
+ * @param options.consentMechanism - Mechanism used (e.g. "opt-in-form", "api-consent-endpoint").
1735
+ * @param options.consentHash - SHA-256 of the consent record.
1736
+ * @param options.dataCategories - Categories of personal data processed.
1679
1737
  */
1680
- witnessCharter(options) {
1681
- if (!options.charterText && !options.charterHash) {
1682
- throw new Error("Provide charterText or charterHash");
1683
- }
1684
- const computed = options.charterHash ?? sha256Truncated(options.charterText);
1685
- const match = options.expectedHash ? computed === options.expectedHash : true;
1738
+ witnessConsent(options) {
1739
+ const fa = options.subjectsCovered;
1740
+ const fb = CONSENT_BASIS_CODES[options.legalBasisType] ?? 0;
1741
+ const fc = options.withdrawalAvailable ? 1 : 0;
1686
1742
  const [ts, epoch] = timestampMs();
1687
- const fa = 1, fb = match ? 1 : 0, fc = 0;
1688
- const fp = mintFingerprint(this.config.tenantId, "AI-CHR.1", fa, fb, fc, ts);
1743
+ const fp = mintFingerprint(this.config.tenantId, "AI-CONSENT.1", fa, fb, fc, ts);
1689
1744
  const payload = {
1690
- procedure_id: "AI-CHR.1", factor_a: fa, factor_b: fb, factor_c: fc,
1745
+ procedure_id: "AI-CONSENT.1",
1746
+ factor_a: fa, factor_b: fb, factor_c: fc,
1691
1747
  clearing_level: this.config.clearingLevel,
1692
1748
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1693
1749
  };
1694
1750
  if (this.config.clearingLevel <= 1) {
1695
- payload.ai_model_id = "charter";
1696
- const ctx = { provider: "charter", charter_hash: computed };
1697
- if (options.expectedHash)
1698
- ctx.expected_hash = options.expectedHash;
1751
+ payload.ai_model_id = `consent-${options.legalBasisType}`;
1752
+ const ctx = {
1753
+ provider: "consent-management",
1754
+ legal_basis_type: options.legalBasisType,
1755
+ };
1756
+ if (options.purpose)
1757
+ ctx.purpose = options.purpose;
1758
+ if (options.retentionDays != null)
1759
+ ctx.retention_days = options.retentionDays;
1760
+ if (options.consentMechanism)
1761
+ ctx.consent_mechanism = options.consentMechanism;
1762
+ if (options.consentHash)
1763
+ ctx.consent_hash = options.consentHash;
1764
+ if (options.dataCategories)
1765
+ ctx.data_categories = options.dataCategories;
1699
1766
  payload.ai_context = ctx;
1700
1767
  }
1701
- const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1768
+ const policyHash = this.config.policyVersion
1769
+ ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1702
1770
  this._applyOperationalMetadata(payload, policyHash);
1703
1771
  this.buffer.enqueueMany([payload]);
1704
1772
  return payload;
1705
1773
  }
1774
+ // ── Multi-Agent Delegation (AI-MULTI.1) ───────────────────────
1706
1775
  /**
1707
- * Witness a model registry check (AI-MDL.8).
1776
+ * Witness inter-agent permission delegation (AI-MULTI.1).
1777
+ *
1778
+ * Records the permission envelope when one agent delegates tasks
1779
+ * to another. Complements AI-CHAIN.1/2 (which witness handoffs and
1780
+ * trust degradation) by witnessing WHAT was delegated per
1781
+ * EU AI Act Art. 9 and NIST AI RMF GOVERN 1.3.
1782
+ *
1783
+ * @param options.delegationDepth - Hops from original human authorization.
1784
+ * @param options.permissionsGranted - Count of distinct permissions delegated.
1785
+ * @param options.timeBoundMinutes - Minutes until delegation expires (0 = unbounded).
1786
+ * @param options.parentAgentId - Delegating agent identifier (hashed in context).
1787
+ * @param options.childAgentId - Receiving agent identifier (hashed in context).
1788
+ * @param options.delegatedTools - List of tool names being delegated.
1789
+ * @param options.scopeHash - SHA-256 of the permission manifest.
1790
+ * @param options.authorizationChain - Ordered agent IDs from human to child (each hashed).
1708
1791
  */
1709
- witnessModelRegistry(modelId, registryId, options) {
1710
- const found = options?.found ?? true;
1711
- const status = options?.status ?? "approved";
1792
+ witnessMultiAgentDelegation(options) {
1793
+ const fa = options.delegationDepth;
1794
+ const fb = options.permissionsGranted;
1795
+ const fc = options.timeBoundMinutes;
1712
1796
  const [ts, epoch] = timestampMs();
1713
- const fa = 1, fb = found ? 1 : 0, fc = APPROVAL_STATUS[status] ?? 0;
1714
- const fp = mintFingerprint(this.config.tenantId, "AI-MDL.8", fa, fb, fc, ts);
1797
+ const fp = mintFingerprint(this.config.tenantId, "AI-MULTI.1", fa, fb, fc, ts);
1715
1798
  const payload = {
1716
- procedure_id: "AI-MDL.8", factor_a: fa, factor_b: fb, factor_c: fc,
1799
+ procedure_id: "AI-MULTI.1",
1800
+ factor_a: fa, factor_b: fb, factor_c: fc,
1717
1801
  clearing_level: this.config.clearingLevel,
1718
1802
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1719
1803
  };
1720
1804
  if (this.config.clearingLevel <= 1) {
1721
- payload.ai_model_id = modelId;
1722
- payload.ai_context = {
1723
- provider: "model-registry", model_id: modelId, registry_id: registryId, found, status,
1805
+ payload.ai_model_id = `delegation-depth-${options.delegationDepth}`;
1806
+ const ctx = {
1807
+ provider: "multi-agent",
1808
+ parent_agent_hash: sha256Truncated(options.parentAgentId),
1809
+ child_agent_hash: sha256Truncated(options.childAgentId),
1724
1810
  };
1811
+ if (options.delegatedTools)
1812
+ ctx.delegated_tools = options.delegatedTools;
1813
+ if (options.scopeHash)
1814
+ ctx.scope_hash = options.scopeHash;
1815
+ if (options.authorizationChain) {
1816
+ ctx.authorization_chain = options.authorizationChain.map((id) => sha256Truncated(id));
1817
+ }
1818
+ payload.ai_context = ctx;
1819
+ }
1820
+ const policyHash = this.config.policyVersion
1821
+ ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1822
+ this._applyOperationalMetadata(payload, policyHash);
1823
+ this.buffer.enqueueMany([payload]);
1824
+ return payload;
1825
+ }
1826
+ // ── Model Drift Detection (AI-DRIFT.1) ─────────────────────────
1827
+ /**
1828
+ * Witness model drift detection (AI-DRIFT.1).
1829
+ *
1830
+ * Records statistical drift events including data drift, concept drift,
1831
+ * and prediction drift per EU AI Act Art. 9(2)(b) continuous risk
1832
+ * estimation and NIST AI RMF MEASURE 2.6.
1833
+ */
1834
+ witnessDrift(options) {
1835
+ const fa = options.metricsEvaluated;
1836
+ const fb = options.driftedCount;
1837
+ const fc = DRIFT_TYPE_CODES[options.driftType] ?? 0;
1838
+ const [ts, epoch] = timestampMs();
1839
+ const fp = mintFingerprint(this.config.tenantId, "AI-DRIFT.1", fa, fb, fc, ts);
1840
+ const payload = {
1841
+ procedure_id: "AI-DRIFT.1", factor_a: fa, factor_b: fb, factor_c: fc,
1842
+ clearing_level: this.config.clearingLevel,
1843
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1844
+ };
1845
+ if (this.config.clearingLevel <= 1) {
1846
+ payload.ai_model_id = `drift-${options.driftType}`;
1847
+ const ctx = { provider: "drift-detection", drift_type: options.driftType };
1848
+ if (options.baselineHash)
1849
+ ctx.baseline_hash = options.baselineHash;
1850
+ if (options.driftScore != null)
1851
+ ctx.drift_score = options.driftScore;
1852
+ if (options.detectionMethod)
1853
+ ctx.detection_method = options.detectionMethod;
1854
+ if (options.windowSize != null)
1855
+ ctx.window_size = options.windowSize;
1856
+ if (options.threshold != null)
1857
+ ctx.threshold = options.threshold;
1858
+ payload.ai_context = ctx;
1725
1859
  }
1726
1860
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
1727
1861
  this._applyOperationalMetadata(payload, policyHash);
1728
1862
  this.buffer.enqueueMany([payload]);
1729
1863
  return payload;
1730
1864
  }
1865
+ // ── Audit Log Integrity (AI-AUDIT.1) ──────────────────────────
1731
1866
  /**
1732
- * Witness reviewer identity binding (AI-HITL.3).
1867
+ * Witness audit log integrity verification (AI-AUDIT.1).
1868
+ *
1869
+ * Records verification of audit trail integrity per EU AI Act
1870
+ * Art. 12 (record-keeping) and GDPR Art. 30 (ROPA).
1733
1871
  */
1734
- witnessReviewerIdentity(required, actual, options) {
1735
- const method = options?.method ?? "session";
1872
+ witnessAuditIntegrity(options) {
1873
+ const fa = options.entriesChecked;
1874
+ const fb = options.integrityVerified ? 1 : 0;
1875
+ const fc = LOG_FORMAT_CODES[options.logFormat] ?? 3;
1736
1876
  const [ts, epoch] = timestampMs();
1737
- const fa = required, fb = actual, fc = BINDING_METHODS[method] ?? 0;
1738
- const fp = mintFingerprint(this.config.tenantId, "AI-HITL.3", fa, fb, fc, ts);
1877
+ const fp = mintFingerprint(this.config.tenantId, "AI-AUDIT.1", fa, fb, fc, ts);
1739
1878
  const payload = {
1740
- procedure_id: "AI-HITL.3", factor_a: fa, factor_b: fb, factor_c: fc,
1879
+ procedure_id: "AI-AUDIT.1", factor_a: fa, factor_b: fb, factor_c: fc,
1741
1880
  clearing_level: this.config.clearingLevel,
1742
1881
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1743
1882
  };
1744
1883
  if (this.config.clearingLevel <= 1) {
1745
- payload.ai_model_id = "reviewer-identity";
1746
- const ctx = {
1747
- provider: "reviewer", required, actual, method,
1748
- };
1749
- if (options?.reviewerIdHash)
1750
- ctx.reviewer_id_hash = options.reviewerIdHash;
1884
+ payload.ai_model_id = `audit-${options.logFormat}`;
1885
+ const ctx = { provider: "audit-integrity", log_format: options.logFormat };
1886
+ if (options.logHash)
1887
+ ctx.log_hash = options.logHash;
1888
+ if (options.periodStart)
1889
+ ctx.period_start = options.periodStart;
1890
+ if (options.periodEnd)
1891
+ ctx.period_end = options.periodEnd;
1892
+ if (options.gapsDetected != null)
1893
+ ctx.gaps_detected = options.gapsDetected;
1751
1894
  payload.ai_context = ctx;
1752
1895
  }
1753
1896
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1755,27 +1898,35 @@ export class Witness {
1755
1898
  this.buffer.enqueueMany([payload]);
1756
1899
  return payload;
1757
1900
  }
1901
+ // ── Incident Reporting (AI-INCIDENT.1) ────────────────────────
1758
1902
  /**
1759
- * Witness safe state attestation (AI-SAFE.1).
1903
+ * Witness incident reporting (AI-INCIDENT.1).
1904
+ *
1905
+ * Records that a serious incident was reported per EU AI Act
1906
+ * Art. 62 and NIST AI RMF MANAGE 3.2.
1760
1907
  */
1761
- witnessSafeState(options) {
1762
- const mechanismExists = options?.mechanismExists ?? true;
1763
- const safeStateConfirmed = options?.safeStateConfirmed ?? true;
1908
+ witnessIncident(options) {
1909
+ const fa = options.severityCode;
1910
+ const fb = options.authorityNotified ? 1 : 0;
1911
+ const fc = INCIDENT_TYPE_CODES[options.incidentType] ?? 5;
1764
1912
  const [ts, epoch] = timestampMs();
1765
- const fa = 1, fb = mechanismExists ? 1 : 0, fc = safeStateConfirmed ? 1 : 0;
1766
- const fp = mintFingerprint(this.config.tenantId, "AI-SAFE.1", fa, fb, fc, ts);
1913
+ const fp = mintFingerprint(this.config.tenantId, "AI-INCIDENT.1", fa, fb, fc, ts);
1767
1914
  const payload = {
1768
- procedure_id: "AI-SAFE.1", factor_a: fa, factor_b: fb, factor_c: fc,
1915
+ procedure_id: "AI-INCIDENT.1", factor_a: fa, factor_b: fb, factor_c: fc,
1769
1916
  clearing_level: this.config.clearingLevel,
1770
1917
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1771
1918
  };
1772
1919
  if (this.config.clearingLevel <= 1) {
1773
- payload.ai_model_id = "safe-state";
1774
- const ctx = {
1775
- provider: "safe-state", mechanism_exists: mechanismExists, safe_state_confirmed: safeStateConfirmed,
1776
- };
1777
- if (options?.mechanismType)
1778
- ctx.mechanism_type = options.mechanismType;
1920
+ payload.ai_model_id = `incident-${options.incidentType}`;
1921
+ const ctx = { provider: "incident-reporting", incident_type: options.incidentType };
1922
+ if (options.incidentId)
1923
+ ctx.incident_id = options.incidentId;
1924
+ if (options.authority)
1925
+ ctx.authority = options.authority;
1926
+ if (options.affectedSubjects != null)
1927
+ ctx.affected_subjects = options.affectedSubjects;
1928
+ if (options.remediationStatus)
1929
+ ctx.remediation_status = options.remediationStatus;
1779
1930
  payload.ai_context = ctx;
1780
1931
  }
1781
1932
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1783,34 +1934,37 @@ export class Witness {
1783
1934
  this.buffer.enqueueMany([payload]);
1784
1935
  return payload;
1785
1936
  }
1786
- // ── Training Data (AI-DATA.3 / AI-DATA.4) ──────────────────────
1937
+ // ── Performance Metrics (AI-PERF.1) ───────────────────────────
1787
1938
  /**
1788
- * Witness training dataset summary statistics (AI-DATA.3).
1939
+ * Witness performance/accuracy metrics (AI-PERF.1).
1940
+ *
1941
+ * Records model performance benchmarks per EU AI Act Art. 15(1)
1942
+ * accuracy requirements and NIST AI RMF MEASURE 2.5.
1789
1943
  */
1790
- witnessTrainingStats(rowCount, featureCount, options) {
1944
+ witnessPerformance(options) {
1945
+ const fa = options.metricsEvaluated;
1946
+ const fb = options.metricsPassing;
1947
+ const fc = BENCHMARK_TYPE_CODES[options.benchmarkType] ?? 5;
1791
1948
  const [ts, epoch] = timestampMs();
1792
- const fa = rowCount;
1793
- const fb = featureCount;
1794
- const fc = options?.classBalanceRatio != null ? Math.floor(options.classBalanceRatio * 1000) : 0;
1795
- const fp = mintFingerprint(this.config.tenantId, "AI-DATA.3", fa, fb, fc, ts);
1949
+ const fp = mintFingerprint(this.config.tenantId, "AI-PERF.1", fa, fb, fc, ts);
1796
1950
  const payload = {
1797
- procedure_id: "AI-DATA.3", factor_a: fa, factor_b: fb, factor_c: fc,
1951
+ procedure_id: "AI-PERF.1", factor_a: fa, factor_b: fb, factor_c: fc,
1798
1952
  clearing_level: this.config.clearingLevel,
1799
1953
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1800
1954
  };
1801
1955
  if (this.config.clearingLevel <= 1) {
1802
- payload.ai_model_id = "training-stats";
1803
- const ctx = {
1804
- provider: "training-stats", row_count: rowCount, feature_count: featureCount,
1805
- };
1806
- if (options?.classBalanceRatio != null)
1807
- ctx.class_balance_ratio = options.classBalanceRatio;
1808
- if (options?.distributionHash)
1809
- ctx.distribution_hash = options.distributionHash;
1810
- if (options?.classLabels)
1811
- ctx.class_labels = options.classLabels;
1812
- if (options?.summary)
1813
- ctx.summary = options.summary;
1956
+ payload.ai_model_id = options.modelUnderTest ? `perf-${options.modelUnderTest}` : `perf-${options.benchmarkType}`;
1957
+ const ctx = { provider: "performance-metrics", benchmark_type: options.benchmarkType };
1958
+ if (options.benchmarkId)
1959
+ ctx.benchmark_id = options.benchmarkId;
1960
+ if (options.datasetHash)
1961
+ ctx.dataset_hash = options.datasetHash;
1962
+ if (options.threshold != null)
1963
+ ctx.threshold = options.threshold;
1964
+ if (options.score != null)
1965
+ ctx.score = options.score;
1966
+ if (options.modelUnderTest)
1967
+ ctx.model_under_test = options.modelUnderTest;
1814
1968
  payload.ai_context = ctx;
1815
1969
  }
1816
1970
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1818,32 +1972,35 @@ export class Witness {
1818
1972
  this.buffer.enqueueMany([payload]);
1819
1973
  return payload;
1820
1974
  }
1975
+ // ── Robustness Testing (AI-ROBUST.1) ──────────────────────────
1821
1976
  /**
1822
- * Witness a training data PII lifecycle event (AI-DATA.4).
1977
+ * Witness robustness testing (AI-ROBUST.1).
1978
+ *
1979
+ * Records resilience against errors, faults, and inconsistencies
1980
+ * per EU AI Act Art. 15(3) and NIST AI RMF MEASURE 2.6.
1823
1981
  */
1824
- witnessTrainingPiiLifecycle(recordsAffected, options) {
1825
- const completed = options?.completed ?? true;
1826
- const eventType = options?.eventType ?? "unspecified";
1982
+ witnessRobustness(options) {
1983
+ const fa = options.perturbationsTested;
1984
+ const fb = options.perturbationsSurvived;
1985
+ const fc = PERTURBATION_TYPE_CODES[options.perturbationType] ?? 5;
1827
1986
  const [ts, epoch] = timestampMs();
1828
- const fa = recordsAffected;
1829
- const fb = completed ? 1 : 0;
1830
- const fc = PII_EVENT_TYPES[eventType] ?? 0;
1831
- const fp = mintFingerprint(this.config.tenantId, "AI-DATA.4", fa, fb, fc, ts);
1987
+ const fp = mintFingerprint(this.config.tenantId, "AI-ROBUST.1", fa, fb, fc, ts);
1832
1988
  const payload = {
1833
- procedure_id: "AI-DATA.4", factor_a: fa, factor_b: fb, factor_c: fc,
1989
+ procedure_id: "AI-ROBUST.1", factor_a: fa, factor_b: fb, factor_c: fc,
1834
1990
  clearing_level: this.config.clearingLevel,
1835
1991
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1836
1992
  };
1837
1993
  if (this.config.clearingLevel <= 1) {
1838
- payload.ai_model_id = "pii-lifecycle";
1839
- const ctx = {
1840
- provider: "pii-lifecycle", event_type: eventType,
1841
- records_affected: recordsAffected, completed,
1842
- };
1843
- if (options?.datasetId)
1844
- ctx.dataset_id = options.datasetId;
1845
- if (options?.scope)
1846
- ctx.scope = options.scope;
1994
+ payload.ai_model_id = `robust-${options.perturbationType}`;
1995
+ const ctx = { provider: "robustness-testing", perturbation_type: options.perturbationType };
1996
+ if (options.testSuiteId)
1997
+ ctx.test_suite_id = options.testSuiteId;
1998
+ if (options.degradationPct != null)
1999
+ ctx.degradation_pct = options.degradationPct;
2000
+ if (options.baselineScore != null)
2001
+ ctx.baseline_score = options.baselineScore;
2002
+ if (options.perturbedScore != null)
2003
+ ctx.perturbed_score = options.perturbedScore;
1847
2004
  payload.ai_context = ctx;
1848
2005
  }
1849
2006
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1851,42 +2008,35 @@ export class Witness {
1851
2008
  this.buffer.enqueueMany([payload]);
1852
2009
  return payload;
1853
2010
  }
1854
- // ── Bias Assessment (AI-FAIR.3) ─────────────────────────────────
2011
+ // ── Cybersecurity Attestation (AI-CYBER.1) ────────────────────
1855
2012
  /**
1856
- * Witness a bias assessment (AI-FAIR.3).
1857
- * Records that a bias assessment was conducted, how many protected
1858
- * attributes were tested, and whether all fairness thresholds were met.
2013
+ * Witness cybersecurity measure attestation (AI-CYBER.1).
1859
2014
  *
1860
- * @param protectedAttributeCount - Number of demographic dimensions tested
1861
- * @param allThresholdsMet - true if all fairness thresholds passed
1862
- * @param options.maxDisparityPct - Worst-case disparity percentage (0-100)
1863
- * @param options.methodology - Assessment methodology name
1864
- * @param options.protectedAttributes - List of protected attributes tested
2015
+ * Records cybersecurity assessment results per EU AI Act Art. 15(4)
2016
+ * and NIST Cybersecurity Framework.
1865
2017
  */
1866
- witnessBiasAssessment(protectedAttributeCount, allThresholdsMet, options) {
2018
+ witnessCybersecurity(options) {
2019
+ const fa = options.controlsAssessed;
2020
+ const fb = options.controlsCompliant;
2021
+ const fc = CYBER_FRAMEWORK_CODES[options.framework] ?? 4;
1867
2022
  const [ts, epoch] = timestampMs();
1868
- const fa = protectedAttributeCount;
1869
- const fb = allThresholdsMet ? 1 : 0;
1870
- const fc = options?.maxDisparityPct != null ? Math.round(options.maxDisparityPct) : 0;
1871
- const fp = mintFingerprint(this.config.tenantId, "AI-FAIR.3", fa, fb, fc, ts);
2023
+ const fp = mintFingerprint(this.config.tenantId, "AI-CYBER.1", fa, fb, fc, ts);
1872
2024
  const payload = {
1873
- procedure_id: "AI-FAIR.3", factor_a: fa, factor_b: fb, factor_c: fc,
2025
+ procedure_id: "AI-CYBER.1", factor_a: fa, factor_b: fb, factor_c: fc,
1874
2026
  clearing_level: this.config.clearingLevel,
1875
2027
  anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
1876
2028
  };
1877
2029
  if (this.config.clearingLevel <= 1) {
1878
- payload.ai_model_id = "bias-assessment";
1879
- const ctx = {
1880
- provider: "bias-assessment",
1881
- protected_attribute_count: protectedAttributeCount,
1882
- all_thresholds_met: allThresholdsMet,
1883
- };
1884
- if (options?.methodology)
1885
- ctx.methodology = options.methodology;
1886
- if (options?.protectedAttributes)
1887
- ctx.protected_attributes = options.protectedAttributes;
1888
- if (options?.maxDisparityPct != null)
1889
- ctx.max_disparity_pct = options.maxDisparityPct;
2030
+ payload.ai_model_id = `cyber-${options.framework}`;
2031
+ const ctx = { provider: "cybersecurity-assessment", framework: options.framework };
2032
+ if (options.assessmentId)
2033
+ ctx.assessment_id = options.assessmentId;
2034
+ if (options.frameworkVersion)
2035
+ ctx.framework_version = options.frameworkVersion;
2036
+ if (options.findingsCount != null)
2037
+ ctx.findings_count = options.findingsCount;
2038
+ if (options.criticalFindings != null)
2039
+ ctx.critical_findings = options.criticalFindings;
1890
2040
  payload.ai_context = ctx;
1891
2041
  }
1892
2042
  const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
@@ -1894,8 +2044,1136 @@ export class Witness {
1894
2044
  this.buffer.enqueueMany([payload]);
1895
2045
  return payload;
1896
2046
  }
1897
- // ── Trust Mesh (AI-TRUST.1 / AI-TRUST.2) ────────────────────────
1898
- _trustRegistry;
2047
+ // ── Transparency Disclosure (AI-TRANS.1) ──────────────────────
2048
+ /**
2049
+ * Witness transparency disclosure (AI-TRANS.1).
2050
+ *
2051
+ * Records AI usage disclosures to deployers, end users, or data
2052
+ * subjects per EU AI Act Art. 13 and GDPR Art. 13/14.
2053
+ */
2054
+ witnessTransparency(options) {
2055
+ const fa = options.disclosuresMade;
2056
+ const fb = DISCLOSURE_TYPE_CODES[options.disclosureType] ?? 0;
2057
+ const fc = RECIPIENT_TYPE_CODES[options.recipientType] ?? 0;
2058
+ const [ts, epoch] = timestampMs();
2059
+ const fp = mintFingerprint(this.config.tenantId, "AI-TRANS.1", fa, fb, fc, ts);
2060
+ const payload = {
2061
+ procedure_id: "AI-TRANS.1", factor_a: fa, factor_b: fb, factor_c: fc,
2062
+ clearing_level: this.config.clearingLevel,
2063
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2064
+ };
2065
+ if (this.config.clearingLevel <= 1) {
2066
+ payload.ai_model_id = `trans-${options.disclosureType}`;
2067
+ const ctx = { provider: "transparency-disclosure", disclosure_type: options.disclosureType, recipient_type: options.recipientType };
2068
+ if (options.disclosureId)
2069
+ ctx.disclosure_id = options.disclosureId;
2070
+ if (options.contentHash)
2071
+ ctx.content_hash = options.contentHash;
2072
+ if (options.channel)
2073
+ ctx.channel = options.channel;
2074
+ payload.ai_context = ctx;
2075
+ }
2076
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2077
+ this._applyOperationalMetadata(payload, policyHash);
2078
+ this.buffer.enqueueMany([payload]);
2079
+ return payload;
2080
+ }
2081
+ // ── Watermark Verification (AI-WATERMARK.1) ──────────────────
2082
+ /**
2083
+ * Witness watermark verification (AI-WATERMARK.1).
2084
+ *
2085
+ * Records verification that AI content marking survived downstream
2086
+ * processing per EU AI Act Art. 50(2). Distinct from AI-MARK.1
2087
+ * which witnesses marking; this witnesses verification.
2088
+ */
2089
+ witnessWatermarkVerification(options) {
2090
+ const fa = options.itemsChecked;
2091
+ const fb = options.watermarksDetected;
2092
+ const fc = DETECTION_METHOD_CODES[options.detectionMethod] ?? 4;
2093
+ const [ts, epoch] = timestampMs();
2094
+ const fp = mintFingerprint(this.config.tenantId, "AI-WATERMARK.1", fa, fb, fc, ts);
2095
+ const payload = {
2096
+ procedure_id: "AI-WATERMARK.1", factor_a: fa, factor_b: fb, factor_c: fc,
2097
+ clearing_level: this.config.clearingLevel,
2098
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2099
+ };
2100
+ if (this.config.clearingLevel <= 1) {
2101
+ payload.ai_model_id = `watermark-${options.detectionMethod}`;
2102
+ const ctx = { provider: "watermark-verification", detection_method: options.detectionMethod };
2103
+ if (options.contentHash)
2104
+ ctx.content_hash = options.contentHash;
2105
+ if (options.watermarkProvider)
2106
+ ctx.watermark_provider = options.watermarkProvider;
2107
+ if (options.confidenceScore != null)
2108
+ ctx.confidence_score = options.confidenceScore;
2109
+ if (options.strippedCount != null)
2110
+ ctx.stripped_count = options.strippedCount;
2111
+ payload.ai_context = ctx;
2112
+ }
2113
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2114
+ this._applyOperationalMetadata(payload, policyHash);
2115
+ this.buffer.enqueueMany([payload]);
2116
+ return payload;
2117
+ }
2118
+ // ── Data Protection Impact Assessment (AI-DPIA.1) ─────────────
2119
+ /**
2120
+ * Witness data protection impact assessment (AI-DPIA.1).
2121
+ *
2122
+ * Records DPIA completion per GDPR Art. 35 and EU AI Act Art. 27
2123
+ * for high-risk AI processing.
2124
+ */
2125
+ witnessDpia(options) {
2126
+ const fa = options.risksIdentified;
2127
+ const fb = options.risksMitigated;
2128
+ const fc = PROCESSING_TYPE_CODES[options.processingType] ?? 4;
2129
+ const [ts, epoch] = timestampMs();
2130
+ const fp = mintFingerprint(this.config.tenantId, "AI-DPIA.1", fa, fb, fc, ts);
2131
+ const payload = {
2132
+ procedure_id: "AI-DPIA.1", factor_a: fa, factor_b: fb, factor_c: fc,
2133
+ clearing_level: this.config.clearingLevel,
2134
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2135
+ };
2136
+ if (this.config.clearingLevel <= 1) {
2137
+ payload.ai_model_id = `dpia-${options.processingType}`;
2138
+ const ctx = { provider: "impact-assessment", processing_type: options.processingType };
2139
+ if (options.dpiaId)
2140
+ ctx.dpia_id = options.dpiaId;
2141
+ if (options.assessmentDate)
2142
+ ctx.assessment_date = options.assessmentDate;
2143
+ if (options.dpoConsulted != null)
2144
+ ctx.dpo_consulted = options.dpoConsulted;
2145
+ if (options.residualRiskLevel)
2146
+ ctx.residual_risk_level = options.residualRiskLevel;
2147
+ if (options.supervisoryAuthorityConsulted != null)
2148
+ ctx.supervisory_authority_consulted = options.supervisoryAuthorityConsulted;
2149
+ payload.ai_context = ctx;
2150
+ }
2151
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2152
+ this._applyOperationalMetadata(payload, policyHash);
2153
+ this.buffer.enqueueMany([payload]);
2154
+ return payload;
2155
+ }
2156
+ // ── Automated Decision Notification (AI-AUTO.1) ───────────────
2157
+ /**
2158
+ * Witness automated decision notification (AI-AUTO.1).
2159
+ *
2160
+ * Records notification of automated decisions with legal effects
2161
+ * per GDPR Art. 22 and EU AI Act Art. 14.
2162
+ */
2163
+ witnessAutomatedDecision(options) {
2164
+ const fa = options.decisionsMade;
2165
+ const fb = options.humanReviewed;
2166
+ const fc = DECISION_TYPE_CODES[options.decisionType] ?? 5;
2167
+ const [ts, epoch] = timestampMs();
2168
+ const fp = mintFingerprint(this.config.tenantId, "AI-AUTO.1", fa, fb, fc, ts);
2169
+ const payload = {
2170
+ procedure_id: "AI-AUTO.1", factor_a: fa, factor_b: fb, factor_c: fc,
2171
+ clearing_level: this.config.clearingLevel,
2172
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2173
+ };
2174
+ if (this.config.clearingLevel <= 1) {
2175
+ payload.ai_model_id = `auto-${options.decisionType}`;
2176
+ const ctx = { provider: "automated-decision", decision_type: options.decisionType };
2177
+ if (options.decisionId)
2178
+ ctx.decision_id = options.decisionId;
2179
+ if (options.subjectNotified != null)
2180
+ ctx.subject_notified = options.subjectNotified;
2181
+ if (options.optOutAvailable != null)
2182
+ ctx.opt_out_available = options.optOutAvailable;
2183
+ if (options.humanReviewRequested != null)
2184
+ ctx.human_review_requested = options.humanReviewRequested;
2185
+ payload.ai_context = ctx;
2186
+ }
2187
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2188
+ this._applyOperationalMetadata(payload, policyHash);
2189
+ this.buffer.enqueueMany([payload]);
2190
+ return payload;
2191
+ }
2192
+ // ── Autonomous Generation Depth (AI-AUTO.2) ──────────────────
2193
+ /**
2194
+ * Witness autonomous generation depth (AI-AUTO.2).
2195
+ *
2196
+ * Records the depth of AI-to-AI generation cycles and whether
2197
+ * a human approval gate was present. EU AI Act Art. 14, EO 14110 Sec. 3.
2198
+ */
2199
+ witnessGenerationDepth(options) {
2200
+ const fa = options.maxDepth;
2201
+ const fb = options.observedDepth;
2202
+ const fc = options.humanGatePresent ? 1 : 0;
2203
+ const [ts, epoch] = timestampMs();
2204
+ const fp = mintFingerprint(this.config.tenantId, "AI-AUTO.2", fa, fb, fc, ts);
2205
+ const payload = {
2206
+ procedure_id: "AI-AUTO.2", factor_a: fa, factor_b: fb, factor_c: fc,
2207
+ clearing_level: this.config.clearingLevel,
2208
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2209
+ };
2210
+ if (this.config.clearingLevel <= 1) {
2211
+ payload.ai_model_id = options.sourceAgentId || "autonomous-generator";
2212
+ const ctx = { provider: "generation-depth", max_depth: fa, observed_depth: fb };
2213
+ if (options.generationContext)
2214
+ ctx.generation_context = options.generationContext;
2215
+ if (options.sourceAgentId)
2216
+ ctx.source_agent_id = options.sourceAgentId;
2217
+ if (options.mergeTarget)
2218
+ ctx.merge_target = options.mergeTarget;
2219
+ payload.ai_context = ctx;
2220
+ }
2221
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2222
+ this._applyOperationalMetadata(payload, policyHash);
2223
+ this.buffer.enqueueMany([payload]);
2224
+ return payload;
2225
+ }
2226
+ // ── External Timestamp Attestation (AI-AUDIT.2) ──────────────
2227
+ /**
2228
+ * Witness external timestamp attestation (AI-AUDIT.2).
2229
+ *
2230
+ * Records that a batch of anchors was anchored to an independent
2231
+ * RFC 3161 Timestamp Authority. NIST 800-53 AU-10 (Non-repudiation).
2232
+ */
2233
+ witnessTimestampAttestation(options) {
2234
+ const fa = options.anchorCount;
2235
+ const fb = options.tsaVerified ? 1 : 0;
2236
+ const TSA_CODES = { none: 0, freetsa: 1, digicert: 2, sectigo: 3, custom: 4 };
2237
+ const fc = TSA_CODES[options.tsaProvider] ?? 4;
2238
+ const [ts, epoch] = timestampMs();
2239
+ const fp = mintFingerprint(this.config.tenantId, "AI-AUDIT.2", fa, fb, fc, ts);
2240
+ const payload = {
2241
+ procedure_id: "AI-AUDIT.2", factor_a: fa, factor_b: fb, factor_c: fc,
2242
+ clearing_level: this.config.clearingLevel,
2243
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2244
+ };
2245
+ if (this.config.clearingLevel <= 1) {
2246
+ payload.ai_model_id = "merkle-rollup";
2247
+ const ctx = { provider: "timestamp-attestation", tsa_provider: options.tsaProvider };
2248
+ if (options.merkleRoot)
2249
+ ctx.merkle_root = options.merkleRoot;
2250
+ if (options.tsaUrl)
2251
+ ctx.tsa_url = options.tsaUrl;
2252
+ if (options.tsaSerial)
2253
+ ctx.tsa_serial = options.tsaSerial;
2254
+ payload.ai_context = ctx;
2255
+ }
2256
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2257
+ this._applyOperationalMetadata(payload, policyHash);
2258
+ this.buffer.enqueueMany([payload]);
2259
+ return payload;
2260
+ }
2261
+ // ── Dual-Use Model Classification (AI-DUALUSE.1) ─────────────
2262
+ /**
2263
+ * Witness dual-use model classification (AI-DUALUSE.1).
2264
+ *
2265
+ * Records classification and reporting of dual-use foundation
2266
+ * models per EO 14110 Sec 4(a) and NIST AI RMF GOVERN 1.1.
2267
+ */
2268
+ witnessDualUse(options) {
2269
+ const fa = options.classificationCode;
2270
+ const fb = REPORTING_STATUS_CODES[options.reportingStatus] ?? 0;
2271
+ const fc = options.daysSinceClassification;
2272
+ const [ts, epoch] = timestampMs();
2273
+ const fp = mintFingerprint(this.config.tenantId, "AI-DUALUSE.1", fa, fb, fc, ts);
2274
+ const payload = {
2275
+ procedure_id: "AI-DUALUSE.1", factor_a: fa, factor_b: fb, factor_c: fc,
2276
+ clearing_level: this.config.clearingLevel,
2277
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2278
+ };
2279
+ if (this.config.clearingLevel <= 1) {
2280
+ payload.ai_model_id = options.modelId ?? `dualuse-class-${options.classificationCode}`;
2281
+ const ctx = { provider: "dual-use-classification", reporting_status: options.reportingStatus };
2282
+ if (options.modelId)
2283
+ ctx.model_id = options.modelId;
2284
+ if (options.classificationBasis)
2285
+ ctx.classification_basis = options.classificationBasis;
2286
+ if (options.computeThreshold)
2287
+ ctx.compute_threshold = options.computeThreshold;
2288
+ if (options.authorityNotified)
2289
+ ctx.authority_notified = options.authorityNotified;
2290
+ payload.ai_context = ctx;
2291
+ }
2292
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2293
+ this._applyOperationalMetadata(payload, policyHash);
2294
+ this.buffer.enqueueMany([payload]);
2295
+ return payload;
2296
+ }
2297
+ // ── Supply Chain Risk (AI-SUPPLY.1) ───────────────────────────
2298
+ /**
2299
+ * Witness supply chain risk assessment (AI-SUPPLY.1).
2300
+ *
2301
+ * Records third-party AI supply chain risk metrics per NIST AI
2302
+ * RMF MEASURE 3.1, G7/CISA SBOM-AI, and EO 14028.
2303
+ */
2304
+ witnessSupplyChainRisk(options) {
2305
+ const fa = options.suppliersAssessed;
2306
+ const fb = options.suppliersCompliant;
2307
+ const fc = SUPPLY_RISK_CODES[options.riskLevel] ?? 0;
2308
+ const [ts, epoch] = timestampMs();
2309
+ const fp = mintFingerprint(this.config.tenantId, "AI-SUPPLY.1", fa, fb, fc, ts);
2310
+ const payload = {
2311
+ procedure_id: "AI-SUPPLY.1", factor_a: fa, factor_b: fb, factor_c: fc,
2312
+ clearing_level: this.config.clearingLevel,
2313
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2314
+ };
2315
+ if (this.config.clearingLevel <= 1) {
2316
+ payload.ai_model_id = `supply-risk-${options.riskLevel}`;
2317
+ const ctx = { provider: "supply-chain-risk", risk_level: options.riskLevel };
2318
+ if (options.supplierIdHash)
2319
+ ctx.supplier_id_hash = options.supplierIdHash;
2320
+ if (options.vulnerabilityCount != null)
2321
+ ctx.vulnerability_count = options.vulnerabilityCount;
2322
+ if (options.lastAuditDate)
2323
+ ctx.last_audit_date = options.lastAuditDate;
2324
+ if (options.updateCadenceDays != null)
2325
+ ctx.update_cadence_days = options.updateCadenceDays;
2326
+ payload.ai_context = ctx;
2327
+ }
2328
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2329
+ this._applyOperationalMetadata(payload, policyHash);
2330
+ this.buffer.enqueueMany([payload]);
2331
+ return payload;
2332
+ }
2333
+ // ── Post-Market Monitoring (AI-PMM.1) ─────────────────────────
2334
+ /**
2335
+ * Witness post-market monitoring attestation (AI-PMM.1).
2336
+ *
2337
+ * Records execution of post-market monitoring plans per EU AI Act
2338
+ * Art. 72 and NIST AI RMF MANAGE 4.1.
2339
+ */
2340
+ witnessPostMarketMonitoring(options) {
2341
+ const fa = options.monitoringChecksRun;
2342
+ const fb = options.anomaliesDetected;
2343
+ const fc = PMM_TYPE_CODES[options.monitoringType] ?? 4;
2344
+ const [ts, epoch] = timestampMs();
2345
+ const fp = mintFingerprint(this.config.tenantId, "AI-PMM.1", fa, fb, fc, ts);
2346
+ const payload = {
2347
+ procedure_id: "AI-PMM.1", factor_a: fa, factor_b: fb, factor_c: fc,
2348
+ clearing_level: this.config.clearingLevel,
2349
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2350
+ };
2351
+ if (this.config.clearingLevel <= 1) {
2352
+ payload.ai_model_id = `pmm-${options.monitoringType}`;
2353
+ const ctx = { provider: "post-market-monitoring", monitoring_type: options.monitoringType };
2354
+ if (options.monitoringPlanHash)
2355
+ ctx.monitoring_plan_hash = options.monitoringPlanHash;
2356
+ if (options.periodStart)
2357
+ ctx.period_start = options.periodStart;
2358
+ if (options.periodEnd)
2359
+ ctx.period_end = options.periodEnd;
2360
+ if (options.reportGenerated != null)
2361
+ ctx.report_generated = options.reportGenerated;
2362
+ payload.ai_context = ctx;
2363
+ }
2364
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2365
+ this._applyOperationalMetadata(payload, policyHash);
2366
+ this.buffer.enqueueMany([payload]);
2367
+ return payload;
2368
+ }
2369
+ // ── Chain, Violation, Charter, Registry, Reviewer, Safe State ───
2370
+ /**
2371
+ * Witness a multi-agent chain handoff (AI-CHAIN.1).
2372
+ */
2373
+ witnessChainHandoff(depth, targetAgent, options) {
2374
+ const accepted = options?.accepted ?? true;
2375
+ const [ts, epoch] = timestampMs();
2376
+ const fa = depth;
2377
+ const fb = this.config.cycleId ? 1 : 0;
2378
+ const fc = accepted ? 1 : 0;
2379
+ const fp = mintFingerprint(this.config.tenantId, "AI-CHAIN.1", fa, fb, fc, ts);
2380
+ const payload = {
2381
+ procedure_id: "AI-CHAIN.1", factor_a: fa, factor_b: fb, factor_c: fc,
2382
+ clearing_level: this.config.clearingLevel,
2383
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2384
+ };
2385
+ if (this.config.clearingLevel <= 1) {
2386
+ payload.ai_model_id = targetAgent;
2387
+ payload.ai_context = {
2388
+ provider: "chain", target_agent: targetAgent, depth, accepted,
2389
+ };
2390
+ }
2391
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2392
+ this._applyOperationalMetadata(payload, policyHash);
2393
+ this.buffer.enqueueMany([payload]);
2394
+ return payload;
2395
+ }
2396
+ /**
2397
+ * Witness a trust-level-aware chain handoff (AI-CHAIN.1 + optional AI-CHAIN.2).
2398
+ *
2399
+ * Tracks the effective trust level across all agents in the chain.
2400
+ * If chainMinTrustLevel is configured and strict mode is active,
2401
+ * throws ChainTrustError when the effective level drops below the minimum.
2402
+ *
2403
+ * Auto-mints AI-CHAIN.2 (trust degradation) when the effective trust
2404
+ * level drops compared to the previous handoff.
2405
+ */
2406
+ witnessChainTrustHandoff(targetAgentId, targetTrustLevel, options) {
2407
+ const accepted = options?.accepted ?? true;
2408
+ const prevEffective = this._chainTrustLevels.length > 0
2409
+ ? Math.min(...this._chainTrustLevels)
2410
+ : targetTrustLevel;
2411
+ this._chainTrustLevels.push(targetTrustLevel);
2412
+ const effectiveTrustLevel = Math.min(...this._chainTrustLevels);
2413
+ // Enforce minimum if configured
2414
+ const minLevel = this.config.chainMinTrustLevel;
2415
+ if (minLevel !== undefined && effectiveTrustLevel < minLevel && this._strict) {
2416
+ throw new ChainTrustError(effectiveTrustLevel, minLevel);
2417
+ }
2418
+ const [ts, epoch] = timestampMs();
2419
+ const fa = this._chainTrustLevels.length;
2420
+ const fb = targetTrustLevel;
2421
+ const fc = effectiveTrustLevel;
2422
+ const fp = mintFingerprint(this.config.tenantId, "AI-CHAIN.1", fa, fb, fc, ts);
2423
+ const payload = {
2424
+ procedure_id: "AI-CHAIN.1", factor_a: fa, factor_b: fb, factor_c: fc,
2425
+ clearing_level: this.config.clearingLevel,
2426
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2427
+ };
2428
+ if (this.config.clearingLevel <= 1) {
2429
+ payload.ai_model_id = targetAgentId;
2430
+ payload.ai_context = {
2431
+ provider: "chain-trust",
2432
+ target_agent: targetAgentId,
2433
+ target_trust_level: targetTrustLevel,
2434
+ effective_trust_level: effectiveTrustLevel,
2435
+ chain_depth: this._chainTrustLevels.length,
2436
+ };
2437
+ }
2438
+ const cycleId = options?.cycleId ?? this.config.cycleId;
2439
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2440
+ this._applyOperationalMetadata(payload, policyHash);
2441
+ if (cycleId)
2442
+ payload.cycle_id = cycleId;
2443
+ const payloads = [payload];
2444
+ // Auto-mint AI-CHAIN.2 if trust degraded
2445
+ if (this._chainTrustLevels.length > 1 && effectiveTrustLevel < prevEffective) {
2446
+ const degradation = extractChainTrustDegradationPayload(this.config.tenantId, prevEffective, effectiveTrustLevel, this.config.clearingLevel, this.config.agentId, this.config.signingKey, this.config.signingKeyId, this.config.signingKeyVersion, cycleId, policyHash, this.config.signingAlgorithm);
2447
+ if (this.config.clearingLevel <= 1) {
2448
+ degradation.ai_context = {
2449
+ provider: "chain-trust-degradation",
2450
+ previous_effective: prevEffective,
2451
+ new_effective: effectiveTrustLevel,
2452
+ target_agent: targetAgentId,
2453
+ };
2454
+ }
2455
+ payloads.push(degradation);
2456
+ }
2457
+ this.buffer.enqueueMany(payloads);
2458
+ return payload;
2459
+ }
2460
+ /** The effective (minimum) trust level across all chain handoffs. Returns 4 if no handoffs yet. */
2461
+ get chainEffectiveTrustLevel() {
2462
+ return this._chainTrustLevels.length === 0 ? 4 : Math.min(...this._chainTrustLevels);
2463
+ }
2464
+ /** The trust levels recorded at each chain handoff. */
2465
+ get chainTrustLevels() {
2466
+ return this._chainTrustLevels;
2467
+ }
2468
+ /**
2469
+ * Witness a policy violation (AI-VIO.1).
2470
+ */
2471
+ witnessViolation(severity, description, options) {
2472
+ const autoDetected = options?.autoDetected ?? false;
2473
+ const policyCategory = options?.policyCategory ?? "unspecified";
2474
+ const [ts, epoch] = timestampMs();
2475
+ const fa = Math.max(1, Math.min(4, severity));
2476
+ const fb = autoDetected ? 1 : 0;
2477
+ const fc = POLICY_CATEGORIES[policyCategory] ?? 0;
2478
+ const fp = mintFingerprint(this.config.tenantId, "AI-VIO.1", fa, fb, fc, ts);
2479
+ const payload = {
2480
+ procedure_id: "AI-VIO.1", factor_a: fa, factor_b: fb, factor_c: fc,
2481
+ clearing_level: this.config.clearingLevel,
2482
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2483
+ };
2484
+ if (this.config.clearingLevel <= 1) {
2485
+ payload.ai_model_id = `violation-sev${fa}`;
2486
+ payload.ai_context = {
2487
+ provider: "violation", severity: fa, description, auto_detected: autoDetected, policy_category: policyCategory,
2488
+ };
2489
+ }
2490
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2491
+ this._applyOperationalMetadata(payload, policyHash);
2492
+ this.buffer.enqueueMany([payload]);
2493
+ return payload;
2494
+ }
2495
+ /**
2496
+ * Witness an agent charter or system prompt hash (AI-CHR.1).
2497
+ */
2498
+ witnessCharter(options) {
2499
+ if (!options.charterText && !options.charterHash) {
2500
+ throw new Error("Provide charterText or charterHash");
2501
+ }
2502
+ const computed = options.charterHash ?? sha256Truncated(options.charterText);
2503
+ const match = options.expectedHash ? computed === options.expectedHash : true;
2504
+ const [ts, epoch] = timestampMs();
2505
+ const fa = 1, fb = match ? 1 : 0, fc = 0;
2506
+ const fp = mintFingerprint(this.config.tenantId, "AI-CHR.1", fa, fb, fc, ts);
2507
+ const payload = {
2508
+ procedure_id: "AI-CHR.1", factor_a: fa, factor_b: fb, factor_c: fc,
2509
+ clearing_level: this.config.clearingLevel,
2510
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2511
+ };
2512
+ if (this.config.clearingLevel <= 1) {
2513
+ payload.ai_model_id = "charter";
2514
+ const ctx = { provider: "charter", charter_hash: computed };
2515
+ if (options.expectedHash)
2516
+ ctx.expected_hash = options.expectedHash;
2517
+ payload.ai_context = ctx;
2518
+ }
2519
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2520
+ this._applyOperationalMetadata(payload, policyHash);
2521
+ this.buffer.enqueueMany([payload]);
2522
+ return payload;
2523
+ }
2524
+ /**
2525
+ * Witness a model registry check (AI-MDL.8).
2526
+ */
2527
+ witnessModelRegistry(modelId, registryId, options) {
2528
+ const found = options?.found ?? true;
2529
+ const status = options?.status ?? "approved";
2530
+ const [ts, epoch] = timestampMs();
2531
+ const fa = 1, fb = found ? 1 : 0, fc = APPROVAL_STATUS[status] ?? 0;
2532
+ const fp = mintFingerprint(this.config.tenantId, "AI-MDL.8", fa, fb, fc, ts);
2533
+ const payload = {
2534
+ procedure_id: "AI-MDL.8", factor_a: fa, factor_b: fb, factor_c: fc,
2535
+ clearing_level: this.config.clearingLevel,
2536
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2537
+ };
2538
+ if (this.config.clearingLevel <= 1) {
2539
+ payload.ai_model_id = modelId;
2540
+ payload.ai_context = {
2541
+ provider: "model-registry", model_id: modelId, registry_id: registryId, found, status,
2542
+ };
2543
+ }
2544
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2545
+ this._applyOperationalMetadata(payload, policyHash);
2546
+ this.buffer.enqueueMany([payload]);
2547
+ return payload;
2548
+ }
2549
+ /**
2550
+ * Witness reviewer identity binding (AI-HITL.3).
2551
+ */
2552
+ witnessReviewerIdentity(required, actual, options) {
2553
+ const method = options?.method ?? "session";
2554
+ const [ts, epoch] = timestampMs();
2555
+ const fa = required, fb = actual, fc = BINDING_METHODS[method] ?? 0;
2556
+ const fp = mintFingerprint(this.config.tenantId, "AI-HITL.3", fa, fb, fc, ts);
2557
+ const payload = {
2558
+ procedure_id: "AI-HITL.3", factor_a: fa, factor_b: fb, factor_c: fc,
2559
+ clearing_level: this.config.clearingLevel,
2560
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2561
+ };
2562
+ if (this.config.clearingLevel <= 1) {
2563
+ payload.ai_model_id = "reviewer-identity";
2564
+ const ctx = {
2565
+ provider: "reviewer", required, actual, method,
2566
+ };
2567
+ if (options?.reviewerIdHash)
2568
+ ctx.reviewer_id_hash = options.reviewerIdHash;
2569
+ payload.ai_context = ctx;
2570
+ }
2571
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2572
+ this._applyOperationalMetadata(payload, policyHash);
2573
+ this.buffer.enqueueMany([payload]);
2574
+ return payload;
2575
+ }
2576
+ /**
2577
+ * Witness safe state attestation (AI-SAFE.1).
2578
+ */
2579
+ witnessSafeState(options) {
2580
+ const mechanismExists = options?.mechanismExists ?? true;
2581
+ const safeStateConfirmed = options?.safeStateConfirmed ?? true;
2582
+ const [ts, epoch] = timestampMs();
2583
+ const fa = 1, fb = mechanismExists ? 1 : 0, fc = safeStateConfirmed ? 1 : 0;
2584
+ const fp = mintFingerprint(this.config.tenantId, "AI-SAFE.1", fa, fb, fc, ts);
2585
+ const payload = {
2586
+ procedure_id: "AI-SAFE.1", factor_a: fa, factor_b: fb, factor_c: fc,
2587
+ clearing_level: this.config.clearingLevel,
2588
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2589
+ };
2590
+ if (this.config.clearingLevel <= 1) {
2591
+ payload.ai_model_id = "safe-state";
2592
+ const ctx = {
2593
+ provider: "safe-state", mechanism_exists: mechanismExists, safe_state_confirmed: safeStateConfirmed,
2594
+ };
2595
+ if (options?.mechanismType)
2596
+ ctx.mechanism_type = options.mechanismType;
2597
+ payload.ai_context = ctx;
2598
+ }
2599
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2600
+ this._applyOperationalMetadata(payload, policyHash);
2601
+ this.buffer.enqueueMany([payload]);
2602
+ return payload;
2603
+ }
2604
+ // ── Training Data (AI-DATA.3 / AI-DATA.4) ──────────────────────
2605
+ /**
2606
+ * Witness training dataset summary statistics (AI-DATA.3).
2607
+ */
2608
+ witnessTrainingStats(rowCount, featureCount, options) {
2609
+ const [ts, epoch] = timestampMs();
2610
+ const fa = rowCount;
2611
+ const fb = featureCount;
2612
+ const fc = options?.classBalanceRatio != null ? Math.floor(options.classBalanceRatio * 1000) : 0;
2613
+ const fp = mintFingerprint(this.config.tenantId, "AI-DATA.3", fa, fb, fc, ts);
2614
+ const payload = {
2615
+ procedure_id: "AI-DATA.3", factor_a: fa, factor_b: fb, factor_c: fc,
2616
+ clearing_level: this.config.clearingLevel,
2617
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2618
+ };
2619
+ if (this.config.clearingLevel <= 1) {
2620
+ payload.ai_model_id = "training-stats";
2621
+ const ctx = {
2622
+ provider: "training-stats", row_count: rowCount, feature_count: featureCount,
2623
+ };
2624
+ if (options?.classBalanceRatio != null)
2625
+ ctx.class_balance_ratio = options.classBalanceRatio;
2626
+ if (options?.distributionHash)
2627
+ ctx.distribution_hash = options.distributionHash;
2628
+ if (options?.classLabels)
2629
+ ctx.class_labels = options.classLabels;
2630
+ if (options?.summary)
2631
+ ctx.summary = options.summary;
2632
+ payload.ai_context = ctx;
2633
+ }
2634
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2635
+ this._applyOperationalMetadata(payload, policyHash);
2636
+ this.buffer.enqueueMany([payload]);
2637
+ return payload;
2638
+ }
2639
+ /**
2640
+ * Witness a training data PII lifecycle event (AI-DATA.4).
2641
+ */
2642
+ witnessTrainingPiiLifecycle(recordsAffected, options) {
2643
+ const completed = options?.completed ?? true;
2644
+ const eventType = options?.eventType ?? "unspecified";
2645
+ const [ts, epoch] = timestampMs();
2646
+ const fa = recordsAffected;
2647
+ const fb = completed ? 1 : 0;
2648
+ const fc = PII_EVENT_TYPES[eventType] ?? 0;
2649
+ const fp = mintFingerprint(this.config.tenantId, "AI-DATA.4", fa, fb, fc, ts);
2650
+ const payload = {
2651
+ procedure_id: "AI-DATA.4", factor_a: fa, factor_b: fb, factor_c: fc,
2652
+ clearing_level: this.config.clearingLevel,
2653
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2654
+ };
2655
+ if (this.config.clearingLevel <= 1) {
2656
+ payload.ai_model_id = "pii-lifecycle";
2657
+ const ctx = {
2658
+ provider: "pii-lifecycle", event_type: eventType,
2659
+ records_affected: recordsAffected, completed,
2660
+ };
2661
+ if (options?.datasetId)
2662
+ ctx.dataset_id = options.datasetId;
2663
+ if (options?.scope)
2664
+ ctx.scope = options.scope;
2665
+ payload.ai_context = ctx;
2666
+ }
2667
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2668
+ this._applyOperationalMetadata(payload, policyHash);
2669
+ this.buffer.enqueueMany([payload]);
2670
+ return payload;
2671
+ }
2672
+ // ── Bias Assessment (AI-FAIR.3) ─────────────────────────────────
2673
+ /**
2674
+ * Witness a bias assessment (AI-FAIR.3).
2675
+ * Records that a bias assessment was conducted, how many protected
2676
+ * attributes were tested, and whether all fairness thresholds were met.
2677
+ *
2678
+ * @param protectedAttributeCount - Number of demographic dimensions tested
2679
+ * @param allThresholdsMet - true if all fairness thresholds passed
2680
+ * @param options.maxDisparityPct - Worst-case disparity percentage (0-100)
2681
+ * @param options.methodology - Assessment methodology name
2682
+ * @param options.protectedAttributes - List of protected attributes tested
2683
+ */
2684
+ witnessBiasAssessment(protectedAttributeCount, allThresholdsMet, options) {
2685
+ const [ts, epoch] = timestampMs();
2686
+ const fa = protectedAttributeCount;
2687
+ const fb = allThresholdsMet ? 1 : 0;
2688
+ const fc = options?.maxDisparityPct != null ? Math.round(options.maxDisparityPct) : 0;
2689
+ const fp = mintFingerprint(this.config.tenantId, "AI-FAIR.3", fa, fb, fc, ts);
2690
+ const payload = {
2691
+ procedure_id: "AI-FAIR.3", factor_a: fa, factor_b: fb, factor_c: fc,
2692
+ clearing_level: this.config.clearingLevel,
2693
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2694
+ };
2695
+ if (this.config.clearingLevel <= 1) {
2696
+ payload.ai_model_id = "bias-assessment";
2697
+ const ctx = {
2698
+ provider: "bias-assessment",
2699
+ protected_attribute_count: protectedAttributeCount,
2700
+ all_thresholds_met: allThresholdsMet,
2701
+ };
2702
+ if (options?.methodology)
2703
+ ctx.methodology = options.methodology;
2704
+ if (options?.protectedAttributes)
2705
+ ctx.protected_attributes = options.protectedAttributes;
2706
+ if (options?.maxDisparityPct != null)
2707
+ ctx.max_disparity_pct = options.maxDisparityPct;
2708
+ payload.ai_context = ctx;
2709
+ }
2710
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2711
+ this._applyOperationalMetadata(payload, policyHash);
2712
+ this.buffer.enqueueMany([payload]);
2713
+ return payload;
2714
+ }
2715
+ // ── Governance Infrastructure Attestation (AI-METAGOV.1) ──────────────
2716
+ /**
2717
+ * Witness governance infrastructure configuration (AI-METAGOV.1).
2718
+ *
2719
+ * Attests the governance system's own configuration using the same
2720
+ * protocol it enforces, per the Recursive Governance architecture.
2721
+ * The governance config must be attested before operational events
2722
+ * can be processed.
2723
+ */
2724
+ witnessGovernanceConfig(options) {
2725
+ // Canonical serialization: sort rules by id, concat id+expression+version, hash with domain separator
2726
+ const sorted = [...options.rules].sort((a, b) => a.id.localeCompare(b.id));
2727
+ const canonical = sorted.map(r => `${r.id}:${r.expression}:${r.version ?? ""}`).join("|");
2728
+ const configHash = sha256Truncated(`SWT3:GOVERNANCE:${canonical}`, 12);
2729
+ const fa = options.rules.length;
2730
+ const fb = parseInt(configHash.slice(0, 8), 16) % 1000000;
2731
+ const fc = options.governanceVersion;
2732
+ const [ts, epoch] = timestampMs();
2733
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.1", fa, fb, fc, ts);
2734
+ const payload = {
2735
+ procedure_id: "AI-METAGOV.1", factor_a: fa, factor_b: fb, factor_c: fc,
2736
+ clearing_level: this.config.clearingLevel,
2737
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2738
+ };
2739
+ if (this.config.clearingLevel <= 1) {
2740
+ payload.ai_model_id = `governance-v${options.governanceVersion}`;
2741
+ const ctx = {
2742
+ provider: "governance-infrastructure",
2743
+ config_hash: configHash,
2744
+ rule_count: options.rules.length,
2745
+ governance_version: options.governanceVersion,
2746
+ };
2747
+ if (options.operatorId)
2748
+ ctx.operator_id = options.operatorId;
2749
+ payload.ai_context = ctx;
2750
+ }
2751
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2752
+ this._applyOperationalMetadata(payload, policyHash);
2753
+ this.buffer.enqueueMany([payload]);
2754
+ return payload;
2755
+ }
2756
+ // ── Policy Downgrade Detection (AI-METAGOV.3) ──────────────────────
2757
+ /**
2758
+ * Check policy version and witness downgrade if detected (AI-METAGOV.3).
2759
+ *
2760
+ * Enforces monotonic policy version progression. If the provided version
2761
+ * is lower than the last known good version, mints a downgrade alert anchor.
2762
+ * Returns the payload if a downgrade was detected, or null if version is normal.
2763
+ */
2764
+ checkPolicyDowngrade(options) {
2765
+ const isDowngrade = options.policyVersion < this._lastKnownGoodVersion;
2766
+ if (!isDowngrade) {
2767
+ this._lastKnownGoodVersion = Math.max(this._lastKnownGoodVersion, options.policyVersion);
2768
+ return null;
2769
+ }
2770
+ const fa = options.policyVersion;
2771
+ const fb = safeHexInt(options.policyContentHash);
2772
+ const fc = 1; // downgrade detected
2773
+ const [ts, epoch] = timestampMs();
2774
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.3", fa, fb, fc, ts);
2775
+ const payload = {
2776
+ procedure_id: "AI-METAGOV.3", factor_a: fa, factor_b: fb, factor_c: fc,
2777
+ clearing_level: this.config.clearingLevel,
2778
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2779
+ };
2780
+ if (this.config.clearingLevel <= 1) {
2781
+ payload.ai_model_id = `policy-downgrade`;
2782
+ payload.ai_context = {
2783
+ provider: "policy-monitor",
2784
+ expected_version: this._lastKnownGoodVersion,
2785
+ loaded_version: options.policyVersion,
2786
+ content_hash: options.policyContentHash,
2787
+ downgrade: true,
2788
+ };
2789
+ }
2790
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2791
+ this._applyOperationalMetadata(payload, policyHash);
2792
+ this.buffer.enqueueMany([payload]);
2793
+ if (options.strict) {
2794
+ throw new Error(`SWT3: Policy downgrade detected: version ${options.policyVersion} < ${this._lastKnownGoodVersion}`);
2795
+ }
2796
+ return payload;
2797
+ }
2798
+ // ── Governance Layer Registration (AI-METAGOV.2) ──────────────────────
2799
+ /**
2800
+ * Register an AI governance layer with the witness layer (AI-METAGOV.2).
2801
+ *
2802
+ * Each AI governance layer must register before its outputs are
2803
+ * considered authoritative. Computes governance stack fingerprint
2804
+ * with SWT3:GOVSTACK: domain separator.
2805
+ */
2806
+ registerGovernanceLayer(options) {
2807
+ const stackInput = `${options.layerId}:${options.configHash}:${options.stackPosition}`;
2808
+ const regFingerprint = sha256Truncated(`SWT3:GOVSTACK:${stackInput}`, 12);
2809
+ const fa = 1;
2810
+ const fb = parseInt(regFingerprint.slice(0, 8), 16) % 1000000;
2811
+ const fc = options.stackPosition;
2812
+ const [ts, epoch] = timestampMs();
2813
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.2", fa, fb, fc, ts);
2814
+ const payload = {
2815
+ procedure_id: "AI-METAGOV.2", factor_a: fa, factor_b: fb, factor_c: fc,
2816
+ clearing_level: this.config.clearingLevel,
2817
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2818
+ };
2819
+ if (this.config.clearingLevel <= 1) {
2820
+ payload.ai_model_id = options.modelId ?? options.layerId;
2821
+ const ctx = {
2822
+ provider: "governance-layer-registration",
2823
+ layer_id: options.layerId,
2824
+ config_hash: options.configHash,
2825
+ stack_position: options.stackPosition,
2826
+ registration_fingerprint: regFingerprint,
2827
+ };
2828
+ if (options.modelId)
2829
+ ctx.model_id = options.modelId;
2830
+ payload.ai_context = ctx;
2831
+ }
2832
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2833
+ this._applyOperationalMetadata(payload, policyHash);
2834
+ this.buffer.enqueueMany([payload]);
2835
+ return payload;
2836
+ }
2837
+ /**
2838
+ * Witness an AI governance layer's output/verdict (AI-METAGOV.2).
2839
+ *
2840
+ * Records the governance layer's compliance decision in the non-AI
2841
+ * witness layer, creating an independently verifiable record.
2842
+ */
2843
+ witnessGovernanceOutput(options) {
2844
+ const fa = 1;
2845
+ const fb = safeHexInt(options.evidenceHash);
2846
+ const fc = options.verdict === "PASS" ? 1 : 0;
2847
+ const [ts, epoch] = timestampMs();
2848
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.2", fa, fb, fc, ts);
2849
+ const payload = {
2850
+ procedure_id: "AI-METAGOV.2", factor_a: fa, factor_b: fb, factor_c: fc,
2851
+ clearing_level: this.config.clearingLevel,
2852
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2853
+ };
2854
+ if (this.config.clearingLevel <= 1) {
2855
+ payload.ai_model_id = options.modelId ?? options.layerId;
2856
+ payload.ai_context = {
2857
+ provider: "governance-output",
2858
+ layer_id: options.layerId,
2859
+ verdict: options.verdict,
2860
+ evidence_hash: options.evidenceHash,
2861
+ };
2862
+ }
2863
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2864
+ this._applyOperationalMetadata(payload, policyHash);
2865
+ this.buffer.enqueueMany([payload]);
2866
+ return payload;
2867
+ }
2868
+ // ── Governance Authorization (AI-METAGOV.5) ──────────────────────
2869
+ /**
2870
+ * Authorize a governance configuration change (AI-METAGOV.5).
2871
+ *
2872
+ * Records the operator identity, authority scope, and signature
2873
+ * for governance changes. Supports separation of duties enforcement.
2874
+ */
2875
+ authorizeGovernanceChange(options) {
2876
+ const fa = METAGOV_SCOPE_CODES[options.scopeDomain] ?? 0;
2877
+ const fb = METAGOV_PERMISSION_CODES[options.permissionLevel] ?? 0;
2878
+ const fc = safeHexInt(options.operatorCredentialHash);
2879
+ const [ts, epoch] = timestampMs();
2880
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.5", fa, fb, fc, ts);
2881
+ const payload = {
2882
+ procedure_id: "AI-METAGOV.5", factor_a: fa, factor_b: fb, factor_c: fc,
2883
+ clearing_level: this.config.clearingLevel,
2884
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2885
+ };
2886
+ if (this.config.clearingLevel <= 1) {
2887
+ payload.ai_model_id = `governance-auth-${options.scopeDomain}`;
2888
+ payload.ai_context = {
2889
+ provider: "governance-authorization",
2890
+ scope_domain: options.scopeDomain,
2891
+ permission_level: options.permissionLevel,
2892
+ operator_id: options.operatorId,
2893
+ change_description: options.changeDescription,
2894
+ };
2895
+ }
2896
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2897
+ this._applyOperationalMetadata(payload, policyHash);
2898
+ this.buffer.enqueueMany([payload]);
2899
+ return payload;
2900
+ }
2901
+ // ── Emergency Override Attestation (AI-METAGOV.6) ──────────────────
2902
+ /**
2903
+ * Witness an emergency governance override (AI-METAGOV.6).
2904
+ *
2905
+ * Records governance changes made outside normal approval workflow.
2906
+ * Triggers mandatory review requirement.
2907
+ */
2908
+ witnessEmergencyOverride(options) {
2909
+ const fa = METAGOV_OVERRIDE_REASON_CODES[options.overrideReason] ?? 0;
2910
+ const fb = options.reviewWindowHours;
2911
+ const fc = METAGOV_REVIEW_STATUS_CODES.unreviewed; // always starts unreviewed
2912
+ const [ts, epoch] = timestampMs();
2913
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.6", fa, fb, fc, ts);
2914
+ const payload = {
2915
+ procedure_id: "AI-METAGOV.6", factor_a: fa, factor_b: fb, factor_c: fc,
2916
+ clearing_level: this.config.clearingLevel,
2917
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2918
+ };
2919
+ if (this.config.clearingLevel <= 1) {
2920
+ payload.ai_model_id = `emergency-override`;
2921
+ payload.ai_context = {
2922
+ provider: "governance-emergency",
2923
+ override_reason: options.overrideReason,
2924
+ review_window_hours: options.reviewWindowHours,
2925
+ operator_id: options.operatorId,
2926
+ change_description: options.changeDescription,
2927
+ review_status: "unreviewed",
2928
+ };
2929
+ }
2930
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2931
+ this._applyOperationalMetadata(payload, policyHash);
2932
+ this.buffer.enqueueMany([payload]);
2933
+ return payload;
2934
+ }
2935
+ // ── Governance Sync Verification (AI-METAGOV.7) ──────────────────────
2936
+ /**
2937
+ * Witness governance policy divergence between organizations (AI-METAGOV.7).
2938
+ *
2939
+ * Records whether federated organizations have equivalent, compatible,
2940
+ * or divergent governance policies during trust credential exchange.
2941
+ */
2942
+ witnessGovernanceSync(options) {
2943
+ const fa = METAGOV_DIVERGENCE_CODES[options.divergenceType] ?? 0;
2944
+ const fb = safeHexInt(options.localPolicyHash);
2945
+ const fc = safeHexInt(options.remotePolicyHash);
2946
+ const [ts, epoch] = timestampMs();
2947
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.7", fa, fb, fc, ts);
2948
+ const payload = {
2949
+ procedure_id: "AI-METAGOV.7", factor_a: fa, factor_b: fb, factor_c: fc,
2950
+ clearing_level: this.config.clearingLevel,
2951
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2952
+ };
2953
+ if (this.config.clearingLevel <= 1) {
2954
+ payload.ai_model_id = `governance-sync`;
2955
+ const ctx = {
2956
+ provider: "governance-sync",
2957
+ divergence_type: options.divergenceType,
2958
+ local_policy_hash: options.localPolicyHash,
2959
+ remote_policy_hash: options.remotePolicyHash,
2960
+ };
2961
+ if (options.remoteTenantId)
2962
+ ctx.remote_tenant_id = options.remoteTenantId;
2963
+ payload.ai_context = ctx;
2964
+ }
2965
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
2966
+ this._applyOperationalMetadata(payload, policyHash);
2967
+ this.buffer.enqueueMany([payload]);
2968
+ return payload;
2969
+ }
2970
+ // ── Attestation Purity Verification (AI-METAGOV.8) ──────────────────
2971
+ /**
2972
+ * Verify and attest that the attestation engine is free of AI (AI-METAGOV.8).
2973
+ *
2974
+ * Computes a combined hash of attestation path source files to prove
2975
+ * the witness layer contains no machine learning components.
2976
+ */
2977
+ verifyAttestationPurity(options) {
2978
+ const combinedInput = options.sourceFiles
2979
+ .sort((a, b) => a.path.localeCompare(b.path))
2980
+ .map(f => `${f.path}:${f.hash}`)
2981
+ .join("|");
2982
+ const combinedHash = sha256Truncated(combinedInput, 12);
2983
+ const fa = options.sourceFiles.length;
2984
+ const fb = parseInt(combinedHash.slice(0, 8), 16) % 1000000;
2985
+ const fc = 1; // pure by definition (this SDK has no AI in attestation path)
2986
+ const [ts, epoch] = timestampMs();
2987
+ const fp = mintFingerprint(this.config.tenantId, "AI-METAGOV.8", fa, fb, fc, ts);
2988
+ const payload = {
2989
+ procedure_id: "AI-METAGOV.8", factor_a: fa, factor_b: fb, factor_c: fc,
2990
+ clearing_level: this.config.clearingLevel,
2991
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
2992
+ };
2993
+ if (this.config.clearingLevel <= 1) {
2994
+ payload.ai_model_id = `attestation-purity`;
2995
+ const ctx = {
2996
+ provider: "purity-verification",
2997
+ source_file_count: options.sourceFiles.length,
2998
+ combined_source_hash: combinedHash,
2999
+ purity_tier: "verified_pure",
3000
+ };
3001
+ if (options.buildHash)
3002
+ ctx.build_hash = options.buildHash;
3003
+ payload.ai_context = ctx;
3004
+ }
3005
+ const policyHash = this.config.policyVersion ? sha256Truncated(this.config.policyVersion, 12) : undefined;
3006
+ this._applyOperationalMetadata(payload, policyHash);
3007
+ this.buffer.enqueueMany([payload]);
3008
+ return payload;
3009
+ }
3010
+ // ── Physical AI / Large Engineering Model (AI-ENG.1-5) ──────────
3011
+ /**
3012
+ * Witness AI-generated design provenance (AI-ENG.1).
3013
+ * DO-178C 5.1, ASME V&V 10 3.1, FDA 21 CFR 11.10(a).
3014
+ */
3015
+ witnessDesignProvenance(options) {
3016
+ const fa = options.constraintsApplied;
3017
+ const fb = options.parametersGenerated;
3018
+ const fc = DESIGN_DOMAIN_CODES[options.designDomain] ?? 7;
3019
+ const [ts, epoch] = timestampMs();
3020
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.1", fa, fb, fc, ts);
3021
+ const payload = {
3022
+ procedure_id: "AI-ENG.1", factor_a: fa, factor_b: fb, factor_c: fc,
3023
+ clearing_level: this.config.clearingLevel,
3024
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3025
+ };
3026
+ if (this.config.clearingLevel <= 1) {
3027
+ payload.ai_model_id = `design-${options.designDomain}`;
3028
+ const ctx = { provider: "design-generation", design_domain: options.designDomain };
3029
+ if (options.designHash)
3030
+ ctx.design_hash = options.designHash;
3031
+ if (options.modelVersion)
3032
+ ctx.model_version = options.modelVersion;
3033
+ payload.ai_context = ctx;
3034
+ }
3035
+ this.buffer.enqueueMany([payload]);
3036
+ return payload;
3037
+ }
3038
+ /**
3039
+ * Witness simulation validation of AI-generated design (AI-ENG.2).
3040
+ * DO-178C 6.3, ASME V&V 10 4.1, ISO 26262-4.
3041
+ */
3042
+ witnessSimulationValidation(options) {
3043
+ const fa = options.simulationsRun;
3044
+ const fb = options.simulationsPassed;
3045
+ const fc = SIMULATION_TYPE_CODES[options.simulationType] ?? 6;
3046
+ const [ts, epoch] = timestampMs();
3047
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.2", fa, fb, fc, ts);
3048
+ const payload = {
3049
+ procedure_id: "AI-ENG.2", factor_a: fa, factor_b: fb, factor_c: fc,
3050
+ clearing_level: this.config.clearingLevel,
3051
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3052
+ };
3053
+ if (this.config.clearingLevel <= 1) {
3054
+ payload.ai_model_id = `sim-${options.simulationType}`;
3055
+ const ctx = { provider: "simulation-validation", simulation_type: options.simulationType };
3056
+ if (options.simulationHash)
3057
+ ctx.simulation_hash = options.simulationHash;
3058
+ if (options.acceptanceCriteria)
3059
+ ctx.acceptance_criteria = options.acceptanceCriteria;
3060
+ payload.ai_context = ctx;
3061
+ }
3062
+ this.buffer.enqueueMany([payload]);
3063
+ return payload;
3064
+ }
3065
+ /**
3066
+ * Witness safety-critical review gate (AI-ENG.3).
3067
+ * DO-178C 7.2, FDA 21 CFR 11.10(g), ISO 26262-2.
3068
+ */
3069
+ witnessSafetyReview(options) {
3070
+ const fa = options.reviewersRequired;
3071
+ const fb = options.reviewersApproved;
3072
+ const fc = APPROVAL_TYPE_CODES[options.approvalType] ?? 0;
3073
+ const [ts, epoch] = timestampMs();
3074
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.3", fa, fb, fc, ts);
3075
+ const payload = {
3076
+ procedure_id: "AI-ENG.3", factor_a: fa, factor_b: fb, factor_c: fc,
3077
+ clearing_level: this.config.clearingLevel,
3078
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3079
+ };
3080
+ if (this.config.clearingLevel <= 1) {
3081
+ payload.ai_model_id = `review-${options.approvalType}`;
3082
+ const ctx = { provider: "safety-review", approval_type: options.approvalType };
3083
+ if (options.reviewId)
3084
+ ctx.review_id = options.reviewId;
3085
+ if (options.peLicense)
3086
+ ctx.pe_license = options.peLicense;
3087
+ payload.ai_context = ctx;
3088
+ }
3089
+ this.buffer.enqueueMany([payload]);
3090
+ return payload;
3091
+ }
3092
+ /**
3093
+ * Witness material specification compliance (AI-ENG.4).
3094
+ * ASME V&V 10 3.3, DO-254 5.3, ISO 26262-8.
3095
+ */
3096
+ witnessMaterialCompliance(options) {
3097
+ const fa = options.specificationsChecked;
3098
+ const fb = options.specificationsMet;
3099
+ const fc = MATERIAL_STANDARD_CODES[options.standard] ?? 6;
3100
+ const [ts, epoch] = timestampMs();
3101
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.4", fa, fb, fc, ts);
3102
+ const payload = {
3103
+ procedure_id: "AI-ENG.4", factor_a: fa, factor_b: fb, factor_c: fc,
3104
+ clearing_level: this.config.clearingLevel,
3105
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3106
+ };
3107
+ if (this.config.clearingLevel <= 1) {
3108
+ payload.ai_model_id = `material-${options.standard}`;
3109
+ const ctx = { provider: "material-compliance", standard: options.standard };
3110
+ if (options.materialId)
3111
+ ctx.material_id = options.materialId;
3112
+ if (options.specificationRef)
3113
+ ctx.specification_ref = options.specificationRef;
3114
+ payload.ai_context = ctx;
3115
+ }
3116
+ this.buffer.enqueueMany([payload]);
3117
+ return payload;
3118
+ }
3119
+ /**
3120
+ * Witness design revision chain (AI-ENG.5).
3121
+ * DO-178C 7.3, FDA 21 CFR 11.10(e), ASME V&V 10 2.4.
3122
+ */
3123
+ witnessDesignChain(options) {
3124
+ const fa = options.totalRevisions;
3125
+ const fb = options.aiGeneratedRevisions;
3126
+ const fc = CHAIN_STATUS_CODES[options.chainStatus] ?? 0;
3127
+ const [ts, epoch] = timestampMs();
3128
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.5", fa, fb, fc, ts);
3129
+ const payload = {
3130
+ procedure_id: "AI-ENG.5", factor_a: fa, factor_b: fb, factor_c: fc,
3131
+ clearing_level: this.config.clearingLevel,
3132
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3133
+ };
3134
+ if (this.config.clearingLevel <= 1) {
3135
+ payload.ai_model_id = `design-chain-${options.chainStatus}`;
3136
+ const ctx = { provider: "design-revision-chain", chain_status: options.chainStatus, ai_revision_ratio: options.aiGeneratedRevisions / Math.max(options.totalRevisions, 1) };
3137
+ if (options.designId)
3138
+ ctx.design_id = options.designId;
3139
+ if (options.finalHash)
3140
+ ctx.final_hash = options.finalHash;
3141
+ payload.ai_context = ctx;
3142
+ }
3143
+ this.buffer.enqueueMany([payload]);
3144
+ return payload;
3145
+ }
3146
+ /**
3147
+ * Witness fabrication release attestation (AI-ENG.6).
3148
+ * DO-178C 5.5, FDA 21 CFR 11.10(f), ISO 26262-4 7.4.4.
3149
+ */
3150
+ witnessFabricationRelease(options) {
3151
+ const fa = options.designHashVerified ? 1 : 0;
3152
+ const fb = options.authorizationCount;
3153
+ const fc = RELEASE_TYPE_CODES[options.releaseType] ?? 0;
3154
+ const [ts, epoch] = timestampMs();
3155
+ const fp = mintFingerprint(this.config.tenantId, "AI-ENG.6", fa, fb, fc, ts);
3156
+ const payload = {
3157
+ procedure_id: "AI-ENG.6", factor_a: fa, factor_b: fb, factor_c: fc,
3158
+ clearing_level: this.config.clearingLevel,
3159
+ anchor_fingerprint: fp, anchor_epoch: epoch, fingerprint_timestamp_ms: ts,
3160
+ };
3161
+ if (this.config.clearingLevel <= 1) {
3162
+ payload.ai_model_id = `fabrication-${options.releaseType}`;
3163
+ const ctx = { provider: "fabrication-release", release_type: options.releaseType, design_hash_verified: options.designHashVerified };
3164
+ if (options.productionSystemId)
3165
+ ctx.production_system_id = options.productionSystemId;
3166
+ if (options.approvedDesignHash)
3167
+ ctx.approved_design_hash = options.approvedDesignHash;
3168
+ if (options.finalDesignHash)
3169
+ ctx.final_design_hash = options.finalDesignHash;
3170
+ payload.ai_context = ctx;
3171
+ }
3172
+ this.buffer.enqueueMany([payload]);
3173
+ return payload;
3174
+ }
3175
+ // ── Trust Mesh (AI-TRUST.1 / AI-TRUST.2) ────────────────────────
3176
+ _trustRegistry;
1899
3177
  _witnessedProcedures = new Set();
1900
3178
  get trustRegistry() {
1901
3179
  if (!this._trustRegistry)
@@ -2115,4 +3393,81 @@ export class Witness {
2115
3393
  return this.buffer.receipts;
2116
3394
  }
2117
3395
  }
3396
+ /**
3397
+ * Validate a governance rule graph for circular dependencies (AI-METAGOV.4).
3398
+ *
3399
+ * Uses Kahn's algorithm (BFS topological sort) to detect cycles in governance
3400
+ * rule dependency graphs. Returns validation results including any detected cycles.
3401
+ */
3402
+ export function validateGovernanceGraph(rules) {
3403
+ // Build adjacency list and in-degree map
3404
+ const adj = new Map();
3405
+ const inDegree = new Map();
3406
+ for (const rule of rules) {
3407
+ if (!adj.has(rule.id))
3408
+ adj.set(rule.id, []);
3409
+ if (!inDegree.has(rule.id))
3410
+ inDegree.set(rule.id, 0);
3411
+ for (const dep of rule.dependencies ?? []) {
3412
+ if (!adj.has(dep))
3413
+ adj.set(dep, []);
3414
+ if (!inDegree.has(dep))
3415
+ inDegree.set(dep, 0);
3416
+ adj.get(dep).push(rule.id);
3417
+ inDegree.set(rule.id, (inDegree.get(rule.id) ?? 0) + 1);
3418
+ }
3419
+ }
3420
+ // Kahn's algorithm
3421
+ const queue = [];
3422
+ for (const [node, deg] of inDegree) {
3423
+ if (deg === 0)
3424
+ queue.push(node);
3425
+ }
3426
+ const sorted = [];
3427
+ const depths = new Map();
3428
+ for (const node of queue)
3429
+ depths.set(node, 0);
3430
+ while (queue.length > 0) {
3431
+ const node = queue.shift();
3432
+ sorted.push(node);
3433
+ for (const neighbor of adj.get(node) ?? []) {
3434
+ const newDeg = (inDegree.get(neighbor) ?? 1) - 1;
3435
+ inDegree.set(neighbor, newDeg);
3436
+ depths.set(neighbor, Math.max(depths.get(neighbor) ?? 0, (depths.get(node) ?? 0) + 1));
3437
+ if (newDeg === 0)
3438
+ queue.push(neighbor);
3439
+ }
3440
+ }
3441
+ // Nodes not in sorted = part of cycles
3442
+ const cycleNodes = new Set();
3443
+ for (const [node, deg] of inDegree) {
3444
+ if (deg > 0)
3445
+ cycleNodes.add(node);
3446
+ }
3447
+ // Extract cycle paths from remaining nodes
3448
+ const cycles = [];
3449
+ if (cycleNodes.size > 0) {
3450
+ const visited = new Set();
3451
+ for (const start of cycleNodes) {
3452
+ if (visited.has(start))
3453
+ continue;
3454
+ const cycle = [];
3455
+ let current = start;
3456
+ while (current && !visited.has(current) && cycleNodes.has(current)) {
3457
+ visited.add(current);
3458
+ cycle.push(current);
3459
+ current = (adj.get(current) ?? []).find(n => cycleNodes.has(n) && !visited.has(n));
3460
+ }
3461
+ if (cycle.length > 0)
3462
+ cycles.push(cycle);
3463
+ }
3464
+ }
3465
+ const maxDepth = Math.max(0, ...Array.from(depths.values()));
3466
+ return {
3467
+ valid: cycles.length === 0,
3468
+ cycles,
3469
+ maxDepth,
3470
+ ruleCount: rules.length,
3471
+ };
3472
+ }
2118
3473
  //# sourceMappingURL=witness.js.map