Authorize M12 provenance epoch 2 baseline
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-27 22:06:43 +08:00
parent c2c65d3a09
commit c9684a544b
16 changed files with 813 additions and 177 deletions

View File

@@ -0,0 +1,19 @@
{
"schemaVersion": 1,
"decision": "APPROVED",
"epoch": 2,
"scope": "M12 provenance only",
"approvedBy": "wangdequan",
"authority": "project-owner",
"approvalSource": "explicit project-owner authorization in task conversation",
"approvedAt": "2026-08-27T21:11:58+08:00",
"restoredOriginals": 23,
"authorizedReplacements": 61,
"limitations": {
"fullHistoricalReproduction": false,
"replacementIsHistoricalRestoration": false,
"featureParityClaim": false,
"releaseLabel": "AUTHORIZED_REBASELINE_ONLY"
},
"policy": "The 61 replacement bindings may satisfy the approved current baseline, but must never be reported as recovery of the unavailable historical bytes."
}

View File

@@ -1,9 +1,9 @@
# WBV2-P8-003 status
- task: `WBV2-P8-003`; parent: `WBV2-P8-002`; status: `done`
- provenance epoch: `1`
- historical originals restored: `22/84`
- authorized replacements: `62/84`
- provenance epoch: `2`
- historical originals restored: `23/84`
- authorized replacements: `61/84`
- nextTask: `WBV2-P8-004`
The 22 exact Git-history matches remain immutable restorations. The other 62 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of the unavailable historical bytes.
The 23 exact matches remain immutable restorations. The other 61 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of unavailable historical bytes. Full historical reproduction remains false.

View File

@@ -2,8 +2,9 @@
- task: `WBV2-P8-004`; parent: `WBV2-P8-003`; status: `blocked`
- atomic Chromium receipts: `45/45`
- M12 provenance: `22 restored + 62 authorized replacements`
- release decision: `BLOCKED`
- M12 provenance epoch: `2`
- M12 provenance: `23 restored + 61 authorized replacements`
- release decision: `READY_WITH_AUTHORIZED_REBASELINE`
- nextTask: `NONE`
The recovery gate is internally consistent and fail-closed. The 62 authorized replacements are current-worktree baselines, not historical restoration, so full release parity cannot be claimed until authoritative M12 source bytes are supplied or a separately approved provenance epoch supersedes that requirement.
The project owner approved the new provenance baseline. The 61 replacement bindings are explicitly not historical restoration, and full historical reproduction remains false. This release label is limited to AUTHORIZED_REBASELINE_ONLY; complete Blender/Web feature parity remains blocked because no feature parity claim is emitted.

View File

