chainlesschain 0.166.92 → 0.166.94
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 +16 -7
- 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-C74YzqwJ.js → AIOps-CzxfrB7_.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-TFef1hOE.js → ActionButton-6a4WFIb0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYsWpkkU.js → Analytics-O3Hv5QVR.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFf9kjwu.js → AppLayout-D96Jtyrz.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-TQqa94YO.js → Artifacts-BxbCrGsv.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B79ayqfS.js → Audit-Dvhj3ev4.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-pjkHfLP9.js → BackgroundAgents-zgrU13eK.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CE6A-t_r.js → Backup-B3ePsQ8z.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CwcgWMBY.js → BaseInput-CemgxVZi.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BIkDNesY.js → Chat-BNxuigZo.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-DgaokYts.js → ChatBubbleRenderer-DE73IMLf.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-MbypIy5V.js → Checkbox-BvHaZkOM.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DiFHWDnt.js → Codegen--DNXNLnq.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BNMlYMso.js → Col-C8xvHu-3.js} +1 -1
- package/src/assets/web-panel/assets/{Community-B3HVyHOX.js → Community-v19Cxqtl.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C7hlAubb.js → Compact-BdQ659sW.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-PaXZu6sE.js → Compliance-CE0-97Ph.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BGiojbm-.js → Cowork-YCuhzIZE.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Bmr-1QAx.js → Cron-C5xa6iEB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BwUvWCVd.js → Crosschain-CmsyQp8f.js} +1 -1
- package/src/assets/web-panel/assets/{DID-k_4QZocW.js → DID-FY-oN652.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-_ieRo2C5.js → Dashboard-CFJD_yB7.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DYHh6T27.js → Dropdown-QM5qyalT.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BNlQcWQX.js → EmailListRenderer-BbA-SPX0.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-DIkZ6U2D.js → EvolutionSettings-BGH3oR71.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dq7qSr0P.js → FamilyGuardDashboard-C4s2LeR4.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C64e3Cbx.js → Federation-Cfb8190f.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-D-GE2vUa.js → FormItemContext-DFVYcD2A.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DO3B2gis.js → GenericCardRenderer-CU-yqT1M.js} +1 -1
- package/src/assets/web-panel/assets/{Git-0ETirIQH.js → Git-tYiQuWYO.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C9fnRygX.js → Governance-DRH8tKKy.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CLJ9RTsK.js → Inference-v2GbRYb4.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-D3C_GxrN.js → KnowledgeGraph-B5Ff0wSA.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-C5ctGbkN.js → Logs-mcHQsQZC.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Ce-eWK3j.js → MarkdownRenderer-rk-aXvLV.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-GF_t6hJ_.js → Marketplace-LUstH49t.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BGsGzgQs.js → McpTools-kFFP54H9.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-CcrY2A0j.js → Memory--KBUL4b_.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bi4T0RlS.js → MobileBridge-CQL_xVyD.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DoIR8HA0.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-DL77Vf-k.js → Mtc-BrUPLX-C.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-CDy_Uswb.js → MtcAudit-46jjW0Ne.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DL0BAO_c.js → Multisig-3XX8crha.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-B-woh5IR.js → NLProgramming-C53SRk52.js} +1 -1
- package/src/assets/web-panel/assets/Notes-RxpNEOb6.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-BqPPMuAP.js → NotificationSettings-C2R6A0rD.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Bhhp4H-K.js +1 -0
- package/src/assets/web-panel/assets/{Organization-B1gX8jlr.js → Organization-B48YmG99.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CeMxuUZy.js → Overflow-BYPoJ7Qo.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5aIRWwJ.js → P2P-CI9F_5Xz.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-6rYgejd4.js → PdhVaultBrowser-C50vLFTe.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CqCp2SIl.js → Permissions-CKMhcV4D.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BsA7DJWW.js → PersonalDataHub-CFwVht-l.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CiW6HeZh.js → Pipeline-BQliRCrn.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DckUOLYq.js → Privacy-z-9F-MIF.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CZppOOYR.js → ProjectInit-DAuaSe48.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B9QPzhDU.js → ProjectSettings-BpCCZLAx.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BErjjGha.js → Projects-CguDJz4k.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DehU6Qiz.js → Providers-DOXv8vOy.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-E1SUvv1m.js → QrScannerModal-BiMsPToH.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-COWFxyH3.js → QuickAsk-Dxjfq39w.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-D26pWKxX.js → Recommend-Y5kQ_a2f.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DCOIaId3.js → RemoteSession-BSIDk0es.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DT_AHGAR.js → Reputation-BLjwaybi.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B50S-1nl.js → Row-7geSc2GW.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BaBnHg3Q.js → RssFeed-BophPGWk.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BVdnLuuS.js → Search-iBXsRvIQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BnacH74J.js → Security-sM5aX0dn.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CxM08Zch.js → Services-8n708_pG.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DE7CIc1N.js → Skeleton-D2rl_ikr.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CGI0SJmf.js → Skills-DJpknGnz.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DpEzPcqc.js → Sla-mA8eEXRj.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CTmnmMHn.js → SpeechSettings-BVrmiTgd.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Dxgrd9hd.js → SyncSettings-Cd-KRX72.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CW4slS0A.js → Tasks-DYAvmen_.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DxvGWDgB.js → Templates-DPdlYX7S.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-_Q0o2tNK.js → Tenant-wfSNgGDT.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BTZn8pow.js → Terminal-BqJDIQEC.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CauL0KFe.js → TimelineRenderer-eeuMKufC.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CDoM2qeT.js → Tokens-DW9xE5CY.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B-QYGEU7.js → Trigger-BBniBnCp.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BD6XJHT-.js → Trust-C7fZAxYI.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-x4TFwCy0.js → UkeySign-X_cT1LN_.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-t3imBK_0.js → VideoEditing-C95qSEAg.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BCfkWwNC.js → Wallet-_Y76V1eI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-WH314Mdm.js → WebAuthn-CUpi7QWI.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-jUlcjrUg.js → WorkflowEditor-CdTwu4JZ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Dg3VASTL.js → chat-D2hW7s3x.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BNvmBRKE.js → colors-Cxes7tn4.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BGOfoqf4.js → compact-item-BuLnefA8.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BNQeqKAs.js → createContext-DSJr7jrZ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BHLx7Ctv.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bg3AjCrq.js → hasIn-CPtCYTi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-2D04Zltx.js → index--J0mLXrw.js} +3 -3
- package/src/assets/web-panel/assets/{index-COol3xfA.js → index--gm5GIKK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcCnO0RU.js → index-5Vtfy09g.js} +1 -1
- package/src/assets/web-panel/assets/{index-fOwii3LP.js → index-B5GXCqB0.js} +1 -1
- package/src/assets/web-panel/assets/{index-OUFoxUgH.js → index-BC-FDx0Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bkz1tgFR.js → index-BDaNLJss.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLwEXRrb.js → index-BOKMxs4C.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBCMulQ-.js → index-BOXgWdJY.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_JmInC0.js → index-BSHkOFqM.js} +1 -1
- package/src/assets/web-panel/assets/{index-pVdQieac.js → index-B_mChW9O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmTacaQV.js → index-Bq-CMI2h.js} +1 -1
- package/src/assets/web-panel/assets/{index-Wo0f2iqb.js → index-BudaM8zA.js} +1 -1
- package/src/assets/web-panel/assets/{index-B--0QM0S.js → index-C2qdbxEw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaPvEvB4.js → index-C6jDeixf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dkp-okWa.js → index-C88mhge1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSNhW95G.js → index-C8xMmdFz.js} +1 -1
- package/src/assets/web-panel/assets/{index-7QJUWemf.js → index-CCI2rS5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-xzaUx19r.js → index-CFTO4avR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cbp-wp-U.js → index-CVgzXcvk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co_LnCWD.js → index-C_RLdbKl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY8cRKHR.js → index-CighFQgt.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0mgngoB.js → index-CmV_i-tY.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZD5Kd8tx.js → index-Ct9hZUrk.js} +1 -1
- package/src/assets/web-panel/assets/{index-uH2LnAs_.js → index-D4YILZTK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCFZN66A.js → index-DDSmCL8t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYn5DnDk.js → index-DFSJeXBu.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx2EXRfr.js → index-DGIumCxN.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6UqK83L.js → index-DIkV-pwg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO0VlNtc.js → index-DTtVX2yD.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_O2ZjPk.js → index-Dz6h62uC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-mSvCQK.js → index-PyLgXmQZ.js} +1 -1
- package/src/assets/web-panel/assets/index-V4IYxvvE.js +1 -0
- package/src/assets/web-panel/assets/{index--I3UF5t1.js → index-_AYMw6sF.js} +1 -1
- package/src/assets/web-panel/assets/{index-hG7jXGEW.js → index-ePTIQg1n.js} +1 -1
- package/src/assets/web-panel/assets/{index-60AnjUTX.js → index-f1fHG0MC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DS04wRll.js → index-lOl7QbP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DF_FKSVH.js → index-vsUYvuDU.js} +1 -1
- package/src/assets/web-panel/assets/index-y4vqXg0S.js +1 -0
- package/src/assets/web-panel/assets/{index-D072oLjp.js → index-ystQEkV4.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B8PN9AxJ.js → initDefaultProps-CAxtYUKo.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BHivfw5Q.js → motion-CgPmr4vy.js} +1 -1
- package/src/assets/web-panel/assets/{move-B0QU5nDd.js → move-XGK3_B35.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DRwRM3PE.js → mtc-parser-C6Vfqz8e.js} +1 -1
- package/src/assets/web-panel/assets/{omit-SHt2rV2p.js → omit-DquSN-3H.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CcmDlEb2.js → pickAttrs-BH-ir5eD.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DYatmXDS.js → placementArrow-Drf-QXk8.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B7qrsXq5.js → responsiveObserve-BUBMbJsH.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BRGhlOWd.js → slide-BCqinMKC.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CT-7NXsQ.js → statusUtils-CAp3-0Ss.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-rZdw_Yyp.js → styleChecker-DIuQh0dB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D8YNIP4P.js → useFlexGapSupport-CWXPAfZR.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-B8pt0Gu-.js → useFs-905ulWWY.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-VMmYM1tt.js → usePersonalDataHub-DajnovG6.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-UNDuoPoq.js → vnode-BE_Yg3pz.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-dN-u667S.js → zoom-BLndEna7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +26 -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 +209 -129
- package/src/lib/evolution/rrsi-history-ledger-adapter.js +25 -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-observed-text-index.js +978 -0
- package/src/lib/evolution/rrsi-registry-runtime-policy.js +648 -0
- package/src/lib/evolution/rrsi-registry-store-policy.js +95 -15
- 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-release-registry.js +20 -5
- package/src/lib/process-execution-broker/windows-native-evaluator-capabilities.js +291 -30
- package/src/lib/process-execution-broker/windows-native-evaluator.js +247 -28
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +140 -6
- package/src/lib/remote-read-loop-guard.js +227 -24
- package/src/lib/settings-loader.cjs +10 -1
- package/src/lib/task-progress-tracker.js +6 -1
- package/src/lib/with-file-lock.js +86 -16
- package/src/runtime/agent-core.js +71 -23
- package/src/assets/web-panel/assets/MobileProjects-DvjEGyvf.js +0 -1
- package/src/assets/web-panel/assets/Notes-CEFVCxk7.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-GUKQ1xwp.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B7_ypN1G.js +0 -1
- package/src/assets/web-panel/assets/index-B-jSKJK6.js +0 -1
- package/src/assets/web-panel/assets/index-P4FXZJqI.js +0 -1
|
@@ -0,0 +1,978 @@
|
|
|
1
|
+
/** Retained observations and prohibitions, never proof of causal generation. */
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { isProxy } from "node:util/types";
|
|
4
|
+
import { captureRrsiRegistryStorePolicy } from "./rrsi-registry-store-policy.js";
|
|
5
|
+
import { captureEvolutionLedgerFileBackend } from "./evolution-ledger-file-backend.js";
|
|
6
|
+
import {
|
|
7
|
+
EvolutionArtifactPorts,
|
|
8
|
+
EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA,
|
|
9
|
+
captureEvolutionArtifactStoreDirectoryBoundary,
|
|
10
|
+
} from "./evolution-artifact-ports.js";
|
|
11
|
+
import {
|
|
12
|
+
EVOLUTION_ARTIFACT_REF_SCHEMA,
|
|
13
|
+
EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA,
|
|
14
|
+
EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA,
|
|
15
|
+
EVOLUTION_LEDGER_MAX_EVENTS,
|
|
16
|
+
} from "./evolution-ledger.js";
|
|
17
|
+
import {
|
|
18
|
+
captureRrsiHistoryLedgerAdapter,
|
|
19
|
+
RRSI_HISTORY_EVENT_TYPE,
|
|
20
|
+
RRSI_HISTORY_EVENT_SCHEMA,
|
|
21
|
+
} from "./rrsi-history-ledger-adapter.js";
|
|
22
|
+
import {
|
|
23
|
+
rrsiCanonical,
|
|
24
|
+
rrsiHash,
|
|
25
|
+
rrsiDigest,
|
|
26
|
+
rrsiInteger,
|
|
27
|
+
rrsiId,
|
|
28
|
+
rrsiExact,
|
|
29
|
+
rrsiEnvelope,
|
|
30
|
+
snapshotRrsiData,
|
|
31
|
+
freezeRrsiData,
|
|
32
|
+
} from "./rrsi-data.js";
|
|
33
|
+
|
|
34
|
+
export const RRSI_OBSERVED_TEXT_MAX_BYTES = 1024 * 1024;
|
|
35
|
+
export const RRSI_OBSERVED_TEXT_CHUNK_BYTES = 64 * 1024;
|
|
36
|
+
export const RRSI_OBSERVED_TEXT_EVENT_TYPE =
|
|
37
|
+
"rrsi.content-restriction.observed";
|
|
38
|
+
export const RRSI_OBSERVED_TEXT_HOLD_CODE = "CC_RRSI_CONTENT_PROVENANCE_HOLD";
|
|
39
|
+
const CHUNK_TYPE = "rrsi-observed-text-chunk";
|
|
40
|
+
const MANIFEST_TYPE = "rrsi-observed-text-manifest";
|
|
41
|
+
const EVENT_TYPE = "rrsi-content-restriction-event";
|
|
42
|
+
const CHUNK_SCHEMA = "chainlesschain.rrsi-observed-text-chunk/v1";
|
|
43
|
+
const MANIFEST_SCHEMA = "chainlesschain.rrsi-observed-text-manifest/v1";
|
|
44
|
+
const RECORD_SCHEMA = "chainlesschain.rrsi-content-restriction-event/v1";
|
|
45
|
+
const INDEX_SCHEMA = "chainlesschain.rrsi-observed-text-index/v1";
|
|
46
|
+
const MAX_RECORDS = 256;
|
|
47
|
+
const REQUIRED = ["generation-unverified", "rrsi-evidence-required"];
|
|
48
|
+
const CODES = [
|
|
49
|
+
...REQUIRED,
|
|
50
|
+
"source-conflict",
|
|
51
|
+
"cross-pool-exposure",
|
|
52
|
+
"publication-incomplete",
|
|
53
|
+
];
|
|
54
|
+
const INDEXES = new WeakMap();
|
|
55
|
+
const hashBytes = (bytes) =>
|
|
56
|
+
`sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
57
|
+
const same = (a, b) => rrsiCanonical(a) === rrsiCanonical(b);
|
|
58
|
+
const head = (value) =>
|
|
59
|
+
Object.fromEntries(
|
|
60
|
+
["ledgerId", "identityDigest", "epoch", "sequence", "headDigest"].map(
|
|
61
|
+
(key) => [key, value[key]],
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
const identity = (value) =>
|
|
65
|
+
Object.fromEntries(
|
|
66
|
+
["ledgerId", "identityDigest", "epoch"].map((key) => [key, value[key]]),
|
|
67
|
+
);
|
|
68
|
+
function hold(message, cause) {
|
|
69
|
+
throw Object.assign(new Error(message, cause ? { cause } : undefined), {
|
|
70
|
+
code: RRSI_OBSERVED_TEXT_HOLD_CODE,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function guarded(operation) {
|
|
74
|
+
try {
|
|
75
|
+
return operation();
|
|
76
|
+
} catch (cause) {
|
|
77
|
+
if (
|
|
78
|
+
[
|
|
79
|
+
RRSI_OBSERVED_TEXT_HOLD_CODE,
|
|
80
|
+
"STATE_LOCK_OWNERSHIP_LOST",
|
|
81
|
+
"CC_RRSI_TEXT_COMMIT_UNKNOWN",
|
|
82
|
+
].includes(cause?.code)
|
|
83
|
+
)
|
|
84
|
+
throw cause;
|
|
85
|
+
hold("observed text index could not authenticate its boundary", cause);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function own(input, names) {
|
|
89
|
+
if (
|
|
90
|
+
!input ||
|
|
91
|
+
isProxy(input) ||
|
|
92
|
+
Object.getPrototypeOf(input) !== Object.prototype ||
|
|
93
|
+
Reflect.ownKeys(input).length !== names.length
|
|
94
|
+
)
|
|
95
|
+
hold("observed text requires plain own fields");
|
|
96
|
+
return Object.fromEntries(
|
|
97
|
+
names.map((name) => {
|
|
98
|
+
const field = Object.getOwnPropertyDescriptor(input, name);
|
|
99
|
+
if (!field?.enumerable || !("value" in field))
|
|
100
|
+
hold("observed text cannot use accessors");
|
|
101
|
+
return [name, field.value];
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
function ref(value) {
|
|
106
|
+
if (isProxy(value)) hold("observed text reference cannot be a proxy");
|
|
107
|
+
const copied = Object.fromEntries(
|
|
108
|
+
["schema", "ref", "digest"].map((key) => {
|
|
109
|
+
const field = Object.getOwnPropertyDescriptor(value, key);
|
|
110
|
+
if (!field?.enumerable || !("value" in field))
|
|
111
|
+
hold("observed text requires original own reference data");
|
|
112
|
+
return [key, field.value];
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
if (copied.schema !== EVOLUTION_ARTIFACT_REF_SCHEMA)
|
|
116
|
+
hold("observed text reference schema differs");
|
|
117
|
+
rrsiDigest(copied.digest, "artifact digest");
|
|
118
|
+
if (typeof copied.ref !== "string" || copied.ref.length > 256)
|
|
119
|
+
hold("observed text reference is invalid");
|
|
120
|
+
return copied;
|
|
121
|
+
}
|
|
122
|
+
function sortedRefs(values) {
|
|
123
|
+
const compare = (a, b) => (a === b ? 0 : a < b ? -1 : 1);
|
|
124
|
+
return values
|
|
125
|
+
.map(ref)
|
|
126
|
+
.sort((a, b) => compare(a.ref, b.ref) || compare(a.digest, b.digest));
|
|
127
|
+
}
|
|
128
|
+
/** Strings preserve BOM, CRLF and Unicode; lone surrogates are rejected. */
|
|
129
|
+
export function encodeRrsiObservedSkillText(text) {
|
|
130
|
+
if (typeof text !== "string") hold("Skill text must be a string");
|
|
131
|
+
if (
|
|
132
|
+
text.length < 1 ||
|
|
133
|
+
text.length > RRSI_OBSERVED_TEXT_MAX_BYTES ||
|
|
134
|
+
Buffer.byteLength(text, "utf8") > RRSI_OBSERVED_TEXT_MAX_BYTES
|
|
135
|
+
)
|
|
136
|
+
hold("Skill text exceeds its nonempty 1 MiB bound");
|
|
137
|
+
const bytes = Buffer.from(text, "utf8");
|
|
138
|
+
if (bytes.length < 1 || bytes.length > RRSI_OBSERVED_TEXT_MAX_BYTES)
|
|
139
|
+
hold("Skill text exceeds its nonempty 1 MiB bound");
|
|
140
|
+
const decoded = new TextDecoder("utf-8", {
|
|
141
|
+
fatal: true,
|
|
142
|
+
ignoreBOM: true,
|
|
143
|
+
}).decode(bytes);
|
|
144
|
+
if (decoded !== text) hold("Skill text does not roundtrip as exact UTF-8");
|
|
145
|
+
return bytes;
|
|
146
|
+
}
|
|
147
|
+
function restrictions(input) {
|
|
148
|
+
const values = snapshotRrsiData(input);
|
|
149
|
+
if (
|
|
150
|
+
!Array.isArray(values) ||
|
|
151
|
+
values.length > CODES.length ||
|
|
152
|
+
values.some((code) => !CODES.includes(code)) ||
|
|
153
|
+
new Set(values).size !== values.length
|
|
154
|
+
)
|
|
155
|
+
hold("text restrictions must be distinct supported prohibition codes");
|
|
156
|
+
return [...new Set([...REQUIRED, ...values])].sort();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function createRrsiObservedTextIndex(input) {
|
|
160
|
+
const options = own(input, [
|
|
161
|
+
"storePolicy",
|
|
162
|
+
"backend",
|
|
163
|
+
"artifactPorts",
|
|
164
|
+
"ledgerArtifactResolver",
|
|
165
|
+
]);
|
|
166
|
+
const policy = captureRrsiRegistryStorePolicy(options.storePolicy);
|
|
167
|
+
const backend = captureEvolutionLedgerFileBackend(options.backend);
|
|
168
|
+
if (
|
|
169
|
+
!policy.matchesBackend(backend) ||
|
|
170
|
+
!policy.matchesArtifactPorts(options.artifactPorts) ||
|
|
171
|
+
!policy.matchesArtifactResolver(options.ledgerArtifactResolver)
|
|
172
|
+
)
|
|
173
|
+
hold("text index requires the original policy storage graph");
|
|
174
|
+
const ledger = backend.ledger;
|
|
175
|
+
const artifactBoundary = captureEvolutionArtifactStoreDirectoryBoundary(
|
|
176
|
+
options.artifactPorts,
|
|
177
|
+
);
|
|
178
|
+
if (
|
|
179
|
+
artifactBoundary.descriptor.artifactTenantId !==
|
|
180
|
+
policy.descriptor.artifactTenantId ||
|
|
181
|
+
artifactBoundary.descriptor.audience !== policy.descriptor.audience
|
|
182
|
+
)
|
|
183
|
+
hold("text index artifact directory boundary scope differs");
|
|
184
|
+
const artifactStoreDirectoryBoundaryDigest = rrsiHash(
|
|
185
|
+
"chainlesschain.rrsi-file-artifact-store-directory-boundary/v1",
|
|
186
|
+
artifactBoundary.descriptor,
|
|
187
|
+
);
|
|
188
|
+
const methods = Object.fromEntries(
|
|
189
|
+
["verify", "read", "appendDomainEvent"].map((name) => {
|
|
190
|
+
const method = Object.getOwnPropertyDescriptor(ledger, name)?.value;
|
|
191
|
+
if (!Object.isFrozen(ledger) || typeof method !== "function")
|
|
192
|
+
hold("text index requires original frozen v2 journal methods");
|
|
193
|
+
return [name, (...args) => Reflect.apply(method, ledger, args)];
|
|
194
|
+
}),
|
|
195
|
+
);
|
|
196
|
+
const originalIdentity = freezeRrsiData(identity(methods.verify()));
|
|
197
|
+
const descriptor = freezeRrsiData({
|
|
198
|
+
schema: INDEX_SCHEMA,
|
|
199
|
+
tenantId: policy.descriptor.tenantId,
|
|
200
|
+
artifactTenantId: policy.descriptor.artifactTenantId,
|
|
201
|
+
audience: policy.descriptor.audience,
|
|
202
|
+
purpose: policy.descriptor.purpose,
|
|
203
|
+
indexId: `rrsi-text.${rrsiHash(INDEX_SCHEMA, policy.descriptor.tenantId).slice(7)}`,
|
|
204
|
+
ledgerIdentity: originalIdentity,
|
|
205
|
+
observationBoundary: "authenticated-retained-readback",
|
|
206
|
+
tenantWideIndexAuthorityVerified: false,
|
|
207
|
+
generationProvenanceVerified: false,
|
|
208
|
+
grantsMutationOrPromotionAuthority: false,
|
|
209
|
+
});
|
|
210
|
+
const context = {
|
|
211
|
+
audience: descriptor.audience,
|
|
212
|
+
purpose: descriptor.purpose,
|
|
213
|
+
retention: "ledger",
|
|
214
|
+
};
|
|
215
|
+
function resolve(reference, type, validate) {
|
|
216
|
+
const copied = ref(reference);
|
|
217
|
+
const resolution = options.ledgerArtifactResolver({
|
|
218
|
+
ledgerId: originalIdentity.ledgerId,
|
|
219
|
+
epoch: originalIdentity.epoch,
|
|
220
|
+
ref: copied,
|
|
221
|
+
tenantId: descriptor.artifactTenantId,
|
|
222
|
+
});
|
|
223
|
+
if (
|
|
224
|
+
resolution?.schema !== EVOLUTION_ARTIFACT_RESOLUTION_SCHEMA ||
|
|
225
|
+
resolution.authenticated !== true ||
|
|
226
|
+
resolution.found !== true ||
|
|
227
|
+
resolution.ref !== copied.ref ||
|
|
228
|
+
resolution.digest !== copied.digest ||
|
|
229
|
+
!Buffer.isBuffer(resolution.bytes) ||
|
|
230
|
+
resolution.bytes.length > 1024 * 1024
|
|
231
|
+
)
|
|
232
|
+
hold("retained text artifact cannot be authenticated");
|
|
233
|
+
const stored = JSON.parse(
|
|
234
|
+
new TextDecoder("utf-8", { fatal: true }).decode(resolution.bytes),
|
|
235
|
+
);
|
|
236
|
+
rrsiExact(
|
|
237
|
+
stored,
|
|
238
|
+
[
|
|
239
|
+
"schema",
|
|
240
|
+
"tenantId",
|
|
241
|
+
"audience",
|
|
242
|
+
"purpose",
|
|
243
|
+
"retention",
|
|
244
|
+
"type",
|
|
245
|
+
"value",
|
|
246
|
+
],
|
|
247
|
+
"retained text record",
|
|
248
|
+
);
|
|
249
|
+
if (
|
|
250
|
+
stored.schema !== EVOLUTION_DURABLE_ARTIFACT_RECORD_SCHEMA ||
|
|
251
|
+
stored.tenantId !== descriptor.artifactTenantId ||
|
|
252
|
+
stored.audience !== descriptor.audience ||
|
|
253
|
+
stored.purpose !== descriptor.purpose ||
|
|
254
|
+
stored.retention !== "ledger" ||
|
|
255
|
+
stored.type !== type
|
|
256
|
+
)
|
|
257
|
+
hold("retained text artifact scope or retention differs");
|
|
258
|
+
const validated = validate(stored.value);
|
|
259
|
+
if (!Buffer.from(rrsiCanonical(stored)).equals(resolution.bytes))
|
|
260
|
+
hold("retained text artifact is not exact canonical bytes");
|
|
261
|
+
return validated;
|
|
262
|
+
}
|
|
263
|
+
function publish(type, value, assertOwnership, validate) {
|
|
264
|
+
assertOwnership();
|
|
265
|
+
const result = Reflect.apply(
|
|
266
|
+
EvolutionArtifactPorts.prototype.putCanonical,
|
|
267
|
+
options.artifactPorts,
|
|
268
|
+
[type, value, context],
|
|
269
|
+
);
|
|
270
|
+
if (
|
|
271
|
+
result?.receipt?.persisted !== true ||
|
|
272
|
+
result.receipt.integrityVerified !== true ||
|
|
273
|
+
result.receipt.readbackVerified !== true ||
|
|
274
|
+
result.receipt.retention !== "ledger" ||
|
|
275
|
+
!same(resolve(result.ref, type, validate), value)
|
|
276
|
+
)
|
|
277
|
+
hold("text artifact publication cannot be retained exactly");
|
|
278
|
+
assertOwnership();
|
|
279
|
+
return ref(result.ref);
|
|
280
|
+
}
|
|
281
|
+
function validateChunk(value) {
|
|
282
|
+
rrsiExact(
|
|
283
|
+
value,
|
|
284
|
+
["schema", "byteLength", "chunkDigest", "bytesBase64"],
|
|
285
|
+
"text chunk",
|
|
286
|
+
);
|
|
287
|
+
if (
|
|
288
|
+
value.schema !== CHUNK_SCHEMA ||
|
|
289
|
+
!Number.isSafeInteger(value.byteLength) ||
|
|
290
|
+
value.byteLength < 1 ||
|
|
291
|
+
value.byteLength > RRSI_OBSERVED_TEXT_CHUNK_BYTES ||
|
|
292
|
+
typeof value.bytesBase64 !== "string" ||
|
|
293
|
+
value.bytesBase64.length >
|
|
294
|
+
4 * Math.ceil(RRSI_OBSERVED_TEXT_CHUNK_BYTES / 3)
|
|
295
|
+
)
|
|
296
|
+
hold("text chunk exceeds its bound");
|
|
297
|
+
const bytes = Buffer.from(value.bytesBase64, "base64");
|
|
298
|
+
if (
|
|
299
|
+
bytes.length !== value.byteLength ||
|
|
300
|
+
bytes.toString("base64") !== value.bytesBase64 ||
|
|
301
|
+
hashBytes(bytes) !== value.chunkDigest
|
|
302
|
+
)
|
|
303
|
+
hold("text chunk bytes or digest differ");
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
function validateManifest(input) {
|
|
307
|
+
const value = snapshotRrsiData(input);
|
|
308
|
+
rrsiExact(
|
|
309
|
+
value,
|
|
310
|
+
["schema", "skillTextDigest", "byteLength", "chunks"],
|
|
311
|
+
"text manifest",
|
|
312
|
+
);
|
|
313
|
+
rrsiDigest(value.skillTextDigest, "Skill text digest");
|
|
314
|
+
if (
|
|
315
|
+
value.schema !== MANIFEST_SCHEMA ||
|
|
316
|
+
!Number.isSafeInteger(value.byteLength) ||
|
|
317
|
+
value.byteLength < 1 ||
|
|
318
|
+
value.byteLength > RRSI_OBSERVED_TEXT_MAX_BYTES ||
|
|
319
|
+
!Array.isArray(value.chunks) ||
|
|
320
|
+
value.chunks.length !==
|
|
321
|
+
Math.ceil(value.byteLength / RRSI_OBSERVED_TEXT_CHUNK_BYTES)
|
|
322
|
+
)
|
|
323
|
+
hold("text manifest length or chunk count differs");
|
|
324
|
+
value.chunks.forEach((entry) => {
|
|
325
|
+
rrsiExact(entry, ["ref", "byteLength", "chunkDigest"], "manifest chunk");
|
|
326
|
+
ref(entry.ref);
|
|
327
|
+
rrsiDigest(entry.chunkDigest, "chunk digest");
|
|
328
|
+
});
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
331
|
+
function readBytes(reference, expectedDigest) {
|
|
332
|
+
const manifest = resolve(reference, MANIFEST_TYPE, validateManifest);
|
|
333
|
+
if (manifest.skillTextDigest !== expectedDigest)
|
|
334
|
+
hold("text manifest belongs to another Skill text digest");
|
|
335
|
+
const chunks = manifest.chunks.map((entry, index) => {
|
|
336
|
+
const value = resolve(entry.ref, CHUNK_TYPE, validateChunk);
|
|
337
|
+
if (
|
|
338
|
+
value.chunkDigest !== entry.chunkDigest ||
|
|
339
|
+
value.byteLength !== entry.byteLength ||
|
|
340
|
+
value.byteLength !==
|
|
341
|
+
Math.min(
|
|
342
|
+
RRSI_OBSERVED_TEXT_CHUNK_BYTES,
|
|
343
|
+
manifest.byteLength - index * RRSI_OBSERVED_TEXT_CHUNK_BYTES,
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
hold("text chunk order or actual length differs");
|
|
347
|
+
return Buffer.from(value.bytesBase64, "base64");
|
|
348
|
+
});
|
|
349
|
+
const bytes = Buffer.concat(chunks, manifest.byteLength);
|
|
350
|
+
if (
|
|
351
|
+
bytes.length !== manifest.byteLength ||
|
|
352
|
+
hashBytes(bytes) !== expectedDigest
|
|
353
|
+
)
|
|
354
|
+
hold("reconstructed Skill text digest differs");
|
|
355
|
+
const text = new TextDecoder("utf-8", {
|
|
356
|
+
fatal: true,
|
|
357
|
+
ignoreBOM: true,
|
|
358
|
+
}).decode(bytes);
|
|
359
|
+
if (!encodeRrsiObservedSkillText(text).equals(bytes))
|
|
360
|
+
hold("retained text does not roundtrip as exact UTF-8");
|
|
361
|
+
return text;
|
|
362
|
+
}
|
|
363
|
+
function retain(bytes, assertOwnership) {
|
|
364
|
+
const chunks = [];
|
|
365
|
+
for (
|
|
366
|
+
let offset = 0;
|
|
367
|
+
offset < bytes.length;
|
|
368
|
+
offset += RRSI_OBSERVED_TEXT_CHUNK_BYTES
|
|
369
|
+
) {
|
|
370
|
+
const chunk = bytes.subarray(
|
|
371
|
+
offset,
|
|
372
|
+
offset + RRSI_OBSERVED_TEXT_CHUNK_BYTES,
|
|
373
|
+
);
|
|
374
|
+
const value = {
|
|
375
|
+
schema: CHUNK_SCHEMA,
|
|
376
|
+
byteLength: chunk.length,
|
|
377
|
+
chunkDigest: hashBytes(chunk),
|
|
378
|
+
bytesBase64: chunk.toString("base64"),
|
|
379
|
+
};
|
|
380
|
+
chunks.push({
|
|
381
|
+
ref: publish(CHUNK_TYPE, value, assertOwnership, validateChunk),
|
|
382
|
+
byteLength: value.byteLength,
|
|
383
|
+
chunkDigest: value.chunkDigest,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
const value = {
|
|
387
|
+
schema: MANIFEST_SCHEMA,
|
|
388
|
+
skillTextDigest: hashBytes(bytes),
|
|
389
|
+
byteLength: bytes.length,
|
|
390
|
+
chunks,
|
|
391
|
+
};
|
|
392
|
+
return publish(MANIFEST_TYPE, value, assertOwnership, validateManifest);
|
|
393
|
+
}
|
|
394
|
+
function validateRecord(input) {
|
|
395
|
+
const value = snapshotRrsiData(input);
|
|
396
|
+
const keys = [
|
|
397
|
+
"descriptor",
|
|
398
|
+
"ordinal",
|
|
399
|
+
"skillTextDigest",
|
|
400
|
+
"manifestRef",
|
|
401
|
+
"association",
|
|
402
|
+
"restrictions",
|
|
403
|
+
"previousRecordDigest",
|
|
404
|
+
"observedHead",
|
|
405
|
+
];
|
|
406
|
+
rrsiExact(
|
|
407
|
+
value,
|
|
408
|
+
[
|
|
409
|
+
"schema",
|
|
410
|
+
...keys,
|
|
411
|
+
"recordDigest",
|
|
412
|
+
"structuralOnly",
|
|
413
|
+
"authenticated",
|
|
414
|
+
"readyForExecution",
|
|
415
|
+
"qualifiesForPromotion",
|
|
416
|
+
],
|
|
417
|
+
"text restriction record",
|
|
418
|
+
);
|
|
419
|
+
if (
|
|
420
|
+
!same(
|
|
421
|
+
value,
|
|
422
|
+
rrsiEnvelope(
|
|
423
|
+
RECORD_SCHEMA,
|
|
424
|
+
"recordDigest",
|
|
425
|
+
Object.fromEntries(keys.map((key) => [key, value[key]])),
|
|
426
|
+
),
|
|
427
|
+
)
|
|
428
|
+
)
|
|
429
|
+
hold("text restriction envelope differs");
|
|
430
|
+
if (
|
|
431
|
+
!same(value.descriptor, descriptor) ||
|
|
432
|
+
!same(value.restrictions, restrictions(value.restrictions))
|
|
433
|
+
)
|
|
434
|
+
hold("text restriction scope or mandatory prohibitions differ");
|
|
435
|
+
rrsiDigest(value.skillTextDigest, "Skill text digest");
|
|
436
|
+
ref(value.manifestRef);
|
|
437
|
+
rrsiExact(
|
|
438
|
+
value.association,
|
|
439
|
+
[
|
|
440
|
+
"historyScopeId",
|
|
441
|
+
"goalId",
|
|
442
|
+
"campaignDigest",
|
|
443
|
+
"executionId",
|
|
444
|
+
"historyDescriptor",
|
|
445
|
+
"registrationRecord",
|
|
446
|
+
],
|
|
447
|
+
"preparation association",
|
|
448
|
+
);
|
|
449
|
+
rrsiExact(
|
|
450
|
+
value.association.registrationRecord,
|
|
451
|
+
["recordDigest", "ref", "sequence"],
|
|
452
|
+
"preparation registration",
|
|
453
|
+
);
|
|
454
|
+
rrsiDigest(value.association.campaignDigest, "associated campaign digest");
|
|
455
|
+
rrsiId(
|
|
456
|
+
value.association.executionId,
|
|
457
|
+
"associated preparation execution ID",
|
|
458
|
+
);
|
|
459
|
+
rrsiDigest(
|
|
460
|
+
value.association.registrationRecord.recordDigest,
|
|
461
|
+
"preparation record digest",
|
|
462
|
+
);
|
|
463
|
+
return value;
|
|
464
|
+
}
|
|
465
|
+
function verifyAssociation(
|
|
466
|
+
association,
|
|
467
|
+
events,
|
|
468
|
+
beforeSequence = events.length + 1,
|
|
469
|
+
historyCache = new Map(),
|
|
470
|
+
) {
|
|
471
|
+
const registration = association.registrationRecord;
|
|
472
|
+
if (
|
|
473
|
+
!Number.isSafeInteger(registration.sequence) ||
|
|
474
|
+
registration.sequence < 1 ||
|
|
475
|
+
registration.sequence >= beforeSequence
|
|
476
|
+
)
|
|
477
|
+
hold("preparation declaration must precede its text observation");
|
|
478
|
+
const event = events[registration.sequence - 1];
|
|
479
|
+
if (
|
|
480
|
+
!event ||
|
|
481
|
+
event.type !== RRSI_HISTORY_EVENT_TYPE ||
|
|
482
|
+
event.tenantId !== descriptor.tenantId ||
|
|
483
|
+
event.artifactTenantId !== descriptor.artifactTenantId ||
|
|
484
|
+
event.skillName !== association.goalId ||
|
|
485
|
+
event.correlationId !== association.historyScopeId ||
|
|
486
|
+
!same(ref(event.subjectRef), registration.ref)
|
|
487
|
+
)
|
|
488
|
+
hold("preparation registration is not in the original journal");
|
|
489
|
+
const expectedDescriptor = association.historyDescriptor;
|
|
490
|
+
rrsiExact(
|
|
491
|
+
expectedDescriptor,
|
|
492
|
+
[
|
|
493
|
+
"tenantId",
|
|
494
|
+
"artifactTenantId",
|
|
495
|
+
"goalId",
|
|
496
|
+
"audience",
|
|
497
|
+
"purpose",
|
|
498
|
+
"scopeId",
|
|
499
|
+
"settlementAuthority",
|
|
500
|
+
],
|
|
501
|
+
"associated History descriptor",
|
|
502
|
+
);
|
|
503
|
+
const expectedScope = `rrsi.${rrsiHash("chainlesschain.rrsi-history-scope/v1", { tenantId: descriptor.tenantId, goalId: association.goalId }).slice(7)}`;
|
|
504
|
+
if (
|
|
505
|
+
typeof association.goalId !== "string" ||
|
|
506
|
+
!/^[a-z][a-z0-9-]{0,127}$/u.test(association.goalId) ||
|
|
507
|
+
association.historyScopeId !== expectedScope
|
|
508
|
+
)
|
|
509
|
+
hold("associated History requires its canonical tenant and goal scope");
|
|
510
|
+
if (
|
|
511
|
+
expectedDescriptor.tenantId !== descriptor.tenantId ||
|
|
512
|
+
expectedDescriptor.artifactTenantId !== descriptor.artifactTenantId ||
|
|
513
|
+
expectedDescriptor.audience !== descriptor.audience ||
|
|
514
|
+
expectedDescriptor.purpose !== descriptor.purpose ||
|
|
515
|
+
expectedDescriptor.goalId !== association.goalId ||
|
|
516
|
+
expectedDescriptor.scopeId !== association.historyScopeId
|
|
517
|
+
)
|
|
518
|
+
hold("preparation declaration descriptor differs from its index scope");
|
|
519
|
+
const coreKeys = [
|
|
520
|
+
"descriptor",
|
|
521
|
+
"ledgerId",
|
|
522
|
+
"epoch",
|
|
523
|
+
"operationId",
|
|
524
|
+
"kind",
|
|
525
|
+
"payload",
|
|
526
|
+
"previousRecordDigest",
|
|
527
|
+
"acceptedAt",
|
|
528
|
+
];
|
|
529
|
+
const cacheKey = rrsiCanonical(expectedDescriptor);
|
|
530
|
+
if (!historyCache.has(cacheKey)) {
|
|
531
|
+
const declarations = new Map();
|
|
532
|
+
const operations = new Set();
|
|
533
|
+
let previous = null;
|
|
534
|
+
for (const item of events) {
|
|
535
|
+
if (
|
|
536
|
+
item.type !== RRSI_HISTORY_EVENT_TYPE ||
|
|
537
|
+
item.tenantId !== descriptor.tenantId ||
|
|
538
|
+
item.skillName !== association.goalId
|
|
539
|
+
)
|
|
540
|
+
continue;
|
|
541
|
+
if (
|
|
542
|
+
declarations.size >= 5000 ||
|
|
543
|
+
item.schema !== EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA ||
|
|
544
|
+
item.artifactTenantId !== descriptor.artifactTenantId ||
|
|
545
|
+
item.correlationId !== association.historyScopeId ||
|
|
546
|
+
item.decision !== "accepted"
|
|
547
|
+
)
|
|
548
|
+
hold("preparation declaration chain event scope differs");
|
|
549
|
+
const candidate = resolve(
|
|
550
|
+
item.subjectRef,
|
|
551
|
+
"rrsi-history-event",
|
|
552
|
+
snapshotRrsiData,
|
|
553
|
+
);
|
|
554
|
+
rrsiId(candidate.operationId, "History declaration operation ID");
|
|
555
|
+
if (operations.has(candidate.operationId))
|
|
556
|
+
hold("History declaration has duplicate operations");
|
|
557
|
+
operations.add(candidate.operationId);
|
|
558
|
+
const rebuilt = rrsiEnvelope(
|
|
559
|
+
RRSI_HISTORY_EVENT_SCHEMA,
|
|
560
|
+
"recordDigest",
|
|
561
|
+
Object.fromEntries(coreKeys.map((key) => [key, candidate[key]])),
|
|
562
|
+
);
|
|
563
|
+
const scopeDigest = rrsiHash(
|
|
564
|
+
"chainlesschain.rrsi-history-descriptor/v1",
|
|
565
|
+
expectedDescriptor,
|
|
566
|
+
);
|
|
567
|
+
const expectedId = `rrsi.${rrsiHash("chainlesschain.rrsi-history-operation/v1", { scopeDigest, operationId: candidate.operationId }).slice(7)}`;
|
|
568
|
+
if (
|
|
569
|
+
!same(candidate, rebuilt) ||
|
|
570
|
+
!same(candidate.descriptor, expectedDescriptor) ||
|
|
571
|
+
candidate.previousRecordDigest !== previous ||
|
|
572
|
+
candidate.ledgerId !== originalIdentity.ledgerId ||
|
|
573
|
+
candidate.epoch !== originalIdentity.epoch ||
|
|
574
|
+
candidate.acceptedAt !== item.timestamp ||
|
|
575
|
+
item.eventId !== expectedId
|
|
576
|
+
)
|
|
577
|
+
hold(
|
|
578
|
+
"preparation declaration envelope, predecessor or original event differs",
|
|
579
|
+
);
|
|
580
|
+
declarations.set(item.sequence, candidate);
|
|
581
|
+
previous = candidate.recordDigest;
|
|
582
|
+
}
|
|
583
|
+
historyCache.set(cacheKey, declarations);
|
|
584
|
+
}
|
|
585
|
+
const record = historyCache.get(cacheKey).get(registration.sequence);
|
|
586
|
+
if (
|
|
587
|
+
!record ||
|
|
588
|
+
event.sourceRefs.length !== 0 ||
|
|
589
|
+
record.recordDigest !== registration.recordDigest ||
|
|
590
|
+
record.ledgerId !== originalIdentity.ledgerId ||
|
|
591
|
+
record.epoch !== originalIdentity.epoch ||
|
|
592
|
+
record.kind !== "reserve-preparation" ||
|
|
593
|
+
record.payload.executionId !== association.executionId ||
|
|
594
|
+
record.payload.phase !== "candidate-proposal" ||
|
|
595
|
+
record.payload.campaignDigest !== association.campaignDigest
|
|
596
|
+
)
|
|
597
|
+
hold("preparation declaration reference differs");
|
|
598
|
+
}
|
|
599
|
+
function load() {
|
|
600
|
+
artifactBoundary.recheck();
|
|
601
|
+
const before = head(methods.verify());
|
|
602
|
+
if (!same(identity(before), originalIdentity))
|
|
603
|
+
hold("text index journal identity changed");
|
|
604
|
+
const events = methods.read({
|
|
605
|
+
afterSequence: 0,
|
|
606
|
+
limit: EVOLUTION_LEDGER_MAX_EVENTS,
|
|
607
|
+
});
|
|
608
|
+
if (
|
|
609
|
+
events.length !== before.sequence ||
|
|
610
|
+
events.some((event, index) => event.sequence !== index + 1) ||
|
|
611
|
+
(events.at(-1)?.eventDigest ?? null) !== before.headDigest
|
|
612
|
+
)
|
|
613
|
+
hold("text index requires complete contiguous journal history");
|
|
614
|
+
const historyCache = new Map();
|
|
615
|
+
const records = [],
|
|
616
|
+
entries = new Map(),
|
|
617
|
+
operations = new Map();
|
|
618
|
+
for (const event of events) {
|
|
619
|
+
if (event.type !== RRSI_OBSERVED_TEXT_EVENT_TYPE) continue;
|
|
620
|
+
if (
|
|
621
|
+
records.length >= MAX_RECORDS ||
|
|
622
|
+
event.schema !== EVOLUTION_LEDGER_DOMAIN_EVENT_SCHEMA ||
|
|
623
|
+
event.tenantId !== descriptor.tenantId ||
|
|
624
|
+
event.artifactTenantId !== descriptor.artifactTenantId ||
|
|
625
|
+
event.correlationId !== descriptor.indexId ||
|
|
626
|
+
event.skillName !== null ||
|
|
627
|
+
event.decision !== "quarantined"
|
|
628
|
+
)
|
|
629
|
+
hold("text restriction history scope or capacity differs");
|
|
630
|
+
const record = resolve(event.subjectRef, EVENT_TYPE, validateRecord);
|
|
631
|
+
const operationId = `rrsi-text.${rrsiHash(RECORD_SCHEMA, { skillTextDigest: record.skillTextDigest, association: record.association, restrictions: record.restrictions }).slice(7)}`;
|
|
632
|
+
if (
|
|
633
|
+
record.ordinal !== records.length + 1 ||
|
|
634
|
+
record.previousRecordDigest !==
|
|
635
|
+
(records.at(-1)?.record.recordDigest ?? null) ||
|
|
636
|
+
!same(record.observedHead, {
|
|
637
|
+
...originalIdentity,
|
|
638
|
+
sequence: event.sequence - 1,
|
|
639
|
+
headDigest: event.prevDigest,
|
|
640
|
+
}) ||
|
|
641
|
+
event.eventId !== operationId ||
|
|
642
|
+
operations.has(operationId) ||
|
|
643
|
+
!same(
|
|
644
|
+
event.sourceRefs.map(ref),
|
|
645
|
+
sortedRefs([
|
|
646
|
+
record.manifestRef,
|
|
647
|
+
record.association.registrationRecord.ref,
|
|
648
|
+
...(records.length ? [records.at(-1).ref] : []),
|
|
649
|
+
]),
|
|
650
|
+
)
|
|
651
|
+
)
|
|
652
|
+
hold("text restriction chain, operation or original head differs");
|
|
653
|
+
verifyAssociation(
|
|
654
|
+
record.association,
|
|
655
|
+
events,
|
|
656
|
+
event.sequence,
|
|
657
|
+
historyCache,
|
|
658
|
+
);
|
|
659
|
+
const text = readBytes(record.manifestRef, record.skillTextDigest);
|
|
660
|
+
const previous = entries.get(record.skillTextDigest);
|
|
661
|
+
if (previous && previous.text !== text)
|
|
662
|
+
hold("same text digest has conflicting retained bytes");
|
|
663
|
+
entries.set(record.skillTextDigest, {
|
|
664
|
+
text,
|
|
665
|
+
manifestRef: record.manifestRef,
|
|
666
|
+
restrictions: [
|
|
667
|
+
...new Set([
|
|
668
|
+
...(previous?.restrictions ?? []),
|
|
669
|
+
...record.restrictions,
|
|
670
|
+
]),
|
|
671
|
+
].sort(),
|
|
672
|
+
associations: [...(previous?.associations ?? []), record.association],
|
|
673
|
+
recordDigest: record.recordDigest,
|
|
674
|
+
});
|
|
675
|
+
const retained = {
|
|
676
|
+
record,
|
|
677
|
+
ref: ref(event.subjectRef),
|
|
678
|
+
eventSequence: event.sequence,
|
|
679
|
+
};
|
|
680
|
+
records.push(retained);
|
|
681
|
+
operations.set(operationId, retained);
|
|
682
|
+
}
|
|
683
|
+
if (!same(before, head(methods.verify())))
|
|
684
|
+
hold("text index journal changed during authenticated readback");
|
|
685
|
+
artifactBoundary.recheck();
|
|
686
|
+
return { head: before, events, records, entries, operations };
|
|
687
|
+
}
|
|
688
|
+
function historyPrefix(state, checkpoint) {
|
|
689
|
+
rrsiExact(
|
|
690
|
+
checkpoint,
|
|
691
|
+
["ledgerId", "identityDigest", "epoch", "sequence", "headDigest"],
|
|
692
|
+
"observed history checkpoint",
|
|
693
|
+
);
|
|
694
|
+
rrsiInteger(
|
|
695
|
+
checkpoint.sequence,
|
|
696
|
+
"observed history sequence",
|
|
697
|
+
1,
|
|
698
|
+
state.head.sequence,
|
|
699
|
+
);
|
|
700
|
+
rrsiDigest(checkpoint.headDigest, "observed history event head digest");
|
|
701
|
+
if (
|
|
702
|
+
!same(identity(checkpoint), originalIdentity) ||
|
|
703
|
+
state.events[checkpoint.sequence - 1].eventDigest !==
|
|
704
|
+
checkpoint.headDigest
|
|
705
|
+
)
|
|
706
|
+
hold("observed history checkpoint is not the original journal prefix");
|
|
707
|
+
const records = state.records.filter(
|
|
708
|
+
(entry) => entry.eventSequence <= checkpoint.sequence,
|
|
709
|
+
);
|
|
710
|
+
const entries = new Map();
|
|
711
|
+
for (const { record } of records)
|
|
712
|
+
entries.set(
|
|
713
|
+
record.skillTextDigest,
|
|
714
|
+
[
|
|
715
|
+
...new Set([
|
|
716
|
+
...(entries.get(record.skillTextDigest) ?? []),
|
|
717
|
+
...record.restrictions,
|
|
718
|
+
]),
|
|
719
|
+
].sort(),
|
|
720
|
+
);
|
|
721
|
+
const sorted = [...entries]
|
|
722
|
+
.sort(([a], [b]) => (a === b ? 0 : a < b ? -1 : 1))
|
|
723
|
+
.map(([skillTextDigest, codes]) => ({
|
|
724
|
+
skillTextDigest,
|
|
725
|
+
restrictions: codes,
|
|
726
|
+
}));
|
|
727
|
+
return freezeRrsiData({
|
|
728
|
+
checkpoint,
|
|
729
|
+
restrictionHistory: {
|
|
730
|
+
recordCount: records.length,
|
|
731
|
+
tailRecordDigest: records.at(-1)?.record.recordDigest ?? null,
|
|
732
|
+
restrictionsDigest: rrsiHash(
|
|
733
|
+
"chainlesschain.rrsi-observed-text-restriction-set/v1",
|
|
734
|
+
sorted,
|
|
735
|
+
),
|
|
736
|
+
},
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
function captureHistoryCheckpoints(input) {
|
|
740
|
+
const request = snapshotRrsiData(input);
|
|
741
|
+
rrsiExact(request, ["checkpoints"], "observed history checkpoint request");
|
|
742
|
+
if (!Array.isArray(request.checkpoints) || request.checkpoints.length > 2)
|
|
743
|
+
hold("observed history requires at most two checkpoints");
|
|
744
|
+
const state = load();
|
|
745
|
+
// Anchor v1 cannot represent the genuine null digest at sequence zero.
|
|
746
|
+
// Fresh v2 migration events are included in this nonempty event prefix.
|
|
747
|
+
const current = historyPrefix(state, state.head);
|
|
748
|
+
const prefixes = request.checkpoints.map((checkpoint) =>
|
|
749
|
+
historyPrefix(state, checkpoint),
|
|
750
|
+
);
|
|
751
|
+
const snapshot = rrsiEnvelope(
|
|
752
|
+
"chainlesschain.rrsi-observed-text-history-snapshot/v1",
|
|
753
|
+
"historySnapshotDigest",
|
|
754
|
+
{
|
|
755
|
+
tenantId: descriptor.tenantId,
|
|
756
|
+
indexId: descriptor.indexId,
|
|
757
|
+
ledgerIdentity: originalIdentity,
|
|
758
|
+
artifactScope: {
|
|
759
|
+
artifactTenantId: descriptor.artifactTenantId,
|
|
760
|
+
audience: descriptor.audience,
|
|
761
|
+
purpose: descriptor.purpose,
|
|
762
|
+
},
|
|
763
|
+
indexDescriptorDigest: rrsiHash(
|
|
764
|
+
"chainlesschain.rrsi-observed-text-index-descriptor/v1",
|
|
765
|
+
descriptor,
|
|
766
|
+
),
|
|
767
|
+
localCompositionDigest: rrsiHash(
|
|
768
|
+
"chainlesschain.rrsi-observed-text-local-composition/v1",
|
|
769
|
+
{
|
|
770
|
+
indexDescriptor: descriptor,
|
|
771
|
+
policyDescriptor: policy.descriptor,
|
|
772
|
+
backendDescriptor: backend.descriptor,
|
|
773
|
+
},
|
|
774
|
+
),
|
|
775
|
+
current,
|
|
776
|
+
prefixes,
|
|
777
|
+
localRetainedHistoryReplayed: true,
|
|
778
|
+
artifactStoreDirectoryBoundaryDigest,
|
|
779
|
+
artifactStoreDirectoryBoundaryRechecked: true,
|
|
780
|
+
artifactStoreBoundaryScope: "root-and-files-directories",
|
|
781
|
+
fullPhysicalStorageGraphVerified: false,
|
|
782
|
+
tenantWideIndexAuthorityVerified: false,
|
|
783
|
+
generationProvenanceVerified: false,
|
|
784
|
+
grantsMutationOrPromotionAuthority: false,
|
|
785
|
+
decision: "HOLD",
|
|
786
|
+
},
|
|
787
|
+
);
|
|
788
|
+
const recheck = () =>
|
|
789
|
+
guarded(() => {
|
|
790
|
+
artifactBoundary.recheck();
|
|
791
|
+
if (!same(state.head, head(methods.verify())))
|
|
792
|
+
hold("observed history head changed after prefix capture");
|
|
793
|
+
artifactBoundary.recheck();
|
|
794
|
+
return true;
|
|
795
|
+
});
|
|
796
|
+
recheck();
|
|
797
|
+
return Object.freeze({ snapshot, recheck });
|
|
798
|
+
}
|
|
799
|
+
function lookup(skillTextDigest) {
|
|
800
|
+
rrsiDigest(skillTextDigest, "Skill text digest");
|
|
801
|
+
const state = load();
|
|
802
|
+
const entry = state.entries.get(skillTextDigest);
|
|
803
|
+
if (!entry)
|
|
804
|
+
hold("unknown Skill text has no authenticated restriction record");
|
|
805
|
+
return { state, entry };
|
|
806
|
+
}
|
|
807
|
+
function readObservedText(skillTextDigest) {
|
|
808
|
+
return lookup(skillTextDigest).entry.text;
|
|
809
|
+
}
|
|
810
|
+
function inspectRestrictions(skillTextDigest) {
|
|
811
|
+
const { state, entry } = lookup(skillTextDigest);
|
|
812
|
+
return freezeRrsiData({
|
|
813
|
+
skillTextDigest,
|
|
814
|
+
manifestRef: entry.manifestRef,
|
|
815
|
+
restrictions: entry.restrictions,
|
|
816
|
+
associations: entry.associations,
|
|
817
|
+
recordDigest: entry.recordDigest,
|
|
818
|
+
currentHead: state.head,
|
|
819
|
+
observedBytesAuthenticated: true,
|
|
820
|
+
observationBoundary: descriptor.observationBoundary,
|
|
821
|
+
preparationDeclarationRetained: true,
|
|
822
|
+
generationProvenanceVerified: false,
|
|
823
|
+
sourceDerivationVerified: false,
|
|
824
|
+
tenantWideIndexAuthorityVerified: false,
|
|
825
|
+
decision: "HOLD",
|
|
826
|
+
readyForExecution: false,
|
|
827
|
+
qualifiesForPromotion: false,
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
function registerObservedSkillText(input) {
|
|
831
|
+
const request = own(input, [
|
|
832
|
+
"text",
|
|
833
|
+
"historyAdapter",
|
|
834
|
+
"preparationExecutionId",
|
|
835
|
+
"restrictionCodes",
|
|
836
|
+
]);
|
|
837
|
+
const bytes = encodeRrsiObservedSkillText(request.text);
|
|
838
|
+
const codes = restrictions(request.restrictionCodes);
|
|
839
|
+
rrsiId(request.preparationExecutionId, "preparation execution ID");
|
|
840
|
+
const history = captureRrsiHistoryLedgerAdapter(request.historyAdapter);
|
|
841
|
+
if (
|
|
842
|
+
history.ledger !== ledger ||
|
|
843
|
+
history.artifactPorts !== options.artifactPorts ||
|
|
844
|
+
history.ledgerArtifactResolver !== options.ledgerArtifactResolver ||
|
|
845
|
+
history.descriptor.tenantId !== descriptor.tenantId ||
|
|
846
|
+
history.descriptor.artifactTenantId !== descriptor.artifactTenantId ||
|
|
847
|
+
history.descriptor.audience !== descriptor.audience ||
|
|
848
|
+
history.descriptor.purpose !== descriptor.purpose
|
|
849
|
+
)
|
|
850
|
+
hold("text observation requires the same original History storage graph");
|
|
851
|
+
// Resolve History before taking the index/policy lock; no reversed lock nesting.
|
|
852
|
+
const preparation = history.resolvePreparation(
|
|
853
|
+
request.preparationExecutionId,
|
|
854
|
+
);
|
|
855
|
+
if (
|
|
856
|
+
preparation.reservation.bindings.phase !== "candidate-proposal" ||
|
|
857
|
+
!same(preparation.identity, originalIdentity)
|
|
858
|
+
)
|
|
859
|
+
hold(
|
|
860
|
+
"text observation requires an original candidate-proposal preparation",
|
|
861
|
+
);
|
|
862
|
+
const association = snapshotRrsiData({
|
|
863
|
+
historyScopeId: history.descriptor.scopeId,
|
|
864
|
+
goalId: history.descriptor.goalId,
|
|
865
|
+
campaignDigest: preparation.reservation.bindings.campaignDigest,
|
|
866
|
+
executionId: request.preparationExecutionId,
|
|
867
|
+
historyDescriptor: history.descriptor,
|
|
868
|
+
registrationRecord: preparation.registrationRecord,
|
|
869
|
+
});
|
|
870
|
+
return policy.maintain((assertOwnership) => {
|
|
871
|
+
const state = load();
|
|
872
|
+
const assertCurrent = () => {
|
|
873
|
+
assertOwnership();
|
|
874
|
+
if (!same(state.head, head(methods.verify())))
|
|
875
|
+
hold("text index head changed before artifact publication");
|
|
876
|
+
assertOwnership();
|
|
877
|
+
};
|
|
878
|
+
const skillTextDigest = hashBytes(bytes);
|
|
879
|
+
const operationId = `rrsi-text.${rrsiHash(RECORD_SCHEMA, { skillTextDigest, association, restrictions: codes }).slice(7)}`;
|
|
880
|
+
verifyAssociation(association, state.events);
|
|
881
|
+
if (state.operations.has(operationId))
|
|
882
|
+
return inspectRestrictions(skillTextDigest);
|
|
883
|
+
if (state.records.length >= MAX_RECORDS)
|
|
884
|
+
hold("text restriction log reached its bounded capacity");
|
|
885
|
+
const previous = state.entries.get(skillTextDigest);
|
|
886
|
+
if (previous && !encodeRrsiObservedSkillText(previous.text).equals(bytes))
|
|
887
|
+
hold("same Skill text digest conflicts with the observed bytes");
|
|
888
|
+
const manifestRef = previous?.manifestRef ?? retain(bytes, assertCurrent);
|
|
889
|
+
const record = rrsiEnvelope(RECORD_SCHEMA, "recordDigest", {
|
|
890
|
+
descriptor,
|
|
891
|
+
ordinal: state.records.length + 1,
|
|
892
|
+
skillTextDigest,
|
|
893
|
+
manifestRef,
|
|
894
|
+
association,
|
|
895
|
+
restrictions: codes,
|
|
896
|
+
previousRecordDigest: state.records.at(-1)?.record.recordDigest ?? null,
|
|
897
|
+
observedHead: state.head,
|
|
898
|
+
});
|
|
899
|
+
const reference = publish(
|
|
900
|
+
EVENT_TYPE,
|
|
901
|
+
record,
|
|
902
|
+
assertCurrent,
|
|
903
|
+
validateRecord,
|
|
904
|
+
);
|
|
905
|
+
if (!same(state.head, head(methods.verify())))
|
|
906
|
+
hold("text index head changed before commit");
|
|
907
|
+
assertOwnership();
|
|
908
|
+
try {
|
|
909
|
+
const receipt = methods.appendDomainEvent(
|
|
910
|
+
{
|
|
911
|
+
type: RRSI_OBSERVED_TEXT_EVENT_TYPE,
|
|
912
|
+
eventId: operationId,
|
|
913
|
+
tenantId: descriptor.tenantId,
|
|
914
|
+
artifactTenantId: descriptor.artifactTenantId,
|
|
915
|
+
correlationId: descriptor.indexId,
|
|
916
|
+
skillName: null,
|
|
917
|
+
decision: "quarantined",
|
|
918
|
+
reason:
|
|
919
|
+
"Retained text observation; generation and tenant-wide authority remain unverified",
|
|
920
|
+
sourceRefs: [
|
|
921
|
+
manifestRef,
|
|
922
|
+
association.registrationRecord.ref,
|
|
923
|
+
...(state.records.length ? [state.records.at(-1).ref] : []),
|
|
924
|
+
],
|
|
925
|
+
subjectRef: reference,
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
expectedHeadDigest: state.head.headDigest,
|
|
929
|
+
expectedSequence: state.head.sequence,
|
|
930
|
+
},
|
|
931
|
+
);
|
|
932
|
+
if (receipt?.authenticated !== true || receipt.durable !== true)
|
|
933
|
+
hold("text restriction commit receipt is uncertain");
|
|
934
|
+
} catch (cause) {
|
|
935
|
+
throw Object.assign(
|
|
936
|
+
new Error(
|
|
937
|
+
"text restriction commit is uncertain; re-read the original index",
|
|
938
|
+
{ cause },
|
|
939
|
+
),
|
|
940
|
+
{ code: "CC_RRSI_TEXT_COMMIT_UNKNOWN" },
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
assertOwnership();
|
|
944
|
+
const committed = load().operations.get(operationId);
|
|
945
|
+
if (committed?.record.recordDigest !== record.recordDigest)
|
|
946
|
+
hold("text restriction commit could not be read back exactly");
|
|
947
|
+
return inspectRestrictions(skillTextDigest);
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
// Reopen validates every retained declaration and chunk; an empty fresh
|
|
951
|
+
// graph still gives unknown/HOLD and never a non-RRSI admission default.
|
|
952
|
+
guarded(load);
|
|
953
|
+
const index = Object.freeze({
|
|
954
|
+
descriptor,
|
|
955
|
+
registerObservedSkillText: (input) =>
|
|
956
|
+
guarded(() => registerObservedSkillText(input)),
|
|
957
|
+
readObservedText: (digest) => guarded(() => readObservedText(digest)),
|
|
958
|
+
inspectRestrictions: (digest) => guarded(() => inspectRestrictions(digest)),
|
|
959
|
+
});
|
|
960
|
+
INDEXES.set(
|
|
961
|
+
index,
|
|
962
|
+
Object.freeze({
|
|
963
|
+
descriptor,
|
|
964
|
+
matchesPolicy: (value) => value === options.storePolicy,
|
|
965
|
+
readObservedText: index.readObservedText,
|
|
966
|
+
inspectRestrictions: index.inspectRestrictions,
|
|
967
|
+
captureHistoryCheckpoints: (input) =>
|
|
968
|
+
guarded(() => captureHistoryCheckpoints(input)),
|
|
969
|
+
}),
|
|
970
|
+
);
|
|
971
|
+
return index;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
export function captureRrsiObservedTextIndex(value) {
|
|
975
|
+
const captured = INDEXES.get(value);
|
|
976
|
+
if (!captured) hold("a genuine observed text index is required");
|
|
977
|
+
return captured;
|
|
978
|
+
}
|