chainlesschain 0.166.91 → 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.
- package/README.md +17 -17
- package/package.json +3 -3
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DgV7xb8F.js → AIOps-oo9rE0gh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CgANpkKu.js → ActionButton-CVJVVv4i.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DnvpX7RB.js → Analytics-CUXuwmia.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-C2bHccBM.js → AppLayout-iM4PvCuY.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BIhijC9g.js → Artifacts-DKUIJbf9.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CKRjWGdp.js → Audit-C4_SzFN2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CblYtgBE.js → BackgroundAgents-C3427uy-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cq35b78a.js → Backup-BpEQQiog.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DcB7NoRz.js → BaseInput-C_exQomZ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-tc3b-s7i.js → Chat-DzpkLtWa.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DX4XmTWm.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-BLD5bH5u.js → Checkbox-CxAC1CU8.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BLOsoazN.js → Codegen-wDFAGCLp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bdr7JwIx.js → Col-BvwirhMf.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84BsWE0.js → Community-BJuA7paY.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Dzdwd04z.js → Compact-DzV35_u2.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CCG-R0EV.js → Compliance-CIDPPvr9.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BYj72SK0.js → Cowork-DyTMxP3N.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B6iKAwOf.js → Cron-PcNLjMFx.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BJ-oDC6u.js → Crosschain-B_O7ck6Z.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BnMckGLr.js → DID-CII35Me1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cyje-gCO.js → Dashboard-DU56fkNz.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BpNlenjK.js → Dropdown-DHC8HVeJ.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BhonO7Nv.js → EmailListRenderer-oUOHFNsD.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DVoNU-Id.js → EvolutionSettings-D7RCAWNl.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-tdn-KC67.js → FamilyGuardDashboard-CGONPZxC.js} +1 -1
- package/src/assets/web-panel/assets/{Federation--EEVrHhz.js → Federation-BbDlPWcl.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cy8zr0-4.js → FormItemContext-BBJbFQQT.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BuUhpgFi.js → GenericCardRenderer-iuxAero4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Ctd3E5Pe.js → Git-Dw0prdY5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Ce7dV6aU.js → Governance-DOGqi_uV.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CD1vExIH.js → Inference-BY5oUGGj.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Dn64OdQ7.js → KnowledgeGraph-CcE2EVYX.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-PmElVRrT.js → Logs-DyfN4R5w.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BFiVKf5t.js → MarkdownRenderer-Bj62Aq0M.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-OW4jTXwx.js → Marketplace-CuuuAXUh.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BEq2Ib4x.js → McpTools-948Fithv.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Can_P2oK.js → Memory-D4PINvyy.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DJ8R-dn3.js → MobileBridge-ECKMaLzX.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B7kV9GOt.js → MobileProjects-CB5MAcvD.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BfxamolS.js → Mtc-BRzIM3HJ.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-DHtuv7av.js → MtcAudit-CGeAXJGn.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DLkLpvxc.js → Multisig-C_qJ-8K-.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-u4XtJTIt.js → NLProgramming-DAEyCn7T.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BwuuPJLS.js → Notes-DmD3MEec.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-HEeu-E9v.js → NotificationSettings-Cv4Q3VC9.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BNlpaFjH.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Yh-czs3b.js → Organization-DqAFdz6p.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DmE8mYVM.js → Overflow-8Ye9cIcE.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWVck8WN.js → P2P-755SfHoJ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DgFqekod.js → PdhVaultBrowser-CgZLiucX.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-BtJBVOHV.js → Permissions-C-vFF_rL.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-6VBObXzd.js → PersonalDataHub-Diz1oXM3.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-D222FmqY.js → Pipeline-D4kIzsZG.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bi9FMikp.js → Privacy-QKLkSAUH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bo52H47H.js → ProjectInit-I0S9o_RT.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BPkesfOc.js → ProjectSettings-DdgV3-Ho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-GynohSFX.js → Projects-BJHHegtj.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DVdMg04n.js → Providers-uVa1zfbS.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DqJCb595.js → QrScannerModal-YLVpOChR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-J7loQbXi.js → QuickAsk-535AYH61.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BI5aURVc.js → Recommend-C_P6eNSw.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BN2sqGvz.js → RemoteSession-EXH1SbNj.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BGOND-Fi.js → Reputation-Cxc7d3eU.js} +1 -1
- package/src/assets/web-panel/assets/{Row-77dfwaUk.js → Row-EDqJy-wS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-FtBAxS3g.js → RssFeed-C03Xeg9_.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BaYVLFb7.js → Search-DsIga9DK.js} +1 -1
- package/src/assets/web-panel/assets/{Security-LE3Vv6ab.js → Security-DgArMFc-.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5pP-Whz.js → Services-MooDpHBP.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CLqKUVsF.js → Skeleton-B10P1Dr6.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BPjN0SX5.js → Skills-DHLHEkLl.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-14jD70kg.js → Sla-D4RT7d4g.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dr9ij42W.js → SpeechSettings-D8u6F-LV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BzLHP7B8.js → SyncSettings-4nvNzRq8.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-YqV9b0rV.js → Tasks-CmCb8zNO.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CxxAE4PK.js → Templates-CzESIa21.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CRb3PcKJ.js → Tenant-Ch_N3p4d.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CTzPpBaP.js → Terminal-BZccUf_X.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DjFUj_hy.js → TimelineRenderer-FrKcNy_3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bbb8tPvx.js → Tokens-4xvLpXfD.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CSeWGM0W.js → Trigger-84UjyxXd.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-JgESMBo3.js → Trust-M6UtHnji.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CiObLk0T.js → UkeySign-L_xEgtCg.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CFEZaQ2x.js → VideoEditing-BLJCX9ru.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DR8ZGDNn.js → Wallet-DwL6uJCj.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DxZukvu7.js → WebAuthn-Bmn9pdzz.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CKgSZQwn.js → WorkflowEditor-DSsZ5xG1.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTxEQE66.js → chat--FGNUaa8.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CAjKMUu3.js → colors-DeuwNdqX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BXuz49at.js → compact-item-I4XKxRFU.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFN_Hwr9.js → createContext-RoD2p5Ba.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ctnml4IW.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BwoSBSfP.js → hasIn-BsvyddUM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CB3kVd9c.js → index-0tRU1Sv-.js} +1 -1
- package/src/assets/web-panel/assets/{index-o9DpkZKf.js → index-4xHc2WjT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmQITjMU.js → index-B8-eGLN9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY-gBSm8.js → index-BS_uqSTa.js} +1 -1
- package/src/assets/web-panel/assets/{index-F2E5RCwz.js → index-BYEVBlCl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF9lWi1o.js → index-BcBM065G.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu2P6u8m.js → index-BnrL4s-3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv7V2kg6.js → index-BrZPb0On.js} +1 -1
- package/src/assets/web-panel/assets/index-C7PN8mh1.js +1 -0
- package/src/assets/web-panel/assets/{index-DViK2bkv.js → index-CBazK4-7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmXpdcHI.js → index-CPS3zv1c.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqv_Cray.js → index-CSrZiiAs.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7kp-zRE.js → index-CVwZMt9Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0QbLlWn.js → index-CdgKZYgm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjF5BOZx.js → index-CesTu01s.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSmFby3Q.js → index-CiHlSuMl.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2o_BBjg.js → index-CsLVac9n.js} +1 -1
- package/src/assets/web-panel/assets/{index-CehdwJ_Q.js → index-D1ONyBTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj4hIiLW.js → index-D4IZsKbF.js} +1 -1
- package/src/assets/web-panel/assets/{index-_ZtCyUdz.js → index-D4P4vpmv.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9yR7zqr.js → index-D6J8dz7X.js} +1 -1
- package/src/assets/web-panel/assets/{index-u9_DM3ZC.js → index-DChy2sHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8er4W9u.js → index-DKUCl_Lk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK4ftQ4d.js → index-DRluW3_r.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2tEnBPx.js → index-DWUmhNO-.js} +1 -1
- package/src/assets/web-panel/assets/{index-IY9bd5az.js → index-DXnpVGG3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp5y7lX_.js → index-DYOpAS6-.js} +1 -1
- package/src/assets/web-panel/assets/{index-T3MTE6jB.js → index-DiH-3cR2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxunxaTw.js → index-DlEfwgzr.js} +1 -1
- package/src/assets/web-panel/assets/index-KnbBJAO-.js +1 -0
- package/src/assets/web-panel/assets/{index-DTX9CJPx.js → index-R4St_zjR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Tz5dheZa.js → index-ScgoDU9V.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmkbAADP.js → index-UWdT_lty.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw9s2d3c.js → index-VAlor744.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN53dE_u.js → index-Wco_uvRo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpdDnZX_.js → index-ZgFED_Zd.js} +1 -1
- package/src/assets/web-panel/assets/{index-IahILygB.js → index-jaHeti4i.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cgk0YEiq.js → index-rJDabtw4.js} +1 -1
- package/src/assets/web-panel/assets/{index-t2Ch_JKn.js → index-vRiGKIP0.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BoiGJDoO.js → initDefaultProps-BHT0PacY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-5eL4E0pA.js → motion-CBYsMtsC.js} +1 -1
- package/src/assets/web-panel/assets/{move-DjggDi_1.js → move-DnHfFV4K.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Ce8Vo2T3.js → mtc-parser-DfGkRYrx.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D1yOBaO2.js → omit-SjLcPQA9.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-8NLceQe8.js → pickAttrs-CCZHF4ep.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CsIdBRmQ.js → placementArrow-DjCGn2sJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-GM5NE8En.js → responsiveObserve-BCFCl2on.js} +1 -1
- package/src/assets/web-panel/assets/{slide-44yj3u49.js → slide-DsfmuIZu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B8tqtWcX.js → statusUtils-hPKuJUia.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NhDPBbyB.js → styleChecker-DOXKH7Kf.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C8Qz1GtN.js → useFlexGapSupport-B_G7yqio.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-ClUv4kih.js → useFs-BXOTOm2l.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BwkOVEh6.js → usePersonalDataHub-CRvie3g7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode--gMF33R0.js → vnode-D9_zMmww.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DXg3TqOP.js → zoom-C4tW03qI.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +52 -0
- package/src/lib/artifact-store.js +51 -3
- package/src/lib/bounded-artifact-file-read.js +131 -0
- package/src/lib/evolution/evolution-artifact-ports.js +235 -129
- package/src/lib/evolution/evolution-eval-cohort-enrollment.js +713 -47
- package/src/lib/evolution/evolution-eval-gate.js +146 -0
- package/src/lib/evolution/evolution-eval-launch-admission.js +168 -90
- package/src/lib/evolution/evolution-eval-ledger-capture.js +50 -0
- package/src/lib/evolution/evolution-eval-readonly-audit.js +106 -0
- package/src/lib/evolution/evolution-ledger-file-backend.js +20 -0
- package/src/lib/evolution/evolution-ledger-ports.js +59 -27
- package/src/lib/evolution/evolution-ledger-v2-journal.js +55 -18
- package/src/lib/evolution/evolution-workbench-file-resources.js +19 -1
- package/src/lib/evolution/rrsi-cohort-registration.js +275 -0
- package/src/lib/evolution/rrsi-contracts.js +742 -0
- package/src/lib/evolution/rrsi-data.js +196 -0
- package/src/lib/evolution/rrsi-evaluation-adapter.js +275 -0
- package/src/lib/evolution/rrsi-evaluation-variants.js +267 -0
- package/src/lib/evolution/rrsi-group-statistics.js +553 -0
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +3286 -0
- package/src/lib/evolution/rrsi-installation-route-contracts.js +275 -0
- package/src/lib/evolution/rrsi-installation-route-reader.js +282 -0
- package/src/lib/evolution/rrsi-native-batch-evidence.js +520 -0
- package/src/lib/evolution/rrsi-native-eval-row-collector.js +538 -0
- package/src/lib/evolution/rrsi-native-evaluation-batch.js +547 -0
- package/src/lib/evolution/rrsi-native-evaluation-plan.js +431 -0
- package/src/lib/evolution/rrsi-native-group-statistics-plan.js +121 -0
- package/src/lib/evolution/rrsi-native-group-statistics.js +482 -0
- package/src/lib/evolution/rrsi-native-quality-receipt-contracts.js +321 -0
- package/src/lib/evolution/rrsi-native-quality-receipt.js +256 -0
- package/src/lib/evolution/rrsi-native-statistics-protocol.js +330 -0
- package/src/lib/evolution/rrsi-observed-text-index.js +978 -0
- package/src/lib/evolution/rrsi-parent-binding.js +290 -0
- package/src/lib/evolution/rrsi-pm-execution-bridge.js +500 -0
- package/src/lib/evolution/rrsi-pm-training-mapping.js +134 -0
- package/src/lib/evolution/rrsi-preparation-contracts.js +213 -0
- package/src/lib/evolution/rrsi-registry-history-binding.js +193 -0
- package/src/lib/evolution/rrsi-registry-runtime-policy.js +648 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +1271 -0
- package/src/lib/evolution/rrsi-runtime-composition.js +79 -0
- package/src/lib/evolution/rrsi-selector.js +434 -0
- package/src/lib/evolution/rrsi-statistics-simulation.js +354 -0
- package/src/lib/evolution/rrsi-tenant-index-anchor-contracts.js +223 -0
- package/src/lib/evolution/rrsi-tenant-index-anchor-history.js +157 -0
- package/src/lib/evolution/skill-candidate-registry.js +216 -29
- package/src/lib/evolution/skill-registry-maintenance.js +80 -0
- package/src/lib/evolution/skill-registry-writer-control.js +138 -0
- package/src/lib/evolution/skill-release-registry.js +414 -169
- package/src/lib/formal-quality-eval-runtime.js +2 -14
- package/src/lib/goal-store.js +225 -16
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +291 -30
- package/src/lib/record-replay/skill-recorder.js +38 -3
- package/src/lib/remote-read-loop-guard.js +227 -24
- package/src/lib/scheduler-kernel/authority-resolver.js +12 -163
- package/src/lib/scheduler-kernel/contract.js +27 -414
- package/src/lib/scheduler-kernel/runtime.js +21 -823
- package/src/lib/scheduler-kernel/service.js +11 -328
- package/src/lib/scheduler-kernel/source-locator-path.js +7 -142
- package/src/lib/scheduler-kernel/store.js +67 -5931
- package/src/lib/secure-fs.js +16 -1314
- package/src/lib/task-progress-tracker.js +6 -1
- package/src/lib/with-file-lock.js +122 -20
- package/src/runtime/agent-core.js +71 -23
- package/src/assets/web-panel/assets/ChatBubbleRenderer-fcc_Tvqu.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BtvN-Qwh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CfB8DxT2.js +0 -1
- package/src/assets/web-panel/assets/index-CCsRfd0k.js +0 -1
- package/src/assets/web-panel/assets/index-CsmiZIQ4.js +0 -1
|
@@ -6,6 +6,12 @@ import { types as utilTypes } from "node:util";
|
|
|
6
6
|
import { getHomeDir } from "../paths.js";
|
|
7
7
|
import { ensurePrivateDirectory, ensurePrivateFile } from "../secure-fs.js";
|
|
8
8
|
import { withEvolutionFileIdentity } from "./evolution-file-identity.js";
|
|
9
|
+
import { createSkillRegistryWriterControl } from "./skill-registry-writer-control.js";
|
|
10
|
+
import {
|
|
11
|
+
captureRrsiRegistryComponentBinding,
|
|
12
|
+
assertOutsideRrsiRegistryNamespace,
|
|
13
|
+
RRSI_REGISTRY_STORE_POLICY_HOLD_CODE,
|
|
14
|
+
} from "./rrsi-registry-store-policy.js";
|
|
9
15
|
import {
|
|
10
16
|
SKILL_CANDIDATE_MIGRATION_RECEIPT_SCHEMA,
|
|
11
17
|
SKILL_CANDIDATE_MIGRATION_RECORD_SCHEMA,
|
|
@@ -62,6 +68,7 @@ export const SKILL_RELEASE_JOURNAL_ARCHIVE_SCHEMA =
|
|
|
62
68
|
|
|
63
69
|
const JOURNAL_SCHEMA = "chainlesschain.skill-release-journal/v4";
|
|
64
70
|
const REGISTRY_READERS = new WeakMap();
|
|
71
|
+
const REGISTRY_WRITERS = new WeakMap();
|
|
65
72
|
|
|
66
73
|
export function captureSkillReleaseRegistryReader(value) {
|
|
67
74
|
const reader = REGISTRY_READERS.get(value);
|
|
@@ -72,6 +79,16 @@ export function captureSkillReleaseRegistryReader(value) {
|
|
|
72
79
|
throw new TypeError("a genuine SkillReleaseRegistry reader is required");
|
|
73
80
|
return reader;
|
|
74
81
|
}
|
|
82
|
+
|
|
83
|
+
export function captureSkillReleaseRegistryWriterControl(value) {
|
|
84
|
+
captureSkillReleaseRegistryReader(value);
|
|
85
|
+
const control = REGISTRY_WRITERS.get(value);
|
|
86
|
+
if (!control)
|
|
87
|
+
throw new TypeError(
|
|
88
|
+
"a genuine release Registry writer control is required",
|
|
89
|
+
);
|
|
90
|
+
return control;
|
|
91
|
+
}
|
|
75
92
|
const INTENT_SCHEMA = "chainlesschain.skill-release-transition-intent/v2";
|
|
76
93
|
const RELEASE_DOMAIN = `${SKILL_RELEASE_SCHEMA}\0`;
|
|
77
94
|
const STATE_DOMAIN = `${SKILL_RELEASE_STATE_SCHEMA}\0`;
|
|
@@ -1850,128 +1867,151 @@ export function archiveLegacySkillReleaseJournal(input) {
|
|
|
1850
1867
|
) {
|
|
1851
1868
|
throw migrationRequired("legacy journal archive paths are invalid");
|
|
1852
1869
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
);
|
|
1867
|
-
const expectedBytes = serialize(archive);
|
|
1868
|
-
let created = false;
|
|
1869
|
-
if (lstatOrNull(fsImpl, archivePath) === null) {
|
|
1870
|
-
const source = readBoundedSingleLinkFile(
|
|
1871
|
-
fsImpl,
|
|
1872
|
-
sourcePath,
|
|
1873
|
-
MAX_FILE_BYTES,
|
|
1874
|
-
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1875
|
-
"legacy release journal source",
|
|
1870
|
+
// An independent archive helper can also retire bytes under a tenant's
|
|
1871
|
+
// journals directory. It must participate in that physical root's writer
|
|
1872
|
+
// protocol rather than bypassing the class-method maintenance boundary.
|
|
1873
|
+
const writer = createSkillRegistryWriterControl({
|
|
1874
|
+
rootDir: path.dirname(sourceDirectory),
|
|
1875
|
+
tenantId: disposition.tenantId,
|
|
1876
|
+
component: TENANT_MARKER_COMPONENT,
|
|
1877
|
+
fsImpl,
|
|
1878
|
+
});
|
|
1879
|
+
return writer.runSync(() => {
|
|
1880
|
+
const sourcePath = path.join(
|
|
1881
|
+
sourceDirectory,
|
|
1882
|
+
path.basename(requestedSourcePath),
|
|
1876
1883
|
);
|
|
1877
|
-
if (
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1884
|
+
if (input.secure) {
|
|
1885
|
+
ensurePrivateDirectory(archiveDirectory, {
|
|
1886
|
+
applyWindowsAcl: true,
|
|
1887
|
+
failIfUnavailable: true,
|
|
1888
|
+
});
|
|
1881
1889
|
}
|
|
1882
|
-
const
|
|
1890
|
+
const archivePath = path.join(
|
|
1883
1891
|
archiveDirectory,
|
|
1884
|
-
|
|
1892
|
+
`${disposition.planDigest.slice("sha256:".length)}.json`,
|
|
1885
1893
|
);
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
fsImpl.fsyncSync(descriptor);
|
|
1891
|
-
fsImpl.closeSync(descriptor);
|
|
1892
|
-
descriptor = null;
|
|
1893
|
-
if (input.secure) {
|
|
1894
|
-
ensurePrivateFile(temporaryPath, {
|
|
1895
|
-
applyWindowsAcl: true,
|
|
1896
|
-
failIfUnavailable: true,
|
|
1897
|
-
});
|
|
1898
|
-
}
|
|
1899
|
-
const staged = readBoundedSingleLinkFile(
|
|
1894
|
+
const expectedBytes = serialize(archive);
|
|
1895
|
+
let created = false;
|
|
1896
|
+
if (lstatOrNull(fsImpl, archivePath) === null) {
|
|
1897
|
+
const source = readBoundedSingleLinkFile(
|
|
1900
1898
|
fsImpl,
|
|
1901
|
-
|
|
1899
|
+
sourcePath,
|
|
1902
1900
|
MAX_FILE_BYTES,
|
|
1903
1901
|
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1904
|
-
"legacy journal
|
|
1902
|
+
"legacy release journal source",
|
|
1905
1903
|
);
|
|
1906
|
-
if (!
|
|
1907
|
-
throw migrationRequired(
|
|
1904
|
+
if (!source.bytes.equals(serialize(journal))) {
|
|
1905
|
+
throw migrationRequired(
|
|
1906
|
+
"legacy release journal source bytes differ from the verified input",
|
|
1907
|
+
);
|
|
1908
1908
|
}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1909
|
+
const temporaryPath = path.join(
|
|
1910
|
+
archiveDirectory,
|
|
1911
|
+
`.journal-${process.pid}-${crypto.randomBytes(16).toString("hex")}.tmp`,
|
|
1912
|
+
);
|
|
1913
|
+
let descriptor = null;
|
|
1913
1914
|
try {
|
|
1914
|
-
fsImpl.
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1915
|
+
descriptor = fsImpl.openSync(temporaryPath, "wx", 0o600);
|
|
1916
|
+
fsImpl.writeFileSync(descriptor, expectedBytes);
|
|
1917
|
+
fsImpl.fsyncSync(descriptor);
|
|
1918
|
+
fsImpl.closeSync(descriptor);
|
|
1919
|
+
descriptor = null;
|
|
1920
|
+
if (input.secure) {
|
|
1921
|
+
ensurePrivateFile(temporaryPath, {
|
|
1922
|
+
applyWindowsAcl: true,
|
|
1923
|
+
failIfUnavailable: true,
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
const staged = readBoundedSingleLinkFile(
|
|
1927
|
+
fsImpl,
|
|
1928
|
+
temporaryPath,
|
|
1929
|
+
MAX_FILE_BYTES,
|
|
1930
|
+
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1931
|
+
"legacy journal archive temporary",
|
|
1932
|
+
);
|
|
1933
|
+
if (!staged.bytes.equals(expectedBytes)) {
|
|
1934
|
+
throw migrationRequired(
|
|
1935
|
+
"legacy journal archive write was incomplete",
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
checkpoint("after-archive-fsync", {
|
|
1939
|
+
archiveDigest: archive.archiveDigest,
|
|
1940
|
+
dispositionPlanDigest: disposition.planDigest,
|
|
1941
|
+
});
|
|
1942
|
+
try {
|
|
1943
|
+
writer.assertIfWriting();
|
|
1944
|
+
fsImpl.linkSync(temporaryPath, archivePath);
|
|
1945
|
+
created = true;
|
|
1946
|
+
} catch (error) {
|
|
1947
|
+
if (error?.code !== "EEXIST") throw error;
|
|
1948
|
+
}
|
|
1928
1949
|
fsImpl.unlinkSync(temporaryPath);
|
|
1950
|
+
fsyncDirectory(fsImpl, archiveDirectory);
|
|
1951
|
+
checkpoint("after-archive-publish", {
|
|
1952
|
+
archiveDigest: archive.archiveDigest,
|
|
1953
|
+
dispositionPlanDigest: disposition.planDigest,
|
|
1954
|
+
});
|
|
1955
|
+
} finally {
|
|
1956
|
+
if (descriptor !== null) fsImpl.closeSync(descriptor);
|
|
1957
|
+
let cleanupOwned = false;
|
|
1958
|
+
try {
|
|
1959
|
+
writer.assertIfWriting();
|
|
1960
|
+
cleanupOwned = true;
|
|
1961
|
+
} catch {
|
|
1962
|
+
/* Preserve private debris after lost ownership. */
|
|
1963
|
+
}
|
|
1964
|
+
if (cleanupOwned && lstatOrNull(fsImpl, temporaryPath) !== null)
|
|
1965
|
+
fsImpl.unlinkSync(temporaryPath);
|
|
1966
|
+
}
|
|
1929
1967
|
}
|
|
1930
|
-
|
|
1931
|
-
const persisted = readBoundedSingleLinkFile(
|
|
1932
|
-
fsImpl,
|
|
1933
|
-
archivePath,
|
|
1934
|
-
MAX_FILE_BYTES,
|
|
1935
|
-
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1936
|
-
"legacy journal archive",
|
|
1937
|
-
);
|
|
1938
|
-
if (
|
|
1939
|
-
!persisted.bytes.equals(expectedBytes) ||
|
|
1940
|
-
canonicalJson(
|
|
1941
|
-
verifySkillReleaseJournalArchive(
|
|
1942
|
-
JSON.parse(
|
|
1943
|
-
new TextDecoder("utf-8", { fatal: true }).decode(persisted.bytes),
|
|
1944
|
-
),
|
|
1945
|
-
),
|
|
1946
|
-
) !== canonicalJson(archive)
|
|
1947
|
-
) {
|
|
1948
|
-
throw migrationRequired("legacy journal archive readback differs");
|
|
1949
|
-
}
|
|
1950
|
-
checkpoint("after-archive-readback", {
|
|
1951
|
-
archiveDigest: archive.archiveDigest,
|
|
1952
|
-
dispositionPlanDigest: disposition.planDigest,
|
|
1953
|
-
});
|
|
1954
|
-
if (lstatOrNull(fsImpl, sourcePath) !== null) {
|
|
1955
|
-
const source = readBoundedSingleLinkFile(
|
|
1968
|
+
const persisted = readBoundedSingleLinkFile(
|
|
1956
1969
|
fsImpl,
|
|
1957
|
-
|
|
1970
|
+
archivePath,
|
|
1958
1971
|
MAX_FILE_BYTES,
|
|
1959
1972
|
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1960
|
-
"legacy
|
|
1973
|
+
"legacy journal archive",
|
|
1961
1974
|
);
|
|
1962
|
-
if (
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1975
|
+
if (
|
|
1976
|
+
!persisted.bytes.equals(expectedBytes) ||
|
|
1977
|
+
canonicalJson(
|
|
1978
|
+
verifySkillReleaseJournalArchive(
|
|
1979
|
+
JSON.parse(
|
|
1980
|
+
new TextDecoder("utf-8", { fatal: true }).decode(persisted.bytes),
|
|
1981
|
+
),
|
|
1982
|
+
),
|
|
1983
|
+
) !== canonicalJson(archive)
|
|
1984
|
+
) {
|
|
1985
|
+
throw migrationRequired("legacy journal archive readback differs");
|
|
1966
1986
|
}
|
|
1967
|
-
|
|
1968
|
-
fsyncDirectory(fsImpl, sourceDirectory);
|
|
1969
|
-
checkpoint("after-source-retire", {
|
|
1987
|
+
checkpoint("after-archive-readback", {
|
|
1970
1988
|
archiveDigest: archive.archiveDigest,
|
|
1971
1989
|
dispositionPlanDigest: disposition.planDigest,
|
|
1972
1990
|
});
|
|
1973
|
-
|
|
1974
|
-
|
|
1991
|
+
if (lstatOrNull(fsImpl, sourcePath) !== null) {
|
|
1992
|
+
const source = readBoundedSingleLinkFile(
|
|
1993
|
+
fsImpl,
|
|
1994
|
+
sourcePath,
|
|
1995
|
+
MAX_FILE_BYTES,
|
|
1996
|
+
SKILL_RELEASE_MIGRATION_REQUIRED_CODE,
|
|
1997
|
+
"legacy release journal source",
|
|
1998
|
+
);
|
|
1999
|
+
if (!source.bytes.equals(serialize(journal))) {
|
|
2000
|
+
throw migrationRequired(
|
|
2001
|
+
"legacy release journal changed before retirement",
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
writer.assertIfWriting();
|
|
2005
|
+
fsImpl.unlinkSync(sourcePath);
|
|
2006
|
+
fsyncDirectory(fsImpl, sourceDirectory);
|
|
2007
|
+
checkpoint("after-source-retire", {
|
|
2008
|
+
archiveDigest: archive.archiveDigest,
|
|
2009
|
+
dispositionPlanDigest: disposition.planDigest,
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
writer.assertIfWriting();
|
|
2013
|
+
return deepFreeze({ archive, archivePath, created, sourceRetired: true });
|
|
2014
|
+
});
|
|
1975
2015
|
}
|
|
1976
2016
|
|
|
1977
2017
|
/**
|
|
@@ -2472,6 +2512,7 @@ const REGISTRY_OPTION_KEYS = new Set([
|
|
|
2472
2512
|
"randomToken",
|
|
2473
2513
|
"rootDir",
|
|
2474
2514
|
"secure",
|
|
2515
|
+
"storePolicyBinding",
|
|
2475
2516
|
"tenantId",
|
|
2476
2517
|
"transactionLedger",
|
|
2477
2518
|
]);
|
|
@@ -2659,6 +2700,7 @@ function normalizeRegistryOptions(options) {
|
|
|
2659
2700
|
data.rootDir ??
|
|
2660
2701
|
path.join(getHomeDir(), "evolution", "registry", "releases"),
|
|
2661
2702
|
secure: data.secure ?? true,
|
|
2703
|
+
storePolicyBinding: data.storePolicyBinding,
|
|
2662
2704
|
tenantId: tenantId(data.tenantId),
|
|
2663
2705
|
transactionLedger: data.transactionLedger,
|
|
2664
2706
|
};
|
|
@@ -2696,6 +2738,9 @@ export class SkillReleaseRegistry {
|
|
|
2696
2738
|
#ledgerQuery;
|
|
2697
2739
|
|
|
2698
2740
|
#pins = new WeakMap();
|
|
2741
|
+
#writerControl;
|
|
2742
|
+
#storeBinding;
|
|
2743
|
+
#runtimeMode = "initialized";
|
|
2699
2744
|
|
|
2700
2745
|
constructor(options) {
|
|
2701
2746
|
const {
|
|
@@ -2706,9 +2751,34 @@ export class SkillReleaseRegistry {
|
|
|
2706
2751
|
randomToken,
|
|
2707
2752
|
rootDir,
|
|
2708
2753
|
secure,
|
|
2754
|
+
storePolicyBinding,
|
|
2709
2755
|
tenantId: ownerTenantId,
|
|
2710
2756
|
transactionLedger,
|
|
2711
2757
|
} = normalizeRegistryOptions(options);
|
|
2758
|
+
const requestedBase = path.resolve(rootDir);
|
|
2759
|
+
if (storePolicyBinding !== undefined) {
|
|
2760
|
+
this.#storeBinding =
|
|
2761
|
+
captureRrsiRegistryComponentBinding(storePolicyBinding);
|
|
2762
|
+
const descriptor = this.#storeBinding.descriptor;
|
|
2763
|
+
if (
|
|
2764
|
+
new.target !== SkillReleaseRegistry ||
|
|
2765
|
+
fsImpl !== fs ||
|
|
2766
|
+
secure !== true ||
|
|
2767
|
+
descriptor.component !== TENANT_MARKER_COMPONENT ||
|
|
2768
|
+
descriptor.tenantId !== ownerTenantId ||
|
|
2769
|
+
!samePath(descriptor.baseDir, requestedBase)
|
|
2770
|
+
)
|
|
2771
|
+
throw failure(
|
|
2772
|
+
RRSI_REGISTRY_STORE_POLICY_HOLD_CODE,
|
|
2773
|
+
"release v2 binding or native storage options differ",
|
|
2774
|
+
);
|
|
2775
|
+
// Authenticate the original port object before reading any caller method.
|
|
2776
|
+
this.#storeBinding.assertTransactionLedger(transactionLedger);
|
|
2777
|
+
this.#storeBinding.recheckForOpen();
|
|
2778
|
+
this.#runtimeMode = this.#storeBinding.runtimeDirectories
|
|
2779
|
+
? "authenticated-empty-read-only"
|
|
2780
|
+
: "uninitialized";
|
|
2781
|
+
} else assertOutsideRrsiRegistryNamespace(requestedBase);
|
|
2712
2782
|
if (
|
|
2713
2783
|
!transactionLedger ||
|
|
2714
2784
|
typeof transactionLedger.prepare !== "function" ||
|
|
@@ -2742,57 +2812,104 @@ export class SkillReleaseRegistry {
|
|
|
2742
2812
|
this.#now = now;
|
|
2743
2813
|
this.#leaseTtlMs = leaseTtlMs;
|
|
2744
2814
|
this.#crashHook = crashHook;
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
? transactionLedger.migrate.bind(transactionLedger)
|
|
2815
|
+
const captureTransactionMethod = (name) => {
|
|
2816
|
+
const method = transactionLedger[name];
|
|
2817
|
+
return typeof method === "function"
|
|
2818
|
+
? (...args) => Reflect.apply(method, transactionLedger, args)
|
|
2750
2819
|
: null;
|
|
2751
|
-
|
|
2820
|
+
};
|
|
2821
|
+
this.#ledgerPrepare = captureTransactionMethod("prepare");
|
|
2822
|
+
this.#ledgerFinalize = captureTransactionMethod("finalize");
|
|
2823
|
+
this.#ledgerMigrate = captureTransactionMethod("migrate");
|
|
2824
|
+
this.#ledgerQuery = captureTransactionMethod("query");
|
|
2752
2825
|
Object.freeze(transactionLedger);
|
|
2753
2826
|
|
|
2754
2827
|
this.tenantId = ownerTenantId;
|
|
2755
2828
|
this.tenantKey = deriveSkillReleaseTenantKey(ownerTenantId);
|
|
2756
|
-
const requestedBase = path.resolve(rootDir);
|
|
2757
2829
|
try {
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
this.#
|
|
2787
|
-
|
|
2830
|
+
if (this.#storeBinding) {
|
|
2831
|
+
this.#boundaries = this.#storeBinding.boundaries;
|
|
2832
|
+
this.baseDir = this.#boundaries.base.path;
|
|
2833
|
+
this.rootDir = this.#boundaries.tenantRoot.path;
|
|
2834
|
+
this.#rootIdentity = this.#boundaries.tenantRoot.identity;
|
|
2835
|
+
this.#markerPath = path.join(this.rootDir, TENANT_MARKER_FILE);
|
|
2836
|
+
this.#markerIdentity = this.#storeBinding.marker.identity;
|
|
2837
|
+
this.#directories =
|
|
2838
|
+
this.#storeBinding.runtimeDirectories ?? deepFreeze({});
|
|
2839
|
+
this.#assertBoundary();
|
|
2840
|
+
} else {
|
|
2841
|
+
const base = this.#initializeDirectory(requestedBase, {
|
|
2842
|
+
recursive: true,
|
|
2843
|
+
harden: false,
|
|
2844
|
+
});
|
|
2845
|
+
this.baseDir = base.path;
|
|
2846
|
+
this.#assertUnboundNamespace();
|
|
2847
|
+
this.#assertNoLegacyBaseLayout();
|
|
2848
|
+
const tenants = this.#initializeDirectory(
|
|
2849
|
+
path.join(this.baseDir, "tenants"),
|
|
2850
|
+
{ parent: base, harden: false },
|
|
2851
|
+
);
|
|
2852
|
+
const tenantRoot = this.#initializeDirectory(
|
|
2853
|
+
path.join(tenants.path, this.tenantKey),
|
|
2854
|
+
{ parent: tenants, harden: false },
|
|
2855
|
+
);
|
|
2856
|
+
this.rootDir = tenantRoot.path;
|
|
2857
|
+
this.#assertUnboundNamespace();
|
|
2858
|
+
this.#boundaries = deepFreeze({ base, tenantRoot, tenants });
|
|
2859
|
+
this.#rootIdentity = tenantRoot.identity;
|
|
2860
|
+
this.#markerPath = path.join(this.rootDir, TENANT_MARKER_FILE);
|
|
2861
|
+
this.#writerControl = createSkillRegistryWriterControl({
|
|
2862
|
+
rootDir: this.rootDir,
|
|
2863
|
+
tenantId: this.tenantId,
|
|
2864
|
+
component: TENANT_MARKER_COMPONENT,
|
|
2865
|
+
fsImpl: this.#fs,
|
|
2866
|
+
});
|
|
2867
|
+
this.#writerControl.runSync(() => {
|
|
2868
|
+
if (this.#secure) {
|
|
2869
|
+
for (const [entry, parent] of [
|
|
2870
|
+
[base, null],
|
|
2871
|
+
[tenants, base],
|
|
2872
|
+
[tenantRoot, tenants],
|
|
2873
|
+
]) {
|
|
2874
|
+
this.#writerControl.assertIfWriting();
|
|
2875
|
+
const hardened = this.#initializeDirectory(entry.path, {
|
|
2876
|
+
parent,
|
|
2877
|
+
});
|
|
2878
|
+
if (
|
|
2879
|
+
hardened.identity !== entry.identity ||
|
|
2880
|
+
!samePath(hardened.path, entry.path)
|
|
2881
|
+
)
|
|
2882
|
+
throw failure(
|
|
2883
|
+
"SKILL_RELEASE_STORE_UNSAFE",
|
|
2884
|
+
"release bootstrap identity changed before permission hardening",
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
this.#writerControl.assertIfWriting();
|
|
2889
|
+
this.#initializeTenantMarker();
|
|
2890
|
+
this.#directories = {};
|
|
2891
|
+
for (const name of [
|
|
2892
|
+
"artifacts",
|
|
2893
|
+
"active",
|
|
2894
|
+
"journals",
|
|
2895
|
+
"locks",
|
|
2896
|
+
"state-migrations",
|
|
2897
|
+
"staging",
|
|
2898
|
+
]) {
|
|
2899
|
+
const directory = path.join(this.rootDir, name);
|
|
2900
|
+
this.#directories[name] = this.#initializeDirectory(directory, {
|
|
2901
|
+
parent: tenantRoot,
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
this.#directories = deepFreeze(this.#directories);
|
|
2905
|
+
this.#assertBoundary();
|
|
2906
|
+
this.#assertNoLegacyTenantSchemas();
|
|
2907
|
+
this.#recoverAll();
|
|
2908
|
+
this.#cleanupDebris();
|
|
2788
2909
|
});
|
|
2789
2910
|
}
|
|
2790
|
-
this.#directories = deepFreeze(this.#directories);
|
|
2791
|
-
this.#assertBoundary();
|
|
2792
|
-
this.#assertNoLegacyTenantSchemas();
|
|
2793
|
-
this.#recoverAll();
|
|
2794
|
-
this.#cleanupDebris();
|
|
2795
2911
|
} catch (cause) {
|
|
2912
|
+
if (cause?.code === RRSI_REGISTRY_STORE_POLICY_HOLD_CODE) throw cause;
|
|
2796
2913
|
if (cause instanceof SkillReleaseRegistryError) throw cause;
|
|
2797
2914
|
throw failure(
|
|
2798
2915
|
"SKILL_RELEASE_STORE_UNSAFE",
|
|
@@ -2804,20 +2921,28 @@ export class SkillReleaseRegistry {
|
|
|
2804
2921
|
this,
|
|
2805
2922
|
Object.freeze({
|
|
2806
2923
|
tenantId: ownerTenantId,
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2924
|
+
storePolicyDescriptor: this.#storeBinding?.descriptor ?? null,
|
|
2925
|
+
matchesStorePolicyBinding: (value) =>
|
|
2926
|
+
value === storePolicyBinding && this.#storeBinding !== undefined,
|
|
2927
|
+
// Private reads never dispatch through a genuine subclass or mutable
|
|
2928
|
+
// function.bind property. Constructor recovery uses these paths too.
|
|
2929
|
+
readActive: (name) => this.#readActive(name),
|
|
2930
|
+
readState: (name) => this.#readState(name),
|
|
2931
|
+
readRelease: (value) => this.#readRelease(value),
|
|
2932
|
+
readInventory: () => this.#readInventory(),
|
|
2811
2933
|
matchesTransactionLedger: (value) => value === transactionLedger,
|
|
2812
2934
|
}),
|
|
2813
2935
|
);
|
|
2936
|
+
REGISTRY_WRITERS.set(this, this.#writerControl);
|
|
2814
2937
|
Object.freeze(this);
|
|
2815
2938
|
}
|
|
2816
2939
|
|
|
2817
2940
|
#initializeDirectory(
|
|
2818
2941
|
requestedPath,
|
|
2819
|
-
{ parent = null, recursive = false } = {},
|
|
2942
|
+
{ parent = null, recursive = false, harden = true } = {},
|
|
2820
2943
|
) {
|
|
2944
|
+
this.#assertMutationNamespace();
|
|
2945
|
+
const namespaceTarget = assertOutsideRrsiRegistryNamespace(requestedPath);
|
|
2821
2946
|
const before = lstatOrNull(this.#fs, requestedPath);
|
|
2822
2947
|
if (before && (!before.isDirectory() || before.isSymbolicLink())) {
|
|
2823
2948
|
throw failure(
|
|
@@ -2826,6 +2951,16 @@ export class SkillReleaseRegistry {
|
|
|
2826
2951
|
);
|
|
2827
2952
|
}
|
|
2828
2953
|
if (!before) {
|
|
2954
|
+
if (
|
|
2955
|
+
!samePath(
|
|
2956
|
+
assertOutsideRrsiRegistryNamespace(requestedPath),
|
|
2957
|
+
namespaceTarget,
|
|
2958
|
+
)
|
|
2959
|
+
)
|
|
2960
|
+
throw failure(
|
|
2961
|
+
RRSI_REGISTRY_STORE_POLICY_HOLD_CODE,
|
|
2962
|
+
"release initialization ancestor changed",
|
|
2963
|
+
);
|
|
2829
2964
|
this.#fs.mkdirSync(requestedPath, { recursive, mode: 0o700 });
|
|
2830
2965
|
}
|
|
2831
2966
|
let stat = this.#fs.lstatSync(requestedPath);
|
|
@@ -2837,6 +2972,12 @@ export class SkillReleaseRegistry {
|
|
|
2837
2972
|
}
|
|
2838
2973
|
const capturedIdentity = identity(stat);
|
|
2839
2974
|
const canonical = realpath(this.#fs, requestedPath);
|
|
2975
|
+
assertOutsideRrsiRegistryNamespace(canonical);
|
|
2976
|
+
if (!samePath(canonical, namespaceTarget))
|
|
2977
|
+
throw failure(
|
|
2978
|
+
RRSI_REGISTRY_STORE_POLICY_HOLD_CODE,
|
|
2979
|
+
"release canonical initialization target changed",
|
|
2980
|
+
);
|
|
2840
2981
|
const canonicalStat = this.#fs.lstatSync(canonical);
|
|
2841
2982
|
const canonicalParent = realpath(this.#fs, path.dirname(requestedPath));
|
|
2842
2983
|
const expectedCanonical = path.join(
|
|
@@ -2857,7 +2998,7 @@ export class SkillReleaseRegistry {
|
|
|
2857
2998
|
"release registry directory escaped its canonical parent",
|
|
2858
2999
|
);
|
|
2859
3000
|
}
|
|
2860
|
-
if (this.#secure) {
|
|
3001
|
+
if (this.#secure && harden) {
|
|
2861
3002
|
ensurePrivateDirectory(canonical, {
|
|
2862
3003
|
applyWindowsAcl: true,
|
|
2863
3004
|
failIfUnavailable: true,
|
|
@@ -2878,6 +3019,18 @@ export class SkillReleaseRegistry {
|
|
|
2878
3019
|
return deepFreeze({ path: canonical, identity: capturedIdentity });
|
|
2879
3020
|
}
|
|
2880
3021
|
|
|
3022
|
+
#assertUnboundNamespace() {
|
|
3023
|
+
if (this.#storeBinding) return;
|
|
3024
|
+
for (const directory of [this.baseDir, this.rootDir])
|
|
3025
|
+
if (directory !== undefined)
|
|
3026
|
+
assertOutsideRrsiRegistryNamespace(directory);
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
#assertMutationNamespace() {
|
|
3030
|
+
this.#storeBinding?.assertMutationAllowed();
|
|
3031
|
+
this.#assertUnboundNamespace();
|
|
3032
|
+
}
|
|
3033
|
+
|
|
2881
3034
|
#assertNoLegacyBaseLayout() {
|
|
2882
3035
|
for (const entry of this.#fs.readdirSync(this.baseDir)) {
|
|
2883
3036
|
if (entry !== "tenants") {
|
|
@@ -2890,6 +3043,7 @@ export class SkillReleaseRegistry {
|
|
|
2890
3043
|
}
|
|
2891
3044
|
|
|
2892
3045
|
#initializeTenantMarker() {
|
|
3046
|
+
this.#assertMutationNamespace();
|
|
2893
3047
|
return withEvolutionFileIdentity(
|
|
2894
3048
|
this.#fs,
|
|
2895
3049
|
this.#markerPath,
|
|
@@ -2899,6 +3053,7 @@ export class SkillReleaseRegistry {
|
|
|
2899
3053
|
}
|
|
2900
3054
|
|
|
2901
3055
|
#initializeTenantMarkerWithIdentity(sameStable) {
|
|
3056
|
+
this.#assertMutationNamespace();
|
|
2902
3057
|
const existing = lstatOrNull(this.#fs, this.#markerPath);
|
|
2903
3058
|
if (existing) {
|
|
2904
3059
|
const verified = this.#readAndVerifyTenantMarker();
|
|
@@ -3002,6 +3157,10 @@ export class SkillReleaseRegistry {
|
|
|
3002
3157
|
}
|
|
3003
3158
|
|
|
3004
3159
|
#readAndVerifyTenantMarker() {
|
|
3160
|
+
if (this.#storeBinding) {
|
|
3161
|
+
this.#storeBinding.recheck();
|
|
3162
|
+
return this.#storeBinding.marker;
|
|
3163
|
+
}
|
|
3005
3164
|
try {
|
|
3006
3165
|
const stored = readBoundedSingleLinkFile(
|
|
3007
3166
|
this.#fs,
|
|
@@ -3053,6 +3212,12 @@ export class SkillReleaseRegistry {
|
|
|
3053
3212
|
}
|
|
3054
3213
|
|
|
3055
3214
|
#assertBoundary() {
|
|
3215
|
+
if (this.#storeBinding) {
|
|
3216
|
+
this.#storeBinding.recheck();
|
|
3217
|
+
return;
|
|
3218
|
+
}
|
|
3219
|
+
this.#assertUnboundNamespace();
|
|
3220
|
+
this.#writerControl?.assertIfWriting();
|
|
3056
3221
|
for (const entry of [
|
|
3057
3222
|
...Object.values(this.#boundaries),
|
|
3058
3223
|
...Object.values(this.#directories),
|
|
@@ -3253,6 +3418,7 @@ export class SkillReleaseRegistry {
|
|
|
3253
3418
|
}
|
|
3254
3419
|
|
|
3255
3420
|
#writeTemporary(fileName, value) {
|
|
3421
|
+
this.#assertMutationNamespace();
|
|
3256
3422
|
if (!TEMP_PATTERN.test(fileName)) {
|
|
3257
3423
|
throw failure("SKILL_RELEASE_STORE_UNSAFE", "temporary name is invalid");
|
|
3258
3424
|
}
|
|
@@ -3263,6 +3429,7 @@ export class SkillReleaseRegistry {
|
|
|
3263
3429
|
}
|
|
3264
3430
|
|
|
3265
3431
|
#writeTemporaryWithIdentity(filePath, value, sameStable) {
|
|
3432
|
+
this.#assertMutationNamespace();
|
|
3266
3433
|
const bytes = serialize(value);
|
|
3267
3434
|
let descriptor = null;
|
|
3268
3435
|
let writtenIdentity = null;
|
|
@@ -3312,6 +3479,7 @@ export class SkillReleaseRegistry {
|
|
|
3312
3479
|
}
|
|
3313
3480
|
|
|
3314
3481
|
#atomicWrite(area, destination, value) {
|
|
3482
|
+
this.#assertMutationNamespace();
|
|
3315
3483
|
const expectedBytes = serialize(value);
|
|
3316
3484
|
const name = `.write-${process.pid}-${this.#token()}.tmp`;
|
|
3317
3485
|
const temporary = this.#writeTemporary(name, value);
|
|
@@ -3357,6 +3525,7 @@ export class SkillReleaseRegistry {
|
|
|
3357
3525
|
}
|
|
3358
3526
|
|
|
3359
3527
|
#unlink(filePath, directory) {
|
|
3528
|
+
this.#assertMutationNamespace();
|
|
3360
3529
|
try {
|
|
3361
3530
|
this.#fs.unlinkSync(filePath);
|
|
3362
3531
|
fsyncDirectory(this.#fs, directory);
|
|
@@ -3366,6 +3535,7 @@ export class SkillReleaseRegistry {
|
|
|
3366
3535
|
}
|
|
3367
3536
|
|
|
3368
3537
|
#publishRelease(release) {
|
|
3538
|
+
this.#assertMutationNamespace();
|
|
3369
3539
|
const destination = this.#releasePath(release.releaseDigest);
|
|
3370
3540
|
const name = `.release-${process.pid}-${this.#token()}.tmp`;
|
|
3371
3541
|
const temporary = this.#writeTemporary(name, release);
|
|
@@ -3377,7 +3547,7 @@ export class SkillReleaseRegistry {
|
|
|
3377
3547
|
this.#fs.linkSync(temporary, destination);
|
|
3378
3548
|
} catch (error) {
|
|
3379
3549
|
if (error?.code !== "EEXIST") throw error;
|
|
3380
|
-
const existing = this
|
|
3550
|
+
const existing = this.#readRelease(release.releaseDigest);
|
|
3381
3551
|
if (!serialize(existing).equals(bytes)) {
|
|
3382
3552
|
throw failure("SKILL_RELEASE_CONFLICT", "release digest collision");
|
|
3383
3553
|
}
|
|
@@ -3428,17 +3598,26 @@ export class SkillReleaseRegistry {
|
|
|
3428
3598
|
}
|
|
3429
3599
|
|
|
3430
3600
|
#createRelease(input) {
|
|
3601
|
+
this.#assertMutationNamespace();
|
|
3431
3602
|
const release = buildSkillRelease(input);
|
|
3432
3603
|
const created = this.#publishRelease(release);
|
|
3433
3604
|
return deepFreeze({ release, created });
|
|
3434
3605
|
}
|
|
3435
3606
|
|
|
3436
3607
|
migrateLegacyRelease(input, migrationAuthority) {
|
|
3608
|
+
this.#assertMutationNamespace();
|
|
3437
3609
|
if (arguments.length !== 2) {
|
|
3438
3610
|
throw migrationRequired(
|
|
3439
3611
|
"legacy release migration requires input and a durable audit authority",
|
|
3440
3612
|
);
|
|
3441
3613
|
}
|
|
3614
|
+
return this.#writerControl.runSync(() =>
|
|
3615
|
+
this.#migrateLegacyRelease(input, migrationAuthority),
|
|
3616
|
+
);
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
#migrateLegacyRelease(input, migrationAuthority) {
|
|
3620
|
+
this.#assertMutationNamespace();
|
|
3442
3621
|
assertExactKeys(
|
|
3443
3622
|
migrationAuthority,
|
|
3444
3623
|
RELEASE_MIGRATION_AUTHORITY_KEYS,
|
|
@@ -3575,11 +3754,19 @@ export class SkillReleaseRegistry {
|
|
|
3575
3754
|
}
|
|
3576
3755
|
|
|
3577
3756
|
migrateLegacyState(planInput, migrationAuthority) {
|
|
3757
|
+
this.#assertMutationNamespace();
|
|
3578
3758
|
if (arguments.length !== 2 || this.#ledgerMigrate === null) {
|
|
3579
3759
|
throw migrationRequired(
|
|
3580
3760
|
"legacy state migration requires a plan, durable authority, and authenticated ledger migration port",
|
|
3581
3761
|
);
|
|
3582
3762
|
}
|
|
3763
|
+
return this.#writerControl.runSync(() =>
|
|
3764
|
+
this.#migrateLegacyState(planInput, migrationAuthority),
|
|
3765
|
+
);
|
|
3766
|
+
}
|
|
3767
|
+
|
|
3768
|
+
#migrateLegacyState(planInput, migrationAuthority) {
|
|
3769
|
+
this.#assertMutationNamespace();
|
|
3583
3770
|
const plan = verifySkillReleaseStateMigrationPlan(planInput);
|
|
3584
3771
|
if (plan.tenantId !== this.tenantId) {
|
|
3585
3772
|
throw migrationRequired("state migration plan belongs to another tenant");
|
|
@@ -3607,8 +3794,8 @@ export class SkillReleaseRegistry {
|
|
|
3607
3794
|
migrationAuthority.handlerArtifactDigest,
|
|
3608
3795
|
"stateMigrationAuthority.handlerArtifactDigest",
|
|
3609
3796
|
);
|
|
3610
|
-
const active = this
|
|
3611
|
-
const lastKnownGood = this
|
|
3797
|
+
const active = this.#readRelease(plan.activeReleaseDigest);
|
|
3798
|
+
const lastKnownGood = this.#readRelease(plan.lastKnownGoodReleaseDigest);
|
|
3612
3799
|
if (
|
|
3613
3800
|
active.skillName !== plan.skillName ||
|
|
3614
3801
|
lastKnownGood.skillName !== plan.skillName ||
|
|
@@ -3681,7 +3868,7 @@ export class SkillReleaseRegistry {
|
|
|
3681
3868
|
{ stateMigrationDigest: plan.stateMigrationDigest },
|
|
3682
3869
|
);
|
|
3683
3870
|
}
|
|
3684
|
-
const existing = this
|
|
3871
|
+
const existing = this.#readState(plan.skillName);
|
|
3685
3872
|
if (existing.revision > 0) {
|
|
3686
3873
|
if (
|
|
3687
3874
|
existing.transactionId !== plan.stateMigrationDigest ||
|
|
@@ -3783,7 +3970,19 @@ export class SkillReleaseRegistry {
|
|
|
3783
3970
|
}
|
|
3784
3971
|
|
|
3785
3972
|
readRelease(releaseDigest) {
|
|
3973
|
+
return this.#readRelease(releaseDigest);
|
|
3974
|
+
}
|
|
3975
|
+
|
|
3976
|
+
#readRelease(releaseDigest) {
|
|
3786
3977
|
const expected = digest(releaseDigest, "releaseDigest");
|
|
3978
|
+
if (
|
|
3979
|
+
["uninitialized", "authenticated-empty-read-only"].includes(
|
|
3980
|
+
this.#runtimeMode,
|
|
3981
|
+
)
|
|
3982
|
+
) {
|
|
3983
|
+
this.#assertBoundary();
|
|
3984
|
+
throw failure("SKILL_RELEASE_NOT_FOUND", "release was not found");
|
|
3985
|
+
}
|
|
3787
3986
|
let value;
|
|
3788
3987
|
try {
|
|
3789
3988
|
value = this.#readJson(
|
|
@@ -3819,6 +4018,14 @@ export class SkillReleaseRegistry {
|
|
|
3819
4018
|
|
|
3820
4019
|
#readStateRaw(name) {
|
|
3821
4020
|
const normalizedName = skillName(name);
|
|
4021
|
+
if (
|
|
4022
|
+
["uninitialized", "authenticated-empty-read-only"].includes(
|
|
4023
|
+
this.#runtimeMode,
|
|
4024
|
+
)
|
|
4025
|
+
) {
|
|
4026
|
+
this.#assertBoundary();
|
|
4027
|
+
return initialState(normalizedName, this.tenantId);
|
|
4028
|
+
}
|
|
3822
4029
|
try {
|
|
3823
4030
|
const state = verifySkillReleaseState(
|
|
3824
4031
|
this.#readJson(
|
|
@@ -3888,8 +4095,8 @@ export class SkillReleaseRegistry {
|
|
|
3888
4095
|
"active pointer is not finalized by the trusted transaction ledger",
|
|
3889
4096
|
);
|
|
3890
4097
|
}
|
|
3891
|
-
const active = this
|
|
3892
|
-
const lkg = this
|
|
4098
|
+
const active = this.#readRelease(state.activeReleaseDigest);
|
|
4099
|
+
const lkg = this.#readRelease(state.lastKnownGoodReleaseDigest);
|
|
3893
4100
|
if (
|
|
3894
4101
|
active.skillName !== state.skillName ||
|
|
3895
4102
|
lkg.skillName !== state.skillName ||
|
|
@@ -3907,17 +4114,25 @@ export class SkillReleaseRegistry {
|
|
|
3907
4114
|
}
|
|
3908
4115
|
|
|
3909
4116
|
readState(name) {
|
|
4117
|
+
return this.#readState(name);
|
|
4118
|
+
}
|
|
4119
|
+
|
|
4120
|
+
#readState(name) {
|
|
3910
4121
|
const state = this.#readStateRaw(name);
|
|
3911
4122
|
return state.revision === 0 ? state : this.#verifyCommittedState(state);
|
|
3912
4123
|
}
|
|
3913
4124
|
|
|
3914
4125
|
readActive(name) {
|
|
3915
|
-
|
|
4126
|
+
return this.#readActive(name);
|
|
4127
|
+
}
|
|
4128
|
+
|
|
4129
|
+
#readActive(name) {
|
|
4130
|
+
const state = this.#readState(name);
|
|
3916
4131
|
return state.revision === 0
|
|
3917
4132
|
? null
|
|
3918
4133
|
: deepFreeze({
|
|
3919
4134
|
state,
|
|
3920
|
-
release: this
|
|
4135
|
+
release: this.#readRelease(state.activeReleaseDigest),
|
|
3921
4136
|
});
|
|
3922
4137
|
}
|
|
3923
4138
|
|
|
@@ -3981,7 +4196,17 @@ export class SkillReleaseRegistry {
|
|
|
3981
4196
|
}
|
|
3982
4197
|
|
|
3983
4198
|
readInventory() {
|
|
4199
|
+
return this.#readInventory();
|
|
4200
|
+
}
|
|
4201
|
+
|
|
4202
|
+
#readInventory() {
|
|
3984
4203
|
this.#assertBoundary();
|
|
4204
|
+
if (
|
|
4205
|
+
["uninitialized", "authenticated-empty-read-only"].includes(
|
|
4206
|
+
this.#runtimeMode,
|
|
4207
|
+
)
|
|
4208
|
+
)
|
|
4209
|
+
return deepFreeze({ active: [], releases: [] });
|
|
3985
4210
|
const releasePattern = /^[a-f0-9]{64}\.json$/u;
|
|
3986
4211
|
const statePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\.json$/u;
|
|
3987
4212
|
const beforeReleases = this.#readInventoryNames(
|
|
@@ -3999,11 +4224,11 @@ export class SkillReleaseRegistry {
|
|
|
3999
4224
|
);
|
|
4000
4225
|
}
|
|
4001
4226
|
const releases = beforeReleases.map((name) =>
|
|
4002
|
-
this
|
|
4227
|
+
this.#readRelease(`sha256:${name.slice(0, -".json".length)}`),
|
|
4003
4228
|
);
|
|
4004
4229
|
const active = beforeStates.map((name) => {
|
|
4005
4230
|
const skill = name.slice(0, -".json".length);
|
|
4006
|
-
const value = this
|
|
4231
|
+
const value = this.#readActive(skill);
|
|
4007
4232
|
if (value === null) {
|
|
4008
4233
|
throw failure(
|
|
4009
4234
|
"SKILL_RELEASE_STATE_CORRUPT",
|
|
@@ -4041,7 +4266,7 @@ export class SkillReleaseRegistry {
|
|
|
4041
4266
|
const afterReleases = this.#readInventoryNames("artifacts", releasePattern);
|
|
4042
4267
|
const afterStates = this.#readInventoryNames("active", statePattern);
|
|
4043
4268
|
const afterStateDigests = afterStates.map(
|
|
4044
|
-
(name) => this
|
|
4269
|
+
(name) => this.#readState(name.slice(0, -".json".length)).stateDigest,
|
|
4045
4270
|
);
|
|
4046
4271
|
if (
|
|
4047
4272
|
canonicalJson(beforeReleases) !== canonicalJson(afterReleases) ||
|
|
@@ -4060,7 +4285,7 @@ export class SkillReleaseRegistry {
|
|
|
4060
4285
|
}
|
|
4061
4286
|
|
|
4062
4287
|
pinActive(name) {
|
|
4063
|
-
const active = this
|
|
4288
|
+
const active = this.#readActive(name);
|
|
4064
4289
|
if (!active)
|
|
4065
4290
|
throw failure("SKILL_RELEASE_NOT_ACTIVE", "Skill has no active release");
|
|
4066
4291
|
const pin = Object.freeze(Object.create(null));
|
|
@@ -4094,7 +4319,7 @@ export class SkillReleaseRegistry {
|
|
|
4094
4319
|
"pinned activation is not committed",
|
|
4095
4320
|
);
|
|
4096
4321
|
}
|
|
4097
|
-
return this
|
|
4322
|
+
return this.#readRelease(binding.releaseDigest);
|
|
4098
4323
|
}
|
|
4099
4324
|
|
|
4100
4325
|
#owner(kind, token, { skill = null, transactionId = null, fence = 0 } = {}) {
|
|
@@ -4210,6 +4435,7 @@ export class SkillReleaseRegistry {
|
|
|
4210
4435
|
}
|
|
4211
4436
|
|
|
4212
4437
|
#createLock(lockPath, owner) {
|
|
4438
|
+
this.#assertMutationNamespace();
|
|
4213
4439
|
this.#fs.mkdirSync(lockPath, { mode: 0o700 });
|
|
4214
4440
|
let descriptor = null;
|
|
4215
4441
|
try {
|
|
@@ -4239,6 +4465,7 @@ export class SkillReleaseRegistry {
|
|
|
4239
4465
|
}
|
|
4240
4466
|
|
|
4241
4467
|
#removeLock(lockPath, expectedToken = null) {
|
|
4468
|
+
this.#assertMutationNamespace();
|
|
4242
4469
|
let owner;
|
|
4243
4470
|
try {
|
|
4244
4471
|
owner = this.#readOwner(lockPath);
|
|
@@ -4300,6 +4527,7 @@ export class SkillReleaseRegistry {
|
|
|
4300
4527
|
}
|
|
4301
4528
|
|
|
4302
4529
|
#renewLease(lease) {
|
|
4530
|
+
this.#assertMutationNamespace();
|
|
4303
4531
|
const current = this.#readOwner(lease.lockPath);
|
|
4304
4532
|
if (
|
|
4305
4533
|
current.token !== lease.token ||
|
|
@@ -4338,6 +4566,7 @@ export class SkillReleaseRegistry {
|
|
|
4338
4566
|
}
|
|
4339
4567
|
|
|
4340
4568
|
#acquireLease(name, transactionId, expectedRevision, expectedParentDigest) {
|
|
4569
|
+
this.#assertMutationNamespace();
|
|
4341
4570
|
const journalPath = this.#journalPath(name);
|
|
4342
4571
|
if (this.#exists(journalPath)) {
|
|
4343
4572
|
this.#withRecoveryLock(() => this.#recoverSkill(name));
|
|
@@ -4350,11 +4579,11 @@ export class SkillReleaseRegistry {
|
|
|
4350
4579
|
}
|
|
4351
4580
|
const lockPath = this.#leasePath(name);
|
|
4352
4581
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4353
|
-
const state = this
|
|
4582
|
+
const state = this.#readState(name);
|
|
4354
4583
|
const active =
|
|
4355
4584
|
state.activeReleaseDigest === null
|
|
4356
4585
|
? null
|
|
4357
|
-
: this
|
|
4586
|
+
: this.#readRelease(state.activeReleaseDigest);
|
|
4358
4587
|
const actualParent = active?.contentDigest ?? EMPTY_SKILL_ACTIVE_DIGEST;
|
|
4359
4588
|
if (
|
|
4360
4589
|
state.revision !== expectedRevision ||
|
|
@@ -4805,6 +5034,7 @@ export class SkillReleaseRegistry {
|
|
|
4805
5034
|
}
|
|
4806
5035
|
|
|
4807
5036
|
#prepare(intent, targetRelease) {
|
|
5037
|
+
this.#assertMutationNamespace();
|
|
4808
5038
|
let projection;
|
|
4809
5039
|
try {
|
|
4810
5040
|
projection = this.#ledgerPrepare(intent, targetRelease);
|
|
@@ -4836,6 +5066,7 @@ export class SkillReleaseRegistry {
|
|
|
4836
5066
|
}
|
|
4837
5067
|
|
|
4838
5068
|
#finalize(journal, prepareReceipt) {
|
|
5069
|
+
this.#assertMutationNamespace();
|
|
4839
5070
|
const request = deepFreeze({
|
|
4840
5071
|
authorityReceiptDigest: journal.intent.authorityReceiptDigest,
|
|
4841
5072
|
expectedPrepareReceiptDigest: prepareReceipt.receiptDigest,
|
|
@@ -4882,6 +5113,7 @@ export class SkillReleaseRegistry {
|
|
|
4882
5113
|
}
|
|
4883
5114
|
|
|
4884
5115
|
#writePointer(state, stagedFile) {
|
|
5116
|
+
this.#assertMutationNamespace();
|
|
4885
5117
|
const stagedPath = this.#path("staging", stagedFile);
|
|
4886
5118
|
if (!this.#exists(stagedPath)) this.#writeTemporary(stagedFile, state);
|
|
4887
5119
|
const expectedBytes = serialize(state);
|
|
@@ -4994,7 +5226,7 @@ export class SkillReleaseRegistry {
|
|
|
4994
5226
|
);
|
|
4995
5227
|
}
|
|
4996
5228
|
|
|
4997
|
-
const verifiedRelease = this
|
|
5229
|
+
const verifiedRelease = this.#readRelease(release.releaseDigest);
|
|
4998
5230
|
if (
|
|
4999
5231
|
verifiedRelease.tenantId !== this.tenantId ||
|
|
5000
5232
|
verifiedRelease.skillName !== state.skillName ||
|
|
@@ -5022,7 +5254,7 @@ export class SkillReleaseRegistry {
|
|
|
5022
5254
|
#assertJournalFinalizationArtifacts(journal) {
|
|
5023
5255
|
let release;
|
|
5024
5256
|
try {
|
|
5025
|
-
release = this
|
|
5257
|
+
release = this.#readRelease(journal.nextState.activeReleaseDigest);
|
|
5026
5258
|
} catch (cause) {
|
|
5027
5259
|
throw failure(
|
|
5028
5260
|
"SKILL_RELEASE_FINALIZATION_INPUT_INVALID",
|
|
@@ -5091,6 +5323,7 @@ export class SkillReleaseRegistry {
|
|
|
5091
5323
|
}
|
|
5092
5324
|
|
|
5093
5325
|
#recoverJournal(journal) {
|
|
5326
|
+
this.#assertMutationNamespace();
|
|
5094
5327
|
const expected = {
|
|
5095
5328
|
authorityReceiptDigest: journal.intent.authorityReceiptDigest,
|
|
5096
5329
|
intentDigest: journal.intent.intentDigest,
|
|
@@ -5132,6 +5365,7 @@ export class SkillReleaseRegistry {
|
|
|
5132
5365
|
}
|
|
5133
5366
|
|
|
5134
5367
|
#recoverSkill(name, { force = false } = {}) {
|
|
5368
|
+
this.#assertMutationNamespace();
|
|
5135
5369
|
const journalPath = this.#journalPath(name);
|
|
5136
5370
|
const lockPath = this.#leasePath(name);
|
|
5137
5371
|
if (!this.#exists(journalPath)) {
|
|
@@ -5174,6 +5408,7 @@ export class SkillReleaseRegistry {
|
|
|
5174
5408
|
}
|
|
5175
5409
|
|
|
5176
5410
|
#recoverStateMigration(journal, { force = false } = {}) {
|
|
5411
|
+
this.#assertMutationNamespace();
|
|
5177
5412
|
const lockPath = this.#leasePath(journal.skillName);
|
|
5178
5413
|
if (this.#exists(lockPath)) {
|
|
5179
5414
|
const owner = this.#readOwner(lockPath);
|
|
@@ -5222,13 +5457,14 @@ export class SkillReleaseRegistry {
|
|
|
5222
5457
|
journal.state,
|
|
5223
5458
|
);
|
|
5224
5459
|
}
|
|
5225
|
-
const release = this
|
|
5460
|
+
const release = this.#readRelease(journal.state.activeReleaseDigest);
|
|
5226
5461
|
this.#assertFinalizationArtifacts(journal.state, release);
|
|
5227
5462
|
this.#cleanupStateMigration(journal);
|
|
5228
5463
|
return "committed";
|
|
5229
5464
|
}
|
|
5230
5465
|
|
|
5231
5466
|
#recoverAll() {
|
|
5467
|
+
this.#assertMutationNamespace();
|
|
5232
5468
|
this.#withRecoveryLock(() => {
|
|
5233
5469
|
for (const name of this.#fs.readdirSync(
|
|
5234
5470
|
this.#directories["state-migrations"].path,
|
|
@@ -5275,6 +5511,7 @@ export class SkillReleaseRegistry {
|
|
|
5275
5511
|
}
|
|
5276
5512
|
|
|
5277
5513
|
#cleanupDebris() {
|
|
5514
|
+
this.#assertMutationNamespace();
|
|
5278
5515
|
const referenced = new Set();
|
|
5279
5516
|
for (const name of this.#fs.readdirSync(this.#directories.journals.path)) {
|
|
5280
5517
|
if (name.endsWith(".json")) {
|
|
@@ -5463,6 +5700,14 @@ export class SkillReleaseRegistry {
|
|
|
5463
5700
|
}
|
|
5464
5701
|
|
|
5465
5702
|
async applyTransition(capability) {
|
|
5703
|
+
this.#assertMutationNamespace();
|
|
5704
|
+
return this.#writerControl.runAsync(() =>
|
|
5705
|
+
this.#applyTransition(capability),
|
|
5706
|
+
);
|
|
5707
|
+
}
|
|
5708
|
+
|
|
5709
|
+
async #applyTransition(capability) {
|
|
5710
|
+
this.#assertMutationNamespace();
|
|
5466
5711
|
const payload = this.#validateTransitionPayload(
|
|
5467
5712
|
consumeRegistryTransitionCapability(capability, this),
|
|
5468
5713
|
);
|
|
@@ -5477,7 +5722,7 @@ export class SkillReleaseRegistry {
|
|
|
5477
5722
|
target = created.release;
|
|
5478
5723
|
releaseCreated = created.created;
|
|
5479
5724
|
} else {
|
|
5480
|
-
target = this
|
|
5725
|
+
target = this.#readRelease(payload.targetReleaseDigest);
|
|
5481
5726
|
}
|
|
5482
5727
|
if (
|
|
5483
5728
|
target.skillName !== payload.skillName ||
|