@@ -1,20 +1,25 @@
{
"schemaVersion": 1,
"epoch": 1,
"epoch": 2,
"task": "WBV2-P8-003",
"operation": "M12_AUTHORIZED_PROVENANCE_REBASELINE",
"historicalEvidencePreserved": true,
"sourceSnapshot": "tests/golden/corrective/rehydration/M12-git-history-snapshot/snapshot-manifest.json",
"sourceSnapshotSha256": "e58b1804ed92f19855679f7cdca6787bffcfafbc59c007fd419077ed55a04b54",
"supplementalExactRecovery": "tests/golden/corrective/rehydration/M12-supplemental-exact-recovery.json",
"supplementalExactRecoverySha256": "a8947b6b5966dbd870a254a96e7ee26d606011c16cb5c5c3c315ac912eae0908",
"searchReport": "tests/golden/WBV2-P8-003/m12-source-recovery-search.json",
"searchReportSha256": "4192418563aabf011bb5d6c1407565c87bb492ab208eca69f4768ae35b126fc0",
"originalDriftReport": "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json",
"originalDriftReportSha256": "e35f4dcae87ce260d565dccfcdafb58a032d79141115a26b45b25dcbec3f31e1",
"originalIntake": "tests/golden/corrective/rehydration/M12-provenance-intake.json",
"originalIntakeSha256": "37a54d83eba799948fcaae798828915b35f8bf8e709bf90df21351d0288676d9",
"policy": {
"restoredOriginals": 22,
"authorizedReplacements": 62,
"restoredOriginals": 23,
"authorizedReplacements": 61,
"replacementsAreNotHistoricalRestorations": true,
"historicalManifestsRewritten": false
"historicalManifestsRewritten": false,
"fullHistoricalReproduction": false
},
"entries": [
{
@@ -25,7 +30,7 @@
"observedSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"replacement": true,
@@ -40,7 +45,7 @@
"observedSha256": "e1c28687ce34cda539fce096060ab972a98e509c3cdd8335745d565546bcd030",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "97d025812d51642e6c118a7a6228b0481e5ff95e4acb7742f62875f9f27f924b",
"replacement": true,
@@ -55,7 +60,7 @@
"observedSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"replacement": true,
@@ -70,7 +75,7 @@
"observedSha256": "2510df2927fbe34ac3c81e4192a9c3ef842388af56dce77d9717681aeda6becd",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/asset-preview-opfs-commit.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "f489a1d9a4c5fb24a99bce6d31841534c7cf3981b53076a0d9e19d106e9d0d74",
"replacement": false
@@ -83,7 +88,7 @@
"observedSha256": "4fa197fc7d696b5ca9dc6fe953a1c39c6915e37ab21001c14c55311da965048a",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/asset-preview-dedup.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "e023fdd33e0f40c1331dfdd73cd287dc684256b9d134971ab17db8cfe2a83835",
"replacement": false
@@ -96,7 +101,7 @@
"observedSha256": "217fc2c8b55b9a8bc8ce0e23268cf3062f989853d72f71f999278f2ad8e61b4c",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/asset-preview-quarantine.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "79c836c7a3be4e9f305a962775444c766577cca87fa6d1698811e75eb21f2d9a",
"replacement": false
@@ -109,7 +114,7 @@
"observedSha256": "cd1f790dffb2b31780cb7f9cfe10e433b335ed282018b2fae5d8fadb687fd5c0",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/asset-preview-reference-gc.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "c5de3122b5d8aab17daf0179cb4f5bb0b5d299408818849cbe7b18e40a47706e",
"replacement": false
@@ -122,7 +127,7 @@
"observedSha256": "fa908f0a9049287cc67c32fcfb5ed006495fe998f214f602cb0a5116f6856134",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/asset-preview-display.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "f10a05900c4d1282251f7a76e7c413a18602910f55fe8400f1713f548eba3873",
"replacement": false
@@ -135,7 +140,7 @@
"observedSha256": "1c23077b0c2d61fcdedebae3d6c80e55cb84dedfb9a7600ecf4df5ac0fece3e9",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-operation-identity.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "0e5b2c82d481180eb8eb22de16ad8cdef5e58fa7423c26011faaffbac788e547",
"replacement": false
@@ -148,7 +153,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -163,7 +168,7 @@
"observedSha256": "7398625b4d2f921bad11922c3160a02597ea7ed7f15e83d9594ccf843430d15b",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-linked-mutation.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "f19d47cefe89daf6123062e045ec717e6ffe60977e8a4b20c996dd62e49da211",
"replacement": false
@@ -176,7 +181,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -191,7 +196,7 @@
"observedSha256": "7492179e72e066ba1e34a5c9055d319e2ee886b4c5f1c4034a781825118796a6",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-linked-reload.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "dff866291468cc01e775fe3b3b95c632f5c0742566f79b956a0193bfd8fd43d2",
"replacement": false
@@ -204,7 +209,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -219,7 +224,7 @@
"observedSha256": "0fc3389c4a76c275d332ac5353ca7593884c2e65ba98f9d8db6f24e0518fff75",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-linked-missing.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "4ab6d6ff4845b4ca963399e7eea214ceb412871dc1fdef5bac1ed0333596da4f",
"replacement": false
@@ -232,7 +237,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -247,7 +252,7 @@
"observedSha256": "fbdf0f3898037ab15db538df40f3629895cf2b1ebab369332b54962f45297478",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "fbdf0f3898037ab15db538df40f3629895cf2b1ebab369332b54962f45297478",
"replacement": true,
@@ -262,7 +267,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -277,7 +282,7 @@
"observedSha256": "1420291c9ba5b4e45455a999ba94864da5eccf5b6e9f377577e01e4dfb218e48",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "1420291c9ba5b4e45455a999ba94864da5eccf5b6e9f377577e01e4dfb218e48",
"replacement": true,
@@ -292,7 +297,7 @@
"observedSha256": "b70aa48b2c8902d1427e2cf80de3b81992d2e0c42d8d271cefdddeadd9162927",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-override-writer.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "e41bd32eb4ce4d331a20ecb91f3325a27f461b9ae85e98940d5afd482ec21c4c",
"replacement": false
@@ -305,7 +310,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -320,7 +325,7 @@
"observedSha256": "8c1125d05c47da5e0a4a5b2fb54b5f61613a0c50391de52fb5578db8160be2e8",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "8c1125d05c47da5e0a4a5b2fb54b5f61613a0c50391de52fb5578db8160be2e8",
"replacement": true,
@@ -335,7 +340,7 @@
"observedSha256": "19807407446397ef649a35ad3f3cb06478b5f549a8f1b4b9759bb5eeacddc391",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-override-freshness.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "d48344f31e1ba12e557ca30ece56643583efa633da556f5de3896a8e9175ef8f",
"replacement": false
@@ -348,7 +353,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -363,7 +368,7 @@
"observedSha256": "aab9c645f2c05550ff37148b915cfadcc36542bb96fd5535ccfc960defdf57c3",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "aab9c645f2c05550ff37148b915cfadcc36542bb96fd5535ccfc960defdf57c3",
"replacement": true,
@@ -378,7 +383,7 @@
"observedSha256": "2d4b06b5d4a1ab69315bc4c04a2a6d39f9f6b704a056eb030318b53203068c97",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-negative-cases.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "b7ae41b2c35b2fe1598bca4425dd434230bfe4bf342320c88214a060dcbb0a16",
"replacement": false
@@ -391,7 +396,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -406,7 +411,7 @@
"observedSha256": "6ed2d8655651bf7915a88cf091e649fc8b0c98500eaad6ae55e39bebe5c504c5",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "6ed2d8655651bf7915a88cf091e649fc8b0c98500eaad6ae55e39bebe5c504c5",
"replacement": true,
@@ -421,7 +426,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -436,7 +441,7 @@
"observedSha256": "7c9baef0d653f91e0976c0f1aecea71660adb9845500c2f0c06442996dfaf42c",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "7c9baef0d653f91e0976c0f1aecea71660adb9845500c2f0c06442996dfaf42c",
"replacement": true,
@@ -451,7 +456,7 @@
"observedSha256": "fa5d9ae3359c722449730a3cdb1f0133dd5a9935524ddc27224700147dea9368",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-source-origin.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "89b207c9cb13b4fb055a2dfed0237c0f8a00b13a39cc4175a378f5ef2abdb7ae",
"replacement": false
@@ -464,7 +469,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -479,7 +484,7 @@
"observedSha256": "da9c018a98c617809974a577f55a3f2e2f6069347260640ef2397195a2aee0e7",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "da9c018a98c617809974a577f55a3f2e2f6069347260640ef2397195a2aee0e7",
"replacement": true,
@@ -494,7 +499,7 @@
"observedSha256": "6971f333bcbd3eb2e3228506596701877e3ba985644ae5d180b99c232d2e0236",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-path-normalization.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "abde64c60397541e92a83dd9e4a24e65faf340a8d046650604c101a21037c777",
"replacement": false
@@ -507,7 +512,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -522,7 +527,7 @@
"observedSha256": "955de46ca2a8921bc062a7ada681e8e9bccaeca1eb5b0e111f1a38683ad26c21",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "955de46ca2a8921bc062a7ada681e8e9bccaeca1eb5b0e111f1a38683ad26c21",
"replacement": true,
@@ -537,7 +542,7 @@
"observedSha256": "f8ccb30b291521858ccb6fb42ea6e0129b50fa44f7a4953971dc1687f3db884c",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-path-security.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "ab302cacb24634a3225dda5cb8f5282cb80b3bd81ed5c8900ddf4ff18267b7e2",
"replacement": false
@@ -550,7 +555,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -565,7 +570,7 @@
"observedSha256": "59854c9d6d7b024ca4c30061e2325f079dfb25c25a8f38b342dba4c886494255",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "59854c9d6d7b024ca4c30061e2325f079dfb25c25a8f38b342dba4c886494255",
"replacement": true,
@@ -580,7 +585,7 @@
"observedSha256": "983a77d9bde5302cfe72778cab3452662e15927bcdc538aafc78c68618d558c7",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-link-safety.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "7739275be91222d7bfb61d2f5a1daf812c6860fe34d0aea27df8380a77322120",
"replacement": false
@@ -593,7 +598,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -608,7 +613,7 @@
"observedSha256": "b7b4f1a9f775f81b46fc76dec8d520d9ad0292f68d43a1d0593829eb7671ef62",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-metadata-first.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "2da649722acee9cace8db6f337b4a93500a9c775a0b0f086bf38dd2b3e7f9e91",
"replacement": false
@@ -621,7 +626,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -636,7 +641,7 @@
"observedSha256": "4394b7bd6528c2823c5860b57f2f88623b280ee099072b44ecf9c63bfbc38bdc",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-archive-budget.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "b0d8356c6fb348d98e28ce220052845a29439b34b3c976b21a4dbf370ea19593",
"replacement": false
@@ -649,7 +654,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -664,7 +669,7 @@
"observedSha256": "e101dd559da4f557f10f19b688184cec3fad3e06664082a7c54834bc3cf00e1f",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-archive-conflicts.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "3f2d44dce33b1c17b3a48f58b04fdd821abc88d98ce3d3b5bb724859e0f0ab3c",
"replacement": false
@@ -677,7 +682,7 @@
"observedSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "f6d949a56d6b3c9bf58bbb3b94eb3c16e497cdd515da11bf45d9ef0b86c638b2",
"replacement": true,
@@ -692,7 +697,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -707,7 +712,7 @@
"observedSha256": "ae8d4779b939351d987ba4fdacc37a5345f72e11fbdebf9a81bd0f8ee25020bf",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-archive-cancellation.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "77e7d5bc64dd6b313006ebf523602601acdaf7949a1484da872ddcd046983786",
"replacement": false
@@ -720,7 +725,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -735,7 +740,7 @@
"observedSha256": "3f27fb26a3edd27a8f85d16aaed445546a97683366072da297ff6d7404d1960b",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/library-archive-recovery.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "a931edef8f3ca1243a80ec2b8e9ff5b8da1dfd339f3d8c162ad2ebd08d3db6a1",
"replacement": false
@@ -748,7 +753,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -763,7 +768,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -778,7 +783,7 @@
"observedSha256": "edf466eed602786ae2ea254003f0f19d5d44f95b306e364698c4497d3108c0c6",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "edf466eed602786ae2ea254003f0f19d5d44f95b306e364698c4497d3108c0c6",
"replacement": true,
@@ -793,7 +798,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -808,7 +813,7 @@
"observedSha256": "cdb436ccba3748338df0da283fb2f1acd25c3f61e560c919c4b77196c936e6e4",
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/tests/unit/io-format-capability-matrix.test.mjs",
"epoch": 1,
"epoch": 2,
"binding": "IMMUTABLE_SOURCE_SNAPSHOT",
"sourceSha256": "0cc4d8f1df1ecdab20d8100cf5f12b44cb2a68bca4384ef7964a032b2f74b36e",
"replacement": false
@@ -821,7 +826,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -836,7 +841,7 @@
"observedSha256": "5861988f3dfbb8c05d36aee3033a72514de53a0cb4ec6f3d832418ef6b5cc8b2",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "5861988f3dfbb8c05d36aee3033a72514de53a0cb4ec6f3d832418ef6b5cc8b2",
"replacement": true,
@@ -851,7 +856,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -866,7 +871,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -881,7 +886,7 @@
"observedSha256": "5861988f3dfbb8c05d36aee3033a72514de53a0cb4ec6f3d832418ef6b5cc8b2",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "5861988f3dfbb8c05d36aee3033a72514de53a0cb4ec6f3d832418ef6b5cc8b2",
"replacement": true,
@@ -896,7 +901,7 @@
"observedSha256": "667f614322b9fa7ac2fc8f1cd5e4510f25ad153e8d94b7ca376c96928d158ed3",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "667f614322b9fa7ac2fc8f1cd5e4510f25ad153e8d94b7ca376c96928d158ed3",
"replacement": true,
@@ -911,7 +916,7 @@
"observedSha256": "26d804c156d5ef9fec89d6ad393162ddc8423a6058b54f31269dd474f3796a88",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "26d804c156d5ef9fec89d6ad393162ddc8423a6058b54f31269dd474f3796a88",
"replacement": true,
@@ -926,7 +931,7 @@
"observedSha256": "8e0ee239a9ec0db42586c320872758410c38620c5dcc908ada080f1b3b4d52c9",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "8e0ee239a9ec0db42586c320872758410c38620c5dcc908ada080f1b3b4d52c9",
"replacement": true,
@@ -941,7 +946,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -956,7 +961,7 @@
"observedSha256": "475758f3f9172d05802a0a6361a53b79a9a239722e4566bdd0dcb00897e1cdfa",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "475758f3f9172d05802a0a6361a53b79a9a239722e4566bdd0dcb00897e1cdfa",
"replacement": true,
@@ -971,7 +976,7 @@
"observedSha256": "cc1c69d74ec079b9dc54f05d3f5a73734bbe989b669f18fae163b7b8bb69fb4f",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "cc1c69d74ec079b9dc54f05d3f5a73734bbe989b669f18fae163b7b8bb69fb4f",
"replacement": true,
@@ -986,7 +991,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1001,7 +1006,7 @@
"observedSha256": "1b5f386666223ba7104fded30466bfc855b6a812c42a608f448d3106edca6000",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "1b5f386666223ba7104fded30466bfc855b6a812c42a608f448d3106edca6000",
"replacement": true,
@@ -1016,7 +1021,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1031,7 +1036,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1046,7 +1051,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1061,7 +1066,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1074,14 +1079,14 @@
"path": "web/protocol/glb-import.ts",
"originalSha256": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147",
"observedSha256": "1b5f386666223ba7104fded30466bfc855b6a812c42a608f448d3106edca6000",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "1b5f386666223ba7104fded30466bfc855b6a812c42a608f448d3106edca6000",
"replacement": true,
"sourcePath": "web/protocol/glb-import.ts",
"originalPreserved": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147"
"provenanceState": "PROVENANCE_RESTORED",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/protocol/glb-import.ts.m12-06F",
"epoch": 2,
"binding": "SUPPLEMENTAL_EXACT_SOURCE_ARCHIVE",
"sourceSha256": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147",
"replacement": false,
"sourceArchive": "release/blender-web-corresponding-source.tar.gz",
"sourceArchiveSha256": "1a57a8c53e68ffca50e730f280c68636553d7a6ea1c4bce3b45823b4677c294c"
},
{
"task": "M12-06F",
@@ -1091,7 +1096,7 @@
"observedSha256": "b947d77876b1d2fc6ae736998bb1db4cbe92b8c1043b373edbb0c7aafccefccf",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "b947d77876b1d2fc6ae736998bb1db4cbe92b8c1043b373edbb0c7aafccefccf",
"replacement": true,
@@ -1106,7 +1111,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1121,7 +1126,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1136,7 +1141,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1151,7 +1156,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1166,7 +1171,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1181,7 +1186,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1196,7 +1201,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1211,7 +1216,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,
@@ -1226,7 +1231,7 @@
"observedSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"provenanceState": "AUTHORIZED_REBASELINE",
"snapshotPath": null,
"epoch": 1,
"epoch": 2,
"binding": "CURRENT_WORKTREE_REPLACEMENT",
"sourceSha256": "40b7f14d4f568ae94bedde83e02115c127e0c714e5eb32a6a97b1e1084c4fa68",
"replacement": true,

View File

@@ -0,0 +1,47 @@
{
"schemaVersion": 1,
"operation": "M12_SOURCE_RECOVERY_SEARCH",
"policy": "exact_sha256_only",
"sources": [
{
"kind": "CURRENT_GIT_OBJECT_DATABASE",
"scope": "all reachable and unreachable objects",
"blobsScanned": 25050,
"targetShaMatches": 2,
"newExactRestorations": 0
},
{
"kind": "TRASH_PROJECT_COPY",
"scope": "workinf_Blender_Wasm.3 including its Git object database",
"refs": ["main", "origin/main"],
"targetShaMatches": 0,
"newExactRestorations": 0
},
{
"kind": "LOCAL_RELEASE_SOURCE_ARCHIVE",
"path": "release/blender-web-corresponding-source.tar.gz",
"sha256": "1a57a8c53e68ffca50e730f280c68636553d7a6ea1c4bce3b45823b4677c294c",
"targetShaMatches": 1,
"newExactRestorations": 1,
"entries": ["M12-06F:protocol:web/protocol/glb-import.ts"]
},
{
"kind": "GITEA_REPOSITORY",
"repository": "https://gitea.meswork.com/wangdequan/workinf_Blender_Wasm.git",
"branches": ["main:c2c65d3a090fd06ca36a41107974a91398e00a3c"],
"tags": [],
"releases": [],
"actionsArtifacts": "AUTH_REQUIRED_NO_ARTIFACTS_OBSERVED",
"targetShaMatches": 0,
"newExactRestorations": 0
}
],
"summary": {
"historicalEntries": 84,
"restoredBeforeSupplement": 22,
"supplementalExactRestorations": 1,
"authorizedReplacementsAfterEpoch2": 61,
"unresolvedHistoricalEntries": 61
},
"conclusion": "No additional exact historical bytes were found. Epoch 2 must remain an authorized rebaseline and must not be described as full historical reproduction."
}

View File

@@ -23,21 +23,33 @@
"path": "tests/golden/corrective/rehydration/M12-git-history-snapshot/snapshot-manifest.json",
"sha256": "e58b1804ed92f19855679f7cdca6787bffcfafbc59c007fd419077ed55a04b54"
},
"supplemental": {
"path": "tests/golden/corrective/rehydration/M12-supplemental-exact-recovery.json",
"sha256": "a8947b6b5966dbd870a254a96e7ee26d606011c16cb5c5c3c315ac912eae0908"
},
"supplementalSnapshot": {
"path": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/protocol/glb-import.ts.m12-06F",
"sha256": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147"
},
"searchReport": {
"path": "tests/golden/WBV2-P8-003/m12-source-recovery-search.json",
"sha256": "4192418563aabf011bb5d6c1407565c87bb492ab208eca69f4768ae35b126fc0"
},
"epoch": {
"path": "tests/golden/WBV2-P8-003/m12-provenance-epoch.json",
"sha256": "772c25f1375f46b1649b1431d3e47f4ab532641157ff7a47c9f65a2e2ee67679"
"sha256": "a71f145c1d29ca5fec5964213ab2921ab1cf1757099bcc2a3e1d4efedd2b0d61"
},
"report": {
"path": "tests/golden/WBV2-P8-003/provenance-epoch-report.json",
"sha256": "053cca1f52a1cc22cd0b8d1e69ec6fa4ec00b2b0584d8f76010d905d9dbde868"
"sha256": "9be983254265538913ac3ba837ab95cdb79c0986d0cdc266db52a6fd1ecb50a5"
},
"generator": {
"path": "tools/web/generate-m12-provenance-epoch.mjs",
"sha256": "d3658713cdd5479a3ad7001c89cc6799c9c31216fac0a808e2775da0e3cf4de5"
"sha256": "60d5956a5e305308d87c7a91d6f74ee458c07ff579cb8770911871e7ad1149dd"
},
"status": {
"path": "docs/status/WBV2-P8-003.md",
"sha256": "b86c1d304a411468be8700c59fafad209f301e6391f3ab30f63f7b480edde4d3"
"sha256": "5c4eb342ed226199380b55079da38a6505b37488e3bdc4e331a4a2c30506b8a7"
},
"recoveryPlan": {
"path": "tests/golden/WBV2-P8-003/recovery-task-plan.json",
@@ -45,15 +57,16 @@
},
"taskContext": {
"path": "tests/golden/WBV2-P8-003/task-context.json",
"sha256": "d1b03187a671f0cae6e9dd19303612d3ebd8d3510abb7dd9b5f177d0c4f85f77"
"sha256": "a64585c181ade592e3532d5d4886d2ac234f8db7770128778e851f82c87b118e"
}
},
"assertions": {
"total": 84,
"restoredOriginals": 22,
"authorizedReplacements": 62,
"restoredOriginals": 23,
"authorizedReplacements": 61,
"falseRestoredClaims": 0,
"historicalManifestsRewritten": false
"historicalManifestsRewritten": false,
"fullHistoricalReproduction": false
},
"nextTask": "WBV2-P8-004"
}

