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
@@ -8,11 +8,15 @@ import {
8
8
  readRetainedWikiRevision,
9
9
  createKnowledgeWikiSourceTracker,
10
10
  } from "./knowledge-wiki-source-provenance.js";
11
+ import {
12
+ GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE,
13
+ verifyGovernedKnowledgeQuarantineReleaseRecord,
14
+ } from "./governed-knowledge-quarantine-release.js";
11
15
 
12
16
  export { WIKI_SOURCE_ADMISSION_INVALID_CODE } from "./knowledge-wiki-source-provenance.js";
13
17
  export const WIKI_SOURCE_REVOKED_CODE = "CC_EVOLUTION_WIKI_SOURCE_REVOKED";
14
18
  const WIKI_EVENT = "wiki.revision.committed";
15
- const TERMINAL = new Set(["revoked", "tombstoned"]);
19
+ const TERMINAL = new Set(["quarantined", "revoked", "tombstoned"]);
16
20
 
17
21
  function canonical(value) {
18
22
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -24,6 +28,121 @@ function canonical(value) {
24
28
  }
25
29
  const same = (a, b) => canonical(a) === canonical(b);
26
30
 
31
+ function quarantineReleaseFor({
32
+ events,
33
+ prepared,
34
+ descriptor,
35
+ resolveSubject,
36
+ fail,
37
+ }) {
38
+ const eventId = `${GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE}.${prepared.operationDigest.slice(7)}`;
39
+ const matches = events.filter(
40
+ (event) =>
41
+ event.type === GOVERNED_KNOWLEDGE_QUARANTINE_RELEASE_EVENT_TYPE &&
42
+ event.eventId === eventId &&
43
+ event.tenantId === prepared.tenantId,
44
+ );
45
+ if (matches.length > 1) fail("quarantine release is ambiguous");
46
+ if (matches.length === 0) return null;
47
+ const event = matches[0];
48
+ const value = readWikiSourceRecord(
49
+ event,
50
+ "governed-knowledge-quarantine-release",
51
+ descriptor,
52
+ resolveSubject,
53
+ ).value;
54
+ let release;
55
+ try {
56
+ release = verifyGovernedKnowledgeQuarantineReleaseRecord(value, {
57
+ tenantId: prepared.tenantId,
58
+ });
59
+ } catch {
60
+ fail("quarantine release record is invalid");
61
+ }
62
+ const quarantines = prepared.knowledge.dependencies.filter(
63
+ (dependency) => dependency.disposition === "quarantine",
64
+ );
65
+ if (
66
+ event.decision !== "committed" ||
67
+ event.timestamp !== release.committedAt ||
68
+ !Array.isArray(event.sourceRefs) ||
69
+ event.sourceRefs.length !== 0 ||
70
+ release.preparedRecordDigest !== prepared.recordDigest ||
71
+ release.knowledgeId !== prepared.knowledge.knowledgeId ||
72
+ release.contentDigest !== prepared.knowledge.contentDigest ||
73
+ !same(release.dependencies, quarantines)
74
+ ) {
75
+ fail("quarantine release does not bind the prepared revocation");
76
+ }
77
+ return release;
78
+ }
79
+
80
+ function isReleasedWikiRestoration(
81
+ previous,
82
+ candidate,
83
+ patternId,
84
+ release,
85
+ releaseCoversRun,
86
+ baseline,
87
+ ) {
88
+ if (
89
+ !release ||
90
+ !releaseCoversRun ||
91
+ !baseline ||
92
+ previous.patterns[patternId]?.status !== "quarantined" ||
93
+ !candidate.state.patterns[patternId] ||
94
+ TERMINAL.has(candidate.state.patterns[patternId].status) ||
95
+ !release.dependencies.some(
96
+ (dependency) =>
97
+ dependency.kind === "wiki" && dependency.disposition === "quarantine",
98
+ )
99
+ ) {
100
+ return false;
101
+ }
102
+ const expectedPattern = {
103
+ ...baseline.patterns[patternId],
104
+ updatedAt: release.committedAt,
105
+ };
106
+ const actualPattern = candidate.state.patterns[patternId];
107
+ const expectedIndex = [
108
+ {
109
+ patternId: expectedPattern.patternId,
110
+ kind: expectedPattern.kind,
111
+ status: expectedPattern.status,
112
+ summary: expectedPattern.summary,
113
+ confidence: expectedPattern.operationalConfidence,
114
+ actionable: expectedPattern.actionable,
115
+ skillNames: expectedPattern.skillNames,
116
+ },
117
+ ];
118
+ const refs = [
119
+ ...new Set([
120
+ ...expectedPattern.positiveEvidence,
121
+ ...expectedPattern.negativeEvidence,
122
+ ]),
123
+ ].sort();
124
+ if (
125
+ !same(actualPattern, expectedPattern) ||
126
+ !same(
127
+ candidate.state.index.filter((entry) => entry.patternId === patternId),
128
+ expectedIndex,
129
+ ) ||
130
+ !same(
131
+ refs.map((ref) => candidate.state.evidence[ref]),
132
+ refs.map((ref) => baseline.evidence[ref]),
133
+ )
134
+ ) {
135
+ return false;
136
+ }
137
+ return candidate.state.evolutionLog.some(
138
+ (entry) =>
139
+ entry.type === "pattern-quarantine-released" &&
140
+ entry.subjectId === patternId &&
141
+ entry.details?.operationDigest === release.operationDigest &&
142
+ entry.details?.releaseRecordDigest === release.recordDigest,
143
+ );
144
+ }
145
+
27
146
  // Only called with bytes resolved and digest-authenticated by the real Ledger
28
147
  // while its write lock is held. There is no public success flag / writer port.
29
148
  export function assertKnowledgeWikiSourceAdmission({
@@ -83,16 +202,44 @@ export function assertKnowledgeWikiSourceAdmission({
83
202
  `${GOVERNED_KNOWLEDGE_DEPENDENCY_PREPARED_EVENT_TYPE}.${prepared.operationDigest.slice(7)}`
84
203
  )
85
204
  fail("revocation is not an exact durable prepared operation");
205
+ const release = quarantineReleaseFor({
206
+ events,
207
+ prepared,
208
+ descriptor,
209
+ resolveSubject,
210
+ fail,
211
+ });
86
212
  const tracker = createKnowledgeWikiSourceTracker({
87
213
  tenantId: input.tenantId,
88
214
  knowledge: prepared.knowledge,
89
215
  readWiki: wiki,
90
216
  });
91
217
  for (const entry of history) tracker.visit(entry, wiki(entry));
218
+ const releaseWikiDigests = new Set(
219
+ (release?.dependencies ?? [])
220
+ .filter(
221
+ (dependency) =>
222
+ dependency.kind === "wiki" &&
223
+ dependency.disposition === "quarantine",
224
+ )
225
+ .map((dependency) => dependency.digest),
226
+ );
227
+ const releaseCoversRun = history
228
+ .filter((event) => event.correlationId === input.correlationId)
229
+ .some((event) => releaseWikiDigests.has(wiki(event).stateDigest));
92
230
  const { previous, unsafePatternIds } = tracker.visit(input, candidate, {
93
231
  proposed: true,
94
232
  });
95
233
  for (const id of unsafePatternIds) {
234
+ let restorationBaseline = null;
235
+ for (const event of history) {
236
+ if (event.correlationId !== input.correlationId) continue;
237
+ const state = wiki(event).state;
238
+ if (state.patterns[id] && state.patterns[id].status !== "quarantined") {
239
+ restorationBaseline = state;
240
+ }
241
+ if (state.patterns[id]?.status === "quarantined") break;
242
+ }
96
243
  const next = candidate.state.patterns[id];
97
244
  // Permit removal/terminalization and unchanged pending cleanup batches.
98
245
  if (!next || (TERMINAL.has(next.status) && next.actionable === false))
@@ -101,6 +248,18 @@ export function assertKnowledgeWikiSourceAdmission({
101
248
  !previous.patterns[id] ||
102
249
  !same(exposure(previous, id), exposure(candidate.state, id))
103
250
  ) {
251
+ if (
252
+ isReleasedWikiRestoration(
253
+ previous,
254
+ candidate,
255
+ id,
256
+ release,
257
+ releaseCoversRun,
258
+ restorationBaseline,
259
+ )
260
+ ) {
261
+ continue;
262
+ }
104
263
  const error = new Error(
105
264
  "Wiki source admission: revoked Knowledge cannot create, rewrite or reactivate a Wiki pattern",
106
265
  );
@@ -27,6 +27,7 @@ const DIGEST = /^sha256:[a-f0-9]{64}$/u;
27
27
  const PATTERN = /^pat-[a-z0-9][a-z0-9-]{2,127}$/u;
28
28
  const STATUSES = new Set(Object.values(WIKI_PATTERN_STATUS));
29
29
  const TERMINAL = new Set([
30
+ WIKI_PATTERN_STATUS.QUARANTINED,
30
31
  WIKI_PATTERN_STATUS.REVOKED,
31
32
  WIKI_PATTERN_STATUS.TOMBSTONED,
32
33
  ]);
@@ -1596,6 +1596,9 @@ export class SkillCandidateRegistry {
1596
1596
  Object.freeze({
1597
1597
  tenantId,
1598
1598
  read: Object.freeze(SkillCandidateRegistry.prototype.read.bind(this)),
1599
+ readInventory: Object.freeze(
1600
+ SkillCandidateRegistry.prototype.readInventory.bind(this),
1601
+ ),
1599
1602
  }),
1600
1603
  );
1601
1604
  }
@@ -2914,14 +2917,29 @@ export class SkillCandidateRegistry {
2914
2917
  `limit must be an integer from 1 to ${MAX_LIST_LIMIT}`,
2915
2918
  );
2916
2919
  }
2917
- const names = this._assertNoMixedTenantArtifacts()
2920
+ return Object.freeze(this.readInventory().slice(0, limit));
2921
+ }
2922
+
2923
+ readInventory() {
2924
+ const before = this._assertNoMixedTenantArtifacts()
2918
2925
  .filter((name) => CANDIDATE_FILE_PATTERN.test(name))
2919
2926
  .sort();
2920
- const candidates = names.slice(0, limit).map((name) => {
2927
+ const candidates = before.map((name) => {
2921
2928
  const match = CANDIDATE_FILE_PATTERN.exec(name);
2922
2929
  return this.read(`sha256:${match[1]}`);
2923
2930
  });
2924
- this._assertBoundary();
2931
+ const after = this._assertNoMixedTenantArtifacts()
2932
+ .filter((name) => CANDIDATE_FILE_PATTERN.test(name))
2933
+ .sort();
2934
+ if (
2935
+ before.length !== after.length ||
2936
+ before.some((name, index) => name !== after[index])
2937
+ ) {
2938
+ throw registryError(
2939
+ "SKILL_CANDIDATE_STORE_UNSAFE",
2940
+ "candidate tenant inventory changed during authenticated enumeration",
2941
+ );
2942
+ }
2925
2943
  return Object.freeze(candidates);
2926
2944
  }
2927
2945
  }
@@ -87,6 +87,9 @@ const TENANT_KEY_PATTERN = /^[a-f0-9]{64}$/u;
87
87
  const TEMP_PATTERN = /^\.(?:release|state|write)-[A-Za-z0-9._-]+\.tmp$/u;
88
88
  const MAX_FILE_BYTES = 4 * 1024 * 1024;
89
89
  const MAX_TENANT_MARKER_BYTES = 4096;
90
+ export const SKILL_RELEASE_INVENTORY_MAX_ENTRIES = 4_096;
91
+ export const SKILL_RELEASE_INVENTORY_MAX_BYTES = 32 * 1024 * 1024;
92
+ export const SKILL_RELEASE_INVENTORY_MAX_NODES = 1_000_000;
90
93
  const MAX_CANONICAL_DEPTH = 32;
91
94
  const MAX_CANONICAL_NODES = 100_000;
92
95
  const MAX_CANONICAL_ARRAY_ENTRIES = 65_536;
@@ -2783,6 +2786,8 @@ export class SkillReleaseRegistry {
2783
2786
  readActive: SkillReleaseRegistry.prototype.readActive.bind(this),
2784
2787
  readState: SkillReleaseRegistry.prototype.readState.bind(this),
2785
2788
  readRelease: SkillReleaseRegistry.prototype.readRelease.bind(this),
2789
+ readInventory:
2790
+ SkillReleaseRegistry.prototype.readInventory.bind(this),
2786
2791
  matchesTransactionLedger: (value) => value === transactionLedger,
2787
2792
  }),
2788
2793
  );
@@ -3882,6 +3887,144 @@ export class SkillReleaseRegistry {
3882
3887
  });
3883
3888
  }
3884
3889
 
3890
+ #readInventoryNames(area, pattern) {
3891
+ const directory = this.#directories[area]?.path;
3892
+ if (!directory || typeof this.#fs.opendirSync !== "function") {
3893
+ throw failure(
3894
+ "SKILL_RELEASE_STORE_UNSAFE",
3895
+ "release inventory requires bounded directory enumeration",
3896
+ );
3897
+ }
3898
+ const names = [];
3899
+ let handle = null;
3900
+ let enumerationError = null;
3901
+ try {
3902
+ handle = this.#fs.opendirSync(directory);
3903
+ while (true) {
3904
+ const entry = handle.readSync();
3905
+ if (entry === null) break;
3906
+ if (
3907
+ !entry ||
3908
+ typeof entry.name !== "string" ||
3909
+ !pattern.test(entry.name)
3910
+ ) {
3911
+ throw failure(
3912
+ "SKILL_RELEASE_STORE_UNSAFE",
3913
+ `release inventory found an unexpected ${area} entry`,
3914
+ );
3915
+ }
3916
+ if (names.length >= SKILL_RELEASE_INVENTORY_MAX_ENTRIES) {
3917
+ throw failure(
3918
+ "SKILL_RELEASE_STORE_LIMIT",
3919
+ `release inventory ${area} entry limit was exceeded`,
3920
+ );
3921
+ }
3922
+ names.push(entry.name);
3923
+ }
3924
+ } catch (cause) {
3925
+ enumerationError =
3926
+ cause instanceof SkillReleaseRegistryError
3927
+ ? cause
3928
+ : failure(
3929
+ "SKILL_RELEASE_STORE_UNSAFE",
3930
+ `release inventory could not enumerate ${area} safely`,
3931
+ { cause },
3932
+ );
3933
+ }
3934
+ if (handle !== null && typeof handle.closeSync === "function") {
3935
+ try {
3936
+ handle.closeSync();
3937
+ } catch (cause) {
3938
+ enumerationError = failure(
3939
+ "SKILL_RELEASE_STORE_UNSAFE",
3940
+ `release inventory could not close ${area} safely`,
3941
+ { cause, enumerationError },
3942
+ );
3943
+ }
3944
+ }
3945
+ if (enumerationError !== null) throw enumerationError;
3946
+ return names.sort();
3947
+ }
3948
+
3949
+ readInventory() {
3950
+ this.#assertBoundary();
3951
+ const releasePattern = /^[a-f0-9]{64}\.json$/u;
3952
+ const statePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\.json$/u;
3953
+ const beforeReleases = this.#readInventoryNames(
3954
+ "artifacts",
3955
+ releasePattern,
3956
+ );
3957
+ const beforeStates = this.#readInventoryNames("active", statePattern);
3958
+ if (
3959
+ beforeReleases.length + beforeStates.length >
3960
+ SKILL_RELEASE_INVENTORY_MAX_ENTRIES
3961
+ ) {
3962
+ throw failure(
3963
+ "SKILL_RELEASE_STORE_LIMIT",
3964
+ "release inventory aggregate entry limit was exceeded",
3965
+ );
3966
+ }
3967
+ const releases = beforeReleases.map((name) =>
3968
+ this.readRelease(`sha256:${name.slice(0, -".json".length)}`),
3969
+ );
3970
+ const active = beforeStates.map((name) => {
3971
+ const skill = name.slice(0, -".json".length);
3972
+ const value = this.readActive(skill);
3973
+ if (value === null) {
3974
+ throw failure(
3975
+ "SKILL_RELEASE_STATE_CORRUPT",
3976
+ "persisted active state has no committed release",
3977
+ );
3978
+ }
3979
+ return deepFreeze({ skillName: skill, ...value });
3980
+ });
3981
+ let bytes = 0;
3982
+ let nodes = 0;
3983
+ const stack = [...releases, ...active.map(({ state }) => state)];
3984
+ for (const value of stack) {
3985
+ bytes += Buffer.byteLength(canonicalJson(value), "utf8");
3986
+ const pending = [value];
3987
+ while (pending.length > 0) {
3988
+ const node = pending.pop();
3989
+ nodes += 1;
3990
+ if (nodes > SKILL_RELEASE_INVENTORY_MAX_NODES) {
3991
+ throw failure(
3992
+ "SKILL_RELEASE_STORE_LIMIT",
3993
+ "release inventory aggregate node limit was exceeded",
3994
+ );
3995
+ }
3996
+ if (node !== null && typeof node === "object") {
3997
+ pending.push(...(Array.isArray(node) ? node : Object.values(node)));
3998
+ }
3999
+ }
4000
+ }
4001
+ if (bytes > SKILL_RELEASE_INVENTORY_MAX_BYTES) {
4002
+ throw failure(
4003
+ "SKILL_RELEASE_STORE_LIMIT",
4004
+ "release inventory aggregate byte limit was exceeded",
4005
+ );
4006
+ }
4007
+ const afterReleases = this.#readInventoryNames("artifacts", releasePattern);
4008
+ const afterStates = this.#readInventoryNames("active", statePattern);
4009
+ const afterStateDigests = afterStates.map((name) =>
4010
+ this.readState(name.slice(0, -".json".length)).stateDigest,
4011
+ );
4012
+ if (
4013
+ canonicalJson(beforeReleases) !== canonicalJson(afterReleases) ||
4014
+ canonicalJson(beforeStates) !== canonicalJson(afterStates) ||
4015
+ active.some(
4016
+ ({ state }, index) => state.stateDigest !== afterStateDigests[index],
4017
+ )
4018
+ ) {
4019
+ throw failure(
4020
+ "SKILL_RELEASE_STORE_UNSAFE",
4021
+ "release inventory changed during authenticated enumeration",
4022
+ );
4023
+ }
4024
+ this.#assertBoundary();
4025
+ return deepFreeze({ active, releases });
4026
+ }
4027
+
3885
4028
  pinActive(name) {
3886
4029
  const active = this.readActive(name);
3887
4030
  if (!active)
@@ -162,6 +162,7 @@ export class WikiMaintainerLedgerAdapter {
162
162
  descriptor: this.descriptor,
163
163
  matchesLedger: (candidate) => candidate === ledger,
164
164
  loadWiki: () => this.#loadWiki(),
165
+ readInventory: () => this.#readInventory(),
165
166
  readRevision: (input) => this.#readRevision(input),
166
167
  readKnowledgeProvenance: (input) =>
167
168
  this.#readKnowledgeProvenance(input),
@@ -177,6 +178,7 @@ export class WikiMaintainerLedgerAdapter {
177
178
  sourceDigest = null,
178
179
  allowed = [],
179
180
  checkpoint = null,
181
+ inventory = false,
180
182
  revisionId = null,
181
183
  stateRevisionDigest = null,
182
184
  } = {}) {
@@ -231,12 +233,25 @@ export class WikiMaintainerLedgerAdapter {
231
233
  event.tenantId === this.descriptor.tenantId &&
232
234
  event.correlationId === this.descriptor.evolutionRunId,
233
235
  );
236
+ const tenantWikiRunIds = [
237
+ ...new Set(
238
+ events
239
+ .filter(
240
+ (event) =>
241
+ event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
242
+ event.type === WIKI_LEDGER_EVENT_TYPE &&
243
+ event.tenantId === this.descriptor.tenantId,
244
+ )
245
+ .map((event) => requiredString(event.correlationId, "correlationId")),
246
+ ),
247
+ ].sort();
234
248
  let state = createEmptyWikiState(this.descriptor.tenantId);
235
249
  let viewState = state;
236
250
  let latest = null;
237
251
  let selectedRevision = null;
238
252
  let source = sourceDigest === digestWikiState(state) ? state : null;
239
253
  const successors = [];
254
+ const revisions = [];
240
255
  let retainedBytes = 0;
241
256
  let batch = [];
242
257
  for (const [index, event] of matches.entries()) {
@@ -301,6 +316,37 @@ export class WikiMaintainerLedgerAdapter {
301
316
  );
302
317
  }
303
318
  verifyRequestTransition(state, revision);
319
+ if (inventory) {
320
+ const wikiSourceRevisionIds = [
321
+ ...new Set(
322
+ Object.values(revision.state.evidence)
323
+ .flatMap((entry) => [entry.ref, entry.artifactRef])
324
+ .filter(
325
+ (ref) =>
326
+ typeof ref === "string" &&
327
+ ref.startsWith(`wiki-source://${this.descriptor.tenantId}/wiki:`),
328
+ )
329
+ .map((ref) => ref.slice(ref.lastIndexOf("/") + 1)),
330
+ ),
331
+ ].sort();
332
+ revisions.push(
333
+ freeze({
334
+ revision: revision.revision,
335
+ revisionId: revision.revisionId,
336
+ priorStateDigest: revision.priorStateDigest,
337
+ stateDigest: revision.stateDigest,
338
+ artifactRef: event.subjectRef,
339
+ wikiSourceRevisionIds,
340
+ checkpoint: {
341
+ epoch: event.epoch,
342
+ ledgerId: event.ledgerId,
343
+ identityDigest: event.identityDigest,
344
+ sequence: event.sequence,
345
+ headDigest: event.eventDigest,
346
+ },
347
+ }),
348
+ );
349
+ }
304
350
  if (
305
351
  revision.revisionId === revisionId ||
306
352
  revision.stateDigest === stateRevisionDigest
@@ -380,9 +426,24 @@ export class WikiMaintainerLedgerAdapter {
380
426
  source,
381
427
  successors,
382
428
  selectedRevision,
429
+ revisions,
430
+ tenantWikiRunIds,
383
431
  };
384
432
  }
385
433
 
434
+ #readInventory() {
435
+ const { head, revisions, tenantWikiRunIds } = this.#history({
436
+ inventory: true,
437
+ });
438
+ return freeze({
439
+ authenticated: true,
440
+ descriptor: this.descriptor,
441
+ ledgerHead: head,
442
+ revisions,
443
+ tenantWikiRunIds,
444
+ });
445
+ }
446
+
386
447
  #readKnowledgeProvenance({
