chainlesschain 0.166.92 → 0.166.93

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 (174) hide show
  1. package/package.json +3 -3
  2. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  3. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-C74YzqwJ.js → AIOps-oo9rE0gh.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-TFef1hOE.js → ActionButton-CVJVVv4i.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-CYsWpkkU.js → Analytics-CUXuwmia.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CFf9kjwu.js → AppLayout-iM4PvCuY.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-TQqa94YO.js → Artifacts-DKUIJbf9.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-B79ayqfS.js → Audit-C4_SzFN2.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-pjkHfLP9.js → BackgroundAgents-C3427uy-.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-CE6A-t_r.js → Backup-BpEQQiog.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-CwcgWMBY.js → BaseInput-C_exQomZ.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-BIkDNesY.js → Chat-DzpkLtWa.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DgaokYts.js → ChatBubbleRenderer-DX4XmTWm.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-MbypIy5V.js → Checkbox-CxAC1CU8.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-DiFHWDnt.js → Codegen-wDFAGCLp.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-BNMlYMso.js → Col-BvwirhMf.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-B3HVyHOX.js → Community-BJuA7paY.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-C7hlAubb.js → Compact-DzV35_u2.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-PaXZu6sE.js → Compliance-CIDPPvr9.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BGiojbm-.js → Cowork-DyTMxP3N.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-Bmr-1QAx.js → Cron-PcNLjMFx.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-BwUvWCVd.js → Crosschain-B_O7ck6Z.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-k_4QZocW.js → DID-CII35Me1.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-_ieRo2C5.js → Dashboard-DU56fkNz.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-DYHh6T27.js → Dropdown-DHC8HVeJ.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-BNlQcWQX.js → EmailListRenderer-oUOHFNsD.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-DIkZ6U2D.js → EvolutionSettings-D7RCAWNl.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dq7qSr0P.js → FamilyGuardDashboard-CGONPZxC.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C64e3Cbx.js → Federation-BbDlPWcl.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-D-GE2vUa.js → FormItemContext-BBJbFQQT.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-DO3B2gis.js → GenericCardRenderer-iuxAero4.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-0ETirIQH.js → Git-Dw0prdY5.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-C9fnRygX.js → Governance-DOGqi_uV.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-CLJ9RTsK.js → Inference-BY5oUGGj.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-D3C_GxrN.js → KnowledgeGraph-CcE2EVYX.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-C5ctGbkN.js → Logs-DyfN4R5w.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-Bj62Aq0M.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-GF_t6hJ_.js → Marketplace-CuuuAXUh.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-BGsGzgQs.js → McpTools-948Fithv.js} +2 -2
  41. package/src/assets/web-panel/assets/{Memory-CcrY2A0j.js → Memory-D4PINvyy.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-Bi4T0RlS.js → MobileBridge-ECKMaLzX.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-DvjEGyvf.js → MobileProjects-CB5MAcvD.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-DL77Vf-k.js → Mtc-BRzIM3HJ.js} +4 -4
  45. package/src/assets/web-panel/assets/{MtcAudit-CDy_Uswb.js → MtcAudit-CGeAXJGn.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-DL0BAO_c.js → Multisig-C_qJ-8K-.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B-woh5IR.js → NLProgramming-DAEyCn7T.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-CEFVCxk7.js → Notes-DmD3MEec.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-BqPPMuAP.js → NotificationSettings-Cv4Q3VC9.js} +1 -1
  50. package/src/assets/web-panel/assets/OrderTableRenderer-BNlpaFjH.js +1 -0
  51. package/src/assets/web-panel/assets/{Organization-B1gX8jlr.js → Organization-DqAFdz6p.js} +2 -2
  52. package/src/assets/web-panel/assets/{Overflow-CeMxuUZy.js → Overflow-8Ye9cIcE.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-B5aIRWwJ.js → P2P-755SfHoJ.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-6rYgejd4.js → PdhVaultBrowser-CgZLiucX.js} +4 -4
  55. package/src/assets/web-panel/assets/{Permissions-CqCp2SIl.js → Permissions-C-vFF_rL.js} +3 -3
  56. package/src/assets/web-panel/assets/{PersonalDataHub-BsA7DJWW.js → PersonalDataHub-Diz1oXM3.js} +5 -5
  57. package/src/assets/web-panel/assets/{Pipeline-CiW6HeZh.js → Pipeline-D4kIzsZG.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-DckUOLYq.js → Privacy-QKLkSAUH.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-CZppOOYR.js → ProjectInit-I0S9o_RT.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-B9QPzhDU.js → ProjectSettings-DdgV3-Ho.js} +2 -2
  61. package/src/assets/web-panel/assets/{Projects-BErjjGha.js → Projects-BJHHegtj.js} +1 -1
  62. package/src/assets/web-panel/assets/{Providers-DehU6Qiz.js → Providers-uVa1zfbS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-E1SUvv1m.js → QrScannerModal-YLVpOChR.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-COWFxyH3.js → QuickAsk-535AYH61.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-D26pWKxX.js → Recommend-C_P6eNSw.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DCOIaId3.js → RemoteSession-EXH1SbNj.js} +2 -2
  67. package/src/assets/web-panel/assets/{Reputation-DT_AHGAR.js → Reputation-Cxc7d3eU.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-B50S-1nl.js → Row-EDqJy-wS.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BaBnHg3Q.js → RssFeed-C03Xeg9_.js} +2 -2
  70. package/src/assets/web-panel/assets/{Search-BVdnLuuS.js → Search-DsIga9DK.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-BnacH74J.js → Security-DgArMFc-.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-CxM08Zch.js → Services-MooDpHBP.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DE7CIc1N.js → Skeleton-B10P1Dr6.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-CGI0SJmf.js → Skills-DHLHEkLl.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-DpEzPcqc.js → Sla-D4RT7d4g.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-CTmnmMHn.js → SpeechSettings-D8u6F-LV.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-Dxgrd9hd.js → SyncSettings-4nvNzRq8.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-CW4slS0A.js → Tasks-CmCb8zNO.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-DxvGWDgB.js → Templates-CzESIa21.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-_Q0o2tNK.js → Tenant-Ch_N3p4d.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BTZn8pow.js → Terminal-BZccUf_X.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-CauL0KFe.js → TimelineRenderer-FrKcNy_3.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CDoM2qeT.js → Tokens-4xvLpXfD.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-B-QYGEU7.js → Trigger-84UjyxXd.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-BD6XJHT-.js → Trust-M6UtHnji.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-x4TFwCy0.js → UkeySign-L_xEgtCg.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-t3imBK_0.js → VideoEditing-BLJCX9ru.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BCfkWwNC.js → Wallet-DwL6uJCj.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-WH314Mdm.js → WebAuthn-Bmn9pdzz.js} +5 -5
  90. package/src/assets/web-panel/assets/{WorkflowEditor-jUlcjrUg.js → WorkflowEditor-DSsZ5xG1.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-Dg3VASTL.js → chat--FGNUaa8.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-BNvmBRKE.js → colors-DeuwNdqX.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-BGOfoqf4.js → compact-item-I4XKxRFU.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BNQeqKAs.js → createContext-RoD2p5Ba.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-ctnml4IW.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-Bg3AjCrq.js → hasIn-BsvyddUM.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-D6UqK83L.js → index-0tRU1Sv-.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-uH2LnAs_.js → index-4xHc2WjT.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-xzaUx19r.js → index-B8-eGLN9.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DYn5DnDk.js → index-BS_uqSTa.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DO0VlNtc.js → index-BYEVBlCl.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DF_FKSVH.js → index-BcBM065G.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CY8cRKHR.js → index-BnrL4s-3.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-COol3xfA.js → index-BrZPb0On.js} +1 -1
  105. package/src/assets/web-panel/assets/index-C7PN8mh1.js +1 -0
  106. package/src/assets/web-panel/assets/{index-BBCMulQ-.js → index-CBazK4-7.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-OUFoxUgH.js → index-CPS3zv1c.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-60AnjUTX.js → index-CSrZiiAs.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D072oLjp.js → index-CVwZMt9Z.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D_O2ZjPk.js → index-CdgKZYgm.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DcCnO0RU.js → index-CesTu01s.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-7QJUWemf.js → index-CiHlSuMl.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DS04wRll.js → index-CsLVac9n.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Dkp-okWa.js → index-D1ONyBTW.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BmTacaQV.js → index-D4IZsKbF.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BaPvEvB4.js → index-D4P4vpmv.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Co_LnCWD.js → index-D6J8dz7X.js} +1 -1
  118. package/src/assets/web-panel/assets/{index--I3UF5t1.js → index-DChy2sHE.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-B0mgngoB.js → index-DKUCl_Lk.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Cx2EXRfr.js → index-DRluW3_r.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B_JmInC0.js → index-DWUmhNO-.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DLwEXRrb.js → index-DXnpVGG3.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-fOwii3LP.js → index-DYOpAS6-.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ZD5Kd8tx.js → index-DiH-3cR2.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D-mSvCQK.js → index-DlEfwgzr.js} +1 -1
  126. package/src/assets/web-panel/assets/index-KnbBJAO-.js +1 -0
  127. package/src/assets/web-panel/assets/{index-B--0QM0S.js → index-R4St_zjR.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CCFZN66A.js → index-ScgoDU9V.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BSNhW95G.js → index-UWdT_lty.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Cbp-wp-U.js → index-VAlor744.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bkz1tgFR.js → index-Wco_uvRo.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-pVdQieac.js → index-ZgFED_Zd.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-2D04Zltx.js → index-jaHeti4i.js} +3 -3
  134. package/src/assets/web-panel/assets/{index-hG7jXGEW.js → index-rJDabtw4.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-Wo0f2iqb.js → index-vRiGKIP0.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-B8PN9AxJ.js → initDefaultProps-BHT0PacY.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BHivfw5Q.js → motion-CBYsMtsC.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-B0QU5nDd.js → move-DnHfFV4K.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-DRwRM3PE.js → mtc-parser-DfGkRYrx.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-SHt2rV2p.js → omit-SjLcPQA9.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-CcmDlEb2.js → pickAttrs-CCZHF4ep.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-DYatmXDS.js → placementArrow-DjCGn2sJ.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-B7qrsXq5.js → responsiveObserve-BCFCl2on.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-BRGhlOWd.js → slide-DsfmuIZu.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-CT-7NXsQ.js → statusUtils-hPKuJUia.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-rZdw_Yyp.js → styleChecker-DOXKH7Kf.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-D8YNIP4P.js → useFlexGapSupport-B_G7yqio.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-B8pt0Gu-.js → useFs-BXOTOm2l.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-VMmYM1tt.js → usePersonalDataHub-CRvie3g7.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-UNDuoPoq.js → vnode-D9_zMmww.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-dN-u667S.js → zoom-C4tW03qI.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/data/changelog.json +13 -0
  154. package/src/lib/artifact-store.js +51 -3
  155. package/src/lib/bounded-artifact-file-read.js +131 -0
  156. package/src/lib/evolution/evolution-artifact-ports.js +209 -129
  157. package/src/lib/evolution/rrsi-history-ledger-adapter.js +25 -0
  158. package/src/lib/evolution/rrsi-installation-route-contracts.js +275 -0
  159. package/src/lib/evolution/rrsi-installation-route-reader.js +282 -0
  160. package/src/lib/evolution/rrsi-observed-text-index.js +978 -0
  161. package/src/lib/evolution/rrsi-registry-runtime-policy.js +648 -0
  162. package/src/lib/evolution/rrsi-registry-store-policy.js +95 -15
  163. package/src/lib/evolution/rrsi-tenant-index-anchor-contracts.js +223 -0
  164. package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +157 -0
  165. package/src/lib/evolution/skill-release-registry.js +20 -5
  166. package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +291 -30
  167. package/src/lib/remote-read-loop-guard.js +227 -24
  168. package/src/lib/task-progress-tracker.js +6 -1
  169. package/src/runtime/agent-core.js +71 -23
  170. package/src/assets/web-panel/assets/MarkdownRenderer-Ce-eWK3j.js +0 -1
  171. package/src/assets/web-panel/assets/OrderTableRenderer-GUKQ1xwp.js +0 -1
  172. package/src/assets/web-panel/assets/devWarning-B7_ypN1G.js +0 -1
  173. package/src/assets/web-panel/assets/index-B-jSKJK6.js +0 -1
  174. package/src/assets/web-panel/assets/index-P4FXZJqI.js +0 -1
@@ -0,0 +1,275 @@
1
+ /** Local route declarations only: no installer authorization or durable pin. */
2
+ import { createHash, createPublicKey } from "node:crypto";
3
+ import {
4
+ rrsiCanonical,
5
+ rrsiDigest,
6
+ rrsiEnvelope,
7
+ rrsiExact,
8
+ rrsiFail,
9
+ rrsiId,
10
+ snapshotRrsiData,
11
+ verifyRrsiEnvelope,
12
+ } from "./rrsi-data.js";
13
+ import { verifyRrsiTenantIndexAnchorSignature } from "./rrsi-tenant-index-anchor-contracts.js";
14
+
15
+ export const RRSI_INSTALLATION_ROUTE_HOLD_CODE =
16
+ "CC_RRSI_INSTALLATION_ROUTE_HOLD";
17
+ export const RRSI_INSTALLATION_ROUTE_ROOT_SCHEMA =
18
+ "chainlesschain.rrsi-installation-route-root/v1";
19
+ export const RRSI_INSTALLATION_ROUTES_SCHEMA =
20
+ "chainlesschain.rrsi-installation-routes/v1";
21
+ export const RRSI_INSTALLATION_ROUTE_HIGHWATER_SCHEMA =
22
+ "chainlesschain.rrsi-installation-route-highwater/v1";
23
+ export const RRSI_INSTALLATION_ROUTE_MAX_ANCHORS = 64;
24
+ const ROOT_KEYS = [
25
+ "installationId",
26
+ "tenantId",
27
+ "routingScope",
28
+ "rootPublicKeySpki",
29
+ "rootPublicKeyDigest",
30
+ ];
31
+ const FIXED_ANCHOR_KEYS = [
32
+ "deploymentId",
33
+ "tenantId",
34
+ "routingScope",
35
+ "indexId",
36
+ "ledgerIdentity",
37
+ "artifactScope",
38
+ "storageGraphDigest",
39
+ "rootPublicKeyDigest",
40
+ ];
41
+ const HIGHWATER_KEYS = [
42
+ "installationId",
43
+ "tenantId",
44
+ "rootRecordDigest",
45
+ "routesDigest",
46
+ "anchorRevision",
47
+ "anchorDigest",
48
+ "checkpoint",
49
+ "restrictionHistory",
50
+ ];
51
+ const FALSE_AUTHORITY = Object.freeze({
52
+ selectedContextOnly: true,
53
+ rootAuthorityVerified: false,
54
+ installationBindingSignatureVerified: false,
55
+ routingPinVerified: false,
56
+ historyTransferVerified: false,
57
+ journalPrefixVerified: false,
58
+ restrictionHistoryVerified: false,
59
+ crossProcessRollbackProtectionVerified: false,
60
+ tenantWideIndexAuthorityVerified: false,
61
+ generationProvenanceVerified: false,
62
+ grantsMutationOrPromotionAuthority: false,
63
+ decision: "HOLD",
64
+ });
65
+ const same = (a, b) => rrsiCanonical(a) === rrsiCanonical(b);
66
+ function hold(message) {
67
+ rrsiFail(message, RRSI_INSTALLATION_ROUTE_HOLD_CODE);
68
+ }
69
+
70
+ export function buildRrsiInstallationRouteRoot(input) {
71
+ const value = snapshotRrsiData(input);
72
+ rrsiExact(value, ROOT_KEYS, "installation route root input");
73
+ rrsiId(value.installationId, "installation ID");
74
+ rrsiId(value.tenantId, "installation tenant ID");
75
+ if (value.routingScope !== "installation")
76
+ hold("root scope must be installation");
77
+ rrsiDigest(value.rootPublicKeyDigest, "declared root key digest");
78
+ if (
79
+ typeof value.rootPublicKeySpki !== "string" ||
80
+ value.rootPublicKeySpki.length !== 59
81
+ )
82
+ hold("root key must be canonical Ed25519 SPKI");
83
+ const bytes = Buffer.from(value.rootPublicKeySpki, "base64url");
84
+ if (
85
+ bytes.length !== 44 ||
86
+ bytes.toString("base64url") !== value.rootPublicKeySpki
87
+ )
88
+ hold("root key encoding differs");
89
+ let key;
90
+ try {
91
+ key = createPublicKey({ key: bytes, format: "der", type: "spki" });
92
+ } catch {
93
+ hold("root key cannot be parsed");
94
+ }
95
+ if (
96
+ key.asymmetricKeyType !== "ed25519" ||
97
+ !key.export({ format: "der", type: "spki" }).equals(bytes)
98
+ )
99
+ hold("root key must be exact Ed25519 SPKI");
100
+ if (
101
+ `sha256:${createHash("sha256").update(bytes).digest("hex")}` !==
102
+ value.rootPublicKeyDigest
103
+ )
104
+ hold("root key digest differs");
105
+ return rrsiEnvelope(
106
+ RRSI_INSTALLATION_ROUTE_ROOT_SCHEMA,
107
+ "rootRecordDigest",
108
+ value,
109
+ );
110
+ }
111
+
112
+ export function verifyRrsiInstallationRouteRoot(input) {
113
+ return verifyRrsiEnvelope(
114
+ input,
115
+ RRSI_INSTALLATION_ROUTE_ROOT_SCHEMA,
116
+ "rootRecordDigest",
117
+ ROOT_KEYS,
118
+ buildRrsiInstallationRouteRoot,
119
+ );
120
+ }
121
+
122
+ function signedPacket(value) {
123
+ // The existing verifier enforces exact fields and signatures, not root trust.
124
+ verifyRrsiTenantIndexAnchorSignature(value);
125
+ return value.anchor;
126
+ }
127
+
128
+ export function checkRrsiInstallationAnchorContinuation(input) {
129
+ const value = snapshotRrsiData(input);
130
+ rrsiExact(value, ["previous", "next"], "route continuation input");
131
+ const previous = signedPacket(value.previous),
132
+ next = signedPacket(value.next);
133
+ if (
134
+ previous.routingScope !== "installation" ||
135
+ next.routingScope !== "installation"
136
+ )
137
+ hold("continuation scope must be installation");
138
+ if (value.previous.publicKeySpki !== value.next.publicKeySpki)
139
+ hold("continuation cannot change root key");
140
+ for (const name of FIXED_ANCHOR_KEYS)
141
+ if (!same(previous[name], next[name]))
142
+ hold(`continuation cannot change ${name}`);
143
+ let continuation;
144
+ if (next.revision === previous.revision) {
145
+ if (next.anchorDigest !== previous.anchorDigest)
146
+ hold("same revision has a different anchor");
147
+ continuation = "same-anchor";
148
+ } else {
149
+ if (next.revision !== previous.revision + 1)
150
+ hold("continuation revision must increase exactly once");
151
+ if (next.previousAnchorDigest !== previous.anchorDigest)
152
+ hold("continuation predecessor differs");
153
+ if (!same(next.checkpoint, previous.checkpoint))
154
+ hold("checkpoint advancement requires independent journal prefix proof");
155
+ if (!same(next.restrictionHistory, previous.restrictionHistory))
156
+ hold("restriction change requires independent retained history proof");
157
+ continuation = "declared-successor";
158
+ }
159
+ return rrsiEnvelope(
160
+ "chainlesschain.rrsi-installation-route-continuation-check/v1",
161
+ "continuationCheckDigest",
162
+ {
163
+ previousAnchorDigest: previous.anchorDigest,
164
+ nextAnchorDigest: next.anchorDigest,
165
+ continuation,
166
+ declaredContinuationConsistent: true,
167
+ ...FALSE_AUTHORITY,
168
+ },
169
+ );
170
+ }
171
+
172
+ export function buildRrsiInstallationRoutes(input) {
173
+ const value = snapshotRrsiData(input);
174
+ rrsiExact(value, ["root", "packets"], "installation routes input");
175
+ const root = verifyRrsiInstallationRouteRoot(value.root);
176
+ if (
177
+ !Array.isArray(value.packets) ||
178
+ value.packets.length < 1 ||
179
+ value.packets.length > RRSI_INSTALLATION_ROUTE_MAX_ANCHORS
180
+ )
181
+ hold("routes require one to 64 signed anchors");
182
+ for (let index = 0; index < value.packets.length; index++) {
183
+ const packet = value.packets[index],
184
+ anchor = signedPacket(packet);
185
+ if (
186
+ packet.publicKeySpki !== root.rootPublicKeySpki ||
187
+ anchor.rootPublicKeyDigest !== root.rootPublicKeyDigest
188
+ )
189
+ hold("route signer differs from declared root");
190
+ if (
191
+ anchor.tenantId !== root.tenantId ||
192
+ anchor.routingScope !== root.routingScope
193
+ )
194
+ hold("route tenant or scope differs from root");
195
+ if (index === 0) {
196
+ if (anchor.revision !== 1) hold("routes must retain the first anchor");
197
+ } else {
198
+ const checked = checkRrsiInstallationAnchorContinuation({
199
+ previous: value.packets[index - 1],
200
+ next: packet,
201
+ });
202
+ if (checked.continuation !== "declared-successor")
203
+ hold("routes cannot append a duplicate anchor");
204
+ }
205
+ }
206
+ return rrsiEnvelope(RRSI_INSTALLATION_ROUTES_SCHEMA, "routesDigest", {
207
+ rootRecordDigest: root.rootRecordDigest,
208
+ packets: value.packets,
209
+ });
210
+ }
211
+
212
+ export function verifyRrsiInstallationRoutes(input) {
213
+ const value = snapshotRrsiData(input);
214
+ rrsiExact(value, ["root", "routes"], "installation routes verification");
215
+ const root = verifyRrsiInstallationRouteRoot(value.root);
216
+ return verifyRrsiEnvelope(
217
+ value.routes,
218
+ RRSI_INSTALLATION_ROUTES_SCHEMA,
219
+ "routesDigest",
220
+ ["rootRecordDigest", "packets"],
221
+ (core) => buildRrsiInstallationRoutes({ root, packets: core.packets }),
222
+ );
223
+ }
224
+
225
+ export function buildRrsiInstallationRouteHighwater(input) {
226
+ const value = snapshotRrsiData(input);
227
+ rrsiExact(value, ["root", "routes"], "route highwater input");
228
+ const root = verifyRrsiInstallationRouteRoot(value.root);
229
+ const routes = verifyRrsiInstallationRoutes({ root, routes: value.routes });
230
+ const tail = routes.packets.at(-1).anchor;
231
+ return rrsiEnvelope(
232
+ RRSI_INSTALLATION_ROUTE_HIGHWATER_SCHEMA,
233
+ "highwaterDigest",
234
+ {
235
+ installationId: root.installationId,
236
+ tenantId: root.tenantId,
237
+ rootRecordDigest: root.rootRecordDigest,
238
+ routesDigest: routes.routesDigest,
239
+ anchorRevision: tail.revision,
240
+ anchorDigest: tail.anchorDigest,
241
+ checkpoint: tail.checkpoint,
242
+ restrictionHistory: tail.restrictionHistory,
243
+ },
244
+ );
245
+ }
246
+
247
+ export function verifyRrsiInstallationRouteSnapshot(input) {
248
+ const value = snapshotRrsiData(input);
249
+ rrsiExact(value, ["root", "routes", "highwater"], "route snapshot input");
250
+ const root = verifyRrsiInstallationRouteRoot(value.root);
251
+ const routes = verifyRrsiInstallationRoutes({ root, routes: value.routes });
252
+ const highwater = verifyRrsiEnvelope(
253
+ value.highwater,
254
+ RRSI_INSTALLATION_ROUTE_HIGHWATER_SCHEMA,
255
+ "highwaterDigest",
256
+ HIGHWATER_KEYS,
257
+ () => buildRrsiInstallationRouteHighwater({ root, routes }),
258
+ );
259
+ return rrsiEnvelope(
260
+ "chainlesschain.rrsi-installation-route-snapshot-check/v1",
261
+ "snapshotCheckDigest",
262
+ {
263
+ installationId: root.installationId,
264
+ tenantId: root.tenantId,
265
+ rootRecordDigest: root.rootRecordDigest,
266
+ routesDigest: routes.routesDigest,
267
+ highwaterDigest: highwater.highwaterDigest,
268
+ anchorDigest: highwater.anchorDigest,
269
+ anchorRevision: highwater.anchorRevision,
270
+ declaredRouteConsistent: true,
271
+ signaturesVerifiedRelativeToDeclaredKey: true,
272
+ ...FALSE_AUTHORITY,
273
+ },
274
+ );
275
+ }
@@ -0,0 +1,282 @@
1
+ /** Open-only, immutable readback of caller-selected declarations, never authority. */
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ import {
6
+ rrsiCanonical,
7
+ rrsiDigest,
8
+ rrsiEnvelope,
9
+ rrsiExact,
10
+ rrsiHash,
11
+ rrsiId,
12
+ snapshotRrsiData,
13
+ } from "./rrsi-data.js";
14
+ import {
15
+ RRSI_INSTALLATION_ROUTE_HOLD_CODE,
16
+ verifyRrsiInstallationRouteSnapshot,
17
+ } from "./rrsi-installation-route-contracts.js";
18
+ import { withEvolutionDirectoryFileIdentity } from "./evolution-file-identity.js";
19
+ import { readBoundedDescriptor } from "./bounded-descriptor-read.js";
20
+
21
+ export const RRSI_INSTALLATION_ROUTE_FILE_LIMITS = Object.freeze({
22
+ "root.json": 16 * 1024,
23
+ "routes.json": 256 * 1024,
24
+ "highwater.json": 16 * 1024,
25
+ });
26
+ const NAMES = Object.keys(RRSI_INSTALLATION_ROUTE_FILE_LIMITS).sort();
27
+ const FILE_FIELDS = [
28
+ "dev",
29
+ "ino",
30
+ "mode",
31
+ "uid",
32
+ "gid",
33
+ "nlink",
34
+ "size",
35
+ "mtimeNs",
36
+ "ctimeNs",
37
+ ];
38
+ const DIR_FIELDS = ["dev", "ino", "mode", "uid", "gid"];
39
+ const same = (left, right) => rrsiCanonical(left) === rrsiCanonical(right);
40
+ const canonicalPath = (value) =>
41
+ process.platform === "win32" ? value.toLowerCase() : value;
42
+ const sha = (bytes) =>
43
+ `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
44
+ // The shared identity helper opens directories only. Keep this adaptation local
45
+ // so a lstat/open FIFO race cannot block before its existing fstat checks.
46
+ const DIRECTORY_FS = Object.freeze({
47
+ constants: fs.constants,
48
+ realpathSync: fs.realpathSync,
49
+ lstatSync: (...args) => fs.lstatSync(...args),
50
+ fstatSync: (...args) => fs.fstatSync(...args),
51
+ closeSync: (...args) => fs.closeSync(...args),
52
+ openSync: (target, flags) =>
53
+ fs.openSync(
54
+ target,
55
+ flags | (fs.constants.O_NONBLOCK || 0) | (fs.constants.O_DIRECTORY || 0),
56
+ ),
57
+ });
58
+ function hold(message) {
59
+ const error = new Error(message);
60
+ error.code = RRSI_INSTALLATION_ROUTE_HOLD_CODE;
61
+ throw error;
62
+ }
63
+ function guard(operation) {
64
+ try {
65
+ return operation();
66
+ } catch (cause) {
67
+ if (cause?.code === RRSI_INSTALLATION_ROUTE_HOLD_CODE) throw cause;
68
+ const error = new Error("installation route snapshot read held", { cause });
69
+ error.code = RRSI_INSTALLATION_ROUTE_HOLD_CODE;
70
+ throw error;
71
+ }
72
+ }
73
+ function fields(stat, names) {
74
+ if (names.some((name) => typeof stat[name] !== "bigint"))
75
+ hold("route snapshot requires full-precision stat fields");
76
+ return Object.fromEntries(names.map((name) => [name, String(stat[name])]));
77
+ }
78
+ function ancestry(directory) {
79
+ const chain = [];
80
+ let target = directory;
81
+ for (;;) {
82
+ if (chain.length >= 64) hold("route directory ancestry exceeds limit");
83
+ const stat = fs.lstatSync(target, { bigint: true });
84
+ if (
85
+ !stat.isDirectory() ||
86
+ stat.isSymbolicLink() ||
87
+ canonicalPath(fs.realpathSync.native(target)) !== canonicalPath(target)
88
+ )
89
+ hold("route directory ancestry is not canonical and nonlinked");
90
+ chain.push({ path: target, identity: fields(stat, DIR_FIELDS) });
91
+ const parent = path.dirname(target);
92
+ if (parent === target) break;
93
+ target = parent;
94
+ }
95
+ return chain;
96
+ }
97
+ function inventory(directory) {
98
+ const handle = fs.opendirSync(directory);
99
+ const names = [];
100
+ try {
101
+ let entry;
102
+ while ((entry = handle.readSync()) !== null) {
103
+ names.push(entry.name);
104
+ if (names.length > 3)
105
+ hold("route snapshot has unknown directory entries");
106
+ }
107
+ } finally {
108
+ handle.closeSync();
109
+ }
110
+ if (!same(names.sort(), NAMES))
111
+ hold("route snapshot requires exactly root, routes and highwater files");
112
+ }
113
+ function file(directory, name, samePathHandle) {
114
+ const target = path.join(directory, name);
115
+ const maximum = RRSI_INSTALLATION_ROUTE_FILE_LIMITS[name];
116
+ const before = fs.lstatSync(target, { bigint: true });
117
+ const safe = (stat) => {
118
+ fields(stat, FILE_FIELDS);
119
+ return (
120
+ stat.isFile() &&
121
+ !stat.isSymbolicLink() &&
122
+ stat.nlink === 1n &&
123
+ stat.size > 0n &&
124
+ stat.size <= BigInt(maximum)
125
+ );
126
+ };
127
+ if (
128
+ !safe(before) ||
129
+ canonicalPath(fs.realpathSync.native(target)) !== canonicalPath(target)
130
+ )
131
+ hold(`route ${name} is not a bounded single-link regular file`);
132
+ const fd = fs.openSync(
133
+ target,
134
+ fs.constants.O_RDONLY |
135
+ (fs.constants.O_NOFOLLOW || 0) |
136
+ (fs.constants.O_NONBLOCK || 0),
137
+ );
138
+ try {
139
+ const opened = fs.fstatSync(fd, { bigint: true });
140
+ if (!safe(opened) || !samePathHandle(before, opened))
141
+ hold(`route ${name} changed while opening`);
142
+ const bytes = readBoundedDescriptor(fs, fd, Number(before.size), maximum);
143
+ const after = fs.lstatSync(target, { bigint: true });
144
+ const closed = fs.fstatSync(fd, { bigint: true });
145
+ if (
146
+ !safe(after) ||
147
+ !safe(closed) ||
148
+ !samePathHandle(after, closed) ||
149
+ !same(fields(before, FILE_FIELDS), fields(after, FILE_FIELDS)) ||
150
+ !same(fields(opened, FILE_FIELDS), fields(closed, FILE_FIELDS))
151
+ )
152
+ hold(`route ${name} changed while reading`);
153
+ return {
154
+ name,
155
+ identity: fields(after, FILE_FIELDS),
156
+ bytesDigest: sha(bytes),
157
+ bytes,
158
+ };
159
+ } finally {
160
+ fs.closeSync(fd);
161
+ }
162
+ }
163
+ function parse(bytes) {
164
+ const text = new TextDecoder("utf-8", {
165
+ fatal: true,
166
+ ignoreBOM: true,
167
+ }).decode(bytes);
168
+ const value = snapshotRrsiData(JSON.parse(text));
169
+ if (text !== rrsiCanonical(value) && text !== `${rrsiCanonical(value)}\n`)
170
+ hold(
171
+ "route file must be exact canonical JSON with at most one final newline",
172
+ );
173
+ return value;
174
+ }
175
+ const project = (files) =>
176
+ files.map(({ name, identity, bytesDigest }) => ({
177
+ name,
178
+ identity,
179
+ bytesDigest,
180
+ }));
181
+
182
+ /**
183
+ * Context comes from the caller, so matching it does not authenticate an installer.
184
+ * No writer, bootstrap, environment override, permission repair or recovery API.
185
+ */
186
+ export function openRrsiInstallationRouteSnapshot(input) {
187
+ return guard(() => {
188
+ const selected = snapshotRrsiData(input);
189
+ rrsiExact(
190
+ selected,
191
+ ["directory", "installationId", "tenantId", "rootRecordDigest"],
192
+ "route snapshot selection",
193
+ );
194
+ if (
195
+ typeof selected.directory !== "string" ||
196
+ selected.directory.length > 1024 ||
197
+ !path.isAbsolute(selected.directory) ||
198
+ path.resolve(selected.directory) !== selected.directory
199
+ )
200
+ hold("route snapshot directory must be an absolute normalized path");
201
+ rrsiId(selected.installationId, "selected installation ID");
202
+ rrsiId(selected.tenantId, "selected tenant ID");
203
+ rrsiDigest(selected.rootRecordDigest, "selected root record digest");
204
+ function capture(expected = null) {
205
+ const directories = ancestry(selected.directory);
206
+ inventory(selected.directory);
207
+ if (expected && !same(directories, expected.directories))
208
+ hold("captured route directory identity changed");
209
+ return withEvolutionDirectoryFileIdentity(
210
+ DIRECTORY_FS,
211
+ selected.directory,
212
+ (samePathHandle) => {
213
+ const files = NAMES.map((name) =>
214
+ file(selected.directory, name, samePathHandle),
215
+ );
216
+ const physical = { directories, files: project(files) };
217
+ if (expected && !same(physical, expected))
218
+ hold("captured route file identity or bytes changed");
219
+ const records = Object.fromEntries(
220
+ files.map((entry) => [entry.name, parse(entry.bytes)]),
221
+ );
222
+ const root = records["root.json"];
223
+ const checked = verifyRrsiInstallationRouteSnapshot({
224
+ root,
225
+ routes: records["routes.json"],
226
+ highwater: records["highwater.json"],
227
+ });
228
+ if (
229
+ checked.installationId !== selected.installationId ||
230
+ checked.tenantId !== selected.tenantId ||
231
+ checked.rootRecordDigest !== selected.rootRecordDigest
232
+ )
233
+ hold("route root differs from explicitly selected context");
234
+ const rechecked = NAMES.map((name) =>
235
+ file(selected.directory, name, samePathHandle),
236
+ );
237
+ inventory(selected.directory);
238
+ if (
239
+ !same(ancestry(selected.directory), directories) ||
240
+ !same(project(rechecked), physical.files)
241
+ )
242
+ hold("route snapshot changed during final readback");
243
+ const result = rrsiEnvelope(
244
+ "chainlesschain.rrsi-installation-route-readback/v1",
245
+ "readbackDigest",
246
+ {
247
+ snapshotCheck: checked,
248
+ physicalSnapshotDigest: rrsiHash(
249
+ "chainlesschain.rrsi-installation-route-physical-snapshot/v1",
250
+ physical,
251
+ ),
252
+ readOnlyOpen: true,
253
+ capturedSnapshotRechecked: true,
254
+ ownerOnlyPermissionsVerified: false,
255
+ atomicSnapshotVerified: false,
256
+ installationBindingSignatureVerified: false,
257
+ selectedContextOnly: true,
258
+ rootAuthorityVerified: false,
259
+ routingPinVerified: false,
260
+ crossProcessRollbackProtectionVerified: false,
261
+ tenantWideIndexAuthorityVerified: false,
262
+ generationProvenanceVerified: false,
263
+ grantsMutationOrPromotionAuthority: false,
264
+ decision: "HOLD",
265
+ },
266
+ );
267
+ return { physical, result };
268
+ },
269
+ );
270
+ }
271
+ const initial = capture();
272
+ return Object.freeze({
273
+ read(...args) {
274
+ return guard(() => {
275
+ if (args.length)
276
+ hold("captured route reader takes no replacement context");
277
+ return capture(initial.physical).result;
278
+ });
279
+ },
280
+ });
281
+ });
282
+ }