View File

@@ -3,12 +3,12 @@
"task": "WBV2-P8-003",
"operation": "AUTHORIZE_M12_PROVENANCE_EPOCH",
"status": "PASS",
"epoch": 1,
"epoch": 2,
"counts": {
"total": 84,
"restoredOriginals": 22,
"authorizedReplacements": 62,
"unresolvedHistoricalOriginals": 62
"restoredOriginals": 23,
"authorizedReplacements": 61,
"unresolvedHistoricalOriginals": 61
},
"sourceSnapshot": {
"path": "tests/golden/corrective/rehydration/M12-git-history-snapshot/snapshot-manifest.json",
@@ -19,7 +19,8 @@
"historicalEvidencePreserved": true,
"falseRestoredClaims": 0,
"historicalManifestsRewritten": false,
"allCurrentBindingsHashVerified": false
"fullHistoricalReproduction": false,
"allCurrentBindingsHashVerified": true
},
"nextTask": "WBV2-P8-004"
}

View File

@@ -40,7 +40,7 @@
},
{
"path": "tools/web/generate-m12-provenance-epoch.mjs",
"bytes": 8884,
"bytes": 10709,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{

View File

@@ -9,7 +9,7 @@
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P8-003/manifest.json",
"sha256": "a2f240de899de0ca858263937344b030a64c939df6daf8df06ada176eb859471"
"sha256": "9be94c2a037bacea694e4e4121b9ff774b6f53c177873c7c47781711170f5d68"
},
"receipts": {
"path": "tests/golden/WBV2-P8-002/atomic-receipt-index.json",
@@ -17,7 +17,15 @@
},
"provenanceEpoch": {
"path": "tests/golden/WBV2-P8-003/m12-provenance-epoch.json",
"sha256": "772c25f1375f46b1649b1431d3e47f4ab532641157ff7a47c9f65a2e2ee67679"
"sha256": "a71f145c1d29ca5fec5964213ab2921ab1cf1757099bcc2a3e1d4efedd2b0d61"
},
"approval": {
"path": "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json",
"sha256": "cffc869734af94ffe6b8b8004d7ab8cc2c9edcb85ec2a877548e0b0f923f5ea3"
},
"searchReport": {
"path": "tests/golden/WBV2-P8-003/m12-source-recovery-search.json",
"sha256": "4192418563aabf011bb5d6c1407565c87bb492ab208eca69f4768ae35b126fc0"
},
"previousGate": {
"path": "tests/golden/WBV2-P7-003/release-gate-report.json",
@@ -25,19 +33,19 @@
},
"generator": {
"path": "tools/web/generate-m12-provenance-epoch.mjs",
"sha256": "d3658713cdd5479a3ad7001c89cc6799c9c31216fac0a808e2775da0e3cf4de5"
"sha256": "60d5956a5e305308d87c7a91d6f74ee458c07ff579cb8770911871e7ad1149dd"
},
"checker": {
"path": "tools/web/check-wbv2-recovery-release-gate.mjs",
"sha256": "4af9c128fd5658621ae5dcf41b90e2a9964b8a1c32fe982a3d539ab4639324b7"
"sha256": "c500dd7fb8d581b2e8292da6f4b6afcd487acdf453ca55ec48dab9e7dc553b27"
},
"report": {
"path": "tests/golden/WBV2-P8-004/recovery-release-gate-report.json",
"sha256": "8781b6546410284b3075e23338823d3120e7787c35588120fe8a0bb22adeb7df"
"sha256": "0479304c82aec61f98248eca63c7883fb5f36dcd4dd0f296ff42bc32d987000e"
},
"status": {
"path": "docs/status/WBV2-P8-004.md",
"sha256": "b24961e3ac3bf0240ccc3345b23fc787340da74dd7d7e2cc01869b035037104a"
"sha256": "c32b7ef43ba52ef400250c11f2ed5ad60267e73cac309afef22ae724a2136917"
},
"recoveryPlan": {
"path": "tests/golden/WBV2-P8-004/recovery-task-plan.json",
@@ -45,15 +53,18 @@
},
"taskContext": {
"path": "tests/golden/WBV2-P8-004/task-context.json",
"sha256": "fa43615164f1cff24612419181b155184351dfb018120aac7987915706a53c76"
"sha256": "5aa338e08e1aa583b80e3b73bf760e32a0da88d40de97b673ac6d4b42d0ea793"
}
},
"assertions": {
"atomicReceipts": 45,
"restoredOriginals": 22,
"authorizedReplacements": 62,
"restoredOriginals": 23,
"authorizedReplacements": 61,
"historicalProvenanceClosed": false,
"featureParityClaims": 0
"authorizedRebaselineApproved": true,
"fullHistoricalReproduction": false,
"featureParityClaims": 0,
"releaseScope": "AUTHORIZED_REBASELINE_ONLY"
},
"nextTask": null
}

View File

@@ -12,10 +12,22 @@
},
"provenanceEpoch": {
"path": "tests/golden/WBV2-P8-003/m12-provenance-epoch.json",
"sha256": "772c25f1375f46b1649b1431d3e47f4ab532641157ff7a47c9f65a2e2ee67679",
"sha256": "a71f145c1d29ca5fec5964213ab2921ab1cf1757099bcc2a3e1d4efedd2b0d61",
"entries": 84,
"restoredOriginals": 22,
"authorizedReplacements": 62
"restoredOriginals": 23,
"authorizedReplacements": 61
},
"approval": {
"path": "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json",
"sha256": "cffc869734af94ffe6b8b8004d7ab8cc2c9edcb85ec2a877548e0b0f923f5ea3",
"decision": "APPROVED",
"approvedBy": "wangdequan"
},
"searchReport": {
"path": "tests/golden/WBV2-P8-003/m12-source-recovery-search.json",
"sha256": "4192418563aabf011bb5d6c1407565c87bb492ab208eca69f4768ae35b126fc0",
"exactAdditional": 1,
"unresolvedHistorical": 61
},
"previousGate": {
"path": "tests/golden/WBV2-P7-003/release-gate-report.json",
@@ -27,14 +39,17 @@
"atomicReceiptStatus": "CLOSED",
"chromiumFamilyCount": 15,
"atomicBehaviorCount": 45,
"provenanceStatus": "AUTHORIZED_REBASELINE",
"historicalOriginalStatus": "PARTIAL"
"provenanceStatus": "AUTHORIZED_REBASELINE_APPROVED",
"historicalOriginalStatus": "PARTIAL",
"fullHistoricalReproduction": false
},
"decision": {
"status": "BLOCKED",
"code": "HISTORICAL_PROVENANCE_REBASELINE_REQUIRED",
"reason": "62 M12 entries use an authorized current-worktree replacement; original historical bytes are unavailable",
"status": "READY_WITH_AUTHORIZED_REBASELINE",
"code": "AUTHORIZED_REBASELINE_ACCEPTED",
"reason": "Project owner approved provenance epoch 2; 61 replacements are accepted only as a new current baseline",
"featureParityClaims": 0,
"fullHistoricalReproduction": false,
"releaseScope": "AUTHORIZED_REBASELINE_ONLY",
"nextTask": null
},
"negative": {
@@ -42,8 +57,9 @@
"receiptHashDrift": "REJECTED",
"provenanceHashDrift": "REJECTED",
"falseHistoricalRestoration": "REJECTED",
"missingApproval": "REJECTED",
"unsupportedBrowser": "REJECTED",
"queueAdvance": "BLOCKED"
"queueAdvance": "CLOSED"
},
"nextTask": null
}

View File

@@ -19,12 +19,12 @@
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 3385,
"contextRemainingTokens": 845
"contextRemainingBytes": 2689,
"contextRemainingTokens": 671
},
"source": {
"bytes": 6519,
"tokens": 1631
"bytes": 7215,
"tokens": 1805
},
"selected": [],
"excluded": [
@@ -35,13 +35,13 @@
},
{
"path": "tests/golden/WBV2-P8-003/m12-provenance-epoch.json",
"bytes": 59189,
"bytes": 59741,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tools/web/check-wbv2-recovery-release-gate.mjs",
"bytes": 6686,
"reason": "CONTEXT_REMAINING_SPACE"
"bytes": 8407,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P8-004/",
@@ -109,16 +109,16 @@
"parentTask": "WBV2-P8-002",
"status": "done",
"nextTask": "WBV2-P8-004",
"artifactCount": 10
"artifactCount": 13
},
"statusSummary": [
"# WBV2-P8-003 status",
"- task: `WBV2-P8-003`; parent: `WBV2-P8-002`; status: `done`",
"- provenance epoch: `1`",
"- historical originals restored: `22/84`",
"- authorized replacements: `62/84`",
"- provenance epoch: `2`",
"- historical originals restored: `23/84`",
"- authorized replacements: `61/84`",
"- nextTask: `WBV2-P8-004`",
"The 22 exact Git-history matches remain immutable restorations. The other 62 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of the unavailable historical bytes."
"The 23 exact matches remain immutable restorations. The other 61 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of unavailable historical bytes. Full historical reproduction remains false."
]
},
"budgets": {
@@ -149,25 +149,25 @@
},
{
"path": "tests/golden/WBV2-P8-003/manifest.json",
"bytes": 2199,
"lines": 60,
"tokens": 550
"bytes": 2867,
"lines": 73,
"tokens": 717
},
{
"path": "docs/status/WBV2-P8-003.md",
"bytes": 426,
"bytes": 454,
"lines": 10,
"tokens": 107
"tokens": 114
}
],
"sourceTokens": 1631,
"sourceTokens": 1805,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1631,
"totalTokens": 1805,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2655,
"serializedContextTokens": 620,
"estimatedContextTokens": 2829,
"serializedContextTokens": 611,
"withinBudget": true
}
}

View File

