chainlesschain 0.166.58 → 0.166.62
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/package.json +3 -2
- package/src/assets/web-panel/assets/{AIOps-DoyI29Aw.js → AIOps-BqoRiuXE.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eZKcEoxc.js → ActionButton-BwBhyFIm.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-B2C2e9A7.js → Analytics-DTW03Emb.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DkZJiu4X.js → AppLayout-CI-wxMLQ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-8PD3BXVa.js → Artifacts-DVqbM3iE.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Cv6sRlFu.js → Audit-DulhOs16.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D-V84Qpm.js → BackgroundAgents-DnRs67e8.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DYJQcxj1.js → Backup-BFEZo0vX.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-KL2IeywH.js → BaseInput-D185sBnp.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Bt9wy_Yn.js → Chat-DUvP-2SK.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-ChB6fH-W.js → ChatBubbleRenderer-u9WKQbZb.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Dm-nfdnd.js → Checkbox-D8Zh_18b.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CYi3yDzv.js → Codegen-WdiWRdfC.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C7sQywfG.js → Col-CnSoVpw6.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DjxuqAM4.js → Community-BJDHgBkw.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CD_4lbxr.js → Compact-uNRdmBaq.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BtDpNJrS.js → Compliance-_6jRTJa3.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-l19ANH6Q.js → Cowork-D5lnbXR6.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-Br-rBoEK.js → Cron-D6tuGBVg.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-60UVvKET.js → Crosschain-Ce5e9Lbm.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B9dqar51.js → DID-1VVKZ_c1.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B39hhdHb.js → Dashboard-DuHcZ13w.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Bm5rCfvF.js → Dropdown-BC3EK0wN.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BI9HANDl.js → EmailListRenderer-DzLpGs5E.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-Cfqn_yCq.js → EvolutionSettings-x2XZHG0Z.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-9Y4_zyhT.js → FamilyGuardDashboard-nAavV50Y.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-vnbbmMdF.js → Federation-CCHWVS5J.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BEKNtNF9.js → FormItemContext-CGod_3Ni.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BmWr16IL.js → GenericCardRenderer-DIFYQa2f.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CUUwAXdn.js → Git-DikM1Nc5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Bw8XZmH9.js → Governance-SzzBXCDX.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CNrml6dn.js → Inference-wVsu9QzM.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BhxOwpW_.js → KnowledgeGraph-DDpVxfO-.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BV8WViUG.js → Logs-BnIjS-2Z.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-3AsRzie6.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-ztcu4mg4.js → Marketplace-Cj3PLhXV.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D-wzRO7z.js → McpTools-DMKO55Kz.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-ChdjWC1R.js → Memory-wWJl5yJL.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-B1QHzIjE.js → MobileBridge-CJ_VIPgJ.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DmaRtaMw.js → MobileProjects-CiJT5cF8.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DRQMr4WP.js → Mtc-BXmndm9a.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-Cwo0on-u.js → MtcAudit-C3hWIAnz.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-QplgySFt.js → Multisig-DU4OUQ7u.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BWkMyuAy.js → NLProgramming-CyAwOeU5.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BI_pSEM0.js → Notes--YvcAg13.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DiuFo6Xe.js → NotificationSettings-Dyu6dC0D.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DZzQhujZ.js → OrderTableRenderer-Df-0iTO2.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DqEdqWB0.js → Organization-a9Em4Sgu.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CO7_2YLN.js → Overflow-CCQtvcsw.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BN5RiNst.js → P2P--CaB5e38.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CapfG4bl.js → PdhVaultBrowser-CmfHjoJG.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-B24c5fWW.js → Permissions-BCDjNsXi.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-D7Mb3_vh.js → PersonalDataHub-ByprqCJd.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-BsfxlbOQ.js → Pipeline-CZRZq-P0.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bq7c7IYy.js → Privacy-CeDay_dV.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Clse2DPl.js → ProjectInit-CgpIfRAZ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CHAEdjri.js → ProjectSettings-CU8iakEs.js} +2 -2
- package/src/assets/web-panel/assets/Projects-pPM0KRfQ.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DQyH3PXU.js → Providers-BfpxsZh1.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-t2Z-N49o.js → QrScannerModal-Dmv3rax1.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BacR7PlI.js → QuickAsk-DBOtB5wd.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D-NAy0CQ.js → Recommend-C_KnHRvS.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CjI3GeVQ.js → RemoteSession-OIO9kT7D.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-HoQ3i2oW.js → Reputation-BCfNIBt3.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CY2jczWa.js → Row-pnhw7dyj.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Bd3o20IY.js → RssFeed-CLJ1A3FF.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C88KjgTv.js → Search-CSQzJ3gj.js} +1 -1
- package/src/assets/web-panel/assets/{Security-yfmfvujK.js → Security-CS_mvkaE.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DLPBWoxT.js → Services-DBqA2Csq.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DzDjvVQi.js → Skeleton-BjR3_iWH.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DqfrJIyP.js → Skills-DwGIXRJS.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BXhsGzkm.js → Sla-DwiHHJtJ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-jxSl2JDo.js → SpeechSettings-QYN_t0CS.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BX2xKtI3.js → SyncSettings-DcXA1Jp3.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-DwWqvoyB.js +1 -0
- package/src/assets/web-panel/assets/{Templates-CTpj9f62.js → Templates-C6MTuLXU.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-nnQuhdPg.js → Tenant-DmbdMB2D.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-cJ0vbuTe.js → Terminal-DYeXnE4A.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DN08D0SD.js → TimelineRenderer-BrwLhsSE.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-C8BWWBUD.js → Tokens-C5kKpRWj.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DhD-LUoe.js → Trigger-C4Zyg1jj.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D0nFyc_Z.js → Trust-D0mrY3kY.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B59G57LP.js → UkeySign-Bq5NMLLb.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BpYACxVC.js → VideoEditing-OObS6euz.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DlZ3rKGD.js → Wallet-Die77ZAO.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-De4dNyig.js → WebAuthn-DFpqn0WO.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-C2Tewnhp.js → WorkflowEditor-BgKZiece.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CDBn4JLE.js → chat-CbWtbRmr.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BNawl0d_.js → colors-Zu_TgmpG.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-n65WDhze.js → compact-item-BqABAwA_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DAKgOdIy.js → createContext-DR6r1ykz.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CmMzSuk5.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DhxFG46W.js → hasIn-BNnYbjOt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeTlqus4.js → index--1t0mcMh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV6iHrUO.js → index--vigBXnN.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByDs4cW4.js → index-55eCb40A.js} +3 -3
- package/src/assets/web-panel/assets/{index-KT94nMha.js → index-B9qA3lcI.js} +1 -1
- package/src/assets/web-panel/assets/{index-PlOBwfR1.js → index-BCyrVLzm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBFjMjmp.js → index-BQ1WFS4G.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDTrf8WH.js → index-BQHn6m4S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFkamspD.js → index-BbHnxChr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkW0HGr-.js → index-BtQDpNFU.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cv7LqHwv.js → index-BvQB-LK5.js} +1 -1
- package/src/assets/web-panel/assets/{index-By-zGgUp.js → index-C912Wlyi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLFRz0_7.js → index-CO9hQ7ri.js} +1 -1
- package/src/assets/web-panel/assets/{index-DleKcclQ.js → index-CR4uB9Mt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAogaHa9.js → index-CSNMSJAt.js} +1 -1
- package/src/assets/web-panel/assets/{index-pzEYIGNA.js → index-CVgcq0cJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds290C06.js → index-CYgH1j85.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW_OUdP8.js → index-CbJgVaoQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzONk4rW.js → index-CkBDWART.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRyzRluv.js → index-CmGll9ri.js} +1 -1
- package/src/assets/web-panel/assets/{index-D34AXxN9.js → index-CpmSx_mp.js} +1 -1
- package/src/assets/web-panel/assets/{index-0Y-ncsVy.js → index-Ct4xnx2r.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE6OcLof.js → index-CuYLjMxX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZI8xwwt.js → index-D08ytPR_.js} +1 -1
- package/src/assets/web-panel/assets/{index-5oJjovnA.js → index-DEdqCQKQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQFAuU1c.js → index-DaKziwj_.js} +1 -1
- package/src/assets/web-panel/assets/{index-L1QnA0gW.js → index-DiaPl_6F.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_-6qQf0.js → index-DuCixW1o.js} +1 -1
- package/src/assets/web-panel/assets/index-Dw-oPGSM.js +1 -0
- package/src/assets/web-panel/assets/{index-CSOgoyqx.js → index-DxloCIDQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BudfMkBy.js → index-GrGT2dft.js} +1 -1
- package/src/assets/web-panel/assets/index-OXemaG8f.js +1 -0
- package/src/assets/web-panel/assets/{index-BfXdTvku.js → index-P-0rrwu0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZJrAg98.js → index-fvl4dSWm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCujBaFg.js → index-hWckjvz-.js} +1 -1
- package/src/assets/web-panel/assets/{index-KZkt4e9N.js → index-hZ41pakD.js} +1 -1
- package/src/assets/web-panel/assets/{index-hA9VUXGr.js → index-n62j7dTt.js} +1 -1
- package/src/assets/web-panel/assets/{index-gG1WJBpa.js → index-rS1lj7A9.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6sWUgN6.js → index-uwS83tsv.js} +1 -1
- package/src/assets/web-panel/assets/{index--76HBS1k.js → index-ys7--3Ab.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B3bCivrt.js → initDefaultProps-BEtGYjIT.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CF5pGsxz.js → motion-Cvnft4fL.js} +1 -1
- package/src/assets/web-panel/assets/{move-CaOFtFLU.js → move-CdxE_5Yl.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Z4-50Y1c.js → mtc-parser-CS0l6IJn.js} +1 -1
- package/src/assets/web-panel/assets/{omit-AK4WqVTT.js → omit-Bnji87sb.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Dbye0px4.js → pickAttrs-BYdnEgN3.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DCmr-Dks.js → placementArrow-DYYd524z.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CJ3Zm_-H.js → responsiveObserve-BbIJIkXp.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BuSk5-ue.js → slide-BSvuvfUS.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-8u_lKSFJ.js → statusUtils-DeLSt3js.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-sy6_m42F.js → styleChecker-DpJTPfyI.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Di5EfYGo.js → useFlexGapSupport-S7WdFQMU.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BTfX_Ri1.js → useFs-CkfCBy52.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-kqurO26X.js → usePersonalDataHub-CA48p8Gt.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DRkH4mPV.js → vnode-C9D1tq_L.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-ON_-UuD_.js → zoom-B0TG7YQI.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +65 -0
- package/src/generated/cc-agent-protocol.schema.json +65 -1
- package/src/lib/background-agent-supervisor.js +10 -1
- package/src/lib/context-memory-kernel/jsonl-session-context-port.js +33 -0
- package/src/lib/context-memory-kernel/task-worklog-port.js +388 -0
- package/src/lib/evolution/evidence-backed-wiki-maintainer.js +119 -12
- package/src/lib/evolution/evolution-artifact-ports.js +3 -0
- package/src/lib/evolution/evolution-deployment-loader.js +23 -0
- package/src/lib/evolution/evolution-eval-gate.js +5 -0
- package/src/lib/evolution/evolution-ledger-ports.js +41 -17
- package/src/lib/evolution/pm-exploration-benchmark.js +253 -0
- package/src/lib/evolution/pm-exploration-ledger-adapter.js +672 -0
- package/src/lib/evolution/pm-exploration-rounds.js +832 -0
- package/src/lib/evolution/pm-result-grader.cjs +287 -0
- package/src/lib/public-ide-capability-manifest.js +1 -0
- package/src/lib/read-file-loop-guard.js +36 -5
- package/src/lib/secure-fs.js +51 -4
- package/src/lib/task-progress-tracker.js +29 -7
- package/src/lib/text-file-search.js +1 -0
- package/src/runtime/agent-core.js +48 -4
- package/src/runtime/headless-stream.js +121 -4
- package/src/assets/web-panel/assets/MarkdownRenderer-CO1qbiOY.js +0 -1
- package/src/assets/web-panel/assets/Projects-C1UHvBEK.js +0 -1
- package/src/assets/web-panel/assets/Tasks-P9MmRYt4.js +0 -1
- package/src/assets/web-panel/assets/devWarning-sBSSW127.js +0 -1
- package/src/assets/web-panel/assets/index-BIJTDSLY.js +0 -1
- package/src/assets/web-panel/assets/index-CrBauOkp.js +0 -1
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isPromise, isProxy } from "node:util/types";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
6
|
+
EvolutionArtifactPorts,
|
|
7
|
+
} from "./evolution-artifact-ports.js";
|
|
8
|
+
import {
|
|
9
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
10
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
11
|
+
EvolutionLedger,
|
|
12
|
+
} from "./evolution-ledger.js";
|
|
13
|
+
import {
|
|
14
|
+
EVOLUTION_ARTIFACT_DURABILITY_BINDING_SCHEMA,
|
|
15
|
+
EVOLUTION_ARTIFACT_DURABILITY_RECEIPT_SCHEMA,
|
|
16
|
+
EVOLUTION_ARTIFACT_DURABILITY_RETAIN_REQUEST_SCHEMA,
|
|
17
|
+
captureEvolutionLedgerDurableArtifactResolver,
|
|
18
|
+
} from "./evolution-ledger-ports.js";
|
|
19
|
+
import {
|
|
20
|
+
exportPmExplorationRecoverySnapshot,
|
|
21
|
+
restorePmExplorationJournal,
|
|
22
|
+
verifyPmExplorationPlan,
|
|
23
|
+
} from "./pm-exploration-rounds.js";
|
|
24
|
+
|
|
25
|
+
export const PM_EXPLORATION_LEDGER_RECORD_SCHEMA =
|
|
26
|
+
"chainlesschain.pm-exploration-ledger-record/v1";
|
|
27
|
+
export const PM_EXPLORATION_LEDGER_EVENT_TYPE =
|
|
28
|
+
"pm.exploration.snapshot-committed";
|
|
29
|
+
export const PM_EXPLORATION_LEDGER_RESTORE_SCHEMA =
|
|
30
|
+
"chainlesschain.pm-exploration-ledger-restore/v1";
|
|
31
|
+
export const PM_EXPLORATION_LEDGER_ACK_SCHEMA =
|
|
32
|
+
"chainlesschain.pm-exploration-ledger-ack/v1";
|
|
33
|
+
export const PM_EXPLORATION_LEDGER_CORRUPT_CODE =
|
|
34
|
+
"CC_PM_EXPLORATION_LEDGER_CORRUPT";
|
|
35
|
+
export const PM_EXPLORATION_LEDGER_CONFLICT_CODE =
|
|
36
|
+
"CC_PM_EXPLORATION_LEDGER_CONFLICT";
|
|
37
|
+
|
|
38
|
+
const ARTIFACT_TYPE = "pm-exploration-recovery-snapshot";
|
|
39
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
40
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,255}$/u;
|
|
41
|
+
const DESCRIPTOR_KEYS = new Set([
|
|
42
|
+
"tenantId",
|
|
43
|
+
"artifactTenantId",
|
|
44
|
+
"audience",
|
|
45
|
+
"purpose",
|
|
46
|
+
"planDigest",
|
|
47
|
+
"durabilityAuthorityId",
|
|
48
|
+
]);
|
|
49
|
+
const RECORD_KEYS = new Set([
|
|
50
|
+
"schema",
|
|
51
|
+
"descriptorDigest",
|
|
52
|
+
"revision",
|
|
53
|
+
"priorSnapshotDigest",
|
|
54
|
+
"snapshotDigest",
|
|
55
|
+
"snapshot",
|
|
56
|
+
"committedAt",
|
|
57
|
+
]);
|
|
58
|
+
const DURABILITY_AUTHORITY_KEYS = new Set(["id", "retain", "resolve"]);
|
|
59
|
+
const DURABILITY_RECEIPT_KEYS = new Set([
|
|
60
|
+
"schema",
|
|
61
|
+
"authenticated",
|
|
62
|
+
"durable",
|
|
63
|
+
"authorityId",
|
|
64
|
+
"artifactTenantId",
|
|
65
|
+
"digest",
|
|
66
|
+
"purpose",
|
|
67
|
+
"ref",
|
|
68
|
+
"retention",
|
|
69
|
+
"type",
|
|
70
|
+
"receiptDigest",
|
|
71
|
+
]);
|
|
72
|
+
const STORE_PORTS = new WeakMap();
|
|
73
|
+
|
|
74
|
+
function canonical(value) {
|
|
75
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
76
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
77
|
+
return `{${Object.keys(value)
|
|
78
|
+
.sort()
|
|
79
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
80
|
+
.join(",")}}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function hash(domain, value) {
|
|
84
|
+
return `sha256:${createHash("sha256")
|
|
85
|
+
.update(domain)
|
|
86
|
+
.update("\0")
|
|
87
|
+
.update(canonical(value))
|
|
88
|
+
.digest("hex")}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function sha256Bytes(value) {
|
|
92
|
+
return `sha256:${createHash("sha256").update(value).digest("hex")}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function same(left, right) {
|
|
96
|
+
return canonical(left) === canonical(right);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function deepFreeze(value, seen = new WeakSet()) {
|
|
100
|
+
if (!value || typeof value !== "object" || seen.has(value)) return value;
|
|
101
|
+
seen.add(value);
|
|
102
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
103
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
104
|
+
if (descriptor && "value" in descriptor) deepFreeze(descriptor.value, seen);
|
|
105
|
+
}
|
|
106
|
+
return Object.freeze(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function exact(value, keys, label) {
|
|
110
|
+
if (
|
|
111
|
+
!value ||
|
|
112
|
+
typeof value !== "object" ||
|
|
113
|
+
Array.isArray(value) ||
|
|
114
|
+
isProxy(value) ||
|
|
115
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value))
|
|
116
|
+
) {
|
|
117
|
+
throw new TypeError(`${label} must be a plain record`);
|
|
118
|
+
}
|
|
119
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
120
|
+
if (
|
|
121
|
+
ownKeys.length !== keys.size ||
|
|
122
|
+
ownKeys.some((key) => typeof key !== "string" || !keys.has(key))
|
|
123
|
+
) {
|
|
124
|
+
throw new TypeError(`${label} has an invalid shape`);
|
|
125
|
+
}
|
|
126
|
+
for (const key of ownKeys) {
|
|
127
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
128
|
+
if (!descriptor || !descriptor.enumerable || !("value" in descriptor))
|
|
129
|
+
throw new TypeError(`${label}.${String(key)} must be an own data field`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function identifier(value, label) {
|
|
134
|
+
if (typeof value !== "string" || !ID.test(value))
|
|
135
|
+
throw new TypeError(`${label} is invalid`);
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function digest(value, label) {
|
|
140
|
+
if (typeof value !== "string" || !DIGEST.test(value))
|
|
141
|
+
throw new TypeError(`${label} must be a sha256 digest`);
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function fail(code, message, options) {
|
|
146
|
+
const error = new Error(message, options);
|
|
147
|
+
error.code = code;
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function corrupt(message, options) {
|
|
152
|
+
fail(PM_EXPLORATION_LEDGER_CORRUPT_CODE, message, options);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function conflict(message, options) {
|
|
156
|
+
fail(PM_EXPLORATION_LEDGER_CONFLICT_CODE, message, options);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function requireExactInstance(value, prototype, label) {
|
|
160
|
+
if (
|
|
161
|
+
!value ||
|
|
162
|
+
typeof value !== "object" ||
|
|
163
|
+
isProxy(value) ||
|
|
164
|
+
Object.getPrototypeOf(value) !== prototype
|
|
165
|
+
) {
|
|
166
|
+
throw new TypeError(`${label} exact instance is required`);
|
|
167
|
+
}
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function normalizeDescriptor(input) {
|
|
172
|
+
exact(input, DESCRIPTOR_KEYS, "PM exploration ledger descriptor");
|
|
173
|
+
const core = {
|
|
174
|
+
tenantId: identifier(input.tenantId, "tenantId"),
|
|
175
|
+
artifactTenantId: identifier(input.artifactTenantId, "artifactTenantId"),
|
|
176
|
+
audience: identifier(input.audience, "audience"),
|
|
177
|
+
purpose: identifier(input.purpose, "purpose"),
|
|
178
|
+
planDigest: digest(input.planDigest, "planDigest"),
|
|
179
|
+
durabilityAuthorityId: identifier(
|
|
180
|
+
input.durabilityAuthorityId,
|
|
181
|
+
"durabilityAuthorityId",
|
|
182
|
+
),
|
|
183
|
+
};
|
|
184
|
+
return deepFreeze({
|
|
185
|
+
...core,
|
|
186
|
+
descriptorDigest: hash(
|
|
187
|
+
"chainlesschain.pm-exploration-ledger-descriptor/v1",
|
|
188
|
+
core,
|
|
189
|
+
),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function captureDurabilityAuthority(value) {
|
|
194
|
+
exact(value, DURABILITY_AUTHORITY_KEYS, "artifact durability authority");
|
|
195
|
+
const retain = Object.getOwnPropertyDescriptor(value, "retain").value;
|
|
196
|
+
const resolve = Object.getOwnPropertyDescriptor(value, "resolve").value;
|
|
197
|
+
if (
|
|
198
|
+
typeof retain !== "function" ||
|
|
199
|
+
typeof resolve !== "function" ||
|
|
200
|
+
isProxy(retain) ||
|
|
201
|
+
isProxy(resolve)
|
|
202
|
+
) {
|
|
203
|
+
throw new TypeError(
|
|
204
|
+
"artifact durability authority requires direct retain and resolve methods",
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return Object.freeze({
|
|
208
|
+
id: identifier(value.id, "artifact durability authority id"),
|
|
209
|
+
retain: retain.bind(value),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function snapshotPlan(plan) {
|
|
214
|
+
verifyPmExplorationPlan(plan);
|
|
215
|
+
return deepFreeze(structuredClone(plan));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function normalizeSnapshot(plan, snapshot) {
|
|
219
|
+
const restored = restorePmExplorationJournal(plan, snapshot);
|
|
220
|
+
return exportPmExplorationRecoverySnapshot(restored);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function parseRecord(resolution, descriptor, plan) {
|
|
224
|
+
if (
|
|
225
|
+
resolution?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
226
|
+
resolution.authenticated !== true ||
|
|
227
|
+
resolution.found !== true ||
|
|
228
|
+
!DIGEST.test(resolution.digest ?? "") ||
|
|
229
|
+
!DIGEST.test(resolution.receiptDigest ?? "") ||
|
|
230
|
+
!Buffer.isBuffer(resolution.bytes)
|
|
231
|
+
) {
|
|
232
|
+
corrupt("PM exploration artifact resolution is unauthenticated");
|
|
233
|
+
}
|
|
234
|
+
let durable;
|
|
235
|
+
const encoded = resolution.bytes.toString("utf8");
|
|
236
|
+
try {
|
|
237
|
+
durable = JSON.parse(encoded);
|
|
238
|
+
} catch (cause) {
|
|
239
|
+
corrupt("PM exploration artifact is not JSON", { cause });
|
|
240
|
+
}
|
|
241
|
+
if (
|
|
242
|
+
durable?.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
243
|
+
durable.tenantId !== descriptor.artifactTenantId ||
|
|
244
|
+
durable.audience !== descriptor.audience ||
|
|
245
|
+
durable.purpose !== descriptor.purpose ||
|
|
246
|
+
durable.retention !== "ledger" ||
|
|
247
|
+
durable.type !== ARTIFACT_TYPE
|
|
248
|
+
) {
|
|
249
|
+
corrupt("PM exploration durable artifact binding is invalid");
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
exact(durable.value, RECORD_KEYS, "PM exploration ledger record");
|
|
253
|
+
} catch (cause) {
|
|
254
|
+
corrupt("PM exploration ledger record shape is invalid", { cause });
|
|
255
|
+
}
|
|
256
|
+
const record = durable.value;
|
|
257
|
+
if (
|
|
258
|
+
record.schema !== PM_EXPLORATION_LEDGER_RECORD_SCHEMA ||
|
|
259
|
+
record.descriptorDigest !== descriptor.descriptorDigest ||
|
|
260
|
+
!Number.isSafeInteger(record.revision) ||
|
|
261
|
+
record.revision < 1 ||
|
|
262
|
+
(record.priorSnapshotDigest !== null &&
|
|
263
|
+
!DIGEST.test(record.priorSnapshotDigest ?? "")) ||
|
|
264
|
+
!DIGEST.test(record.snapshotDigest ?? "") ||
|
|
265
|
+
!Number.isSafeInteger(record.committedAt) ||
|
|
266
|
+
record.committedAt < 0
|
|
267
|
+
) {
|
|
268
|
+
corrupt("PM exploration ledger record fields are invalid");
|
|
269
|
+
}
|
|
270
|
+
let snapshot;
|
|
271
|
+
try {
|
|
272
|
+
snapshot = normalizeSnapshot(plan, record.snapshot);
|
|
273
|
+
} catch (cause) {
|
|
274
|
+
corrupt("PM exploration recovery snapshot is invalid", { cause });
|
|
275
|
+
}
|
|
276
|
+
if (
|
|
277
|
+
snapshot.snapshotDigest !== record.snapshotDigest ||
|
|
278
|
+
!same(snapshot, record.snapshot)
|
|
279
|
+
) {
|
|
280
|
+
corrupt("PM exploration recovery snapshot readback differs");
|
|
281
|
+
}
|
|
282
|
+
return deepFreeze({ ...record, snapshot });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function assertSnapshotExtension(previous, next) {
|
|
286
|
+
if (!previous) return;
|
|
287
|
+
if (previous.frozen !== null)
|
|
288
|
+
conflict("frozen PM exploration state cannot be extended");
|
|
289
|
+
if (next.checkpoints.length < previous.checkpoints.length)
|
|
290
|
+
conflict("PM exploration snapshot would roll back checkpoints");
|
|
291
|
+
if (
|
|
292
|
+
!same(
|
|
293
|
+
next.checkpoints.slice(0, previous.checkpoints.length),
|
|
294
|
+
previous.checkpoints,
|
|
295
|
+
)
|
|
296
|
+
) {
|
|
297
|
+
conflict("PM exploration checkpoint history is not append-only");
|
|
298
|
+
}
|
|
299
|
+
const rank = { broad: 0, "broad-complete": 1, deep: 2, frozen: 3 };
|
|
300
|
+
if (rank[next.stage] < rank[previous.stage])
|
|
301
|
+
conflict("PM exploration stage would move backwards");
|
|
302
|
+
if (previous.merge !== null && !same(previous.merge, next.merge))
|
|
303
|
+
conflict("PM exploration merge evidence changed after commit");
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function sameHead(left, right) {
|
|
307
|
+
return [
|
|
308
|
+
"epoch",
|
|
309
|
+
"ledgerId",
|
|
310
|
+
"identityDigest",
|
|
311
|
+
"sequence",
|
|
312
|
+
"headDigest",
|
|
313
|
+
].every((key) => left?.[key] === right?.[key]);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function acknowledgement(descriptor, entry, recovered) {
|
|
317
|
+
return deepFreeze({
|
|
318
|
+
schema: PM_EXPLORATION_LEDGER_ACK_SCHEMA,
|
|
319
|
+
authenticated: true,
|
|
320
|
+
durable: true,
|
|
321
|
+
ledgerAuthenticated: true,
|
|
322
|
+
ledgerDurable: true,
|
|
323
|
+
artifactPersisted: true,
|
|
324
|
+
artifactReadbackVerified: true,
|
|
325
|
+
durabilityAuthorityId: descriptor.durabilityAuthorityId,
|
|
326
|
+
authorityDurable: true,
|
|
327
|
+
powerLossDurabilityTested: false,
|
|
328
|
+
descriptorDigest: descriptor.descriptorDigest,
|
|
329
|
+
revision: entry.record.revision,
|
|
330
|
+
snapshotDigest: entry.record.snapshotDigest,
|
|
331
|
+
ledgerEventDigest: entry.event.eventDigest,
|
|
332
|
+
recovered,
|
|
333
|
+
snapshotAuthenticated: false,
|
|
334
|
+
qualifiesForPromotion: false,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export class PmExplorationLedgerAdapter {
|
|
339
|
+
#append;
|
|
340
|
+
#clock;
|
|
341
|
+
#plan;
|
|
342
|
+
#put;
|
|
343
|
+
#read;
|
|
344
|
+
#resolve;
|
|
345
|
+
#retain;
|
|
346
|
+
#verify;
|
|
347
|
+
|
|
348
|
+
constructor({
|
|
349
|
+
descriptor: input,
|
|
350
|
+
plan,
|
|
351
|
+
artifactPorts,
|
|
352
|
+
artifactDurabilityAuthority,
|
|
353
|
+
ledger,
|
|
354
|
+
ledgerArtifactResolver,
|
|
355
|
+
now = Date.now,
|
|
356
|
+
} = {}) {
|
|
357
|
+
this.descriptor = normalizeDescriptor(input);
|
|
358
|
+
this.#plan = snapshotPlan(plan);
|
|
359
|
+
if (this.#plan.planDigest !== this.descriptor.planDigest)
|
|
360
|
+
throw new TypeError("PM exploration plan differs from ledger descriptor");
|
|
361
|
+
const trustedArtifactPorts = requireExactInstance(
|
|
362
|
+
artifactPorts,
|
|
363
|
+
EvolutionArtifactPorts.prototype,
|
|
364
|
+
"EvolutionArtifactPorts",
|
|
365
|
+
);
|
|
366
|
+
const trustedLedger = requireExactInstance(
|
|
367
|
+
ledger,
|
|
368
|
+
EvolutionLedger.prototype,
|
|
369
|
+
"EvolutionLedger",
|
|
370
|
+
);
|
|
371
|
+
this.#put =
|
|
372
|
+
EvolutionArtifactPorts.prototype.putCanonical.bind(trustedArtifactPorts);
|
|
373
|
+
this.#read = EvolutionLedger.prototype.read.bind(trustedLedger);
|
|
374
|
+
this.#verify = EvolutionLedger.prototype.verify.bind(trustedLedger);
|
|
375
|
+
this.#append =
|
|
376
|
+
EvolutionLedger.prototype.appendDomainEvent.bind(trustedLedger);
|
|
377
|
+
const durabilityAuthority = captureDurabilityAuthority(
|
|
378
|
+
artifactDurabilityAuthority,
|
|
379
|
+
);
|
|
380
|
+
if (durabilityAuthority.id !== this.descriptor.durabilityAuthorityId)
|
|
381
|
+
throw new TypeError(
|
|
382
|
+
"artifact durability authority differs from ledger descriptor",
|
|
383
|
+
);
|
|
384
|
+
const resolverBinding = captureEvolutionLedgerDurableArtifactResolver(
|
|
385
|
+
ledgerArtifactResolver,
|
|
386
|
+
);
|
|
387
|
+
if (
|
|
388
|
+
resolverBinding.authorityId !== durabilityAuthority.id ||
|
|
389
|
+
resolverBinding.artifactTenantId !== this.descriptor.artifactTenantId ||
|
|
390
|
+
resolverBinding.purpose !== this.descriptor.purpose ||
|
|
391
|
+
!resolverBinding.matchesArtifactPorts(trustedArtifactPorts) ||
|
|
392
|
+
!resolverBinding.matchesDurabilityAuthority(artifactDurabilityAuthority)
|
|
393
|
+
) {
|
|
394
|
+
throw new TypeError(
|
|
395
|
+
"durable artifact resolver differs from PM ledger authorities",
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (typeof now !== "function" || isProxy(now))
|
|
399
|
+
throw new TypeError("now must be a direct function");
|
|
400
|
+
this.#resolve = ledgerArtifactResolver;
|
|
401
|
+
this.#retain = durabilityAuthority.retain;
|
|
402
|
+
this.#clock = now;
|
|
403
|
+
STORE_PORTS.set(
|
|
404
|
+
this,
|
|
405
|
+
Object.freeze({
|
|
406
|
+
load: () => this.load(),
|
|
407
|
+
commitJournal: (journal) => this.commitJournal(journal),
|
|
408
|
+
restoreLatestJournal: () => this.restoreLatestJournal(),
|
|
409
|
+
}),
|
|
410
|
+
);
|
|
411
|
+
Object.freeze(this);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
#events() {
|
|
415
|
+
const events = this.#read();
|
|
416
|
+
if (!Array.isArray(events))
|
|
417
|
+
corrupt("EvolutionLedger did not return an event array");
|
|
418
|
+
return events.filter(
|
|
419
|
+
(event) =>
|
|
420
|
+
event.schema === EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA &&
|
|
421
|
+
event.type === PM_EXPLORATION_LEDGER_EVENT_TYPE &&
|
|
422
|
+
event.tenantId === this.descriptor.tenantId &&
|
|
423
|
+
event.correlationId === this.descriptor.planDigest,
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
#resolveEvent(event, identity) {
|
|
428
|
+
const resolution = this.#resolve({
|
|
429
|
+
epoch: identity.epoch,
|
|
430
|
+
ledgerId: identity.ledgerId,
|
|
431
|
+
ref: event.subjectRef,
|
|
432
|
+
tenantId: this.descriptor.artifactTenantId,
|
|
433
|
+
});
|
|
434
|
+
if (
|
|
435
|
+
resolution?.ref !== event.subjectRef?.ref ||
|
|
436
|
+
resolution?.digest !== event.subjectRef?.digest
|
|
437
|
+
) {
|
|
438
|
+
corrupt("PM exploration ledger subject was substituted");
|
|
439
|
+
}
|
|
440
|
+
return parseRecord(resolution, this.descriptor, this.#plan);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
#historyWithIdentity() {
|
|
444
|
+
const before = this.#verify();
|
|
445
|
+
const events = this.#events();
|
|
446
|
+
const history = [];
|
|
447
|
+
for (const [index, event] of events.entries()) {
|
|
448
|
+
const previous = history.at(-1) ?? null;
|
|
449
|
+
const record = this.#resolveEvent(event, before);
|
|
450
|
+
if (
|
|
451
|
+
record.revision !== index + 1 ||
|
|
452
|
+
record.priorSnapshotDigest !==
|
|
453
|
+
(previous?.record.snapshotDigest ?? null) ||
|
|
454
|
+
event.artifactTenantId !== this.descriptor.artifactTenantId ||
|
|
455
|
+
event.decision !== "committed" ||
|
|
456
|
+
event.skillName !== null ||
|
|
457
|
+
event.eventId !==
|
|
458
|
+
`${PM_EXPLORATION_LEDGER_EVENT_TYPE}.${record.snapshotDigest.slice(7)}` ||
|
|
459
|
+
event.reason !==
|
|
460
|
+
`PM exploration recovery snapshot revision ${record.revision} committed` ||
|
|
461
|
+
event.timestamp !== new Date(record.committedAt).toISOString() ||
|
|
462
|
+
!DIGEST.test(event.eventDigest ?? "") ||
|
|
463
|
+
!Array.isArray(event.sourceRefs) ||
|
|
464
|
+
event.sourceRefs.length !== (previous ? 1 : 0) ||
|
|
465
|
+
(previous && !same(event.sourceRefs[0], previous.event.subjectRef))
|
|
466
|
+
) {
|
|
467
|
+
corrupt("PM exploration ledger history is invalid");
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
assertSnapshotExtension(
|
|
471
|
+
previous?.record.snapshot ?? null,
|
|
472
|
+
record.snapshot,
|
|
473
|
+
);
|
|
474
|
+
} catch (cause) {
|
|
475
|
+
corrupt("PM exploration ledger snapshot history is discontinuous", {
|
|
476
|
+
cause,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
history.push(deepFreeze({ event, record }));
|
|
480
|
+
}
|
|
481
|
+
const after = this.#verify();
|
|
482
|
+
if (!sameHead(before, after))
|
|
483
|
+
conflict("PM exploration ledger changed during authenticated read");
|
|
484
|
+
return deepFreeze({ history, identity: after });
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
load() {
|
|
488
|
+
const latest = this.#historyWithIdentity().history.at(-1) ?? null;
|
|
489
|
+
if (!latest) return null;
|
|
490
|
+
return deepFreeze({
|
|
491
|
+
schema: PM_EXPLORATION_LEDGER_RESTORE_SCHEMA,
|
|
492
|
+
authenticated: true,
|
|
493
|
+
durable: true,
|
|
494
|
+
ledgerAuthenticated: true,
|
|
495
|
+
ledgerDurable: true,
|
|
496
|
+
artifactPersisted: true,
|
|
497
|
+
artifactReadbackVerified: true,
|
|
498
|
+
durabilityAuthorityId: this.descriptor.durabilityAuthorityId,
|
|
499
|
+
authorityDurable: true,
|
|
500
|
+
powerLossDurabilityTested: false,
|
|
501
|
+
descriptorDigest: this.descriptor.descriptorDigest,
|
|
502
|
+
revision: latest.record.revision,
|
|
503
|
+
snapshotDigest: latest.record.snapshotDigest,
|
|
504
|
+
ledgerEventDigest: latest.event.eventDigest,
|
|
505
|
+
snapshot: latest.record.snapshot,
|
|
506
|
+
snapshotAuthenticated: false,
|
|
507
|
+
qualifiesForPromotion: false,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
restoreLatestJournal() {
|
|
512
|
+
const evidence = this.load();
|
|
513
|
+
if (evidence === null) return null;
|
|
514
|
+
const journal = restorePmExplorationJournal(this.#plan, evidence.snapshot);
|
|
515
|
+
return Object.freeze({ journal, evidence });
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
commitJournal(journal) {
|
|
519
|
+
let snapshot;
|
|
520
|
+
try {
|
|
521
|
+
snapshot = exportPmExplorationRecoverySnapshot(journal);
|
|
522
|
+
} catch (cause) {
|
|
523
|
+
if (cause?.message?.includes("Active rounds")) throw cause;
|
|
524
|
+
corrupt("PM exploration journal cannot produce a recovery snapshot", {
|
|
525
|
+
cause,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
if (snapshot.planDigest !== this.descriptor.planDigest)
|
|
529
|
+
conflict("PM exploration journal belongs to another plan");
|
|
530
|
+
const { history, identity } = this.#historyWithIdentity();
|
|
531
|
+
const latest = history.at(-1) ?? null;
|
|
532
|
+
if (latest?.record.snapshotDigest === snapshot.snapshotDigest)
|
|
533
|
+
return acknowledgement(this.descriptor, latest, true);
|
|
534
|
+
assertSnapshotExtension(latest?.record.snapshot ?? null, snapshot);
|
|
535
|
+
|
|
536
|
+
const revision = history.length + 1;
|
|
537
|
+
const committedAt = Number(this.#clock());
|
|
538
|
+
if (!Number.isSafeInteger(committedAt) || committedAt < 0)
|
|
539
|
+
throw new TypeError("PM exploration ledger clock is invalid");
|
|
540
|
+
const record = deepFreeze({
|
|
541
|
+
schema: PM_EXPLORATION_LEDGER_RECORD_SCHEMA,
|
|
542
|
+
descriptorDigest: this.descriptor.descriptorDigest,
|
|
543
|
+
revision,
|
|
544
|
+
priorSnapshotDigest: latest?.record.snapshotDigest ?? null,
|
|
545
|
+
snapshotDigest: snapshot.snapshotDigest,
|
|
546
|
+
snapshot,
|
|
547
|
+
committedAt,
|
|
548
|
+
});
|
|
549
|
+
const published = this.#put(ARTIFACT_TYPE, record, {
|
|
550
|
+
audience: this.descriptor.audience,
|
|
551
|
+
purpose: this.descriptor.purpose,
|
|
552
|
+
retention: "ledger",
|
|
553
|
+
});
|
|
554
|
+
if (
|
|
555
|
+
!published?.ref ||
|
|
556
|
+
published.digest !== published.ref.digest ||
|
|
557
|
+
published.receipt?.persisted !== true ||
|
|
558
|
+
published.receipt.readbackVerified !== true ||
|
|
559
|
+
published.receipt.integrityVerified !== true ||
|
|
560
|
+
published.receipt.retention !== "ledger"
|
|
561
|
+
) {
|
|
562
|
+
corrupt("PM exploration snapshot persistence was not confirmed");
|
|
563
|
+
}
|
|
564
|
+
const durableRecord = deepFreeze({
|
|
565
|
+
audience: this.descriptor.audience,
|
|
566
|
+
purpose: this.descriptor.purpose,
|
|
567
|
+
retention: "ledger",
|
|
568
|
+
schema: EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
569
|
+
tenantId: this.descriptor.artifactTenantId,
|
|
570
|
+
type: ARTIFACT_TYPE,
|
|
571
|
+
value: record,
|
|
572
|
+
});
|
|
573
|
+
const durableBytes = Buffer.from(canonical(durableRecord), "utf8");
|
|
574
|
+
if (sha256Bytes(durableBytes) !== published.digest)
|
|
575
|
+
corrupt("PM exploration canonical artifact bytes differ after publish");
|
|
576
|
+
const durabilityBinding = deepFreeze({
|
|
577
|
+
artifactTenantId: this.descriptor.artifactTenantId,
|
|
578
|
+
digest: published.digest,
|
|
579
|
+
purpose: this.descriptor.purpose,
|
|
580
|
+
ref: published.ref.ref,
|
|
581
|
+
retention: "ledger",
|
|
582
|
+
schema: EVOLUTION_ARTIFACT_DURABILITY_BINDING_SCHEMA,
|
|
583
|
+
type: ARTIFACT_TYPE,
|
|
584
|
+
});
|
|
585
|
+
const durabilityReceipt = this.#retain(
|
|
586
|
+
Object.freeze({
|
|
587
|
+
binding: durabilityBinding,
|
|
588
|
+
bytes: Buffer.from(durableBytes),
|
|
589
|
+
schema: EVOLUTION_ARTIFACT_DURABILITY_RETAIN_REQUEST_SCHEMA,
|
|
590
|
+
}),
|
|
591
|
+
);
|
|
592
|
+
if (isPromise(durabilityReceipt))
|
|
593
|
+
corrupt("PM exploration durability retain must be synchronous");
|
|
594
|
+
try {
|
|
595
|
+
exact(
|
|
596
|
+
durabilityReceipt,
|
|
597
|
+
DURABILITY_RECEIPT_KEYS,
|
|
598
|
+
"PM exploration durability receipt",
|
|
599
|
+
);
|
|
600
|
+
} catch (cause) {
|
|
601
|
+
corrupt("PM exploration durability receipt shape is invalid", { cause });
|
|
602
|
+
}
|
|
603
|
+
if (
|
|
604
|
+
durabilityReceipt.schema !==
|
|
605
|
+
EVOLUTION_ARTIFACT_DURABILITY_RECEIPT_SCHEMA ||
|
|
606
|
+
durabilityReceipt.authenticated !== true ||
|
|
607
|
+
durabilityReceipt.durable !== true ||
|
|
608
|
+
durabilityReceipt.authorityId !== this.descriptor.durabilityAuthorityId ||
|
|
609
|
+
durabilityReceipt.artifactTenantId !==
|
|
610
|
+
durabilityBinding.artifactTenantId ||
|
|
611
|
+
durabilityReceipt.digest !== durabilityBinding.digest ||
|
|
612
|
+
durabilityReceipt.purpose !== durabilityBinding.purpose ||
|
|
613
|
+
durabilityReceipt.ref !== durabilityBinding.ref ||
|
|
614
|
+
durabilityReceipt.retention !== durabilityBinding.retention ||
|
|
615
|
+
durabilityReceipt.type !== durabilityBinding.type ||
|
|
616
|
+
!DIGEST.test(durabilityReceipt.receiptDigest ?? "")
|
|
617
|
+
) {
|
|
618
|
+
corrupt("PM exploration artifact was not durably retained");
|
|
619
|
+
}
|
|
620
|
+
const eventId = `${PM_EXPLORATION_LEDGER_EVENT_TYPE}.${snapshot.snapshotDigest.slice(7)}`;
|
|
621
|
+
try {
|
|
622
|
+
const receipt = this.#append(
|
|
623
|
+
{
|
|
624
|
+
artifactTenantId: this.descriptor.artifactTenantId,
|
|
625
|
+
correlationId: this.descriptor.planDigest,
|
|
626
|
+
decision: "committed",
|
|
627
|
+
eventId,
|
|
628
|
+
reason: `PM exploration recovery snapshot revision ${revision} committed`,
|
|
629
|
+
skillName: null,
|
|
630
|
+
sourceRefs: latest ? [latest.event.subjectRef] : [],
|
|
631
|
+
subjectRef: published.ref,
|
|
632
|
+
tenantId: this.descriptor.tenantId,
|
|
633
|
+
timestamp: new Date(committedAt).toISOString(),
|
|
634
|
+
type: PM_EXPLORATION_LEDGER_EVENT_TYPE,
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
expectedHeadDigest: identity.headDigest,
|
|
638
|
+
expectedSequence: identity.sequence,
|
|
639
|
+
},
|
|
640
|
+
);
|
|
641
|
+
if (
|
|
642
|
+
receipt?.authenticated !== true ||
|
|
643
|
+
receipt.committed !== true ||
|
|
644
|
+
receipt.durable !== true ||
|
|
645
|
+
receipt.eventId !== eventId ||
|
|
646
|
+
!DIGEST.test(receipt.receiptDigest ?? "")
|
|
647
|
+
) {
|
|
648
|
+
corrupt("PM exploration ledger append was not durably authenticated");
|
|
649
|
+
}
|
|
650
|
+
} catch (cause) {
|
|
651
|
+
const recovered = this.#historyWithIdentity().history.at(-1) ?? null;
|
|
652
|
+
if (recovered?.record.snapshotDigest !== snapshot.snapshotDigest)
|
|
653
|
+
throw cause;
|
|
654
|
+
return acknowledgement(this.descriptor, recovered, true);
|
|
655
|
+
}
|
|
656
|
+
const stored = this.#historyWithIdentity().history.at(-1) ?? null;
|
|
657
|
+
if (
|
|
658
|
+
stored?.record.revision !== revision ||
|
|
659
|
+
stored.record.snapshotDigest !== snapshot.snapshotDigest
|
|
660
|
+
) {
|
|
661
|
+
corrupt("PM exploration snapshot readback differs after commit");
|
|
662
|
+
}
|
|
663
|
+
return acknowledgement(this.descriptor, stored, false);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export function capturePmExplorationLedgerStore(adapter) {
|
|
668
|
+
const ports = STORE_PORTS.get(adapter);
|
|
669
|
+
if (!ports)
|
|
670
|
+
throw new TypeError("a real PmExplorationLedgerAdapter is required");
|
|
671
|
+
return ports;
|
|
672
|
+
}
|