chainlesschain 0.166.24 → 0.166.26

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 (184) hide show
  1. package/README.md +52 -3
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-DR-MWcZc.js → AIOps-Z8_dnLd8.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-DT8B7sEb.js → ActionButton-C4bKCISV.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-asjh3dQJ.js → Analytics-GztAv2jy.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DivQ491i.js → AppLayout-DEqNcuVx.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-DPH2uUmy.js → Artifacts-D-R4Ehap.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-Bp2nLyc-.js → Audit-mzzdTIlM.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-CHS28khl.js → BackgroundAgents-DS2QupIC.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CKeaFSfz.js → Backup-CQSirC39.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-CxwM9BAH.js → BaseInput-Bhuc-eOV.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DYLDwaCv.js → Chat-B-RLVGnt.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DdBJDBP0.js → ChatBubbleRenderer-CBbMoVuE.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-uYTWOB8j.js → Checkbox-DxwgBryW.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CvYa_dwT.js → Codegen-Cwrm-7nh.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-CanMAX4m.js → Col-DrSCT-nF.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-B4WaDtHw.js → Community-DY2D9WNs.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-K93Uof_3.js → Compact-o-tV0URw.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-CKeDLgUW.js → Compliance-Bndh6S8f.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-P93grAeB.js → Cowork-CSNQODak.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-BSHnMtDn.js → Cron-CTgxRHdy.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-epAOpUVJ.js → Crosschain-BJoGQzDI.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-ByjXfP7t.js → DID-V0Ztm8ne.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-QztTU8tb.js → Dashboard-B-38THOj.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DhUc9yhN.js → Dropdown-B3FdOwMO.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-C2sLhJJN.js → EmailListRenderer-YQDz4mUF.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CdfbWNDn.js → FamilyGuardDashboard-DYE45IF9.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CcF_R7NW.js → Federation-DjBFjdRZ.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-Cm_X2IBk.js → FormItemContext-CVTXEa0R.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-DUi4NWlb.js → GenericCardRenderer-B6Tkke8X.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-4Sq5FjBt.js → Git-CD0hyAzT.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-Dx2_v4V6.js → Governance-CWOQQJr8.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-7Vr1xekR.js → Inference-lHYwUk-C.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-Cnd2XOzf.js → KnowledgeGraph-Cledxv7t.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-B66QPVf-.js → Logs-D45mt-rM.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-PLsEvhly.js → MarkdownRenderer-DJjPaOnM.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BMIK9BmC.js → Marketplace-Yy30UZPw.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BDbyp3J_.js → McpTools-Cil5l-bh.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-CJdzfZGi.js → Memory-DdJcnyqy.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C2TH5Y3-.js → MobileBridge-IrzFYHEv.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-D1dYXkvV.js → MobileProjects-D8q64LMd.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-B-4A1I1j.js → Mtc-CpdTJzW7.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-Bgcc9UOl.js → MtcAudit-C7Tvw2m6.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-DqOe-etP.js → Multisig-Dmj9F5Kr.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-7VnhzE_6.js → NLProgramming-C9Xchob5.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BxawpeUQ.js → Notes-Bzq6Yry5.js} +4 -4
  47. package/src/assets/web-panel/assets/{NotificationSettings-Cr08G2aE.js → NotificationSettings-DxG9eKb4.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-Ce8bEGlK.js → OrderTableRenderer-BS_IYoCe.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BC7lveGv.js → Organization-kazsRvcq.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CakOW-G0.js → Overflow-i4wP-hwn.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-Cf8CaOBZ.js → P2P-CfGeU3h-.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dc7b98W9.js → PdhVaultBrowser-CS-VhVUx.js} +5 -5
  53. package/src/assets/web-panel/assets/{Permissions-DGJyMEfS.js → Permissions-DnEHXs0I.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-DNIwSdwu.js → PersonalDataHub-DeD82qke.js} +6 -6
  55. package/src/assets/web-panel/assets/{Pipeline-5B1S12wa.js → Pipeline-CMGGLgBY.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-CMB6Ke5t.js → Privacy-CvHoFv32.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-D5PqTFiT.js → ProjectInit-DnJapCc1.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-CbKNdSjV.js → ProjectSettings-CqVdv3-g.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-B_o8vcs_.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-CJF5_-Gs.js → Providers-CPKseoDW.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-CT6iEAdi.js → QrScannerModal-_iBfKbPQ.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-Ci0h9mJ_.js → QuickAsk-CMrlZ69a.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-Da5mobZu.js → Recommend-BwDtSZ0l.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-BaCY8eey.js → RemoteSession-DomUAtn4.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-CaITfTsI.js → Reputation-Cuu2GCHr.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DtUDamyP.js → Row-C7GVts31.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-DX27gFpg.js → RssFeed-DRKvgEog.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DFL69osN.js → Search-BGI9wOeA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-BqGeoWv-.js → Security-BlLaHy_L.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-3z1WnEAc.js → Services-DFqZbjmX.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C_OJQQ9Z.js → Skeleton-BCGxdooP.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-BY7aT6Mo.js → Skills-CwFKgcmm.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-BZv7DSaD.js → Sla-CiXXh9eS.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-WSx2CLqO.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-B6D7STlI.js → SyncSettings-BBIqQOtW.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-Co_FCZAO.js → Tasks-D1BGLjO1.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-CnY-9fgz.js → Templates-CUIl9axA.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-B71yXfZ8.js → Tenant-BFZJ0hNz.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-Dd_P7awo.js → Terminal-Cw-3eYVn.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CvIEMyli.js → TimelineRenderer-bOVPB56L.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DknFBGOi.js → Tokens-Czfyq2VY.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-D_4nJONB.js → Trigger-C-o4uJY0.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BNl21fa7.js → Trust-BKq_S6iF.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CFrCI7uK.js → UkeySign-fKlWUvMx.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-BVfY6JLg.js → VideoEditing-DB5MLuS7.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-Cj9CAK0J.js → Wallet-WGXBn7IS.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-DcqZlzA3.js → WebAuthn-B8TC4EMF.js} +4 -4
  88. package/src/assets/web-panel/assets/{WorkflowEditor-Dfr_dMld.js → WorkflowEditor-DLY--KmM.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-Yv6UF0AD.js → chat-Crw3XQaA.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CDW_-1fs.js → colors-CxhWauPV.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BYOQvd-6.js → compact-item-Cp3ojtk5.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BCGO0BiP.js → createContext-CRuRXjSo.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-CKAQY2zn.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DY-70cfQ.js → hasIn-XGW474dj.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B9ZogJJM.js → index-38TRdZb6.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BBs2mv5M.js → index-B45Vkh3T.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CCwWp3mT.js → index-B5fJS-kn.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CUo27q9J.js → index-BElgeKJ0.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-CFa2fPCk.js → index-BUWZ57T4.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DCtsjhhT.js → index-BVmSfIkJ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-NaCESahy.js → index-BW028Pwn.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CaT8trvf.js → index-BXnNbbwa.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DRFC2Qt0.js → index-BYkjs7eP.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Br3wQLVY.js → index-BetOkRLs.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DuIPq5MX.js → index-BuVA26SD.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C4UJA2ju.js → index-C73pqyDb.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BvK4fjkk.js → index-C8UOVaUH.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-hZ0Eyrrw.js → index-CDIpH_8Q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D--TEyDj.js → index-CPFam-me.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CUP-A2_h.js → index-CTE32qol.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CnZNbcux.js → index-CdlfrcC-.js} +1 -1
  112. package/src/assets/web-panel/assets/index-Cetfwq8j.js +1 -0
  113. package/src/assets/web-panel/assets/{index-C40UdtlS.js → index-Ctu98x57.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B9m5QAMg.js → index-DBcBsJYg.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BXlEx4UH.js → index-DHNixOg_.js} +1 -1
  116. package/src/assets/web-panel/assets/index-DOpcRO2-.js +1 -0
  117. package/src/assets/web-panel/assets/{index-Dg-AQYDf.js → index-DUSVsOGS.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CzeEEazr.js → index-De2FN0xN.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DUDoRk9r.js → index-DfPLIA-f.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Y9akzgFO.js → index-DhomnuaB.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-366wfQBU.js → index-DoUC5_ry.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Bb9nyts1.js → index-Dp2nC5On.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CIyHxV4u.js → index-DxOtBFVy.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BFv1hzF6.js → index-E-RSfImO.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DLOf7BSz.js → index-J_08R33H.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-RjIMPG0u.js → index-QqAuH7-S.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CB_Iw73G.js → index-W8_0yAi_.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DM5c4pc-.js → index-WvNZXbIO.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DT_qVaaV.js → index-Yq3bFbYX.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-NYVBUAVN.js → index-jrIcbPUa.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Cy2NE6AO.js → index-nJR64pA_.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-Bf_Va0S-.js → index-qzmihx1d.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BayRTE5w.js → index-rsACoVT9.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CG99CcR4.js → initDefaultProps-DAu-hgme.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-Z7MH0_0G.js → motion-Db8yk0Hu.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-BX67lOdq.js → move-Cii2jOin.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CmAbG1fE.js → mtc-parser-CnZBDkyZ.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DiU5tI1_.js → omit-Buzt1FTL.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-BGfvLrYL.js → pickAttrs-CpZ_NmE6.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-CggLEgaJ.js → placementArrow-mBrx3dYm.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-t3nlghPZ.js → responsiveObserve-DC_QzljB.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BkV4dL9s.js → slide-DT_UVED-.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-qec1PUoC.js → statusUtils-78t6eNLV.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-ChjX6T8D.js → styleChecker-CV_T1ULL.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-B1jLoZcM.js → useFlexGapSupport-s8edGuXD.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-C3X53s4E.js → useFs-Pk9dH2HC.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-DOvbbnkZ.js → usePersonalDataHub-B_GqAm8c.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-Ie0TEVFT.js → vnode-Cxyss24q.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CRUMVS8l.js → zoom-0UY3cOuc.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/evolution-knowledge.js +40 -1
  152. package/src/commands/serve.js +11 -0
  153. package/src/data/changelog.json +29 -3
  154. package/src/generated/cc-agent-protocol.schema.json +3 -1
  155. package/src/lib/app-server/server.js +49 -0
  156. package/src/lib/app-server/websocket-transport.js +13 -0
  157. package/src/lib/evolution/agent-model-projection.js +252 -32
  158. package/src/lib/evolution/evidence-backed-wiki-maintainer.js +22 -9
  159. package/src/lib/evolution/evolution-artifact-ports.js +3 -0
  160. package/src/lib/evolution/evolution-deployment-loader.js +77 -0
  161. package/src/lib/evolution/evolution-evidence-projector.js +36 -5
  162. package/src/lib/evolution/evolution-ledger-ports.js +210 -18
  163. package/src/lib/evolution/governed-knowledge-dependency-inventory.js +392 -0
  164. package/src/lib/evolution/governed-knowledge-dependency-ledger-executor.js +123 -0
  165. package/src/lib/evolution/governed-knowledge-quarantine-release.js +1013 -0
  166. package/src/lib/evolution/governed-knowledge-revocation-host.js +59 -0
  167. package/src/lib/evolution/governed-knowledge-skill-rollback.js +62 -27
  168. package/src/lib/evolution/governed-knowledge-sync.js +164 -1
  169. package/src/lib/evolution/governed-knowledge-wiki-tombstone.js +88 -34
  170. package/src/lib/evolution/knowledge-wiki-source-admission.js +160 -1
  171. package/src/lib/evolution/knowledge-wiki-source-provenance.js +1 -0
  172. package/src/lib/evolution/skill-candidate-registry.js +21 -3
  173. package/src/lib/evolution/skill-release-registry.js +143 -0
  174. package/src/lib/evolution/wiki-maintainer-ledger-adapter.js +61 -0
  175. package/src/lib/evolution/wiki-target-tombstone-revision.js +15 -7
  176. package/src/lib/read-file-loop-guard.js +222 -0
  177. package/src/lib/read-file-page.js +55 -2
  178. package/src/repl/agent-repl.js +6 -1
  179. package/src/runtime/agent-core.js +177 -57
  180. package/src/assets/web-panel/assets/Projects-ccXaHzYL.js +0 -1
  181. package/src/assets/web-panel/assets/SpeechSettings-6lJKLhCn.js +0 -1
  182. package/src/assets/web-panel/assets/devWarning-H-kXSuf-.js +0 -1
  183. package/src/assets/web-panel/assets/index-B0o4MeNK.js +0 -1
  184. package/src/assets/web-panel/assets/index-BVafOL_I.js +0 -1
@@ -44,6 +44,10 @@ import {
44
44
  GOVERNED_KNOWLEDGE_DEPENDENCY_PREPARED_EVENT_TYPE,
45
45
  verifyGovernedKnowledgeDependencyPrepared,
46
46
  } from "./governed-knowledge-dependency-ledger-executor.js";
47
+ import {
48
+ GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE,
49
+ verifyGovernedKnowledgeQuarantineReleaseRecord,
50
+ } from "./governed-knowledge-quarantine-release.js";
47
51
  import {
48
52
  WIKI_LEDGER_EVENT_TYPE,
49
53
  WikiMaintainerLedgerAdapter,
@@ -2588,16 +2592,166 @@ class EvolutionLedgerDomainPorts {
2588
2592
  }
2589
2593
  }
2590
2594
 
2595
+ *#knowledgeQuarantineReleases(snapshot, tenantId, audience) {
2596
+ const operations = new Set();
2597
+ for (const event of snapshot.events) {
2598
+ if (
2599
+ event.type !== GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE ||
2600
+ event.tenantId !== tenantId
2601
+ ) {
2602
+ continue;
2603
+ }
2604
+ if (
2605
+ event.schema !== EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA ||
2606
+ event.artifactTenantId !== this.#artifactTenantId ||
2607
+ event.decision !== "committed" ||
2608
+ !Array.isArray(event.sourceRefs) ||
2609
+ event.sourceRefs.length !== 0
2610
+ ) {
2611
+ throw portsError(
2612
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2613
+ "quarantine release event binding is invalid",
2614
+ );
2615
+ }
2616
+ const ref = normalizeArtifactRef(
2617
+ event.subjectRef,
2618
+ "quarantine release subjectRef",
2619
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2620
+ );
2621
+ const resolution = assertSynchronous(
2622
+ this.#artifactResolve(
2623
+ deepFreeze({
2624
+ epoch: event.epoch,
2625
+ ledgerId: event.ledgerId,
2626
+ ref,
2627
+ tenantId: this.#artifactTenantId,
2628
+ }),
2629
+ ),
2630
+ "quarantine release artifact resolution",
2631
+ );
2632
+ assertAllExactRecord(
2633
+ resolution,
2634
+ LEDGER_RESOLUTION_KEYS,
2635
+ "quarantine release artifact resolution",
2636
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2637
+ );
2638
+ if (
2639
+ resolution.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
2640
+ resolution.authenticated !== true ||
2641
+ resolution.found !== true ||
2642
+ resolution.ref !== ref.ref ||
2643
+ resolution.digest !== ref.digest
2644
+ ) {
2645
+ throw portsError(
2646
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2647
+ "quarantine release artifact is not authenticated and exactly bound",
2648
+ );
2649
+ }
2650
+ const bytes = copyBytes(resolution.bytes);
2651
+ if (sha256(bytes) !== ref.digest) {
2652
+ throw portsError(
2653
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2654
+ "quarantine release artifact digest mismatch",
2655
+ );
2656
+ }
2657
+ let artifact;
2658
+ try {
2659
+ artifact = JSON.parse(bufferToString(bytes, "utf8"));
2660
+ } catch (cause) {
2661
+ throw portsError(
2662
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2663
+ "quarantine release artifact is not JSON",
2664
+ { cause },
2665
+ );
2666
+ }
2667
+ assertAllExactRecord(
2668
+ artifact,
2669
+ ARTIFACT_RECORD_KEYS,
2670
+ "quarantine release artifact",
2671
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2672
+ );
2673
+ if (
2674
+ canonicalJson(artifact) !== bufferToString(bytes, "utf8") ||
2675
+ artifact.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
2676
+ artifact.tenantId !== this.#artifactTenantId ||
2677
+ artifact.type !== "governed-knowledge-quarantine-release" ||
2678
+ artifact.retention !== "ledger" ||
2679
+ artifact.purpose !== this.#purpose ||
2680
+ artifact.audience !== audience
2681
+ ) {
2682
+ throw portsError(
2683
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2684
+ "quarantine release artifact boundary is invalid",
2685
+ );
2686
+ }
2687
+ let release;
2688
+ try {
2689
+ release = verifyGovernedKnowledgeQuarantineReleaseRecord(
2690
+ artifact.value,
2691
+ { tenantId },
2692
+ );
2693
+ } catch (cause) {
2694
+ throw portsError(
2695
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2696
+ "quarantine release record is invalid",
2697
+ { cause },
2698
+ );
2699
+ }
2700
+ if (
2701
+ event.eventId !==
2702
+ `${GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE}.${release.operationDigest.slice(7)}` ||
2703
+ event.timestamp !== release.committedAt ||
2704
+ operations.has(release.operationDigest)
2705
+ ) {
2706
+ throw portsError(
2707
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2708
+ "quarantine release event identity is invalid or ambiguous",
2709
+ );
2710
+ }
2711
+ operations.add(release.operationDigest);
2712
+ yield release;
2713
+ }
2714
+ }
2715
+
2591
2716
  #assertReleaseNotRevoked(snapshot, binding, targetInput) {