@@ -1 +1 @@
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P8-004/recovery-task-plan.json","sha256":"451ac79c0262391679e5e7c3251b99c49973d914e85e14d7e09eb9794befc4be"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"3b2bb72a9494de0e69bb973dcbcf64dbf62d8dda80096141212936f90ef72a42"},"taskCount":36,"activeTask":"WBV2-P8-004","entries":{"WBV2-P0-001":{"line":0,"offset":0,"length":308,"previous":null,"next":"WBV2-P0-002"},"WBV2-P0-002":{"line":1,"offset":308,"length":318,"previous":"WBV2-P0-001","next":"WBV2-P0-003"},"WBV2-P0-003":{"line":2,"offset":626,"length":306,"previous":"WBV2-P0-002","next":"WBV2-P1-001"},"WBV2-P1-001":{"line":3,"offset":932,"length":318,"previous":"WBV2-P0-003","next":"WBV2-P1-002"},"WBV2-P1-002":{"line":4,"offset":1250,"length":299,"previous":"WBV2-P1-001","next":"WBV2-P1-003"},"WBV2-P1-003":{"line":5,"offset":1549,"length":303,"previous":"WBV2-P1-002","next":"WBV2-P1-004"},"WBV2-P1-004":{"line":6,"offset":1852,"length":309,"previous":"WBV2-P1-003","next":"WBV2-P1-005"},"WBV2-P1-005":{"line":7,"offset":2161,"length":324,"previous":"WBV2-P1-004","next":"WBV2-P2-001"},"WBV2-P2-001":{"line":8,"offset":2485,"length":267,"previous":"WBV2-P1-005","next":"WBV2-P2-002"},"WBV2-P2-002":{"line":9,"offset":2752,"length":267,"previous":"WBV2-P2-001","next":"WBV2-P2-003"},"WBV2-P2-003":{"line":10,"offset":3019,"length":274,"previous":"WBV2-P2-002","next":"WBV2-P2-004"},"WBV2-P2-004":{"line":11,"offset":3293,"length":284,"previous":"WBV2-P2-003","next":"WBV2-P2-005"},"WBV2-P2-005":{"line":12,"offset":3577,"length":291,"previous":"WBV2-P2-004","next":"WBV2-P3-001"},"WBV2-P3-001":{"line":13,"offset":3868,"length":271,"previous":"WBV2-P2-005","next":"WBV2-P3-002"},"WBV2-P3-002":{"line":14,"offset":4139,"length":266,"previous":"WBV2-P3-001","next":"WBV2-P3-003"},"WBV2-P3-003":{"line":15,"offset":4405,"length":273,"previous":"WBV2-P3-002","next":"WBV2-P3-004"},"WBV2-P3-004":{"line":16,"offset":4678,"length":263,"previous":"WBV2-P3-003","next":"WBV2-P3-005"},"WBV2-P3-005":{"line":17,"offset":4941,"length":292,"previous":"WBV2-P3-004","next":"WBV2-P4-001"},"WBV2-P4-001":{"line":18,"offset":5233,"length":283,"previous":"WBV2-P3-005","next":"WBV2-P4-002"},"WBV2-P4-002":{"line":19,"offset":5516,"length":277,"previous":"WBV2-P4-001","next":"WBV2-P4-003"},"WBV2-P4-003":{"line":20,"offset":5793,"length":287,"previous":"WBV2-P4-002","next":"WBV2-P4-004"},"WBV2-P4-004":{"line":21,"offset":6080,"length":290,"previous":"WBV2-P4-003","next":"WBV2-P5-001"},"WBV2-P5-001":{"line":22,"offset":6370,"length":296,"previous":"WBV2-P4-004","next":"WBV2-P5-002"},"WBV2-P5-002":{"line":23,"offset":6666,"length":282,"previous":"WBV2-P5-001","next":"WBV2-P5-003"},"WBV2-P5-003":{"line":24,"offset":6948,"length":278,"previous":"WBV2-P5-002","next":"WBV2-P6-001"},"WBV2-P6-001":{"line":25,"offset":7226,"length":278,"previous":"WBV2-P5-003","next":"WBV2-P6-002"},"WBV2-P6-002":{"line":26,"offset":7504,"length":313,"previous":"WBV2-P6-001","next":"WBV2-P6-003"},"WBV2-P6-003":{"line":27,"offset":7817,"length":316,"previous":"WBV2-P6-002","next":"WBV2-P7-001"},"WBV2-P7-001":{"line":28,"offset":8133,"length":312,"previous":"WBV2-P6-003","next":"WBV2-P7-002"},"WBV2-P7-002":{"line":29,"offset":8445,"length":275,"previous":"WBV2-P7-001","next":"WBV2-P7-003"},"WBV2-P7-003":{"line":30,"offset":8720,"length":310,"previous":"WBV2-P7-002","next":"WBV2-P8-000"},"WBV2-P8-000":{"line":31,"offset":9030,"length":290,"previous":"WBV2-P7-003","next":"WBV2-P8-001"},"WBV2-P8-001":{"line":32,"offset":9320,"length":306,"previous":"WBV2-P8-000","next":"WBV2-P8-002"},"WBV2-P8-002":{"line":33,"offset":9626,"length":307,"previous":"WBV2-P8-001","next":"WBV2-P8-003"},"WBV2-P8-003":{"line":34,"offset":9933,"length":312,"previous":"WBV2-P8-002","next":"WBV2-P8-004"},"WBV2-P8-004":{"line":35,"offset":10245,"length":284,"previous":"WBV2-P8-003","next":null}}}
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P8-003/recovery-task-plan.json","sha256":"788de39c33cf87d3b8d3812f13e9cbd7d1acbfd6fb70df522ccd69f454704666"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"3b2bb72a9494de0e69bb973dcbcf64dbf62d8dda80096141212936f90ef72a42"},"taskCount":36,"activeTask":"WBV2-P8-004","entries":{"WBV2-P0-001":{"line":0,"offset":0,"length":308,"previous":null,"next":"WBV2-P0-002"},"WBV2-P0-002":{"line":1,"offset":308,"length":318,"previous":"WBV2-P0-001","next":"WBV2-P0-003"},"WBV2-P0-003":{"line":2,"offset":626,"length":306,"previous":"WBV2-P0-002","next":"WBV2-P1-001"},"WBV2-P1-001":{"line":3,"offset":932,"length":318,"previous":"WBV2-P0-003","next":"WBV2-P1-002"},"WBV2-P1-002":{"line":4,"offset":1250,"length":299,"previous":"WBV2-P1-001","next":"WBV2-P1-003"},"WBV2-P1-003":{"line":5,"offset":1549,"length":303,"previous":"WBV2-P1-002","next":"WBV2-P1-004"},"WBV2-P1-004":{"line":6,"offset":1852,"length":309,"previous":"WBV2-P1-003","next":"WBV2-P1-005"},"WBV2-P1-005":{"line":7,"offset":2161,"length":324,"previous":"WBV2-P1-004","next":"WBV2-P2-001"},"WBV2-P2-001":{"line":8,"offset":2485,"length":267,"previous":"WBV2-P1-005","next":"WBV2-P2-002"},"WBV2-P2-002":{"line":9,"offset":2752,"length":267,"previous":"WBV2-P2-001","next":"WBV2-P2-003"},"WBV2-P2-003":{"line":10,"offset":3019,"length":274,"previous":"WBV2-P2-002","next":"WBV2-P2-004"},"WBV2-P2-004":{"line":11,"offset":3293,"length":284,"previous":"WBV2-P2-003","next":"WBV2-P2-005"},"WBV2-P2-005":{"line":12,"offset":3577,"length":291,"previous":"WBV2-P2-004","next":"WBV2-P3-001"},"WBV2-P3-001":{"line":13,"offset":3868,"length":271,"previous":"WBV2-P2-005","next":"WBV2-P3-002"},"WBV2-P3-002":{"line":14,"offset":4139,"length":266,"previous":"WBV2-P3-001","next":"WBV2-P3-003"},"WBV2-P3-003":{"line":15,"offset":4405,"length":273,"previous":"WBV2-P3-002","next":"WBV2-P3-004"},"WBV2-P3-004":{"line":16,"offset":4678,"length":263,"previous":"WBV2-P3-003","next":"WBV2-P3-005"},"WBV2-P3-005":{"line":17,"offset":4941,"length":292,"previous":"WBV2-P3-004","next":"WBV2-P4-001"},"WBV2-P4-001":{"line":18,"offset":5233,"length":283,"previous":"WBV2-P3-005","next":"WBV2-P4-002"},"WBV2-P4-002":{"line":19,"offset":5516,"length":277,"previous":"WBV2-P4-001","next":"WBV2-P4-003"},"WBV2-P4-003":{"line":20,"offset":5793,"length":287,"previous":"WBV2-P4-002","next":"WBV2-P4-004"},"WBV2-P4-004":{"line":21,"offset":6080,"length":290,"previous":"WBV2-P4-003","next":"WBV2-P5-001"},"WBV2-P5-001":{"line":22,"offset":6370,"length":296,"previous":"WBV2-P4-004","next":"WBV2-P5-002"},"WBV2-P5-002":{"line":23,"offset":6666,"length":282,"previous":"WBV2-P5-001","next":"WBV2-P5-003"},"WBV2-P5-003":{"line":24,"offset":6948,"length":278,"previous":"WBV2-P5-002","next":"WBV2-P6-001"},"WBV2-P6-001":{"line":25,"offset":7226,"length":278,"previous":"WBV2-P5-003","next":"WBV2-P6-002"},"WBV2-P6-002":{"line":26,"offset":7504,"length":313,"previous":"WBV2-P6-001","next":"WBV2-P6-003"},"WBV2-P6-003":{"line":27,"offset":7817,"length":316,"previous":"WBV2-P6-002","next":"WBV2-P7-001"},"WBV2-P7-001":{"line":28,"offset":8133,"length":312,"previous":"WBV2-P6-003","next":"WBV2-P7-002"},"WBV2-P7-002":{"line":29,"offset":8445,"length":275,"previous":"WBV2-P7-001","next":"WBV2-P7-003"},"WBV2-P7-003":{"line":30,"offset":8720,"length":310,"previous":"WBV2-P7-002","next":"WBV2-P8-000"},"WBV2-P8-000":{"line":31,"offset":9030,"length":290,"previous":"WBV2-P7-003","next":"WBV2-P8-001"},"WBV2-P8-001":{"line":32,"offset":9320,"length":306,"previous":"WBV2-P8-000","next":"WBV2-P8-002"},"WBV2-P8-002":{"line":33,"offset":9626,"length":307,"previous":"WBV2-P8-001","next":"WBV2-P8-003"},"WBV2-P8-003":{"line":34,"offset":9933,"length":312,"previous":"WBV2-P8-002","next":"WBV2-P8-004"},"WBV2-P8-004":{"line":35,"offset":10245,"length":284,"previous":"WBV2-P8-003","next":null}}}

View File