387
448
  tenantId,
388
449
  revisionId,
@@ -23,7 +23,7 @@ function freeze(value) {
23
23
  // Pure derivation only; this function has no persistence or authorization port.
24
24
  // Callers must authenticate the source and authorize the exact operations, then
25
25
  // commit through the real adapter with the same authenticated head/sequence CAS.
26
- export async function deriveWikiTargetTombstoneRevision({
26
+ export async function deriveWikiTargetDispositionRevision({
27
27
  source,
28
28
  descriptor,
29
29
  operations,
@@ -34,15 +34,18 @@ export async function deriveWikiTargetTombstoneRevision({
34
34
  !Array.isArray(operations) ||
35
35
  operations.length < 1 ||
36
36
  operations.length > 128 ||
37
- operations.some((operation) => operation.type !== "tombstone")
37
+ operations.some(
38
+ (operation) => !["quarantine", "tombstone"].includes(operation.type),
39
+ ) ||
40
+ new Set(operations.map((operation) => operation.type)).size !== 1
38
41
  )
39
42
  throw new TypeError(
40
- "target-only Wiki derivation requires bounded tombstones",
43
+ "target-only Wiki derivation requires one bounded disposition",
41
44
  );
42
45
  const ref = Object.keys(source.state.evidence ?? {}).sort()[0];
43
46
  if (!ref)
44
47
  throw new TypeError(
45
- "Wiki tombstones require retained authenticated evidence metadata",
48
+ "Wiki dispositions require retained authenticated evidence metadata",
46
49
  );
47
50
  const core = source.state.evidence[ref];
48
51
  const evidence = { ...core, envelopeDigest: digestWikiState(core) };
@@ -76,9 +79,7 @@ export async function deriveWikiTargetTombstoneRevision({
76
79
  },
77
80
  });
78
81
  if (!revision)
79
- throw new Error(
80
- "Wiki tombstone derivation unexpectedly reused an existing request",
81
- );
82
+ throw new Error("Wiki disposition unexpectedly reused an existing request");
82
83
  // General maintenance also recalculates unrelated patterns. A targeted
83
84
  // revocation has no authority to change their lifecycle, confidence or facts.
84
85
  const scoped = structuredClone(source.state);
@@ -99,3 +100,10 @@ export async function deriveWikiTargetTombstoneRevision({
99
100
  stateDigest: digestWikiState(scoped),
100
101
  });
101
102
  }
103
+
104
+ export async function deriveWikiTargetTombstoneRevision(input) {
105
+ if (input?.operations?.some((operation) => operation.type !== "tombstone")) {
106
+ throw new TypeError("target-only Wiki derivation requires tombstones");
107
+ }
108
+ return deriveWikiTargetDispositionRevision(input);
109
+ }