2592
- const assertCandidate = (prepared, candidateId) => {
2717
+ const releases = new Map(
2718
+ [
2719
+ ...this.#knowledgeQuarantineReleases(
2720
+ snapshot,
2721
+ binding.tenantId,
2722
+ binding.audience,
2723
+ ),
2724
+ ].map((release) => [release.operationDigest, release]),
2725
+ );
2726
+ const seenOperations = new Set();
2727
+ const releaseFor = (prepared) => {
2728
+ const release = releases.get(prepared.operationDigest) ?? null;
2729
+ if (!release) return null;
2730
+ seenOperations.add(prepared.operationDigest);
2731
+ const quarantines = prepared.knowledge.dependencies.filter(
2732
+ (dependency) => dependency.disposition === "quarantine",
2733
+ );
2593
2734
  if (
2594
- prepared.knowledge.dependencies.some(
2595
- (dependency) =>
2596
- dependency.kind === "candidate" &&
2597
- dependency.digest === candidateId &&
2598
- ["reject-candidate", "quarantine"].includes(dependency.disposition),
2599
- )
2735
+ release.knowledgeId !== prepared.knowledge.knowledgeId ||
2736
+ release.contentDigest !== prepared.knowledge.contentDigest ||
2737
+ release.preparedRecordDigest !== prepared.recordDigest ||
2738
+ canonicalJson(release.dependencies) !== canonicalJson(quarantines)
2600
2739
  ) {
2740
+ throw portsError(
2741
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2742
+ "quarantine release does not bind its prepared revocation",
2743
+ );
2744
+ }
2745
+ return release;
2746
+ };
2747
+ const assertCandidate = (prepared, candidateId) => {
2748
+ const blocked = prepared.knowledge.dependencies.find(
2749
+ (dependency) =>
2750
+ dependency.kind === "candidate" &&
2751
+ dependency.digest === candidateId &&
2752
+ ["reject-candidate", "quarantine"].includes(dependency.disposition),
2753
+ );
2754
+ if (blocked) {
2601
2755
  throw portsError(
2602
2756
  EVOLUTION_LEDGER_CANDIDATE_REVOKED_CODE,
2603
2757
  "candidate activation is blocked by a durable knowledge revocation",
@@ -2643,6 +2797,7 @@ class EvolutionLedgerDomainPorts {
2643
2797
  binding.tenantId,
2644
2798
  binding.audience,
2645
2799
  )) {
2800
+ const release = releaseFor(prepared);
2646
2801
  assertCandidate(prepared, binding.candidateId);
2647
2802
  readTarget();
2648
2803
  assertCandidate(prepared, target.candidateId);
@@ -2652,20 +2807,29 @@ class EvolutionLedgerDomainPorts {
2652
2807
  binding,
2653
2808
  target,
2654
2809
  knowledge,
2810
+ release,
2655
2811
  );
2656
2812
  const sourceRef = `knowledge://${encodeURIComponent(binding.tenantId)}/${encodeURIComponent(knowledge.knowledgeId)}`;
2657
- const revokedRelease = knowledge.dependencies.some(
2813
+ const targetDependencies = knowledge.dependencies.filter(
2658
2814
  (dependency) =>
2659
- dependency.kind === "active-skill" &&
2660
- dependency.digest === target.releaseDigest,
2815
+ (dependency.kind === "active-skill" &&
2816
+ dependency.digest === target.releaseDigest) ||
2817
+ (dependency.kind === "candidate" &&
2818
+ dependency.digest === target.candidateId),
2661
2819
  );
2820
+ // Immutable candidate/release identities named by the quarantine remain
2821
+ // fenced forever. A release restores only the reviewed Wiki source so a
2822
+ // newly evaluated successor can traverse the ordinary promotion gates.
2823
+ const revokedRelease = targetDependencies.length > 0;
2824
+ const supersedingTarget = release !== null && !revokedRelease;
2662
2825
  if (
2663
2826
  revokedRelease ||
2664
2827
  wiki?.unsafePatternIds.length ||
2665
- target.candidate.sourceEvidenceRefs.some(
2666
- (item) =>
2667
- item.ref === sourceRef || item.digest === knowledge.contentDigest,
2668
- )
2828
+ (!supersedingTarget &&
2829
+ target.candidate.sourceEvidenceRefs.some(
2830
+ (item) =>
2831
+ item.ref === sourceRef || item.digest === knowledge.contentDigest,
2832
+ ))
2669
2833
  ) {
2670
2834
  throw portsError(
2671
2835
  EVOLUTION_LEDGER_SOURCE_REVOKED_CODE,
@@ -2678,12 +2842,18 @@ class EvolutionLedgerDomainPorts {
2678
2842
  );
2679
2843
  }
2680
2844
  }
2845
+ if (seenOperations.size !== releases.size) {
2846
+ throw portsError(
2847
+ EVOLUTION_LEDGER_PORTS_CORRUPT_CODE,
2848
+ "quarantine release has no authenticated prepared revocation",
2849
+ );
2850
+ }
2681
2851
  // Bare legacy calls remain compatible only before any Knowledge revocation.
2682
2852
  // Once a fence exists, missing provenance must not mean unrelated/safe.
2683
2853
  if (targetInput !== undefined) readTarget();
2684
2854
  }
2685
2855
 
2686
- #releaseWikiProvenance(snapshot, binding, target, knowledge) {
2856
+ #releaseWikiProvenance(snapshot, binding, target, knowledge, release = null) {
2687
2857
  if (target.candidate.derivationMode === "wiki") {
2688
2858
  // Discover the original run on the same authenticated ledger. Neither a
2689
2859
  // configurable reader nor a self-reported safe subset establishes origin.
@@ -2720,9 +2890,8 @@ class EvolutionLedgerDomainPorts {
2720
2890
  },
2721
2891
  ledgerArtifactResolver: this.#artifactResolve,
2722
2892
  });
2723
- const revision = captureWikiRevisionReader(
2724
- adapter,
2725
- ).readKnowledgeProvenance({
2893
+ const reader = captureWikiRevisionReader(adapter);
2894
+ const revision = reader.readKnowledgeProvenance({
2726
2895
  tenantId: binding.tenantId,
2727
2896
  revisionId: target.candidate.wikiRevision,
2728
2897
  knowledgeId: knowledge.knowledgeId,
@@ -2741,6 +2910,29 @@ class EvolutionLedgerDomainPorts {
2741
2910
  "ledger changed while checking immutable Wiki provenance",
2742
2911
  );
2743
2912
  }
2913
+ const releasedDependency = release?.dependencies.find(
2914
+ (dependency) =>
2915
+ dependency.kind === "wiki" &&
2916
+ dependency.disposition === "quarantine" &&
2917
+ dependency.digest === revision.stateDigest,
2918
+ );
2919
+ if (releasedDependency) {
2920
+ const current = reader.loadWiki();
2921
+ const restored = revision.affectedPatternIds.every(
2922
+ (patternId) =>
2923
+ current.state.patterns[patternId]?.status !== "quarantined" &&
2924
+ current.state.evolutionLog.some(
2925
+ (entry) =>
2926
+ entry.type === "pattern-quarantine-released" &&
2927
+ entry.subjectId === patternId &&
2928
+ entry.details?.operationDigest === release.operationDigest &&
2929
+ entry.details?.releaseRecordDigest === release.recordDigest,
2930
+ ),
2931
+ );
2932
+ if (restored) {
2933
+ return deepFreeze({ ...revision, unsafePatternIds: [] });
2934
+ }
2935
+ }
2744
2936
  return revision;
2745
2937
  }
2746
2938
  return null;
@@ -0,0 +1,392 @@
1
+ import { createHash } from "node:crypto";
2
+ import { types as utilTypes } from "node:util";
3
+ import { captureSkillCandidateRegistryReader } from "./skill-candidate-registry.js";
4
+ import { captureSkillReleaseRegistryReader } from "./skill-release-registry.js";
5
+ import { verifyGovernedKnowledgeRecord } from "./governed-knowledge-record.js";
6
+ import { governedKnowledgeSourceRef } from "./governed-knowledge-skill-rollback.js";
7
+ import { captureWikiRevisionReader } from "./wiki-maintainer-ledger-adapter.js";
8
+
9
+ export const GOVERNED_KNOWLEDGE_DEPENDENCY_INVENTORY_SCHEMA =
10
+ "chainlesschain.governed-knowledge-dependency-inventory/v1";
11
+ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
12
+ const ID = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,255}$/u;
13
+ const PLANNERS = new WeakMap();
14
+ const PLANS = new WeakMap();
15
+
16
+ function canonical(value) {
17
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
18
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
19
+ return `{${Object.keys(value)
20
+ .sort()
21
+ .map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
22
+ .join(",")}}`;
23
+ }
24
+
25
+ function freeze(value) {
26
+ if (value && typeof value === "object" && !Object.isFrozen(value)) {
27
+ Object.freeze(value);
28
+ for (const child of Object.values(value)) freeze(child);
29
+ }
30
+ return value;
31
+ }
32
+
33
+ function fail(message) {
34
+ throw new Error(`knowledge dependency inventory: ${message}`);
35
+ }
36
+
37
+ function dataRecord(value, label) {
38
+ if (
39
+ !value ||
40
+ typeof value !== "object" ||
41
+ Array.isArray(value) ||
42
+ utilTypes.isProxy(value) ||
43
+ ![Object.prototype, null].includes(Object.getPrototypeOf(value))
44
+ ) {
45
+ throw new TypeError(`${label} must be a plain data object`);
46
+ }
47
+ for (const key of Reflect.ownKeys(value)) {
48
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
49
+ if (typeof key !== "string" || !Object.hasOwn(descriptor, "value")) {
50
+ throw new TypeError(`${label} must contain only data properties`);
51
+ }
52
+ }
53
+ return value;
54
+ }
55
+
56
+ function sameHead(left, right) {
57
+ return [
58
+ "epoch",
59
+ "ledgerId",
60
+ "identityDigest",
61
+ "sequence",
62
+ "headDigest",
63
+ ].every((key) => left?.[key] === right?.[key]);
64
+ }
65
+
66
+ function orderWikiRuns(affectedRuns, inventories, revisionOwners) {
67
+ const edges = new Map([...affectedRuns].map((run) => [run, new Set()]));
68
+ for (const [run, inventory] of inventories) {
69
+ if (!affectedRuns.has(run)) continue;
70
+ for (const revision of inventory.revisions) {
71
+ for (const sourceRevisionId of revision.wikiSourceRevisionIds) {
72
+ const parent = revisionOwners.get(sourceRevisionId);
73
+ if (parent && parent !== run && affectedRuns.has(parent)) {
74
+ edges.get(run).add(parent);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ const indegree = new Map([...affectedRuns].map((run) => [run, 0]));
80
+ for (const parents of edges.values()) {
81
+ for (const parent of parents)
82
+ indegree.set(parent, indegree.get(parent) + 1);
83
+ }
84
+ const ready = [...affectedRuns]
85
+ .filter((run) => indegree.get(run) === 0)
86
+ .sort();
87
+ const ordered = [];
88
+ while (ready.length > 0) {
89
+ const run = ready.shift();
90
+ ordered.push(run);
91
+ for (const parent of [...edges.get(run)].sort()) {
92
+ indegree.set(parent, indegree.get(parent) - 1);
93
+ if (indegree.get(parent) === 0) {
94
+ ready.push(parent);
95
+ ready.sort();
96
+ }
97
+ }
98
+ }
99
+ if (ordered.length !== affectedRuns.size)
100
+ fail("Wiki source graph contains a cycle");
101
+ return ordered;
102
+ }
103
+
104
+ export function buildGovernedKnowledgeDependencyInventory({
105
+ tenantId,
106
+ knowledgeId,
107
+ contentDigest,
108
+ candidateRegistry,
109
+ releaseRegistry,
110
+ wikiAdapters,
111
+ activeDisposition = "rollback-active",
112
+ candidateDisposition = "reject-candidate",
113
+ wikiDisposition = "tombstone",
114
+ } = {}) {
115
+ if (
116
+ typeof tenantId !== "string" ||
117
+ !ID.test(tenantId) ||
118
+ typeof knowledgeId !== "string" ||
119
+ !ID.test(knowledgeId) ||
120
+ !DIGEST.test(contentDigest ?? "") ||
121
+ !Array.isArray(wikiAdapters) ||
122
+ wikiAdapters.length < 1 ||
123
+ wikiAdapters.length > 64 ||
124
+ !["rollback-active", "quarantine"].includes(activeDisposition) ||
125
+ !["reject-candidate", "quarantine"].includes(candidateDisposition) ||
126
+ !["tombstone", "quarantine"].includes(wikiDisposition)
127
+ ) {
128
+ throw new TypeError(
129
+ "bounded knowledge dependency inventory input is required",
130
+ );
131
+ }
132
+ const candidates = captureSkillCandidateRegistryReader(candidateRegistry);
133
+ const releases = captureSkillReleaseRegistryReader(releaseRegistry);
134
+ if (candidates.tenantId !== tenantId || releases.tenantId !== tenantId) {
135
+ throw new TypeError("knowledge dependency inventory tenant differs");
136
+ }
137
+ const readers = wikiAdapters.map(captureWikiRevisionReader);
138
+ if (readers.some((reader) => reader.descriptor.tenantId !== tenantId)) {
139
+ throw new TypeError("knowledge dependency Wiki tenant differs");
140
+ }
141
+ const inventories = new Map();
142
+ let ledgerHead = null;
143
+ let discoveredRuns = null;
144
+ const revisionOwners = new Map();
145
+ for (const reader of readers) {
146
+ const run = reader.descriptor.evolutionRunId;
147
+ if (inventories.has(run)) fail("duplicate Wiki run reader");
148
+ const inventory = reader.readInventory();
149
+ if (ledgerHead && !sameHead(ledgerHead, inventory.ledgerHead)) {
150
+ fail("Wiki inventories do not share one stable ledger head");
151
+ }
152
+ if (
153
+ discoveredRuns &&
154
+ canonical(discoveredRuns) !== canonical(inventory.tenantWikiRunIds)
155
+ ) {
156
+ fail("Wiki inventories disagree about tenant run completeness");
157
+ }
158
+ ledgerHead = inventory.ledgerHead;
159
+ discoveredRuns = inventory.tenantWikiRunIds;
160
+ inventories.set(run, { inventory, reader });
161
+ for (const revision of inventory.revisions) {
162
+ if (revisionOwners.has(revision.revisionId))
163
+ fail("duplicate Wiki revision identity");
164
+ revisionOwners.set(revision.revisionId, run);
165
+ }
166
+ }
167
+ const suppliedRuns = [...inventories.keys()].sort();
168
+ if (canonical(suppliedRuns) !== canonical(discoveredRuns)) {
169
+ fail("Wiki run manifest is incomplete for this tenant ledger");
170
+ }
171
+ const sourceRef = governedKnowledgeSourceRef({ tenantId, knowledgeId });
172
+ const proofs = new Map();
173
+ const wikiProof = (candidate) => {
174
+ if (candidate.derivationMode !== "wiki") return null;
175
+ const run = revisionOwners.get(candidate.wikiRevision);
176
+ if (!run) fail("Wiki-derived artifact references an unconfigured revision");
177
+ if (!proofs.has(candidate.wikiRevision)) {
178
+ proofs.set(
179
+ candidate.wikiRevision,
180
+ inventories.get(run).reader.readKnowledgeProvenance({
181
+ tenantId,
182
+ revisionId: candidate.wikiRevision,
183
+ knowledgeId,
184
+ contentDigest,
185
+ }),
186
+ );
187
+ }
188
+ return proofs.get(candidate.wikiRevision);
189
+ };
190
+ const depends = (candidate) => {
191
+ const proof = wikiProof(candidate);
192
+ return (
193
+ candidate.sourceEvidenceRefs.some(
194
+ (entry) => entry.ref === sourceRef && entry.digest === contentDigest,
195
+ ) || (proof?.affectedPatternIds.length ?? 0) > 0
196
+ );
197
+ };
198
+ const unsafe = (candidate) => {
199
+ const proof = wikiProof(candidate);
200
+ return (
201
+ candidate.sourceEvidenceRefs.some(
202
+ (entry) => entry.ref === sourceRef || entry.digest === contentDigest,
203
+ ) || (proof?.unsafePatternIds.length ?? 0) > 0
204
+ );
205
+ };
206
+ const candidateItems = candidates.readInventory();
207
+ const releaseItems = releases.readInventory();
208
+ const releasesByDigest = new Map(
209
+ releaseItems.releases.map((release) => [release.releaseDigest, release]),
210
+ );
211
+ const affectedActive = releaseItems.active.filter(({ release }) =>
212
+ depends(release.candidate),
213
+ );
214
+ for (const { state, release } of affectedActive) {
215
+ const lastKnownGood = releasesByDigest.get(
216
+ state.lastKnownGoodReleaseDigest,
217
+ );
218
+ if (
219
+ !lastKnownGood ||
220
+ lastKnownGood.releaseDigest === release.releaseDigest ||
221
+ lastKnownGood.skillName !== release.skillName ||
222
+ unsafe(lastKnownGood.candidate)
223
+ ) {
224
+ fail(
225
+ "affected active Skill has no safe distinct last-known-good release",
226
+ );
227
+ }
228
+ }
229
+ const activeDependencies = affectedActive.map(({ release }) => ({
230
+ kind: "active-skill",
231
+ digest: release.releaseDigest,
232
+ disposition: activeDisposition,
233
+ }));
234
+ const candidateDependencies = candidateItems
235
+ .filter(depends)
236
+ .map((candidate) => ({
237
+ kind: "candidate",
238
+ digest: candidate.candidateId,
239
+ disposition: candidateDisposition,
240
+ }));
241
+ const wikiTargets = new Map();
242
+ for (const [run, { inventory, reader }] of inventories) {
243
+ for (const revision of inventory.revisions) {
244
+ const proof = reader.readKnowledgeProvenance({
245
+ tenantId,
246
+ revisionId: revision.revisionId,
247
+ knowledgeId,
248
+ contentDigest,
249
+ });
250
+ if (proof.affectedPatternIds.length > 0) {
251
+ wikiTargets.set(run, revision.stateDigest);
252
+ break;
253
+ }
254
+ }
255
+ }
256
+ const wikiDependencies = orderWikiRuns(
257
+ new Set(wikiTargets.keys()),
258
+ new Map([...inventories].map(([run, value]) => [run, value.inventory])),
259
+ revisionOwners,
260
+ ).map((run) => ({
261
+ kind: "wiki",
262
+ digest: wikiTargets.get(run),
263
+ disposition: wikiDisposition,
264
+ }));
265
+ const dependencies = [
266
+ ...activeDependencies.sort((a, b) => a.digest.localeCompare(b.digest)),
267
+ ...candidateDependencies.sort((a, b) => a.digest.localeCompare(b.digest)),
268
+ ...wikiDependencies,
269
+ ];
270
+ if (dependencies.length < 1 || dependencies.length > 256) {
271
+ fail("dependency result is empty or exceeds the governed record bound");
272
+ }
273
+ const finalCandidates = candidates.readInventory();
274
+ const finalReleases = releases.readInventory();
275
+ if (
276
+ canonical(candidateItems.map(({ candidateId }) => candidateId)) !==
277
+ canonical(finalCandidates.map(({ candidateId }) => candidateId)) ||
278
+ canonical(
279
+ releaseItems.releases.map(({ releaseDigest }) => releaseDigest),
280
+ ) !==
281
+ canonical(
282
+ finalReleases.releases.map(({ releaseDigest }) => releaseDigest),
283
+ ) ||
284
+ canonical(releaseItems.active.map(({ state }) => state.stateDigest)) !==
285
+ canonical(finalReleases.active.map(({ state }) => state.stateDigest))
286
+ ) {
287
+ fail("Candidate or Release inventory changed while planning");
288
+ }
289
+ for (const [run, { inventory, reader }] of inventories) {
290
+ const finalInventory = reader.readInventory();
291
+ if (canonical(inventory) !== canonical(finalInventory)) {
292
+ fail(`Wiki inventory changed while planning run ${run}`);
293
+ }
294
+ }
295
+ const core = {
296
+ schema: GOVERNED_KNOWLEDGE_DEPENDENCY_INVENTORY_SCHEMA,
297
+ tenantId,
298
+ knowledgeId,
299
+ contentDigest,
300
+ activeDisposition,
301
+ candidateDisposition,
302
+ wikiDisposition,
303
+ ledgerHead,
304
+ wikiRuns: suppliedRuns,
305
+ dependencies,
306
+ };
307
+ return freeze({
308
+ ...core,
309
+ inventoryDigest: `sha256:${createHash("sha256").update(canonical(core)).digest("hex")}`,
310
+ });
311
+ }
312
+
313
+ export class GovernedKnowledgeDependencyInventoryPlanner {
314
+ constructor(options = {}) {
315
+ const tenantId = options.tenantId;
316
+ if (typeof tenantId !== "string" || !ID.test(tenantId)) {
317
+ throw new TypeError("dependency inventory planner tenantId is invalid");
318
+ }
319
+ // Capture and validate genuine sources now; the builder rechecks them on
320
+ // every plan so a substituted object can never inherit this authority.
321
+ const candidates = captureSkillCandidateRegistryReader(
322
+ options.candidateRegistry,
323
+ );
324
+ const releases = captureSkillReleaseRegistryReader(options.releaseRegistry);
325
+ const wikiAdapters = Array.isArray(options.wikiAdapters)
326
+ ? [...options.wikiAdapters]
327
+ : null;
328
+ if (
329
+ candidates.tenantId !== tenantId ||
330
+ releases.tenantId !== tenantId ||
331
+ !wikiAdapters ||
332
+ wikiAdapters.length < 1 ||
333
+ wikiAdapters.length > 64
334
+ ) {
335
+ throw new TypeError("dependency inventory planner sources are invalid");
336
+ }
337
+ wikiAdapters.forEach(captureWikiRevisionReader);
338
+ PLANNERS.set(
339
+ this,
340
+ Object.freeze({
341
+ tenantId,
342
+ candidateRegistry: options.candidateRegistry,
343
+ releaseRegistry: options.releaseRegistry,
344
+ wikiAdapters: Object.freeze(wikiAdapters),
345
+ activeDisposition: options.activeDisposition,
346
+ candidateDisposition: options.candidateDisposition,
347
+ wikiDisposition: options.wikiDisposition,
348
+ }),
349
+ );
350
+ Object.freeze(this);
351
+ }
352
+
353
+ plan(input) {
354
+ const options = PLANNERS.get(this);
355
+ if (!options)
356
+ throw new TypeError("a genuine dependency planner is required");
357
+ dataRecord(input, "knowledge revocation draft");
358
+ if (
359
+ !["tombstone", "revoke"].includes(input.action) ||
360
+ Object.hasOwn(input, "dependencies")
361
+ ) {
362
+ throw new TypeError(
363
+ "revocation draft must not supply its own dependency plan",
364
+ );
365
+ }
366
+ const inventory = buildGovernedKnowledgeDependencyInventory({
367
+ ...options,
368
+ knowledgeId: input.knowledgeId,
369
+ contentDigest: input.contentDigest,
370
+ });
371
+ const knowledge = verifyGovernedKnowledgeRecord(
372
+ { ...structuredClone(input), dependencies: inventory.dependencies },
373
+ { tenantId: options.tenantId },
374
+ );
375
+ const result = freeze({ inventory, knowledge });
376
+ PLANS.set(result, this);
377
+ return result;
378
+ }
379
+ }
380
+
381
+ Object.freeze(GovernedKnowledgeDependencyInventoryPlanner.prototype);
382
+
383
+ export function isGovernedKnowledgeDependencyInventoryPlanner(value) {
384
+ return PLANNERS.has(value);
385
+ }
386
+
387
+ export function captureGovernedKnowledgeDependencyInventoryPlan(planner, plan) {
388
+ if (!PLANNERS.has(planner) || PLANS.get(plan) !== planner) {
389
+ throw new TypeError("a genuine dependency inventory plan is required");
390
+ }
391
+ return plan;
392
+ }