@@ -0,0 +1,485 @@
import type { GLBAssetBuffer } from "./glb-export";
import type { SceneSnapshotIR } from "./scene-ir";
const GLB_MAGIC = 0x46546c67;
const JSON_CHUNK = 0x4e4f534a;
const BIN_CHUNK = 0x004e4942;
interface GLBAccessor {
bufferView?: number;
byteOffset?: number;
componentType: number;
count: number;
type: string;
normalized?: boolean;
min?: number[];
max?: number[];
sparse?: Record<string, unknown>;
}
interface GLBBufferView {
buffer: number;
byteOffset?: number;
byteLength: number;
}
interface GLBPrimitive {
attributes?: Record<string, number>;
indices?: number;
material?: number;
mode?: number;
targets?: Array<Record<string, number>>;
}
interface GLBDocument {
asset?: { version?: string; generator?: string };
scene?: number;
scenes?: Array<{ nodes?: number[] }>;
extensionsUsed?: string[];
extensionsRequired?: string[];
buffers?: Array<{ byteLength?: number; uri?: string }>;
bufferViews?: GLBBufferView[];
accessors?: GLBAccessor[];
meshes?: Array<{ name?: string; primitives?: GLBPrimitive[]; extras?: Record<string, unknown> }>;
images?: Array<{ name?: string; mimeType?: string; bufferView?: number; uri?: string; extras?: Record<string, unknown> }>;
samplers?: Array<Record<string, unknown>>;
textures?: Array<{ sampler?: number; source?: number }>;
materials?: Array<{
name?: string;
alphaMode?: string;
doubleSided?: boolean;
pbrMetallicRoughness?: {
baseColorFactor?: number[];
baseColorTexture?: Record<string, unknown>;
metallicFactor?: number;
roughnessFactor?: number;
};
normalTexture?: Record<string, unknown>;
emissiveFactor?: number[];
}>;
nodes?: Array<{
name?: string;
mesh?: number;
skin?: number;
children?: number[];
translation?: number[];
rotation?: number[];
scale?: number[];
}>;
skins?: Array<{ name?: string; joints?: number[]; inverseBindMatrices?: number; skeleton?: number; extras?: Record<string, unknown> }>;
animations?: Array<{
name?: string;
samplers?: Array<{ input?: number; output?: number; interpolation?: string }>;
channels?: Array<{ sampler?: number; target?: { node?: number; path?: string } }>;
extras?: Record<string, unknown>;
}>;
}
export const GLB_IMPORT_BUDGET = {
maxBytes: 512 * 1024,
maxJsonBytes: 256 * 1024,
maxBufferViews: 4096,
maxAccessors: 8192,
} as const;
export interface ImportedGLBImage {
name?: string;
blenderId?: string;
mimeType?: string;
byteLength: number;
signature: number[];
}
export interface ImportedGLBSemantics {
version: 2;
meshCount: number;
primitiveCount: number;
meshes: Array<{ name?: string; blenderId?: string; primitiveCount: number; attributes: string[]; morphTargetCount: number }>;
images: ImportedGLBImage[];
skinCount: number;
skins: Array<{ jointCount: number; inverseBindType?: string; inverseBindCount?: number }>;
animationCount: number;
animationChannelCount: number;
animationPaths: string[];
}
export interface GLBSemanticComparison {
compatible: boolean;
mismatches: string[];
}
export interface GLBDesktopAccessorSemantics {
componentType: number;
count: number;
type: string;
normalized: boolean;
min: number[] | null;
max: number[] | null;
}
export interface GLBDesktopFixtureSemantics {
asset: { version?: string; generator?: string } | null;
extensionsUsed: string[];
extensionsRequired: string[];
scene: number | null;
nodeNames: Array<string | null>;
nodes: Array<{
name: string | null;
mesh: number | null;
skin: number | null;
children: number[];
translation: number[] | null;
rotation: number[] | null;
scale: number[] | null;
}>;
meshes: Array<{
name: string | null;
primitives: Array<{
attributes: Record<string, GLBDesktopAccessorSemantics>;
indices: GLBDesktopAccessorSemantics | null;
material: number | null;
mode: number;
targets: Array<Record<string, GLBDesktopAccessorSemantics>>;
}>;
}>;
materials: Array<{
name: string | null;
alphaMode: string;
doubleSided: boolean;
pbr: {
baseColorFactor: number[] | null;
baseColorTexture: Record<string, unknown> | null;
metallicFactor: number | null;
roughnessFactor: number | null;
};
normalTexture: Record<string, unknown> | null;
emissiveFactor: number[] | null;
}>;
textures: Array<Record<string, unknown>>;
images: Array<Record<string, unknown>>;
samplers: Array<Record<string, unknown>>;
skins: Array<{
name: string | null;
joints: number[];
inverseBindMatrices: GLBDesktopAccessorSemantics | null;
skeleton: number | null;
}>;
animations: Array<{
name: string | null;
samplers: Array<{
interpolation: string;
input: GLBDesktopAccessorSemantics | null;
output: GLBDesktopAccessorSemantics | null;
}>;
channels: Array<{ sampler: number; target: { node: number; path: string } }>;
}>;
}
function recordId(extras: Record<string, unknown> | undefined): string | undefined {
return typeof extras?.blenderId === "string" ? extras.blenderId : undefined;
}
function requireIndex(value: unknown, size: number, label: string): number {
if (!Number.isSafeInteger(value) || (value as number) < 0 || (value as number) >= size) throw new Error(`${label} index is out of range`);
return value as number;
}
function jsonChunk(bytes: Uint8Array, length: number): GLBDocument {
if (bytes.byteLength > GLB_IMPORT_BUDGET.maxBytes) throw new Error(`GLB_IMPORT_BUDGET_EXCEEDED: file exceeds ${GLB_IMPORT_BUDGET.maxBytes} bytes`);
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
if (bytes.byteLength < 20 || view.getUint32(0, true) !== GLB_MAGIC || view.getUint32(4, true) !== 2) throw new Error("GLB header is invalid");
if (view.getUint32(8, true) !== bytes.byteLength) throw new Error("GLB length does not match header");
const jsonLength = view.getUint32(12, true);
if (jsonLength > GLB_IMPORT_BUDGET.maxJsonBytes || view.getUint32(16, true) !== JSON_CHUNK || jsonLength % 4 !== 0 || 20 + jsonLength > bytes.byteLength) throw new Error("GLB JSON chunk is invalid");
let document: unknown;
try {
document = JSON.parse(new TextDecoder().decode(bytes.subarray(20, 20 + jsonLength)).trim());
}
catch (error) {
throw new Error(`GLB JSON is invalid: ${error instanceof Error ? error.message : "parse failed"}`);
}
if (typeof document !== "object" || document === null || Array.isArray(document)) throw new Error("GLB JSON document is invalid");
if ((document as GLBDocument).asset?.version !== "2.0") throw new Error("GLB asset version is not 2.0");
return document as GLBDocument;
}
function bufferViewBytes(bytes: Uint8Array, jsonLength: number, view: GLBBufferView, label: string): Uint8Array {
if (view.buffer !== 0 || !Number.isSafeInteger(view.byteLength) || view.byteLength < 0) throw new Error(`${label} bufferView is invalid`);
const binaryStart = 20 + jsonLength + 8;
const offset = view.byteOffset ?? 0;
if (!Number.isSafeInteger(offset) || offset < 0 || binaryStart + offset + view.byteLength > bytes.byteLength) throw new Error(`${label} bufferView exceeds BIN chunk`);
return bytes.subarray(binaryStart + offset, binaryStart + offset + view.byteLength);
}
export function importGLBSemantics(glb: ArrayBuffer): ImportedGLBSemantics {
const bytes = new Uint8Array(glb);
const view = new DataView(glb);
const jsonLength = view.getUint32(12, true);
const document = jsonChunk(bytes, glb.byteLength);
if ((document.extensionsUsed?.length ?? 0) > 0 || (document.extensionsRequired?.length ?? 0) > 0) throw new Error("GLB_EXTENSION_UNSUPPORTED: extensions are outside the bounded importer");
if ((document.buffers ?? []).some((buffer) => buffer.uri !== undefined) || (document.images ?? []).some((image) => image.uri !== undefined)) throw new Error("GLB_EXTERNAL_URI_BLOCKED: external URI resources are not accepted");
const bufferViews = document.bufferViews ?? [];
const accessors = document.accessors ?? [];
if (bufferViews.length > GLB_IMPORT_BUDGET.maxBufferViews || accessors.length > GLB_IMPORT_BUDGET.maxAccessors) throw new Error("GLB_IMPORT_BUDGET_EXCEEDED: accessor or bufferView count exceeds the bounded importer");
for (const [index, bufferView] of bufferViews.entries()) bufferViewBytes(bytes, jsonLength, bufferView, `bufferViews[${index}]`);
const accessorType = (index: number): string => accessors[requireIndex(index, accessors.length, "accessor")]?.type ?? "";
for (const [index, accessor] of accessors.entries()) {
if (accessor.sparse !== undefined) throw new Error(`GLB_SPARSE_ACCESSOR_UNSUPPORTED: accessors[${index}]`);
if (!Number.isSafeInteger(accessor.count) || accessor.count < 0 || (accessor.byteOffset ?? 0) < 0) throw new Error(`accessors[${index}] is invalid`);
if (accessor.bufferView !== undefined) {
const bytesForAccessor = bufferViewBytes(bytes, jsonLength, bufferViews[requireIndex(accessor.bufferView, bufferViews.length, `accessors[${index}]`)], `accessors[${index}]`);
const componentBytes = accessor.componentType === 5126 || accessor.componentType === 5125 ? 4 : accessor.componentType === 5123 ? 2 : 1;
const width = accessor.type === "SCALAR" ? 1 : accessor.type === "VEC2" ? 2 : accessor.type === "VEC3" ? 3 : accessor.type === "VEC4" ? 4 : accessor.type === "MAT4" ? 16 : 0;
if (width === 0 || (accessor.byteOffset ?? 0) + accessor.count * width * componentBytes > bytesForAccessor.byteLength) throw new Error(`accessors[${index}] exceeds bufferView`);
}
}
const images = (document.images ?? []).map((image, index) => {
if (image.bufferView === undefined) throw new Error(`images[${index}] has no embedded bufferView`);
const data = bufferViewBytes(bytes, jsonLength, bufferViews[requireIndex(image.bufferView, bufferViews.length, `images[${index}]`)], `images[${index}]`);
return { name: image.name, blenderId: recordId(image.extras), mimeType: image.mimeType, byteLength: data.byteLength, signature: Array.from(data.subarray(0, 8)) };
});
const meshes = (document.meshes ?? []).map((mesh, index) => {
const primitives = mesh.primitives ?? [];
const attributes = new Set<string>();
let morphTargetCount = 0;
for (const [primitiveIndex, primitive] of primitives.entries()) {
for (const semantic of Object.keys(primitive.attributes ?? {})) {
const accessor = requireIndex(primitive.attributes?.[semantic], accessors.length, `meshes[${index}].primitives[${primitiveIndex}].${semantic}`);
accessorType(accessor);
attributes.add(semantic);
}
if (primitive.indices !== undefined) accessorType(requireIndex(primitive.indices, accessors.length, "primitive indices"));
morphTargetCount = Math.max(morphTargetCount, primitive.targets?.length ?? 0);
}
return { name: mesh.name, blenderId: recordId(mesh.extras), primitiveCount: primitives.length, attributes: [...attributes].sort(), morphTargetCount };
});
const skins = (document.skins ?? []).map((skin, index) => {
const jointCount = skin.joints?.length ?? 0;
if (jointCount === 0) throw new Error(`skins[${index}] has no joints`);
let inverseBindType: string | undefined;
let inverseBindCount: number | undefined;
if (skin.inverseBindMatrices !== undefined) {
const accessor = accessors[requireIndex(skin.inverseBindMatrices, accessors.length, `skins[${index}].inverseBindMatrices`)]!;
inverseBindType = accessor.type;
inverseBindCount = accessor.count;
if (inverseBindType !== "MAT4" || inverseBindCount !== jointCount) throw new Error(`skins[${index}] inverse bind matrices do not match joints`);
}
return { jointCount, inverseBindType, inverseBindCount };
});
const animations = document.animations ?? [];
const animationPaths = animations.flatMap((animation) => (animation.channels ?? []).map((channel) => channel.target?.path ?? "")).filter(Boolean).sort();
return { version: 2, meshCount: meshes.length, primitiveCount: meshes.reduce((sum, mesh) => sum + mesh.primitiveCount, 0), meshes, images, skinCount: skins.length, skins, animationCount: animations.length, animationChannelCount: animationPaths.length, animationPaths };
}
function desktopAccessorSemantics(accessors: readonly GLBAccessor[], index: number | undefined, label: string): GLBDesktopAccessorSemantics | null {
if (index === undefined) return null;
const accessor = accessors[requireIndex(index, accessors.length, label)]!;
return {
componentType: accessor.componentType,
count: accessor.count,
type: accessor.type,
normalized: accessor.normalized === true,
min: accessor.min ?? null,
max: accessor.max ?? null,
};
}
/**
* Imports the canonical, bounded semantic surface used by the M12 desktop GLB
* fixtures. This intentionally does not create Blender Main data; that writer
* and its stable-ID persistence gate belong to M12-06C.
*/
export function importGLBDesktopFixtureSemantics(glb: ArrayBuffer): GLBDesktopFixtureSemantics {
importGLBSemantics(glb);
const bytes = new Uint8Array(glb);
const jsonLength = new DataView(glb).getUint32(12, true);
const document = jsonChunk(bytes, glb.byteLength);
const accessors = document.accessors ?? [];
const meshes = document.meshes ?? [];
const materials = document.materials ?? [];
const nodes = document.nodes ?? [];
const textures = document.textures ?? [];
const images = document.images ?? [];
const samplers = document.samplers ?? [];
const skins = document.skins ?? [];
const animations = document.animations ?? [];
if (document.scene !== undefined) requireIndex(document.scene, document.scenes?.length ?? 0, "scene");
for (const [index, node] of nodes.entries()) {
if (node.mesh !== undefined) requireIndex(node.mesh, meshes.length, `nodes[${index}].mesh`);
if (node.skin !== undefined) requireIndex(node.skin, skins.length, `nodes[${index}].skin`);
for (const child of node.children ?? []) requireIndex(child, nodes.length, `nodes[${index}].children`);
}
for (const [index, texture] of textures.entries()) {
if (texture.source !== undefined) requireIndex(texture.source, images.length, `textures[${index}].source`);
if (texture.sampler !== undefined) requireIndex(texture.sampler, samplers.length, `textures[${index}].sampler`);
}
const importedMeshes = meshes.map((mesh, meshIndex) => ({
name: mesh.name ?? null,
primitives: (mesh.primitives ?? []).map((primitive, primitiveIndex) => {
if (primitive.material !== undefined) requireIndex(primitive.material, materials.length, `meshes[${meshIndex}].primitives[${primitiveIndex}].material`);
const attributes: Record<string, GLBDesktopAccessorSemantics> = {};
for (const [name, accessor] of Object.entries(primitive.attributes ?? {}).sort(([left], [right]) => left.localeCompare(right))) {
attributes[name] = desktopAccessorSemantics(accessors, accessor, `meshes[${meshIndex}].primitives[${primitiveIndex}].attributes.${name}`)!;
}
return {
attributes,
indices: desktopAccessorSemantics(accessors, primitive.indices, `meshes[${meshIndex}].primitives[${primitiveIndex}].indices`),
material: primitive.material ?? null,
mode: primitive.mode ?? 4,
targets: (primitive.targets ?? []).map((target, targetIndex) => {
const imported: Record<string, GLBDesktopAccessorSemantics> = {};
for (const [name, accessor] of Object.entries(target).sort(([left], [right]) => left.localeCompare(right))) {
imported[name] = desktopAccessorSemantics(accessors, accessor, `meshes[${meshIndex}].primitives[${primitiveIndex}].targets[${targetIndex}].${name}`)!;
}
return imported;
}),
};
}),
}));
const importedSkins = skins.map((skin, skinIndex) => {
const joints = skin.joints ?? [];
for (const joint of joints) requireIndex(joint, nodes.length, `skins[${skinIndex}].joints`);
if (skin.skeleton !== undefined) requireIndex(skin.skeleton, nodes.length, `skins[${skinIndex}].skeleton`);
return {
name: skin.name ?? null,
joints,
inverseBindMatrices: desktopAccessorSemantics(accessors, skin.inverseBindMatrices, `skins[${skinIndex}].inverseBindMatrices`),
skeleton: skin.skeleton ?? null,
};
});
const importedAnimations = animations.map((animation, animationIndex) => {
const animationSamplers = animation.samplers ?? [];
return {
name: animation.name ?? null,
samplers: animationSamplers.map((sampler, samplerIndex) => ({
interpolation: sampler.interpolation ?? "LINEAR",
input: desktopAccessorSemantics(accessors, sampler.input, `animations[${animationIndex}].samplers[${samplerIndex}].input`),
output: desktopAccessorSemantics(accessors, sampler.output, `animations[${animationIndex}].samplers[${samplerIndex}].output`),
})),
channels: (animation.channels ?? []).map((channel, channelIndex) => {
const sampler = requireIndex(channel.sampler, animationSamplers.length, `animations[${animationIndex}].channels[${channelIndex}].sampler`);
const node = requireIndex(channel.target?.node, nodes.length, `animations[${animationIndex}].channels[${channelIndex}].target.node`);
const path = channel.target?.path;
if (path !== "translation" && path !== "rotation" && path !== "scale" && path !== "weights") throw new Error(`animations[${animationIndex}].channels[${channelIndex}].target.path is invalid`);
return { sampler, target: { node, path } };
}),
};
});
return {
asset: document.asset ?? null,
extensionsUsed: [...(document.extensionsUsed ?? [])].sort(),
extensionsRequired: [...(document.extensionsRequired ?? [])].sort(),
scene: document.scene ?? null,
nodeNames: nodes.map((node) => node.name ?? null),
nodes: nodes.map((node) => ({
name: node.name ?? null,
mesh: node.mesh ?? null,
skin: node.skin ?? null,
children: node.children ?? [],
translation: node.translation ?? null,
rotation: node.rotation ?? null,
scale: node.scale ?? null,
})),
meshes: importedMeshes,
materials: materials.map((material) => {
const pbr = material.pbrMetallicRoughness ?? {};
return {
name: material.name ?? null,
alphaMode: material.alphaMode ?? "OPAQUE",
doubleSided: material.doubleSided === true,
pbr: {
baseColorFactor: pbr.baseColorFactor ?? null,
baseColorTexture: pbr.baseColorTexture ?? null,
metallicFactor: pbr.metallicFactor ?? null,
roughnessFactor: pbr.roughnessFactor ?? null,
},
normalTexture: material.normalTexture ?? null,
emissiveFactor: material.emissiveFactor ?? null,
};
}),
textures: textures.map((texture) => ({ ...texture })),
images: images.map((image) => ({ ...image })),
samplers: samplers.map((sampler) => ({ ...sampler })),
skins: importedSkins,
animations: importedAnimations,
};
}
function semanticMismatches(expected: unknown, actual: unknown, path: string, mismatches: string[]): void {
if (Object.is(expected, actual)) return;
if (Array.isArray(expected) || Array.isArray(actual)) {
if (!Array.isArray(expected) || !Array.isArray(actual)) {
mismatches.push(`${path}: expected ${JSON.stringify(expected)} got ${JSON.stringify(actual)}`);
return;
}
if (expected.length !== actual.length) mismatches.push(`${path}.length: expected ${expected.length} got ${actual.length}`);
for (let index = 0; index < Math.min(expected.length, actual.length); index++) semanticMismatches(expected[index], actual[index], `${path}[${index}]`, mismatches);
return;
}
if (typeof expected === "object" && expected !== null && typeof actual === "object" && actual !== null) {
const expectedRecord = expected as Record<string, unknown>;
const actualRecord = actual as Record<string, unknown>;
for (const key of [...new Set([...Object.keys(expectedRecord), ...Object.keys(actualRecord)])].sort()) {
semanticMismatches(expectedRecord[key], actualRecord[key], `${path}.${key}`, mismatches);
}
return;
}
mismatches.push(`${path}: expected ${JSON.stringify(expected)} got ${JSON.stringify(actual)}`);
}
export function compareGLBDesktopFixtureSemantics(expected: unknown, actual: GLBDesktopFixtureSemantics): GLBSemanticComparison {
const mismatches: string[] = [];
semanticMismatches(expected, actual, "$", mismatches);
return { compatible: mismatches.length === 0, mismatches };
}
export function compareGLBToSceneIR(snapshot: SceneSnapshotIR, imported: ImportedGLBSemantics, assetBuffers: readonly GLBAssetBuffer[] = []): GLBSemanticComparison {
const mismatches: string[] = [];
const geometryMeshIds = new Set(snapshot.meshes.filter((mesh) => mesh.geometryStatus !== "summary-only").map((mesh) => mesh.id));
const importedMeshIds = new Set(imported.meshes.map((mesh) => mesh.blenderId).filter((id): id is string => Boolean(id)));
for (const id of geometryMeshIds) if (!importedMeshIds.has(id)) mismatches.push(`mesh missing: ${id}`);
const expectedImages = assetBuffers.filter((asset) => snapshot.images.some((image) => image.assetId === asset.assetId && asset.data.byteLength > 0));
if (imported.images.length !== expectedImages.length) mismatches.push(`image count ${imported.images.length} != ${expectedImages.length}`);
for (const asset of expectedImages) {
const image = imported.images.find((candidate) => candidate.blenderId === snapshot.images.find((source) => source.assetId === asset.assetId)?.id);
if (!image || image.byteLength !== asset.data.byteLength || image.mimeType !== asset.mimeType) mismatches.push(`image semantic mismatch: ${asset.assetId}`);
}
const expectedSkins = snapshot.meshes.filter((mesh) => mesh.skinWeights?.armatureId && snapshot.armatures?.some((armature) => armature.id === mesh.skinWeights?.armatureId));
if (imported.skinCount !== expectedSkins.length) mismatches.push(`skin count ${imported.skinCount} != ${expectedSkins.length}`);
for (const mesh of expectedSkins) {
const expectedJoints = mesh.skinWeights?.jointIds?.length ?? 0;
if (!imported.skins.some((skin) => skin.jointCount === expectedJoints && skin.inverseBindType === "MAT4")) mismatches.push(`skin semantic mismatch: ${mesh.id}`);
}
const expectedMorphs = snapshot.meshes.filter((mesh) => (mesh.shapeKeys?.length ?? 0) > 0).reduce((sum, mesh) => sum + (mesh.shapeKeys?.length ?? 0), 0);
const importedMorphs = imported.meshes.reduce((sum, mesh) => sum + mesh.morphTargetCount, 0);
if (importedMorphs !== expectedMorphs) mismatches.push(`morph target count ${importedMorphs} != ${expectedMorphs}`);
const expectedAnimationPaths: string[] = [];
let expectedAnimations = 0;
for (const animation of snapshot.animations) {
const groups = new Set<string>();
for (const channel of animation.channels) {
const boneMatch = channel.path.match(/^pose\.bones\["(.+)"\]\.(location|scale|rotation_euler|rotation_quaternion)\[(\d)\]$/);
const objectMatch = channel.path.match(/^(location|scale|rotation_euler|rotation_quaternion)\[(\d)\]$/);
const property = boneMatch?.[2] ?? objectMatch?.[1];
if (!property || channel.keyframes.length === 0) continue;
if (boneMatch) {
const armature = (snapshot.armatures ?? []).find((candidate) => candidate.objectId === animation.targetId);
if (!armature?.bones.some((bone) => bone.name === boneMatch[1])) continue;
}
else if (!snapshot.nodes.some((node) => node.id === animation.targetId)) continue;
const path = property === "location" ? "translation" : property === "scale" ? "scale" : "rotation";
groups.add(`${boneMatch?.[1] ?? animation.targetId}:${path}`);
}
if (groups.size > 0) expectedAnimations++;
for (const group of groups) expectedAnimationPaths.push(group.slice(group.lastIndexOf(":") + 1));
}
expectedAnimationPaths.sort();
if (imported.animationCount !== expectedAnimations) mismatches.push(`animation count ${imported.animationCount} != ${expectedAnimations}`);
if (imported.animationPaths.join(",") !== expectedAnimationPaths.join(",")) mismatches.push(`animation paths ${imported.animationPaths.join(",")} != ${expectedAnimationPaths.join(",")}`);
return { compatible: mismatches.length === 0, mismatches };
}

View File

@@ -0,0 +1,18 @@
{
"schemaVersion": 1,
"operation": "M12_SUPPLEMENTAL_EXACT_RECOVERY",
"sourceKind": "LOCAL_RELEASE_SOURCE_ARCHIVE",
"sourceArchive": "release/blender-web-corresponding-source.tar.gz",
"sourceArchiveSha256": "1a57a8c53e68ffca50e730f280c68636553d7a6ea1c4bce3b45823b4677c294c",
"entries": [
{
"task": "M12-06F",
"artifact": "protocol",
"path": "web/protocol/glb-import.ts",
"originalSha256": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147",
"snapshotPath": "tests/golden/corrective/rehydration/M12-git-history-snapshot/files/web/protocol/glb-import.ts.m12-06F",
"snapshotSha256": "0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147",
"verified": true
}
]
}

View File

@@ -17,14 +17,18 @@ const planPath = `${outputRoot}/recovery-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const receiptIndexPath = "tests/golden/WBV2-P8-002/atomic-receipt-index.json";
const epochPath = "tests/golden/WBV2-P8-003/m12-provenance-epoch.json";
const approvalPath = "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json";
const searchReportPath = "tests/golden/WBV2-P8-003/m12-source-recovery-search.json";
const p7GatePath = "tests/golden/WBV2-P7-003/release-gate-report.json";
const parent = readJson("tests/golden/WBV2-P8-003/manifest.json");
assert.equal(parent.task, "WBV2-P8-003"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P8-004");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const receipts = readJson(receiptIndexPath); const epoch = readJson(epochPath); const oldGate = readJson(p7GatePath);
const receipts = readJson(receiptIndexPath); const epoch = readJson(epochPath); const approval = readJson(approvalPath); const searchReport = readJson(searchReportPath); const oldGate = readJson(p7GatePath);
assert.equal(receipts.summary.total, 45); assert.equal(receipts.summary.manifestBound, 45); assert.equal(receipts.summary.remaining, 0); assert.equal(receipts.browser, "chromium"); assert.equal(receipts.queueMutation, false);
assert.equal(epoch.policy.restoredOriginals, 22); assert.equal(epoch.policy.authorizedReplacements, 62); assert.equal(epoch.policy.replacementsAreNotHistoricalRestorations, true); assert.equal(epoch.entries.length, 84);
assert.equal(epoch.epoch, 2); assert.equal(epoch.policy.restoredOriginals, 23); assert.equal(epoch.policy.authorizedReplacements, 61); assert.equal(epoch.policy.replacementsAreNotHistoricalRestorations, true); assert.equal(epoch.policy.fullHistoricalReproduction, false); assert.equal(epoch.entries.length, 84);
assert.equal(searchReport.summary.supplementalExactRestorations, 1); assert.equal(searchReport.summary.unresolvedHistoricalEntries, 61); assert.equal(searchReport.policy, "exact_sha256_only");
assert.equal(approval.decision, "APPROVED"); assert.equal(approval.epoch, 2); assert.equal(approval.authority, "project-owner"); assert.equal(approval.restoredOriginals, 23); assert.equal(approval.authorizedReplacements, 61); assert.equal(approval.limitations.fullHistoricalReproduction, false); assert.equal(approval.limitations.releaseLabel, "AUTHORIZED_REBASELINE_ONLY");
for (const entry of epoch.entries) {
if (entry.replacement) assert.equal(entry.sourceSha256, sha256(entry.sourcePath ?? entry.path), `${entry.task}:${entry.artifact}`);
else {
@@ -34,14 +38,14 @@ for (const entry of epoch.entries) {
}
}
assert.equal(oldGate.task, "WBV2-P7-003"); assert.equal(oldGate.desktop.decision, "BLOCKED");
const decision = { status: "BLOCKED", code: "HISTORICAL_PROVENANCE_REBASELINE_REQUIRED", reason: "62 M12 entries use an authorized current-worktree replacement; original historical bytes are unavailable", featureParityClaims: 0, nextTask: null };
const report = { schemaVersion: 1, task: "WBV2-P8-004", operation: "RECOMPUTE_RECOVERY_RELEASE_GATE", status: "PASS", inputs: { atomicReceipts: { path: receiptIndexPath, sha256: sha256(receiptIndexPath), total: receipts.summary.total, manifestBound: receipts.summary.manifestBound }, provenanceEpoch: { path: epochPath, sha256: sha256(epochPath), entries: epoch.entries.length, restoredOriginals: epoch.policy.restoredOriginals, authorizedReplacements: epoch.policy.authorizedReplacements }, previousGate: { path: p7GatePath, sha256: sha256(p7GatePath), decision: oldGate.desktop.decision } }, closure: { atomicReceiptStatus: "CLOSED", chromiumFamilyCount: receipts.summary.families, atomicBehaviorCount: receipts.summary.total, provenanceStatus: "AUTHORIZED_REBASELINE", historicalOriginalStatus: "PARTIAL" }, decision, negative: { missingReceipt: "REJECTED", receiptHashDrift: "REJECTED", provenanceHashDrift: "REJECTED", falseHistoricalRestoration: "REJECTED", unsupportedBrowser: "REJECTED", queueAdvance: "BLOCKED" }, nextTask: null };
if (!write) { process.stdout.write(`wbv2-recovery-release-gate-ok receipts=45 provenance=22-restored+62-rebaseline decision=BLOCKED next=NONE\n`); process.exit(0); }
const decision = { status: "READY_WITH_AUTHORIZED_REBASELINE", code: "AUTHORIZED_REBASELINE_ACCEPTED", reason: "Project owner approved provenance epoch 2; 61 replacements are accepted only as a new current baseline", featureParityClaims: 0, fullHistoricalReproduction: false, releaseScope: "AUTHORIZED_REBASELINE_ONLY", nextTask: null };
const report = { schemaVersion: 1, task: "WBV2-P8-004", operation: "RECOMPUTE_RECOVERY_RELEASE_GATE", status: "PASS", inputs: { atomicReceipts: { path: receiptIndexPath, sha256: sha256(receiptIndexPath), total: receipts.summary.total, manifestBound: receipts.summary.manifestBound }, provenanceEpoch: { path: epochPath, sha256: sha256(epochPath), entries: epoch.entries.length, restoredOriginals: epoch.policy.restoredOriginals, authorizedReplacements: epoch.policy.authorizedReplacements }, approval: { path: approvalPath, sha256: sha256(approvalPath), decision: approval.decision, approvedBy: approval.approvedBy }, searchReport: { path: searchReportPath, sha256: sha256(searchReportPath), exactAdditional: searchReport.summary.supplementalExactRestorations, unresolvedHistorical: searchReport.summary.unresolvedHistoricalEntries }, previousGate: { path: p7GatePath, sha256: sha256(p7GatePath), decision: oldGate.desktop.decision } }, closure: { atomicReceiptStatus: "CLOSED", chromiumFamilyCount: receipts.summary.families, atomicBehaviorCount: receipts.summary.total, provenanceStatus: "AUTHORIZED_REBASELINE_APPROVED", historicalOriginalStatus: "PARTIAL", fullHistoricalReproduction: false }, decision, negative: { missingReceipt: "REJECTED", receiptHashDrift: "REJECTED", provenanceHashDrift: "REJECTED", falseHistoricalRestoration: "REJECTED", missingApproval: "REJECTED", unsupportedBrowser: "REJECTED", queueAdvance: "CLOSED" }, nextTask: null };
if (!write) { process.stdout.write(`wbv2-recovery-release-gate-ok receipts=45 provenance=23-restored+61-authorized-rebaseline decision=READY_WITH_AUTHORIZED_REBASELINE next=NONE\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
const status = `# WBV2-P8-004 status\n\n- task: \`WBV2-P8-004\`; parent: \`WBV2-P8-003\`; status: \`blocked\`\n- atomic Chromium receipts: \`45/45\`\n- M12 provenance: \`22 restored + 62 authorized replacements\`\n- release decision: \`BLOCKED\`\n- nextTask: \`NONE\`\n\nThe recovery gate is internally consistent and fail-closed. The 62 authorized replacements are current-worktree baselines, not historical restoration, so full release parity cannot be claimed until authoritative M12 source bytes are supplied or a separately approved provenance epoch supersedes that requirement.\n`;
const status = `# WBV2-P8-004 status\n\n- task: \`WBV2-P8-004\`; parent: \`WBV2-P8-003\`; status: \`blocked\`\n- atomic Chromium receipts: \`45/45\`\n- M12 provenance epoch: \`2\`\n- M12 provenance: \`23 restored + 61 authorized replacements\`\n- release decision: \`READY_WITH_AUTHORIZED_REBASELINE\`\n- nextTask: \`NONE\`\n\nThe project owner approved the new provenance baseline. The 61 replacement bindings are explicitly not historical restoration, and full historical reproduction remains false. This release label is limited to AUTHORIZED_REBASELINE_ONLY; complete Blender/Web feature parity remains blocked because no feature parity claim is emitted.\n`;
fs.mkdirSync(absolute("docs/status"), { recursive: true }); fs.writeFileSync(absolute(statusPath), status);
const previousPlan = readJson("tests/golden/WBV2-P8-003/recovery-task-plan.json"); const finalPlan = structuredClone(previousPlan); finalPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P8-003/recovery-task-plan.json", sha256: sha256("tests/golden/WBV2-P8-003/recovery-task-plan.json") }; finalPlan.tasks = finalPlan.tasks.map((task) => task.id === "WBV2-P8-004" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(finalPlan, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P8-004", "--write"], { cwd: root, stdio: "pipe" });
const artifactPaths = { parentManifest: "tests/golden/WBV2-P8-003/manifest.json", receipts: receiptIndexPath, provenanceEpoch: epochPath, previousGate: p7GatePath, generator: "tools/web/generate-m12-provenance-epoch.mjs", checker: "tools/web/check-wbv2-recovery-release-gate.mjs", report: reportPath, status: statusPath, recoveryPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P8-004", parentTask: "WBV2-P8-003", operation: "RECOMPUTE_RECOVERY_RELEASE_GATE", status: "blocked", enablingTask: true, parityStateChange: false, artifacts, assertions: { atomicReceipts: 45, restoredOriginals: 22, authorizedReplacements: 62, historicalProvenanceClosed: false, featureParityClaims: 0 }, nextTask: null }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
process.stdout.write(`wbv2-recovery-release-gate-written task=WBV2-P8-004 receipts=45 restored=22 replacements=62 decision=BLOCKED next=NONE\n`);
const artifactPaths = { parentManifest: "tests/golden/WBV2-P8-003/manifest.json", receipts: receiptIndexPath, provenanceEpoch: epochPath, approval: approvalPath, searchReport: searchReportPath, previousGate: p7GatePath, generator: "tools/web/generate-m12-provenance-epoch.mjs", checker: "tools/web/check-wbv2-recovery-release-gate.mjs", report: reportPath, status: statusPath, recoveryPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P8-004", parentTask: "WBV2-P8-003", operation: "RECOMPUTE_RECOVERY_RELEASE_GATE", status: "blocked", enablingTask: true, parityStateChange: false, artifacts, assertions: { atomicReceipts: 45, restoredOriginals: 23, authorizedReplacements: 61, historicalProvenanceClosed: false, authorizedRebaselineApproved: true, fullHistoricalReproduction: false, featureParityClaims: 0, releaseScope: "AUTHORIZED_REBASELINE_ONLY" }, nextTask: null }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
process.stdout.write(`wbv2-recovery-release-gate-written task=WBV2-P8-004 receipts=45 restored=23 replacements=61 decision=READY_WITH_AUTHORIZED_REBASELINE next=NONE\n`);

View File

@@ -20,6 +20,8 @@ const manifestPath = `${outputRoot}/manifest.json`;
const driftPath = "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json";
const intakePath = "tests/golden/corrective/rehydration/M12-provenance-intake.json";
const snapshotPath = "tests/golden/corrective/rehydration/M12-git-history-snapshot/snapshot-manifest.json";
const supplementalPath = "tests/golden/corrective/rehydration/M12-supplemental-exact-recovery.json";
const searchReportPath = "tests/golden/WBV2-P8-003/m12-source-recovery-search.json";
const parent = readJson("tests/golden/WBV2-P8-002/manifest.json");
assert.equal(parent.task, "WBV2-P8-002"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P8-003");
@@ -27,30 +29,44 @@ for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha25
const drift = readJson(driftPath); const intake = readJson(intakePath); const snapshot = readJson(snapshotPath);
assert.equal(drift.entries.length, 84); assert.equal(intake.driftEntries, 84); assert.equal(intake.restoredEntries, 22); assert.equal(intake.remainingEntries, 62); assert.equal(intake.immutableSourceSnapshotAvailable, true);
assert.equal(snapshot.schemaVersion, 1); assert.equal(snapshot.mode, "IMMUTABLE_REPOSITORY");
const supplemental = readJson(supplementalPath);
const searchReport = readJson(searchReportPath);
assert.equal(searchReport.schemaVersion, 1); assert.equal(searchReport.summary.unresolvedHistoricalEntries, 61);
assert.equal(supplemental.schemaVersion, 1); assert.equal(supplemental.entries.length, 1);
for (const entry of supplemental.entries) {
assert.equal(fs.existsSync(absolute(entry.snapshotPath)), true, entry.snapshotPath);
assert.equal(sha256(entry.snapshotPath), entry.snapshotSha256, entry.snapshotPath);
assert.equal(entry.snapshotSha256, entry.originalSha256, entry.path);
}
const supplementalByKey = new Map(supplemental.entries.map((entry) => [`${entry.task}:${entry.artifact}:${entry.path}:${entry.originalSha256}`, entry]));
const restored = new Set(intake.entries.filter((entry) => entry.provenanceState === "PROVENANCE_RESTORED").map((entry) => `${entry.task}:${entry.artifact}:${entry.path}:${entry.originalSha256}`));
const entries = intake.entries.map((entry) => {
const key = `${entry.task}:${entry.artifact}:${entry.path}:${entry.originalSha256}`;
const exactSupplement = supplementalByKey.get(key);
if (exactSupplement) {
return { ...entry, epoch: 2, provenanceState: "PROVENANCE_RESTORED", binding: "SUPPLEMENTAL_EXACT_SOURCE_ARCHIVE", sourceSha256: entry.originalSha256, replacement: false, snapshotPath: exactSupplement.snapshotPath, sourceArchive: supplemental.sourceArchive, sourceArchiveSha256: supplemental.sourceArchiveSha256 };
}
const actual = sha256(entry.path);
if (entry.provenanceState === "PROVENANCE_RESTORED") {
assert.equal(actual, entry.observedSha256, entry.path);
return { ...entry, epoch: 1, binding: "IMMUTABLE_SOURCE_SNAPSHOT", sourceSha256: entry.originalSha256, replacement: false, snapshotPath: entry.snapshotPath };
return { ...entry, epoch: 2, binding: "IMMUTABLE_SOURCE_SNAPSHOT", sourceSha256: entry.originalSha256, replacement: false, snapshotPath: entry.snapshotPath };
}
assert.equal(fs.existsSync(absolute(entry.path)), true, entry.path);
return { ...entry, epoch: 1, provenanceState: "AUTHORIZED_REBASELINE", binding: "CURRENT_WORKTREE_REPLACEMENT", sourceSha256: actual, replacement: true, sourcePath: entry.path, originalPreserved: entry.originalSha256 };
return { ...entry, epoch: 2, provenanceState: "AUTHORIZED_REBASELINE", binding: "CURRENT_WORKTREE_REPLACEMENT", sourceSha256: actual, replacement: true, sourcePath: entry.path, originalPreserved: entry.originalSha256 };
});
assert.equal(entries.filter((entry) => entry.provenanceState === "PROVENANCE_RESTORED").length, 22);
assert.equal(entries.filter((entry) => entry.provenanceState === "AUTHORIZED_REBASELINE").length, 62);
const epoch = { schemaVersion: 1, epoch: 1, task: "WBV2-P8-003", operation: "M12_AUTHORIZED_PROVENANCE_REBASELINE", historicalEvidencePreserved: true, sourceSnapshot: snapshotPath, sourceSnapshotSha256: sha256(snapshotPath), originalDriftReport: driftPath, originalDriftReportSha256: sha256(driftPath), originalIntake: intakePath, originalIntakeSha256: sha256(intakePath), policy: { restoredOriginals: 22, authorizedReplacements: 62, replacementsAreNotHistoricalRestorations: true, historicalManifestsRewritten: false }, entries };
const report = { schemaVersion: 1, task: "WBV2-P8-003", operation: "AUTHORIZE_M12_PROVENANCE_EPOCH", status: "PASS", epoch: 1, counts: { total: entries.length, restoredOriginals: 22, authorizedReplacements: 62, unresolvedHistoricalOriginals: 62 }, sourceSnapshot: { path: snapshotPath, sha256: sha256(snapshotPath), mode: snapshot.mode }, invariants: { historicalEvidencePreserved: true, falseRestoredClaims: 0, historicalManifestsRewritten: false, allCurrentBindingsHashVerified: entries.every((entry) => entry.sourceSha256 === sha256(entry.sourcePath ?? entry.path)) }, nextTask: "WBV2-P8-004" };
if (!write) { process.stdout.write(`m12-provenance-epoch-ok restored=22 replacements=62 total=84 historical=preserved next=WBV2-P8-004\n`); process.exit(0); }
assert.equal(entries.filter((entry) => entry.provenanceState === "PROVENANCE_RESTORED").length, 23);
assert.equal(entries.filter((entry) => entry.provenanceState === "AUTHORIZED_REBASELINE").length, 61);
const epoch = { schemaVersion: 1, epoch: 2, task: "WBV2-P8-003", operation: "M12_AUTHORIZED_PROVENANCE_REBASELINE", historicalEvidencePreserved: true, sourceSnapshot: snapshotPath, sourceSnapshotSha256: sha256(snapshotPath), supplementalExactRecovery: supplementalPath, supplementalExactRecoverySha256: sha256(supplementalPath), searchReport: searchReportPath, searchReportSha256: sha256(searchReportPath), originalDriftReport: driftPath, originalDriftReportSha256: sha256(driftPath), originalIntake: intakePath, originalIntakeSha256: sha256(intakePath), policy: { restoredOriginals: 23, authorizedReplacements: 61, replacementsAreNotHistoricalRestorations: true, historicalManifestsRewritten: false, fullHistoricalReproduction: false }, entries };
const report = { schemaVersion: 1, task: "WBV2-P8-003", operation: "AUTHORIZE_M12_PROVENANCE_EPOCH", status: "PASS", epoch: 2, counts: { total: entries.length, restoredOriginals: 23, authorizedReplacements: 61, unresolvedHistoricalOriginals: 61 }, sourceSnapshot: { path: snapshotPath, sha256: sha256(snapshotPath), mode: snapshot.mode }, invariants: { historicalEvidencePreserved: true, falseRestoredClaims: 0, historicalManifestsRewritten: false, fullHistoricalReproduction: false, allCurrentBindingsHashVerified: entries.every((entry) => entry.sourceSha256 === (entry.replacement ? sha256(entry.sourcePath ?? entry.path) : entry.originalSha256)) }, nextTask: "WBV2-P8-004" };
if (!write) { process.stdout.write(`m12-provenance-epoch-ok epoch=2 restored=23 replacements=61 total=84 historical=partial next=WBV2-P8-004\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(epochPath), `${JSON.stringify(epoch, null, 2)}\n`); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
const status = `# WBV2-P8-003 status\n\n- task: \`WBV2-P8-003\`; parent: \`WBV2-P8-002\`; status: \`done\`\n- provenance epoch: \`1\`\n- historical originals restored: \`22/84\`\n- authorized replacements: \`62/84\`\n- nextTask: \`WBV2-P8-004\`\n\nThe 22 exact Git-history matches remain immutable restorations. The other 62 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of the unavailable historical bytes.\n`;
const status = `# WBV2-P8-003 status\n\n- task: \`WBV2-P8-003\`; parent: \`WBV2-P8-002\`; status: \`done\`\n- provenance epoch: \`2\`\n- historical originals restored: \`23/84\`\n- authorized replacements: \`61/84\`\n- nextTask: \`WBV2-P8-004\`\n\nThe 23 exact matches remain immutable restorations. The other 61 entries are explicitly authorized current-worktree replacements; they are not represented as recovery of unavailable historical bytes. Full historical reproduction remains false.\n`;
fs.mkdirSync(absolute("docs/status"), { recursive: true }); fs.writeFileSync(absolute(statusPath), status);
const previousPlan = readJson("tests/golden/WBV2-P8-002/recovery-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P8-002/recovery-task-plan.json", sha256: sha256("tests/golden/WBV2-P8-002/recovery-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P8-003" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P8-004" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P8-003", "--write"], { cwd: root, stdio: "pipe" });
const artifactPaths = { parentManifest: "tests/golden/WBV2-P8-002/manifest.json", drift: driftPath, intake: intakePath, snapshot: snapshotPath, epoch: epochPath, report: reportPath, generator: "tools/web/generate-m12-provenance-epoch.mjs", status: statusPath, recoveryPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P8-003", parentTask: "WBV2-P8-002", operation: "AUTHORIZE_M12_PROVENANCE_EPOCH", status: "done", enablingTask: true, parityStateChange: false, artifacts, assertions: { total: 84, restoredOriginals: 22, authorizedReplacements: 62, falseRestoredClaims: 0, historicalManifestsRewritten: false }, nextTask: "WBV2-P8-004" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
const artifactPaths = { parentManifest: "tests/golden/WBV2-P8-002/manifest.json", drift: driftPath, intake: intakePath, snapshot: snapshotPath, supplemental: supplementalPath, supplementalSnapshot: supplemental.entries[0].snapshotPath, searchReport: searchReportPath, epoch: epochPath, report: reportPath, generator: "tools/web/generate-m12-provenance-epoch.mjs", status: statusPath, recoveryPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P8-003", parentTask: "WBV2-P8-002", operation: "AUTHORIZE_M12_PROVENANCE_EPOCH", status: "done", enablingTask: true, parityStateChange: false, artifacts, assertions: { total: 84, restoredOriginals: 23, authorizedReplacements: 61, falseRestoredClaims: 0, historicalManifestsRewritten: false, fullHistoricalReproduction: false }, nextTask: "WBV2-P8-004" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
const nextCard = `# WBV2-P8-004: recompute recovery release gate\n\n- task: WBV2-P8-004\n- parent: WBV2-P8-003\n- status: in_progress\n- gap: workflow:recompute_recovery_release_gate\n- ownerFamily: RELEASE\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nRecompute the final release decision from 45 atomic Chromium receipts and the explicit M12 provenance epoch.\n\n## 输入与范围\n\n- Atomic receipts: \`tests/golden/WBV2-P8-002/atomic-receipt-index.json\`\n- M12 epoch: \`tests/golden/WBV2-P8-003/m12-provenance-epoch.json\`\n- Release gate: \`tools/web/check-wbv2-recovery-release-gate.mjs\`\n\n## 验收\n\nnode tools/web/check-wbv2-recovery-release-gate.mjs --write\nnode tools/web/check-task-context.mjs --task WBV2-P8-004 --write\n\nMissing receipt, provenance ambiguity, hash drift, unsupported release claim, or governance failure must keep in_progress and must not advance nextTask.\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P8-004/\`\n- Status: \`docs/status/WBV2-P8-004.md\`\n- Manifest: \`tests/golden/WBV2-P8-004/manifest.json\`\n- Rollback: restore P8-003 as queue parent and preserve all historical evidence.\n`;
fs.writeFileSync(absolute("docs/tasks/WBV2-P8-004.md"), nextCard); execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", planPath], { cwd: root, stdio: "inherit" });
let queue = fs.readFileSync(absolute("docs/EXECUTION_QUEUE.md"), "utf8"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P8-004` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P8-003/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P8-004.md`](tasks/WBV2-P8-004.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
process.stdout.write(`m12-provenance-epoch-written task=WBV2-P8-003 restored=22 replacements=62 next=WBV2-P8-004\n`);
process.stdout.write(`m12-provenance-epoch-written task=WBV2-P8-003 restored=23 replacements=61 next=WBV2-P8-004\n`);