Checkpoint web parity through Chromium input tasks
Some checks are pending
M6 deployable RC / quick (push) Waiting to run
M6 deployable RC / chromium (push) Blocked by required conditions
M6 deployable RC / release (push) Blocked by required conditions

This commit is contained in:
mes123456
2026-08-19 10:39:03 -04:00
parent 5a11045ca5
commit 380cbed4ff
634 changed files with 41862 additions and 212 deletions

54
docs/status/M12-03E.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-03E Status
status: done
task: append undo/redo/save/reopen and desktop canonical comparison
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The M12-03D WASM Main append path is compared with the M12-03C Blender 5.2 desktop canonical
report. One append transaction creates the Object/Mesh/Material/packed Image local closure and
advances exactly one SceneIR revision. Undo removes all four IDs, redo restores the canonical
graph, and a saved buffer reopens with the same graph and packed image pixels.
The image comparison normalizes Blender's bottom-up `Image.pixels` row order versus Canvas
top-down `ImageData`. Current SceneIR omits `Image.colorSpace`, so a missing field uses the desktop
canonical sRGB semantic default; an emitted colorspace must match it. All other graph, ID,
ownership, geometry, UV, material-slot, image metadata, and pixel hash fields remain exact. This
task does not claim Link, Library Override, or full N-023 IO parity.
## Evidence
- `node ../tools/web/check-library-main-append.mjs` passed the manifest, artifact hashes, canonical
desktop report, and required test markers.
- `WEB_TEST_PORT=5194 npm --prefix web run test:library-main-append` passed the checker and
Chromium 1/1. The browser test verified one transaction, four writable `LOCAL_MAIN` mappings,
one revision increment, complete Object -> Mesh -> Material -> Image closure, and exact
canonical graphs after append, redo, and save/reopen.
- A stale base revision returned `REVISION_CONFLICT`; a local ID collision returned
`ASSET_MANIFEST_INVALID` without changing the appended revision. Undo reported no Object, Mesh,
Material, or Image; redo restored the Object and canonical closure.
- The canonical packed image remained a 2x2 sRGB RGBA PNG with Float32 pixel SHA-256
`6f0f8c231d65149e69e6ed12d370bcfa095ef90adc202065492ea8c8ef17e45a`.
## Artifact Hashes
- checker: `7fba72c5a38c0877f03682b51cbaaaf6d9a5f315f2beddfdef432bc54b2f1cd2`
- test: `101f67d35c2320da57459f08a59687d769234b910dbd9aaec5a668cee7e0f9f0`
- package commands: `36a29c5be9bd6163b06cf3511edf77d932388fa0b75c08bdcec397e19c0ef45f`
- source `.blend`: `5b60d02926efd588a6ca300ba31414cdf37dbc48786c17b383a70319057c0606`
- clean target `.blend`: `9b1ecbcc3d7f8079ee5469de64193ffcaa0a7b01e0f2ac340bbb18aa88734a63`
- desktop report: `b1d7b8b9e832d18d69081f63981062800e0f00f0c9aec025b18274510ed76e2a`
- manifest: `beaa88ea0385225e712f9816072420bd8744c15da3229ddc352462abec407739`
## Next Task
`M12-03F`: desktop link fixture preserving source library and read-only ownership.
## Rollback
Remove the M12-03E checker, manifest, extended Chromium test, package command, and this status
entry. Restore M12-03D to pending and move the machine queue back to `M12-03D`. No parity ledger
rollback is required.

49
docs/status/M12-03F.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-03F Status
status: done
task: create a desktop linked Object fixture preserving source-library ownership
updated: 2026-08-17 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Blender 5.2 creates a source library containing one Object with a Mesh, Material, and packed Image
dependency closure. A clean target links only the selected Object with `bpy.data.libraries.load(link=True)`.
The Object, Mesh, Material, and Image retain the source library pointer, have no library override,
and map to read-only `SOURCE_LIBRARY` ownership. The target is saved, reopened in a new Main load,
and compared to the pre-save linked graph.
This task freezes the desktop LINK contract only. It does not implement a WASM link writer, linked
mutation, reload/relocate, missing-library placeholders, or full N-023 parity.
## Evidence
- `npm --prefix web run test:library-link-desktop` passed the manifest/artifact hash gate, Blender
5.2 generator rerun, and canonical report comparison.
- The fixture links one root and four dependency IDs. All three dependency edges, 4 vertices, 4
edges, 1 polygon, 4 loops, `UVMap`, material slot, packed 2x2 sRGB RGBA image, and Float32 pixel
SHA-256 `6f0f8c231d65149e69e6ed12d370bcfa095ef90adc202065492ea8c8ef17e45a` survive save/reopen.
- Every linked ID reports `library=m12_link_source.blend` and `isLibraryOverride=false`; all four
stable mappings are `SOURCE_LIBRARY/readOnly=true`. A temporary source/target regeneration matches
the canonical report after normalizing only session-bound blend container hashes.
## Artifact Hashes
- generator: `15a2e34c1c5b2a8ee63b10084dbb894e0f9677b9e1cf4adb7e2ddce6b4c965b1`
- checker: `6a4c024bea227d7bc14f793467b91766b006459fe4d7717cc75dfee12f49f894`
- source `.blend`: `fae97569e9d2e2066fc92749672f86cc42717cd9b97b012faeb9eb92015d7fd1`
- target `.blend`: `acdaf0f297deb08c84e1a8beba30972e3414ef62e60e3b103fe0661199c438a1`
- desktop report: `b278d4c254eff63d41c8cb3ea1d5e0984192137d45b1695ba0672e16f95b58ea`
- manifest: `8220a8f5d560d45a75a62cbed645b3febc1390fe37b07c3c48871fefc1a9b159`
- package commands: `336d8df1914aaaafaeccc181d4e73ed7058165f10e167efe539939c3ac1e0536`
## Next Task
`M12-03G`: linked data writers must fail closed with `LINKED_DATA_MUTATION_BLOCKED`.
## Rollback
Remove the M12-03F link generator/checker, source and target fixtures, desktop report/manifest,
package command, and this status entry. Restore M12-03E to pending and move the machine queue back
to `M12-03E`. No parity ledger rollback is required.

45
docs/status/M12-03G.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-03G Status
status: done
task: block every linked data writer before Main mutation
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 linked mutation gate covers object transforms, mesh geometry, mesh material slots,
material properties, material image nodes, and packed image data. Every request must identify a
`SOURCE_LIBRARY` owner with `linkedLibrary=true` and `readOnly=true`. A current linked request is
blocked with `LINKED_DATA_MUTATION_BLOCKED` before any Main writer can run; stale revisions remain
`REVISION_CONFLICT`, and malformed or ownership-substituted requests fail closed.
This task does not claim a linked writer, reload, relocation, missing-library recovery, or full
N-023 Link parity. The desktop linked ownership contract is the M12-03F input to this gate.
## Evidence
- `npm --prefix web run test:library-linked-mutation` passed 3/3 unit tests.
- All six linked writer operations return `BLOCKED` with exactly
`LINKED_DATA_MUTATION_BLOCKED`, `recoverable=false`, and no Main mutation path. The test also
verifies the schema round-trip for each operation.
- A stale revision returns `REVISION_CONFLICT`; an unknown field, unsupported operation, or owner /
read-only substitution returns `TASK_VALIDATION_FAILED` or `LINKED_DATA_MUTATION_BLOCKED` before
any writer invocation.
## Artifact Hashes
- protocol: `f629e0e7e04dc1f5437b6e2ca62fbe35484fc238830fa47e8358bcab46b7e104`
- unit: `f19d47cefe89daf6123062e045ec717e6ffe60977e8a4b20c996dd62e49da211`
- manifest: `890891fda5c91b08d157927170fb33190ae0d8a49f8962b88c8554307c0c06a8`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03H`: library reload replaces only the matching linked generation snapshot.
## Rollback
Remove the linked mutation protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03F to pending and move the machine queue back to `M12-03F`. No parity ledger rollback
is required.

43
docs/status/M12-03H.md Normal file
View File

@@ -0,0 +1,43 @@
# M12-03H Status
status: done
task: library reload replaces only the matching linked generation snapshot
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 reload requests identify one `SOURCE_LIBRARY` and an expected generation/revision. The
replacement must keep the same library identity, advance exactly one generation, advance the source
revision, and retain a read-only source-library data-block closure. Only the unique matching snapshot
is replaced; other libraries and other generations remain unchanged.
Malformed requests, duplicate state identities, owner substitution, skipped generations, and stale
generation/revision requests fail closed before any Main mutation. A stale request returns
`REVISION_CONFLICT` and an unchanged state.
## Evidence
- `npm --prefix web run test:library-linked-reload` passed 4/4 unit tests.
- The matching-generation case replaces one snapshot atomically while preserving a future generation
and an unrelated library; the input state remains immutable.
- Stale, malformed, duplicate, owner-substituted, and non-adjacent reload cases are rejected without
publishing a partial state.
## Artifact Hashes
- protocol: `8be6f0b2abe36cd566ea7447d1b7de44c0e6a9a7351b863dfdd1372c1761060e`
- unit: `dff866291468cc01e775fe3b3b95c632f5c0742566f79b956a0193bfd8fd43d2`
- manifest: `dd96702dcb064779de3fc33ce1200d75615e7b75a3418a45a309e0e612fdb7df`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03I`: missing library preserves a placeholder and the original source reference.
## Rollback
Remove the linked reload protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03G to pending and move the machine queue back to `M12-03H`. No parity ledger rollback
is required.

42
docs/status/M12-03I.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03I Status
status: done
task: missing library preserves placeholder and original source reference
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 missing-library requests match a linked source library by source identity, generation, and
revision. Marking a matching reference missing changes only its status and adds a
`MISSING_LIBRARY` placeholder. The original locator, source SHA-256, generation, revision, and every
data-block ID remain attached to the reference; unrelated libraries remain unchanged.
Stale generation/revision and source hash drift return a stable conflict without deleting or replacing
the reference. Malformed fields, duplicate identities, and inconsistent placeholder data fail closed.
## Evidence
- `npm --prefix web run test:library-linked-missing` passed 4/4 unit tests.
- The matching case preserves original source metadata and data-block IDs while publishing only the
placeholder status transition.
- Stale, source-drift, undeclared-field, duplicate-identity, and invalid-placeholder cases publish no
partial state.
## Artifact Hashes
- protocol: `5833e8c943ef6bd866a93a0e1666c9521fa6d3e8358861df57b628874b679ec2`
- unit: `4ab6d6ff4845b4ca963399e7eea214ceb412871dc1fdef5bac1ed0333596da4f`
- manifest: `f5fa606161b93e9ee42e7ca8144d2a83379acf601c5045eb8cc76732f8dba431`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03J`: desktop override fixture records reference, local owner, and property override path.
## Rollback
Remove the missing-library protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03H to pending and move the machine queue back to `M12-03I`. No parity ledger rollback
is required.

45
docs/status/M12-03J.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-03J Status
status: done
task: desktop override fixture records reference, local owner, and property override path
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Blender 5.2 creates a real linked Object and converts it through the library override API. The fixture
records the linked reference as `SOURCE_LIBRARY/readOnly=true`, the local hierarchy root as
`LOCAL_OVERRIDE/readOnly=false`, and one explicit custom-property override path. The source marker,
reference ID, local owner, hierarchy root, property operation and value remain stable after save/reopen.
This fixture does not open a general override writer; it freezes the reference/owner/property contract
needed by the next bounded writer task.
## Evidence
- `npm --prefix web run test:library-override-desktop` passed.
- Blender 5.2 source/target fixture regeneration matched the normalized desktop report.
- The reference retains `m12_override_source.blend`; the local object is `LOCAL_OVERRIDE`; the only
recorded property path is `["m12_override_value"]` with value `2.5` and one `REPLACE` operation.
- Save/reopen preserves the reference, hierarchy root, owner semantics, and property metadata.
## Artifact Hashes
- generator: `2cdbac04cac7240360a9d70919380fd90f9479e2cb41d8032fb51626ed4b4dd6`
- checker: `afebb3c9b8715b9d2e0c9b17f463f038bd23e8747074137bccbf1c09c4bfb5ba`
- source blend: `d7f8d78e7e91481bf46ecc9a6bcb01e900a6a397839dd31ab80a53def7675601`
- target blend: `b008a1608ff1e8f679e1e1281bf7be0360f1137e815dd890cbd93e1e98675495`
- report: `19cb13a3417b4b65a8497b622337c42c4697b3f3d48de26a1f70f2d4527ddde0`
- manifest: `01d0f66bb3819eea3e92727d1b5bffbec935d24eeecc28d874b999df78d73fbf`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03K`: expose exactly one verified override writer property.
## Rollback
Remove the override generator/checker, fixture, report, manifest, package command, and this status
entry. Restore M12-03I to pending and move the machine queue back to `M12-03J`. No parity ledger
rollback is required.

42
docs/status/M12-03K.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03K Status
status: done
task: expose exactly one verified override writer property
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 override writer accepts exactly `SET_M12_OVERRIDE_VALUE` for the property path
`["m12_override_value"]`. It requires `LOCAL_OVERRIDE`, `readOnly=false`,
`referenceReadOnly=true`, matching local/reference/hierarchy IDs, and the current revision. A valid
write updates only the verified value and advances the local revision by one.
Linked ownership, a second property path, identity drift, stale revision, malformed fields, and values
outside the bounded float range are blocked before any writer commit.
## Evidence
- `npm --prefix web run test:library-override-writer` passed 4/4 unit tests.
- The valid request applies one property and increments revision exactly once while preserving local
override ownership and reference read-only semantics.
- Stale, linked-owner, identity, alternate-operation, alternate-property, malformed, and out-of-range
requests fail closed.
## Artifact Hashes
- protocol: `dd181c7e9946b98334a5d1c686887afecfe3fc11d732beec246e40bf11a155aa`
- unit: `e41bd32eb4ce4d331a20ecb91f3325a27f461b9ae85e98940d5afd482ec21c4c`
- manifest: `9eeee93e4a806aa59b5c53a6485fe3a1b5e3972c1d2585cdc71b7cfc293afb70`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03L`: block override stale source/revision before Main commit.
## Rollback
Remove the override writer protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03J to pending and move the machine queue back to `M12-03K`. No parity ledger rollback
is required.

41
docs/status/M12-03L.md Normal file
View File

@@ -0,0 +1,41 @@
# M12-03L Status
status: done
task: block override stale source/revision before Main commit
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 override freshness binds the local override to its source library ID, source generation,
source revision, dependency-closure SHA-256, invalidation token, and local/reference/hierarchy IDs.
Only a fully matching `COMMIT_OVERRIDE` request reaches `READY`; no Main mutation is performed by
this gate.
Stale generation/revision, dependency closure, invalidation token, linked ownership, identity drift,
alternate operation, malformed token, and undeclared fields return stable blocking codes before Main.
## Evidence
- `npm --prefix web run test:library-override-freshness` passed 4/4 unit tests.
- The exact source generation/revision/closure/token binding returns `READY`.
- Stale source fields return `REVISION_CONFLICT`; local identity drift returns
`ASSET_SOURCE_HASH_MISMATCH`; linked ownership returns `LINKED_DATA_MUTATION_BLOCKED`.
## Artifact Hashes
- protocol: `2eff7ea7605b1579d7551336d87d4f30adb996b585596ff9eee67aea04ca7d22`
- unit: `d48344f31e1ba12e557ca30ece56643583efa633da556f5de3896a8e9175ef8f`
- manifest: `237f3f168e037b67b805ba8d9c9455250c889a5e90c45cbb17d2d20d9fbdcc50`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03M`: dependency cycle, ID collision, cross-library cycle, and duplicate reload negatives.
## Rollback
Remove the override freshness protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03K to pending and move the machine queue back to `M12-03L`. No parity ledger rollback
is required.

38
docs/status/M12-03M.md Normal file
View File

@@ -0,0 +1,38 @@
# M12-03M Status
status: done
task: dependency cycle, ID collision, cross-library cycle, and duplicate reload negatives
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 negative-case validation checks library dependency graphs, cross-library references,
data-block identity ownership, and reload generation identities. Acyclic graphs with unique IDs are
accepted; dependency/cross-library cycles, missing source libraries, duplicate data-block IDs, and
duplicate reload generations fail with stable codes before any writer or Main mutation.
## Evidence
- `npm --prefix web run test:library-negative-cases` passed 4/4 unit tests.
- Direct dependency cycles and cross-library cycles return `LIBRARY_DEPENDENCY_CYCLE`.
- Data-block collision returns `TASK_VALIDATION_FAILED`; duplicate reload returns `REVISION_CONFLICT`;
a missing source library returns `ASSET_SOURCE_HASH_MISMATCH`.
## Artifact Hashes
- protocol: `efc7cc810089eab6178fc5c2f2a45d641625a032ecfa5b2b4ef37694d0decc97`
- unit: `b7ae41b2c35b2fe1598bca4425dd434230bfe4bf342320c88214a060dcbb0a16`
- manifest: `693cbedfe8e29167283a753d119de5a9cfe5e20bc96aff7ba84d720ffde9148a`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03N`: append/link/override each receive independent desktop/WASM/Chromium commands.
## Rollback
Remove the negative-case protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03L to pending and move the machine queue back to `M12-03M`. No parity ledger rollback
is required.

42
docs/status/M12-03N.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03N Status
status: done
task: append/link/override each receive independent desktop/WASM/Chromium commands
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Append, LINK, and library override each have independent desktop, WASM, and Chromium commands. The
commands are bound to distinct fixtures/protocol tests/browser specs and use separate Chromium ports.
The command checker verifies all nine package entries and their lane-specific targets.
## Evidence
- `npm run test:library-operation-commands` passed with 9 independent commands: 3 operations x 3 lanes.
- Desktop: append fixture, LINK fixture, and Blender 5.2 override fixture all passed.
- WASM: append receipt protocol passed 2/2; LINK aggregate passed 11/11; override aggregate passed 8/8.
- Chromium: append passed 1/1; LINK gate passed 1/1 on port 5195; override writer passed 1/1 on port
5196. Append Chromium passed 1/1 on port 5194.
## Artifact Hashes
- command checker: `3564347393134d835fdf279b8b8f58558ee24fe0165c3b4527195d094a451e98`
- append WASM protocol: `bfd98561cbe797d7b8f07c92c53a25460c839a64ab7222b7795cf58d54dff8d7`
- append WASM unit: `75fc2d626f7ca7e820e9cacf659a453886e15e790cde43348828c03bed752ec7`
- append Chromium: `101f67d35c2320da57459f08a59687d769234b910dbd9aaec5a668cee7e0f9f0`
- link Chromium: `814e3486522fb4f0ffdd59acd385a4fca9c5660cdb07e5a2acb1cadd70376bff`
- override Chromium: `1c12982b4eb4fb4b9a3c88907a842a1fc413b3a3a760a9f57b350f57060d007f`
- manifest: `e4cccc8edc277b5047c3f8006ea40b26b119d28589fe2f3bd9bfa4cc3575c85a`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04A`: library source schema accepts only declared HTTPS origins, project assets, or user-selected files.
## Rollback
Remove the independent command checker, lane-specific tests/wrappers, manifest, package commands, and this
status entry. Restore M12-03M to pending and move the machine queue back to `M12-03N`. No parity ledger
rollback is required.

40
docs/status/M12-04A.md Normal file
View File

@@ -0,0 +1,40 @@
# M12-04A Status
status: done
task: library source schema accepts declared HTTPS origin, project asset, or user-selected file
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 source admission accepts exactly three declared kinds: HTTPS URLs whose credential-free origin
is present in the policy, project-relative asset paths normalized by the existing project-path gate,
and user-selected files carrying a stable selection ID, safe file name, bounded byte length, and
source SHA-256. Accepted sources receive a canonical locator.
Undeclared origins, credentials, unsafe project paths, empty origin policy, malformed file identity,
and undeclared fields fail closed before any library load.
## Evidence
- `npm --prefix web run test:library-source-origin` passed 4/4 unit tests.
- Declared HTTPS, project asset, and user-selected file cases return `READY` with canonical locators.
- Undeclared HTTPS, credential-bearing URLs, traversal paths, empty policies, malformed selection IDs,
and undeclared fields return stable blocking errors.
## Artifact Hashes
- protocol: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `89b207c9cb13b4fb055a2dfed0237c0f8a00b13a39cc4175a378f5ef2abdb7ae`
- manifest: `af80827d925ddd96d8541e446e0f70c956fd4c56e64ac984d187f5449df4cb0d`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04B`: normalize POSIX/Windows separators, `.`, `..`, percent encoding, and Unicode names.
## Rollback
Remove the source-origin protocol, unit suite, manifest, package command, and this status entry. Restore
M12-03N to pending and move the machine queue back to `M12-04A`. No parity ledger rollback is required.

42
docs/status/M12-04B.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-04B Status
status: done
task: normalize POSIX/Windows separators, dot segments, percent encoding, and Unicode names
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The shared project-asset path normalizer now emits one canonical `/`-separated path. It accepts
equivalent POSIX/Windows separators, removes `.` segments, resolves bounded `..` segments without
allowing project-root escape, decodes percent-encoded UTF-8 once, and applies Unicode NFC normalization.
Residual percent octets, malformed encoding, controls, absolute paths, URI schemes, and traversal beyond
the project remain fail-closed.
## Evidence
- `npm --prefix web run test:library-path-normalization` passed 4/4 unit tests.
- Separator and dot aliases converge to one idempotent canonical path.
- Percent-encoded separators/dot segments and decomposed Unicode names match the canonical project asset
locator used by the M12-04A source admission path.
- Re-decoding, malformed percent encoding, and project-root escape return stable path errors.
- `npm --prefix web run typecheck` passed after closing the prior library wrapper/parser type errors.
## Artifact Hashes
- parent manifest: `af80827d925ddd96d8541e446e0f70c956fd4c56e64ac984d187f5449df4cb0d`
- normalizer: `6109d05251fc7355ac32d4c0d8298f85ea8b731767c76c394577c4e44652a6bf`
- source admission: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `abde64c60397541e92a83dd9e4a24e65faf340a8d046650604c101a21037c777`
- manifest: `8cd29c3f5281082584fc6aefe2ec385a2eedf8116e837a4db54c391391ff8f98`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04C`: reject absolute paths, UNC, drive paths, NUL, control characters, and origin escape.
## Rollback
Remove the path normalizer changes, unit suite, manifest, package command, and this status entry. Restore
M12-04A to pending and move the machine queue back to `M12-04B`. No parity ledger rollback is required.

45
docs/status/M12-04C.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-04C Status
status: done
task: reject absolute paths, UNC/drive paths, controls, and origin escape
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The project-asset path gate rejects absolute POSIX paths, UNC and drive-shaped paths, NUL/control
characters, malformed or residual percent encoding, and URI/origin-shaped escapes before a locator is
accepted. HTTPS source policy entries are now strict credential-free origins: path, query, fragment,
encoded controls, and backslash smuggling are rejected instead of being silently reduced to
`URL.origin`. HTTPS resource paths retain the declared-origin check and reject unsafe decoded bytes.
## Evidence
- `npm --prefix web run test:library-path-security` passed 4/4 unit tests.
- Absolute, UNC, drive, raw/encoded NUL and control characters, and origin-style project paths return
stable `ASSET_PATH_OUTSIDE_PROJECT`/`ASSET_PATH_INVALID` errors.
- Raw and encoded backslashes, controls, malformed percent sequences, credentials, undeclared origins,
and policy origin smuggling return `IO_EXTERNAL_URI_BLOCKED`.
- Declared `https://assets.example.test/library/main.blend` remains accepted; policy declarations with
a path, query, fragment, encoded control, or duplicate canonical origin fail closed.
- `WEB_TEST_PORT=5323 npm --prefix web run test:asset-library` passed the N-023 Chromium asset/IO gate 1/1.
- `npm --prefix web run typecheck` passed.
## Artifact Hashes
- parent manifest: `8cd29c3f5281082584fc6aefe2ec385a2eedf8116e837a4db54c391391ff8f98`
- path normalizer: `6109d05251fc7355ac32d4c0d8298f85ea8b731767c76c394577c4e44652a6bf`
- source-origin protocol: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `ab302cacb24634a3225dda5cb8f5282cb80b3bd81ed5c8900ddf4ff18267b7e2`
- manifest: `a7f3a45eb7f68d022f38185a1c1409e1db1b27647fef587d66d2ffa52d78f98e`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04D`: resolve symlink/hardlink entries before writing and constrain them to the temporary root.
## Rollback
Remove the C path-security assertions, manifest, status entry, and strict origin validation. Restore
M12-04B to pending and move the machine queue back to `M12-04C`. No parity ledger rollback is required.

44
docs/status/M12-04D.md Normal file
View File

@@ -0,0 +1,44 @@
# M12-04D Status
status: done
task: resolve symlink/hardlink entries before writing and constrain them to the temporary root
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Archive entries are parsed before any write. Every member is canonicalized as a relative path under
the declared temporary-root identity. Symlink targets resolve relative to the link's parent; hardlink
targets resolve from the archive root and must end at a regular file. Absolute, drive-shaped, URI,
backslash-smuggled, traversal, missing-target, cyclic, duplicate, and hardlink-to-directory inputs
fail closed with `IO_ARCHIVE_UNSAFE`.
The resolver returns a write plan with the final in-root target and an explicit
`withinTemporaryRoot: true` proof for every member. It does not follow or write any link before the
entire manifest has passed validation.
## Evidence
- `npm --prefix web run test:library-link-safety` passed 5/5 unit tests.
- Parent-directory symlinks, archive-root hardlinks, and chained links resolve to canonical in-root
members.
- Absolute/UNC/drive/URI/traversal targets, missing members, cycles, duplicate paths, undeclared
fields, and hardlinks to directories are rejected before a write plan is returned.
## Artifact Hashes
- parent manifest: `a7f3a45eb7f68d022f38185a1c1409e1db1b27647fef587d66d2ffa52d78f98e`
- protocol: `d55a4ba762898aed22bdcc7aa6493c713ee94f6bb1bf58754fdc459d0ddf70d1`
- unit: `7739275be91222d7bfb61d2f5a1daf812c6860fe34d0aea27df8380a77322120`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04E`: archive first reads the central directory/manifest and does not extract payload first.
## Rollback
Remove the archive link-safety protocol, unit suite, manifest, package command, and this status entry.
Restore M12-04C to pending and move the machine queue back to `M12-04D`. No parity ledger rollback is
required.

38
docs/status/M12-04E.md Normal file
View File

@@ -0,0 +1,38 @@
# M12-04E Status
status: done
task: archive first reads the central directory or manifest before payload extraction
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
ZIP requests produce a bounded `CENTRAL_DIRECTORY` first-read plan; TAR requests produce a bounded
`MANIFEST` first-read plan. The plan contains no payload ranges. A read trace is accepted only when
the first exact range is the declared metadata range and every later range is payload; payload-first,
wrong-range, duplicate-metadata, out-of-order, oversized, and out-of-archive reads fail closed with
`IO_ARCHIVE_UNSAFE`.
## Evidence
- `npm --prefix web run test:library-metadata-first` passed 4/4 unit tests.
- ZIP and TAR plans expose metadata-only first reads with an empty payload plan.
- Payload-first, wrong-range, duplicate metadata, out-of-archive, and metadata-budget cases are
rejected before extraction can be scheduled.
## Artifact Hashes
- parent manifest: `1c09abd1f4bd5908d22ab3b22e3e71d050f694af0b82a7f78a351d7a1bf1e664`
- protocol: `869586b041e134c7d1cb2ebd7e13b35218b337223d401697a179f71cd1420f5b`
- unit: `2da649722acee9cace8db6f337b4a93500a9c775a0b0f086bf38dd2b3e7f9e91`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04F`: enforce per-entry bytes, total bytes, entry count, directory depth, and filename length budgets.
## Rollback
Remove the metadata-first protocol, unit suite, manifest, package command, and this status entry. Restore
M12-04D to pending and move the machine queue back to `M12-04E`. No parity ledger rollback is required.

37
docs/status/M12-04F.md Normal file
View File

@@ -0,0 +1,37 @@
# M12-04F Status
status: done
task: enforce archive entry, total, count, directory-depth, and filename-length budgets
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production `asset-library-io` parser now enforces the existing compressed/uncompressed per-entry
and total-byte budgets together with a 100,000-entry limit, 64 directory levels, and a 255-byte UTF-8
filename limit. Compression-ratio and declared source-byte checks remain fail-closed in the same path.
Budget checks happen while parsing metadata, before any payload allocation or extraction.
## Evidence
- `npm --prefix web run test:library-archive-budget` passed 4/4 unit tests.
- Exact boundary cases for entry bytes, total bytes, entry count, directory depth, and Unicode filename
bytes are accepted; one-byte overflows return stable budget errors.
- Existing compression-ratio, duplicate/prefix, and declared source-byte checks remain covered.
## Artifact Hashes
- parent manifest: `d935392fb23c2e6ad651fb6ad6cb67f8ead3d562e626bb230d2febd9d7f03b1c`
- protocol: `e02efa79668f4ee10b1c28786709eba2c93691b28ccf1155c6213dda12f59a8f`
- unit: `b0d8356c6fb348d98e28ce220052845a29439b34b3c976b21a4dbf370ea19593`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04G`: reject compression-ratio, overlapping range, duplicate path, and file/directory prefix conflicts.
## Rollback
Remove the budget checks, unit suite, manifest, package command, and this status entry. Restore M12-04E
to pending and move the machine queue back to `M12-04F`. No parity ledger rollback is required.

39
docs/status/M12-04G.md Normal file
View File

@@ -0,0 +1,39 @@
# M12-04G Status
status: done
task: reject archive compression bombs, overlapping ranges, duplicate paths, and prefix conflicts
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Archive range validation now checks each compressed range against the declared source length and the
global archive bound, sorts ranges by offset, and rejects overlap before any payload read. It also
rejects duplicate canonical paths, file/directory prefix conflicts, zero-byte compression bombs, and
expansion ratios above 100:1. Valid ranges return deterministic totals and explicit non-overlap/path
invariants.
## Evidence
- `npm --prefix web run test:library-archive-conflicts` passed 4/4 unit tests.
- Non-overlapping ranges produce stable compressed/uncompressed totals.
- Compression-ratio, overlap, duplicate, prefix, source-bound, and undeclared-field negatives all
return `IO_ARCHIVE_UNSAFE` before payload scheduling.
## Artifact Hashes
- parent manifest: `cda905b1e27b62d9ea3a05170f975015480ce6739c15bdf1f5a1f0b79f93ce06`
- protocol: `3bec372e4f67ec309f28534cebcbaf8b492144adfa82ff6c8603f88c3ba16254`
- unit: `3f2d44dce33b1c17b3a48f58b04fdd821abc88d98ce3d3b5bb724859e0f0ab3c`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04H`: cancellation removes staging and never modifies the committed project.
## Rollback
Remove the archive conflict protocol, unit suite, manifest, package command, and this status entry.
Restore M12-04F to pending and move the machine queue back to `M12-04G`. No parity ledger rollback is
required.

48
docs/status/M12-04H.md Normal file
View File

@@ -0,0 +1,48 @@
# M12-04H Status
status: done
task: remove extraction staging on cancellation without modifying the committed project
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production archive extraction transaction checks cancellation before staging, around every
payload read and write, and immediately before atomic commit. A pre-commit cancellation returns
`IO_ARCHIVE_CANCELLED`, removes every staged file, publishes no project, and re-reads the committed
project identity to prove that revision and SHA-256 did not change. Once atomic commit starts,
cancellation no longer converts the completed commit into a cancelled result.
Payload identity failure and staging creation/write failure use the same cleanup path. If cleanup
leaves a staged entry or the committed identity drifts, the transaction fails with
`STORAGE_TRANSACTION` instead of claiming successful cancellation.
## Evidence
- `npm --prefix web run test:library-archive-cancellation` passed 6/6 unit tests against real
temporary directories.
- Cancellation before staging, after one staged file, and after the final staged write all leave
zero staging files, zero published projects, and the original committed project bytes.
- The success path publishes revision 9 only after both staged payload hashes pass.
- Payload mismatch, rollback identity drift, stale revision, unsafe path, prefix conflict, and
undeclared-field negatives fail closed.
## Artifact Hashes
- parent manifest: `c35e675e8f512e85b748f0b5578874fed8c99df7674a152e698236a67c9f4fa4`
- protocol: `c40adc1449172014cc1820db567e155828314abb404b66e4de13c26ddee06e4b`
- error codes: `751c70c898540fa7e82fb1b1a79254756ec8db8e4201a88b6d817d7c3d92103f`
- unit: `77e7d5bc64dd6b313006ebf523602601acdaf7949a1484da872ddcd046983786`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `7fce600a416aec5ade1a91a13d86caf4cb1f65b710054b59d525ff8b1d3c7409`
## Next Task
`M12-04I`: release temporary files after quota/OOM and allow a small archive to recover.
## Rollback
Remove the extraction transaction protocol, cancellation code, real-filesystem unit suite, manifest,
package command, and this status entry. Restore M12-04G as the queue tail and move the machine queue
back to `M12-04H`. No parity ledger rollback is required.

47
docs/status/M12-04I.md Normal file
View File

@@ -0,0 +1,47 @@
# M12-04I Status
status: done
task: release archive staging after quota/OOM and recover with a small archive
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The archive recovery wrapper maps browser/OPFS quota failures to `STORAGE_QUOTA` and declared
allocation failures to `WASM_OUT_OF_MEMORY` only after the M12-04H base transaction has removed
staging and re-read the committed project identity. Cleanup or identity drift remains
`STORAGE_TRANSACTION`; unrelated range and IO failures are not misclassified as OOM.
Real temporary-directory tests partially write the failing payload before injecting each fault.
Both paths leave zero staging entries and preserve the previous revision, SHA-256, and committed
bytes. The same storage instance then accepts and atomically commits a smaller archive without a
Worker or process restart.
## Evidence
- `node --test web/tests/unit/library-archive-recovery.test.mjs` passed 4/4.
- Quota and OOM each remove a partially written 4 KiB staging payload and preserve revision 9.
- Each failed storage instance immediately commits `small-project` at revision 10 with zero
staging entries.
- `npm --prefix web run test:library-archive-cancellation` passed 6/6 and
`npm --prefix web run typecheck` passed.
## Artifact Hashes
- parent manifest: `7fce600a416aec5ade1a91a13d86caf4cb1f65b710054b59d525ff8b1d3c7409`
- base transaction: `c40adc1449172014cc1820db567e155828314abb404b66e4de13c26ddee06e4b`
- recovery protocol: `0ae9801ea151403b244c5f58f7f99231bba7a25abb1f61e3669879510b92dccf`
- unit: `a931edef8f3ca1243a80ec2b8e9ff5b8da1dfd339f3d8c162ad2ebd08d3db6a1`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `574afa68a787b9481d0e098d38b94cb810a9827fe185b0df796d62cc160ba7c5`
## Next Task
`M12-04J`: add malicious ZIP/TAR fixtures to the long-term security regression.
## Rollback
Remove the recovery wrapper, real-filesystem unit suite, manifest, and this status entry. Restore
M12-04H as the queue tail and move the machine queue back to `M12-04I`. No parity ledger rollback is
required.

49
docs/status/M12-04J.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-04J Status
status: done
task: keep malicious ZIP/TAR fixtures in the long-term archive security regression
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Six deterministic binary fixtures cover ZIP path traversal, compression-ratio abuse, duplicate
paths, TAR path traversal, symlink escape, and file/directory prefix conflict. The generator fixes
container fields and timestamps; the checker regenerates every file in a temporary directory and
requires byte-for-byte equality with the committed fixtures and catalog SHA-256 values.
The checker reads ZIP EOCD/central-directory and USTAR header metadata, verifies local-header
bindings, TAR checksums, alignment, and end markers, then feeds the actual entry metadata into the
M12-04D/G link and conflict gates. It never invokes `tar`, `unzip`, or an extraction API. All six
fixtures fail closed with `IO_ARCHIVE_UNSAFE` and are included in the existing N-023 Chromium grep.
## Evidence
- `node tools/web/check-malicious-archive-fixtures.mjs` passed 6/6 with three ZIP and three TAR
fixtures and extraction disabled.
- `WEB_TEST_PORT=5408 npm --prefix web run test:asset-library` passed 2/2, including the persistent
binary-fixture security test and the existing N-023 asset/IO gate.
- Fixture byte lengths range from 115 to 3,072 bytes and every committed SHA-256 matches the
generated catalog.
## Artifact Hashes
- parent manifest: `574afa68a787b9481d0e098d38b94cb810a9827fe185b0df796d62cc160ba7c5`
- generator: `b372ea8cb2f97b035ffb2cc18666dae9167dcfb349131851ad9f1ff0fc40ba16`
- checker: `edda2f420f26e55f9990d24b755bb9b4f732ec32c2e072210144b3d0b6634d9b`
- fixture manifest: `a93834316f6a23b8a0e6c1f1f806ec584d6f03aa339c2680cae2ce8133a40e58`
- Chromium spec: `f327500808dd67359a152ce28134b58d027aebd6758416b5535b659b9900bbfe`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `989d417ab44e165849c7054f331f7038ec1d779349c39dd4f5b30050bbaecf56`
## Next Task
`M12-05A`: generate the glTF/GLB, OBJ, STL, PLY, USD, and Alembic format inventory from the pinned
Blender 5.2 build/runtime.
## Rollback
Remove the fixture generator/checker, six binary fixtures and catalog, Chromium spec, golden
manifest, and this status entry. Restore M12-04I as the queue tail and move the machine queue back to
`M12-04J`. No parity ledger rollback is required.

49
docs/status/M12-05A.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-05A Status
status: done
task: generate the Blender 5.2 runtime format inventory
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The pinned `build_blender_5.2.0/bin/blender` runtime generated seven separate format records:
GLTF, GLB, OBJ, STL, PLY, USD, and ALEMBIC. Each record binds import/export operator paths,
registered state, RNA identifier, canonical property identifiers and enum items, file extensions,
format variants, and the build option that gates the operator.
The runtime receipt also binds Blender 5.2.0 LTS version tuple, build hash/branch/platform/type/date,
commit timestamp, selected build options, and the Blender binary SHA-256. On this pinned build,
GLTF/GLB/OBJ/STL/PLY are `AVAILABLE`; USD and Alembic are explicitly `OPERATOR_UNREGISTERED` because
`bpy.app.build_options.usd` and `alembic` are false. This is inventory evidence only and does not
claim import/export round-trip parity.
## Evidence
- `node tools/web/check-io-format-runtime-inventory.mjs` passed; the generator was rerun in a fresh
process and matched the committed JSON byte-for-byte.
- Inventory has 7 formats, 5 available format families and 2 build-disabled families. All available
operators have canonical non-empty RNA property lists; disabled operators fail closed.
- Runtime receipt records binary SHA-256
`d4483926610484ef9c2ad9241aae1469f934d955ebe791f1920e263e0ba85b82`.
## Artifact Hashes
- parent manifest: `989d417ab44e165849c7054f331f7038ec1d779349c39dd4f5b30050bbaecf56`
- generator: `aa926397664240a5195f8864fc3ed5549bafcc963a03c513c7e37926b0559d7d`
- checker: `12853306ea5eb2698ab636c7dfc2f27ae140295641473c57b84f93fa13d4864e`
- inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `202b144c91f8e2c39477e257aeb26f9bd0b1b05b459ff8a246668024e94deec7`
## Next Task
`M12-05B`: declare import/export, local/server, geometry/material/animation support separately for
each inventoried format.
## Rollback
Remove the runtime inventory generator/checker, format inventory, golden manifest, and this status
entry. Restore M12-04J as the queue tail and move the machine queue back to `M12-05A`. No parity
ledger rollback is required.

48
docs/status/M12-05B.md Normal file
View File

@@ -0,0 +1,48 @@
# M12-05B Status
status: done
task: declare per-format import/export local/server and feature support
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 capability matrix binds all seven M12-05A runtime formats and the inventory SHA-256.
Each format has separate IMPORT and EXPORT entries with local and server routes plus explicit
geometry, material, and animation feature status. A runtime operator being registered does not
make a Web route executable.
The only `READY` route is the existing bounded GLB EXPORT local path. All seven IMPORT routes and
all server routes are explicit `BLOCKED/IO_FORMAT_UNSUPPORTED`; other local exports are also blocked.
GLB export features are marked `PARTIAL` with the M12-06 round-trip dependency. Unimplemented
operations stay `UNVERIFIED` rather than claiming geometry/material/animation support.
## Evidence
- `node --test web/tests/unit/io-format-capability-matrix.test.mjs` passed 3/3, including duplicate
format, ready-without-executor, unverified-ready-feature, and missing blocked-code negatives.
- `node tools/web/check-io-format-capability-matrix.mjs` passed; the matrix generator reproduced the
committed JSON byte-for-byte and runtime statuses matched the M12-05A inventory.
- The checker reports 7 formats, 1 local bounded GLB export route, and 27 blocked routes.
## Artifact Hashes
- parent manifest: `202b144c91f8e2c39477e257aeb26f9bd0b1b05b459ff8a246668024e94deec7`
- protocol: `3063ae5e45f5b1642d329aa554187d121998d816a5a6740a2b9662f00c3c5738`
- generator: `746078caaf29fa5aa2281b901b9ea5fc66f9a935eb3f6e282d4fbfb018d4c390`
- checker: `4a8b35cd7f87238c13627a00c3bb0b34c130fc34d597773574efac7d8909b804`
- unit: `0cc4d8f1df1ecdab20d8100cf5f12b44cb2a68bca4384ef7964a032b2f74b36e`
- matrix: `139c9d764736da176b32414ecda840c07eb0ba5f3864da2dc08ce04bae161366`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `8cc9517c9f25138c351bc5a79efe3b1ce6d9f6663d3b7c14397c5e4e8f11181a`
## Next Task
`M12-05C`: prevent matrix-undecared combinations from appearing in file selection and operator search.
## Rollback
Remove the capability matrix protocol/generator/checker, unit test, matrix, golden manifest, and this
status entry. Restore M12-05A as the queue tail and move the machine queue back to `M12-05B`. No
parity ledger rollback is required.

52
docs/status/M12-05C.md Normal file
View File

@@ -0,0 +1,52 @@
# M12-05C Status
status: done
task: prevent matrix-undeclared combinations from appearing in file selection and operator search
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 UI registry is generated from the M12-05B capability matrix and is bound to its exact
SHA-256. Only routes whose runtime operator is `AVAILABLE` and whose local matrix route is `READY`
are exposed to the UI. The current registry therefore accepts `.blend` projects, exposes the existing
bounded local GLB export command, and exposes no blocked import or export route.
The file input uses the registry-derived accept string and performs a second filename gate before
opening. A matrix-blocked or unknown extension returns `IO_FORMAT_UNSUPPORTED` without invoking the
engine or replacing the current scene. Operator search filters every format-tagged command through the
same registry, so blocked server routes and undeclared formats cannot appear as executable results.
## Evidence
- Direct M12-05C lane passed: `node --test web/tests/unit/io-format-ui-gate.test.mjs`,
`node tools/web/check-io-format-ui-gate.mjs`, and Chromium 1/1 on dynamic ports 5413/5417.
- `node tools/web/check-io-format-ui-gate.mjs` reproduced the committed registry byte-for-byte;
import routes=0, local export routes=1, project accept=`.blend,application/octet-stream`.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed.
- `WEB_TEST_PORT=5412 npm --prefix web run test:asset-library` passed 2/2 N-023 Chromium regressions.
- An initial command without `WEB_TEST_PORT` was blocked by an already occupied 5173; rerunning on the
isolated dynamic port passed and left no server/profile process in the test lane.
## Artifact Hashes
- parent manifest: `8cc9517c9f25138c351bc5a79efe3b1ce6d9f6663d3b7c14397c5e4e8f11181a`
- protocol: `fc397ceb947d4ede6c34c1d51438253a6b59244fc40f5eb77ce155bf1c477476`
- generator: `1ef4ae8a3e8d2f73101a87cba1c42ea99a065e1f6846f6a591841b97c0c39e6f`
- checker: `81d6f27df26aab7b633fbe61c6d7b37519668aff41e43314924dceaacb3affde`
- unit: `84ca8fb6022da9f167daa104c44489a6c7d9f059699e57ce621b8d7f64f19082`
- Chromium: `eda2cdb9ede3bcbd717800c9c6fdb28d8cebef96f0296a2ee847a05e60cd0eed`
- registry: `6b410bc6f2cad032af55bf13e1c8ddd841b01e9913ffc0ba381da8b7204285fd`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `f46fd394e2144255d8b4304e8ce4fe60aad4302a80e991fd83d50cd915235ee3`
## Next Task
`M12-05D`: determine capability from runtime receipts and never infer it from filename extensions.
## Rollback
Remove the UI registry protocol, generator/checker, registry, unit/Chromium tests, package command,
golden manifest, and this status entry. Restore M12-05B as the queue tail and move the machine queue
back to `M12-05C`. No parity ledger rollback is required.

54
docs/status/M12-05D.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-05D Status
status: done
task: determine format capability from pinned Blender runtime receipts, never filename extensions
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 runtime receipt set is generated from the pinned Blender 5.2 M12-05A inventory and
bound to that inventory's SHA-256. Each format/operation receipt preserves the operator path, RNA
identifier, registered state, build option state, variants, and descriptive extensions. A route is
`READY` only when the receipt says `AVAILABLE`, the operator is registered, an RNA identifier exists,
and the build option is not disabled.
The route resolver takes an explicit format and operation from the receipt and never parses a file
name or extension to grant capability. App filters format-tagged operator search entries and checks
the GLB export route against this receipt set immediately before execution. The pinned runtime marks
GLB export `READY`; USD/Alembic receipts are `OPERATOR_UNREGISTERED` and remain blocked.
## Evidence
- `node --test web/tests/unit/io-format-runtime-receipt.test.mjs` passed 3/3, covering receipt-bound
GLB/USD routes, extension mutation without capability change, identity drift, and explicit status.
- `node tools/web/check-io-format-runtime-receipts.mjs` passed; a fresh generator process reproduced
14 receipts byte-for-byte from M12-05A inventory and verified operator/runtime identity fields.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed; M12-05C Chromium UI
regression passed 1/1 on port 5417 and N-023 asset/security regression passed 2/2 on port 5418.
- The existing frozen package hash `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
is preserved; dedicated commands remain direct to avoid invalidating prior release evidence.
## Artifact Hashes
- parent manifest: `f46fd394e2144255d8b4304e8ce4fe60aad4302a80e991fd83d50cd915235ee3`
- protocol: `461a84557fa368c29dbc6707959b689faae7c8f7050dccc4d3f12e358b61bb22`
- generator: `796cd641e86d8242c13317f771ae237cbf1692ff675a53bbdb689615edb5f372`
- checker: `aaf9862041f155f96f50ea8481ff765089255bc59ecd8944f12362b81b8c1f1a`
- unit: `a5f09277f5dcdacd25c44191f7407d6cee944f8022b1c467c2a69e172fc2ac6b`
- runtime receipts: `f2c9a77e2cfad0ef3574b804fc06fb22972c07f55c72b0e6db2e359c4d95f57b`
- App receipts: `f2c9a77e2cfad0ef3574b804fc06fb22972c07f55c72b0e6db2e359c4d95f57b`
- App: `74216aac70992f8d879e983237ca324b998008582f0cd4658e90994cf9fae0a8`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3d0049a7b0331f01bb71df043270c18d1a5c9ce6dc74353c49c8ce591761df1b`
## Next Task
`M12-05E`: bind each runtime receipt to source, settings, and runtime hashes.
## Rollback
Remove the runtime receipt protocol, generator/checker, receipt set, App gate, unit test, golden
manifest, and this status entry. Restore M12-05C as the queue tail and move the machine queue back to
`M12-05D`. No parity ledger rollback is required.

49
docs/status/M12-05E.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-05E Status
status: done
task: bind every runtime receipt to source, settings, and runtime hashes
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 bound receipt set derives from M12-05A inventory and M12-05D runtime receipts. Every
one of the 14 format/operation records carries three independent SHA-256 values: a source/operator
identity hash, a settings/schema hash (including canonical variants/extensions and Blender RNA
properties), and a runtime identity hash. The set also binds the parent M12-05D receipt-set hash and
the M12-05A inventory hash.
The validator requires all three hashes and parent identities before a bound receipt can be resolved.
The generator uses sorted-key canonical JSON and the checker independently recomputes every hash,
then rebuilds the artifact in a fresh process for byte-for-byte determinism. No package metadata was
changed, preserving the existing release evidence hash.
## Evidence
- `node --test web/tests/unit/io-format-receipt-binding.test.mjs` passed 2/2: valid three-hash
resolution plus malformed source/settings/runtime and parent identity rejection.
- `node tools/web/check-io-format-receipt-bindings.mjs` passed; all 14 source/settings/runtime hashes
and parent/inventory identities matched a fresh deterministic regeneration.
- `npm --prefix web run typecheck` passed; `git diff --check` passed.
## Artifact Hashes
- parent manifest: `3d0049a7b0331f01bb71df043270c18d1a5c9ce6dc74353c49c8ce591761df1b`
- protocol: `681e719ab2b18eb85d056547fb70b461dd73b3a7fb4fdbe6295b8e49d5649e49`
- generator: `eb7b5c499f141c1788bc37e53585662eedff3f2dabff870f4ad166f4a619796f`
- checker: `ec2b22b468809ecc25ab2d4983065680a66ad3be6705d1827b44bf45ac622e26`
- unit: `e9ae3e360ad41c32da3634a4efa915654853e79a35df36728c1ddf586a0bf7b5`
- bound receipts: `7f765bf16b62466f579b3de00751a0e012fef1c788f229c8e9675a57caa18aad`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `PENDING`
## Next Task
`M12-05F`: reject forged, stale, or cross-version runtime receipts before use.
## Rollback
Remove the binding protocol, generator/checker, bound receipt golden, unit test, manifest, and this
status entry. Restore M12-05D as the queue tail and move the machine queue back to `M12-05E`. No
parity ledger rollback is required.

54
docs/status/M12-05F.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-05F Status
status: done
task: reject forged, stale, or cross-version runtime receipts before use
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 freshness envelope is derived from the M12-05E bound receipt set. It carries the
M12-05E byte identity, a canonical digest of the complete bound receipt set, and a canonical digest
of the pinned Blender runtime identity. Before a route can be used, the parent binding hash,
inventory hash, runtime identity, runtime hash, and receipt-set hash must all match the trusted
expectation. The route resolver re-validates this gate on every use and only then returns `READY`.
Forged receipt content returns `RECEIPT_FORGED`; an older parent or inventory returns
`RECEIPT_STALE`; a different Blender version/build identity returns `RECEIPT_CROSS_VERSION`.
Malformed or unavailable routes remain fail-closed as `IO_FORMAT_UNSUPPORTED`. The App GLB export and
format-tagged operator search now consume the freshness envelope rather than the unbound M12-05D set.
## Evidence
- `node --test web/tests/unit/io-format-receipt-freshness.test.mjs` passed 4/4: exact trusted route,
canonical digest verification, forged content, stale parent, and cross-version negatives.
- `node tools/web/check-io-format-receipt-freshness.mjs` passed; 14 receipts, App artifact parity,
independent canonical digest verification, deterministic regeneration, and all three negative
classes passed.
- Existing M12-05D/M12-05E unit and checker commands passed unchanged.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed; `git diff --check` passed.
## Artifact Hashes
- parent manifest: `2fbaaf39c6acd9f55fbdbadccc0b027e9e7763bf069c954a96ca49b193648990`
- protocol: `111a630c7beccd31989dc4f78932b7d7b741fb6bef03e45cb39a8139f774d235`
- generator: `6a1e798ce46e1d14d833091d4d7ae452dccb13efe583594277785465eb725bbf`
- checker: `7a8fe69ea1aa2c1e121be008a9fb60fc236f7ef776d2088a7b00b14f46fe3fba`
- unit: `cd1c2adca81653f98f9a1c6c7d104ad0e3052283213fb7166dac827c956928fe`
- freshness receipts: `0187ad0d9ea05fc4b152b7abd4945191dbe9ec24dfde4ca7dbe4aadfd1230efe`
- App freshness receipts: `0187ad0d9ea05fc4b152b7abd4945191dbe9ec24dfde4ca7dbe4aadfd1230efe`
- App expected identity: `8d65f78aa774ff252871cb1cc09e69b4ff04fbb45e61200eaf67534c9d2651b2`
- App: `043ff3a2f39ef3a1303791081b80851b427e7db5dfd9af2161926dd6f1ea9ca4`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `63e1506801ddee2f1eaf64cad68a9d5c918405f642ca237c6a1ec249ff297623`
## Next Task
`M12-06A`: desktop generate the bounded Mesh/PBR/UV/skin/animation GLB fixture group.
## Rollback
Remove the freshness protocol, generator/checker, freshness artifacts, unit test, App imports/route
gate, manifest, and this status entry. Restore M12-05E as the queue tail and move the machine queue
back to `M12-05F`. No parity ledger rollback is required.

59
docs/status/M12-06A.md Normal file
View File

@@ -0,0 +1,59 @@
# M12-06A Status
status: done
task: generate the bounded Mesh/PBR/UV/skin/animation GLB fixture group on desktop
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
The pinned Blender 5.2.0 LTS desktop runtime generates five independent GLB 2.0 fixtures: mesh,
PBR, UV texture, two-joint skin, and object animation. Each file has one bounded triangle primitive,
uses no required or optional glTF extension, and remains below the 512 KiB per-file budget. The
fixtures isolate feature ownership so later Web import comparisons cannot hide one unsupported
domain behind an all-in-one scene.
The canonical report records runtime identity, file bytes and SHA-256, nodes, topology accessors,
attributes, materials, textures/images, skins, and animations. The checker binds the M12-05F parent
manifest and the pinned M12-05A Blender binary identity, regenerates all five files in a fresh
temporary directory, and requires both the semantic report and every GLB byte to match exactly.
This enabling task does not claim Web import, `.blend` save/reopen, export loss reporting, or GLB
round-trip parity.
## Evidence
- `node tools/web/check-glb-desktop-fixtures.mjs` passed: 5 fixtures, 8,676 aggregate bytes,
Mesh/PBR/UV/skin/animation assertions, exact report regeneration, and exact GLB regeneration.
- Mesh exports indexed triangles with POSITION/NORMAL/COLOR_0; UV exports TEXCOORD_0 plus one
embedded PNG; skin exports JOINTS_0/WEIGHTS_0 and two inverse-bind matrices; animation exports
translation and rotation channels sampled over 25 frames.
- The runtime binary SHA-256 is
`d4483926610484ef9c2ad9241aae1469f934d955ebe791f1920e263e0ba85b82`, matching M12-05A.
- `npm --prefix web run typecheck`, `npm --prefix web run test:status-consistency`, and
`git diff --check` passed. The package hash remains the frozen
`cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`.
## Artifact Hashes
- parent manifest: `63e1506801ddee2f1eaf64cad68a9d5c918405f642ca237c6a1ec249ff297623`
- generator: `0247dd2405a68b42d99c2b005546ad2aa99b46416e3fe9489832467f6ea4eb4d`
- checker: `211ebdb66bf2e2d349455d5303e889a4a1ae3323639a89dd78b3bda574dd820b`
- desktop report: `dea31cc861622166dc502b333bc177b70b66b54d9c62aaccc6522745dab5ae13`
- mesh GLB: `e52b9268b6524744fb498691f976000635e544ba3b47e9f8ff22b03bcdf17a94`
- PBR GLB: `244cc8a992c5a70692b8bbc8333533718b3bac7022110715ce3b23d2e4c0b361`
- UV GLB: `1e0397d2b69d8261b3252451b50ab4aba6525b94713719f35069a9a9d96fcfa2`
- skin GLB: `4086ee4c8873aa03090338b676575b7a5335fb7c9384fec6ccb36108e71929f6`
- animation GLB: `44f6cc47961a146dc97ea337ae31a8b64bb4ab213b716f81ec22129db704f1fb`
- manifest: `e3554a1e739cbe3f217f6169130532365538b0c0eafbb97afc58d4d56c4287cb`
## Next Task
`M12-06B`: import the desktop GLB fixture group on Web and compare topology, attributes, materials,
nodes, and animations.
## Rollback
Remove the desktop fixture generator/checker, five GLB files, report, manifest, and this status
entry. Restore M12-05F as the queue tail and move the machine queue back to `M12-06A`. No parity
ledger rollback is required.

57
docs/status/M12-06B.md Normal file
View File

@@ -0,0 +1,57 @@
# M12-06B Status
status: done
task: compare desktop GLB topology, attributes, materials, nodes, and animations in Web
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
The production TypeScript GLB parser now exposes a canonical bounded semantic surface for the five
M12-06A desktop fixtures. It validates referenced accessors, nodes, materials, textures, skins, and
animation samplers before returning primitive topology, sorted attributes, PBR material fields,
node hierarchy/TRS, skin bindings, and animation channels. A field-level comparator checks that Web
semantics exactly match the pinned Blender 5.2 desktop report.
Both Node and a real Chromium Worker consume the exact committed GLB bytes and verify each source
SHA-256 before comparing all five domains. The existing summary import API remains compatible. This
task does not create Blender Main data or expose GLB in the file picker; the runtime route remains
`BLOCKED_UNTIL_MAIN_PERSISTENCE` until M12-06C proves save/reopen and stable IDs.
## Evidence
- `node --test web/tests/unit/glb-desktop-import.test.mjs` passed 3/3: five exact fixture imports,
separate domain assertions, and a stable field-level PBR mismatch.
- `node tools/web/check-glb-desktop-import.mjs` passed: 5 fixtures, 5 compared domains, exact
desktop/Web canonical hashes, deterministic report regeneration, and the blocked route state.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5425 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-desktop-import.spec.ts` passed 1/1 from
the `web/` directory using Chrome 150. The Worker verified source SHA-256 and all five semantic
comparisons.
- `npm --prefix web run typecheck`, `npm --prefix web run test:status-consistency`, and
`git diff --check` passed. The package hash remains
`cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`.
## Artifact Hashes
- parent manifest: `e3554a1e739cbe3f217f6169130532365538b0c0eafbb97afc58d4d56c4287cb`
- protocol: `45d9a7912c4a59a552789a8ea0dfaff5f1849f8d213f14d238de024b77acdb0d`
- generator: `6f97527b7da04c7b4f9b09c48b9f367d1270db9f7820498d33832a80754436c2`
- checker: `804a4b5545d95d7ab1ba265469a981d0a10b71dab36f0c96283eb73b401443d2`
- unit: `6bf2a96b3e43e5fae93589ea5dcf98e7a69b10266378e442988198925286a8d8`
- Chromium Worker: `eb32049631113270fb62acb7ae9379e8ff9a03e38086db2fa309c6891cd707bf`
- Chromium test: `fa3e06419c918406f24b5a4260523bd94cfe729a84786e9434517fdfed624d45`
- Web import report: `79933888cc5aa2d1e3639ec349ca4c31d028fe89f751ebb8d4342f06d15ecfc2`
- manifest: `5275310394b34726a05b30ab67658e1381662dddf9163a97cb02f47f646a8fa4`
## Next Task
`M12-06C`: create authoritative Main data from the imported GLB, save `.blend`, reopen it, and
compare stable IDs.
## Rollback
Remove the canonical Web import surface, report generator/checker, Node/Chromium tests, report,
manifest, and this status entry. Restore M12-06A as the queue tail and move the machine queue back to
`M12-06B`. No parity ledger rollback is required.

59
docs/status/M12-06C.md Normal file
View File

@@ -0,0 +1,59 @@
# M12-06C Status
status: done
task: import desktop GLB results into authoritative Main, save `.blend`, reopen, and compare stable IDs
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The pinned Blender 5.2 desktop runtime imports each M12-06A GLB fixture and saves a `.blend`; the
generator reopens every saved file and requires the complete stable Object/Mesh/Material/Image/
Armature/Action ID set to remain unchanged. Chromium then opens those authoritative Main fixtures
through the production WebEngine, applies one Main-owned visibility edit, saves the resulting
`.blend`, reopens it in a fresh isolated open transaction, and compares the stable IDs with the
desktop baseline. The saved edit is checked after reopen and the open resource counters are zero for
input, staging, and active requests.
This task does not expose GLB in the normal `.blend` file picker, claim arbitrary glTF extensions,
or change the N-023 full-parity ledger. M12-06B remains the bounded Web GLB semantic parser and
M12-06D owns export loss reporting.
## Evidence
- `node tools/web/check-glb-main-persistence.mjs` passed the parent manifest, all artifact hashes,
five desktop GLB/Main fixture bindings, stable-ID shape checks, and a fresh Blender regeneration
with exact semantic report/stable-ID comparison.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5437 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-main-persistence.spec.ts` passed 1/1.
Every fixture opened in the production WebEngine, performed one authoritative visibility edit,
serialized a changed `.blend`, reopened it, preserved all stable IDs, restored visibility=false,
and returned zero active requests/input/staging resources.
- `npm --prefix web run typecheck` and `git diff --check` passed. The existing package manifest was
left unchanged so prior M12 evidence remains bound to its frozen package hash.
## Artifact Hashes
- parent manifest: `5275310394b34726a05b30ab67658e1381662dddf9163a97cb02f47f646a8fa4`
- generator: `8989d6ce4196f140a7bfb44b863dc530a6aa462ca4a57fa7b77c468e06ab61ad`
- checker: `5bbbbeaf2d20ff9bbdeb74c8dd10fa6ffc421d1d59f86540e95f29c2cfd10903`
- desktop report: `76b000454a9073ef762d25fa546d5c65a004659a93eb6ec82fad1e679b2e81be`
- Chromium test: `7c97877f1cbbfd0166e106c80faee53f474f78816cca68ea924df5aa3c47776d`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- mesh `.blend`: `66e29adc016f07e220019b6f24eb7e5016c684dca4b3102b20c8e836968d422d`
- PBR `.blend`: `ba08aeb2876d82ddf731abe81d3a42041a1be36617d0b6324c870d5bcd4cc771`
- UV `.blend`: `1270cb452d34d2fd7a19181a2b20f70b7a028bdd2db7cf1bba4e1003f7de0f48`
- skin `.blend`: `23f175e44ec588c75db99d3f9134863fc3d7d1f192bbd815d5d1c4e3218bce0c`
- animation `.blend`: `fa6baf3a67ff11fe3d2922210089a7c508e4ee28bfaabe4cf628ba6addee1ff5`
- manifest: `e3a57636a47591e3b02dff5a07e8a0aec5e0dc43bf6b4829bffc811035dbbb31`
## Next Task
`M12-06D`: Web export generates a machine loss report.
## Rollback
Remove the M12-06C generator/checker, manifest, desktop Main fixtures, report, Chromium test, and
this status entry. Restore M12-06B as the queue tail and move the machine queue back to M12-06C. No
parity ledger rollback is required.

56
docs/status/M12-06D.md Normal file
View File

@@ -0,0 +1,56 @@
# M12-06D Status
status: done
task: Web GLB export generates a machine-readable loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production GLB exporter now has a schema-1 deterministic loss-report wrapper. It records the
source SceneIR identity/revision, exportability, error/warning counts, sorted loss entries and the
bounded data-block surface. Chromium opens all five M12-06C authoritative Main fixtures and sends
their real snapshot/geometry/packed assets through the production exporter Worker. Exportable
PBR/UV/skin/animation outputs are byte-hashed; the mesh fixture's unsupported Color Attribute
shader is reported as `SHADER_GRAPH_UNMAPPABLE` and no GLB bytes are emitted.
This task reports the bounded exporter surface only. It does not claim lossless GLB round-trip,
desktop re-import, arbitrary shader mapping, or GLB file-picker import; those remain later M12-06E/G
tasks or explicit blockers.
## Evidence
- `node --test web/tests/unit/glb-loss-report.test.mjs` passed deterministic sorting/count semantics.
- `node tools/web/check-glb-loss-report.mjs` passed artifact hashes, parent Main fixture binding,
deterministic loss ordering, mesh fail-closed output, and four exportable fixture output hashes.
It reports `fixtures=5 blocked=mesh warnings=3`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5445 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-export-loss-report.spec.ts` passed 1/1.
The test uses `WebEngineClient` and a production module Worker, requests packed image assets,
produces the report, and compares it byte-for-byte with the checked-in golden report.
- `npm --prefix web run typecheck` and `git diff --check` passed. `web/package.json` remains
unchanged so previous M12 package bindings stay valid.
## Artifact Hashes
- parent manifest: `e3a57636a47591e3b02dff5a07e8a0aec5e0dc43bf6b4829bffc811035dbbb31`
- export protocol: `a5d342827860a9e55b49a3bb3a196a01b1e53546325d6e594778afb9360c3125`
- loss report protocol: `dce9c790b2f52d46efe0908ecb044d63d21b3c6c3f7d77ddb5e697b29a7a2d6e`
- Worker: `6f6294d26fe7b717416a5dd25fe834fb4b9a2ecbe8b011395c9559a26701ec77`
- Chromium test: `ce334b6bb5d82c133d317e916c03711029fba1c19c634dec06c06da9eddbd776`
- checker: `a23346860fa26405b2cd24591b0ab36fea29cb561ec8c2991ecfeabcffc17ee1`
- unit: `dfcc2d968e4e0c0cef4496bc304cb481f10d1f0dc4c76a40ea1d6e2f11b6b708`
- web loss report: `c6db52234d867985ef5fbcdc7c62298ec9aaa013028b5a54e2b9a16aa4133397`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `c01c5861d493e1f177e8cde3038bc5283a7671fa39bf84484662d307623325a2`
## Next Task
`M12-06E`: desktop Blender re-imports Web GLB and compares the canonical report.
## Rollback
Remove the loss-report protocol/Worker, checker, manifest, golden report, Chromium test, and this
status entry. Restore M12-06C as the queue tail and move the machine queue back to M12-06D. No parity
ledger rollback is required.

55
docs/status/M12-06E.md Normal file
View File

@@ -0,0 +1,55 @@
# M12-06E Status
status: done
task: desktop Blender re-imports Web GLB and compares canonical report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The four Web GLBs that produced bytes in M12-06D (PBR, UV, skin and animation) are re-imported by
the pinned Blender 5.2 desktop runtime, saved as `.blend`, reopened, and emitted as canonical graph
reports. The checker binds each Web output hash to the M12-06D report and compares Object/Mesh/
Material/Image/Armature/Action graph fields against the M12-06C desktop-import baseline.
PBR and animation are exact. UV records four explicit differences (corner-expanded vertex topology
and Blender's generated texture Mix node); skin records 31 explicit differences (the exporter emits
an additional armature helper mesh and Blender's re-import tessellation changes). These are recorded
machine mismatches, not silently treated as parity. The N-023 parity ledger remains blocked and this
task does not claim lossless GLB round-trip.
## Evidence
- `node tools/web/check-glb-web-reimport.mjs` passed artifact hashes, four Web GLB source bindings,
pinned Blender regeneration determinism, save/reopen stability, and canonical comparison. Output:
`glb-web-reimport-ok fixtures=4 exact=2 mismatched=uv,skin deterministic=true next=M12-06F`.
- The report binds Web GLB hashes `pbr=1ab793...`, `uv=8bd045...`, `skin=4a45d0...` and
`animation=b83de1...`; exact/mismatch counts are fixed at PBR 0, UV 4, skin 31, animation 0.
- The Web export Chromium test that produced the inputs passed 1/1; the desktop generator performs
a fresh Blender import/save/reopen for every input. `npm --prefix web run typecheck` and
`git diff --check` passed.
## Artifact Hashes
- parent manifest: `c01c5861d493e1f177e8cde3038bc5283a7671fa39bf84484662d307623325a2`
- generator: `3ae1ba45e15cae5d0308fc3fcb3766764cd374c096e27eaaddba9228a3d75004`
- checker: `c21b45a975ec70586da1b9e50b8cf4ccf74644300b4f381c3fee0ad735cfcdb9`
- desktop report: `e4d03d25cfac3c4beff4d0af0769b1c39b058670c679c12f4a11ae30d2d91f3c`
- Web export test: `ce334b6bb5d82c133d317e916c03711029fba1c19c634dec06c06da9eddbd776`
- PBR Web GLB: `1ab7936fae6e0c28e1b90e8a6ae24b3893c075c9fc58ac8896f780fdefb8277e`
- UV Web GLB: `8bd045388527ddad7cf886c0c7a2a45b6e7d6db603568a10a959bc6d423ae145`
- skin Web GLB: `4a45d00dfa23638682bb61a4f74b283bcd986126da4890d068902e3c85efc332`
- animation Web GLB: `b83de103df3f5a49487868f3ede3046875c90b0d084bbd998511c3a7c987a4fa`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3d3b13fd54a314fd6f6907fc2d314e66ef74e8ca770a8accd823370d272737fc`
## Next Task
`M12-06F`: sparse accessor, Draco/extension, external URI and over-budget negative cases.
## Rollback
Remove the desktop Web re-import generator/checker, manifest, report, four Web GLB fixtures, and
this status entry. Restore M12-06D as the queue tail and move the machine queue back to M12-06E. No
parity ledger rollback is required.

49
docs/status/M12-06F.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-06F Status
status: done
task: GLB sparse accessor, extension, external URI and over-budget negative cases
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded GLB importer now enforces a 512 KiB input budget, JSON/table budgets, rejects sparse
accessors, rejects all extensions outside the pinned allowlist (currently empty), and blocks external
buffer/image URIs. Errors are stable and fail before semantic/Main publication:
`GLB_SPARSE_ACCESSOR_UNSUPPORTED`, `GLB_EXTENSION_UNSUPPORTED`, `GLB_EXTERNAL_URI_BLOCKED`, and
`GLB_IMPORT_BUDGET_EXCEEDED`.
## Evidence
- `node --test web/tests/unit/glb-negative-cases.test.mjs` passed 2/2 for sparse, extension, external
URI, byte-budget and table-count cases.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5450 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-negative-cases.spec.ts` passed 1/1 in a
production Chromium Worker with all four stable codes.
- `node tools/web/check-glb-negative-cases.mjs` passed the schema-1 negative report and artifact
hashes: `glb-negative-cases-ok cases=4 budget=524288 deterministic=true next=M12-06G`.
- `npm --prefix web run typecheck` and `git diff --check` passed. The package manifest remains
unchanged.
## Artifact Hashes
- parent manifest: `3d3b13fd54a314fd6f6907fc2d314e66ef74e8ca770a8accd823370d272737fc`
- protocol: `0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147`
- unit: `9af1c155143a0c685a62f569f705afd9fcc3bb49e0d724ebf3ad2c6356d63d6d`
- Worker: `d84a6b884ce1bfedd598b2602d803493bf10f6ad62fdfac49d64fca3f30f3931`
- Chromium test: `c6694689ce04ff2faea2c20be648f438a9f7eb25cdfd2f714b94c1f556ea1510`
- checker: `08377c306fd7d1082f7fd734e37809960c9798d29d626681fe9ad3f94cb7a29e`
- negative report: `7367a624b562a9613b4b908c894ab04c731ae0a348a3b58689075f4a9decd90c`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `27b42da0683dab11a884553440088c30cf58d51364268fdaac86668786aaedd4`
## Next Task
`M12-06G`: import/export cancellation, Worker restart and OPFS quota recovery.
## Rollback
Remove the GLB negative-case budget/protocol changes, Worker, tests, checker, report, manifest, and
this status entry. Restore M12-06E as the queue tail and move the machine queue back to M12-06F. No
parity ledger rollback is required.

57
docs/status/M12-06G.md Normal file
View File

@@ -0,0 +1,57 @@
# M12-06G Status
status: done
task: GLB import/export cancellation, Worker restart, and OPFS quota recovery
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 GLB recovery receipts now bind operation, worker generation, source/output SHA-256,
revision, temporary bytes, live requests, commit state, and stable cancellation/restart/quota codes.
Both import and export cancellation release all temporary bytes and publish no result. A new Worker
repeats the same bounded GLB import with an identical semantic result hash.
The GLB asset persistence path uses the existing content-addressed OPFS store. A real Chromium
origin quota of 64 KiB rejects a 128 KiB candidate, while the previously committed GLB remains
readable after Storage Worker restart. Raising the quota allows a small follow-up asset to commit.
## Evidence
- `node --test web/tests/unit/glb-recovery.test.mjs` passed 2/2 for cancel, quota, commit, and
generation transition invariants.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5455 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-recovery.spec.ts` passed 2/2 in Chrome
150. The first real-quota run reached the expected browser failure but the assertion only accepted
the injected error wording; the final run accepts both native and injected quota messages.
- `node tools/web/check-glb-recovery.mjs` passed with
`glb-recovery-ok cancelled=2 workerGeneration=2 quota=GLB_OPFS_QUOTA smallRecovery=true next=M12-07A`.
- `npm --prefix web run typecheck`, `node --check tools/web/check-glb-recovery.mjs`, and
`git diff --check` passed. The package manifest remains unchanged.
## Artifact Hashes
- parent manifest: `27b42da0683dab11a884553440088c30cf58d51364268fdaac86668786aaedd4`
- recovery protocol: `da4e2a546d7598e80798cfebd105e52b7522c896acb545710c78bb8a5c3705aa`
- storage protocol/client/Worker: `2c8ce9e32fcae973e9262a024fd849221680104bcd427ec308f99ef25112d951` /
`00cd35e4632479e4cd153314113e201c822fd209ae6c8e9fbeff5f1399728565` /
`80bf4d2ac59cbf7998c2a72c8961ae38abe43685b60df564d0746e1a45e9e1bc`
- operation Worker/browser adapter: `947c4a768422725ff2f689b2eefa8068bee51bb7ff342af17e8d4a4d0a4a7ca2` /
`2c753a04c153471c2bf7691073b836d968a1a1300e3da038f493983b46738cdf`
- unit/Chromium: `6dd48f62a85c5aaf3a04b6e572a47a7986b23cbec84a099ea510af81e8dd3a3a` /
`7d95e992f44fb913f70c104f0d6b23bd76f47d48db4a21899e35ae1d188e2093`
- checker/report: `b185248fdcd6b3cee84252bd68fcb6921bb6385bfa4a00486e93c58e94755cce` /
`1a008a76590573468446ca6e5cbdfe0ea5a8b27493291590d937b90db90d6e42`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `1c732b8d9f1a0bdb502f44e2e843e91efea12e93483a35658f8a9c70a69a2430`
## Next Task
`M12-07A`: OBJ single-Mesh positive fixture covering position, normal, UV, and material group.
## Rollback
Remove the GLB recovery receipt, quota fault option, Worker/browser adapter, tests, checker, report,
manifest, and this status entry. Restore M12-06F as the queue tail and move the machine queue back to
M12-06G. No parity ledger rollback is required.

49
docs/status/M12-07A.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-07A Status
status: done
task: OBJ single-Mesh desktop positive fixture
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_obj_export` now generates one deterministic Wavefront OBJ object with
four positions, four UV coordinates, one explicit normal, two triangle faces, two material records,
and two material groups. The `.mtl` sidecar is kept beside the OBJ and both files are bound to the
canonical semantic report. Web parsing/import, multi-object and negative cases remain queued.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-obj-single-mesh-fixture.py -- tests/files/web/m12_obj_desktop_v1
tests/golden/M12-07A/desktop-fixture.json` completed with 4 positions, 4 UVs, 1 normal,
2 faces, and 2 materials/groups.
- `node tools/web/check-obj-single-mesh-fixture.mjs` passed deterministic regeneration in a fresh
temporary directory and byte-for-byte OBJ/MTL comparison:
`obj-single-mesh-fixture-ok vertices=4 normals=1 uv=4 faces=2 materials=2 deterministic=true next=M12-07B`.
- Runtime identity matches the pinned M12-05A Blender 5.2 inventory; the report is anchored to
`blender-5.2.0/source/blender/io/wavefront_obj` and `wm.obj_export`.
- Package hash remains frozen; no Web route or parity ledger status was changed.
## Artifact Hashes
- parent manifest: `1c732b8d9f1a0bdb502f44e2e843e91efea12e93483a35658f8a9c70a69a2430`
- generator: `604c3006f194c7c64a487b8f760693b66830f3cfa602928b46769955e7d4f358`
- checker: `3d0208f61a86d4d29796d8284756f53931c90864b15b7dfe4fcc84d7f65a8040`
- desktop report: `6c560a8eecf84973c2b05f9fd50d33bd45515e97c4f7970f1502de406c39f6a5`
- OBJ/MTL: `a56694d1ee28735c68381ff18c3a52581612feebac0101a53e502956c27d144f` /
`392f1b10ff5a0b142d520a9443b4c96191985f15d4244c79b36fdeda0f153715`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `d80b74502202effa7be15640c945dc7e04af703b58e7a15c3fe7babc43c17b46`
## Next Task
`M12-07B`: OBJ multi-object, negative-index, MTL/texture-origin, and malformed-face cases.
## Rollback
Remove the OBJ generator, checker, desktop report, OBJ/MTL fixture, manifest, and this status entry.
Restore M12-06G as the queue tail and move the machine queue back to M12-07A. No parity ledger rollback
is required.

53
docs/status/M12-07B.md Normal file
View File

@@ -0,0 +1,53 @@
# M12-07B Status
status: done
task: OBJ multi-object, negative-index, texture-origin, and malformed-face fixtures
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `wm.obj_export` now produces a two-object OBJ/MTL positive fixture with two
relative `map_Kd` references and a 2x2 PNG texture. The deterministic generator derives a negative
index OBJ variant and a malformed two-vertex face variant from the same positive bytes. The report
keeps multi-object/group/material counts and expected fail-closed `OBJ_FACE_ARITY_INVALID` separate;
it does not claim that a Web parser or OBJ import route exists.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-obj-multi-negative-fixtures.py -- tests/files/web/m12_obj_multi_v1
tests/golden/M12-07B/desktop-fixtures.json` completed with 2 objects, 6 positions, 6 UVs,
2 normals, 2 faces, 2 materials, relative `m12_obj_texture.png`, and both derived variants.
- `node tools/web/check-obj-multi-negative-fixtures.mjs` passed fresh-directory Blender regeneration,
exact OBJ/MTL/PNG/negative/malformed bytes, negative-index acceptance shape, malformed-face arity,
and PNG signature checks:
`obj-multi-negative-fixtures-ok objects=2 negative=true malformed=OBJ_FACE_ARITY_INVALID textureOrigin=relative deterministic=true next=M12-07C`.
- Runtime identity matches M12-05A pinned Blender 5.2; no Web parser, UI route, or parity ledger
status changed. Package hash remains frozen.
## Artifact Hashes
- parent manifest: `d80b74502202effa7be15640c945dc7e04af703b58e7a15c3fe7babc43c17b46`
- generator: `8d4faed82cba76e46bf639e5031b30568e8b9a15240cbddb1c22ee7ad11d697b`
- checker: `61188d67efd6133e714f2d55c7c8516b9d04896de068f994523a3c398eebdd2f`
- desktop report: `b60ff785676c0f0168588605ad442a650615191ac00770b7e5a308cc4ade83ce`
- OBJ/MTL/PNG: `4ed3dced8445b03754cd3916ae2e8cf0dff85e6a5882f1c6f0a4a4e4c5251f6a` /
`80338f569c67a8b1616515ba878ffc72b26e93ef2e8c361131023fb14f132f5f` /
`44e4fd08bdda8403908349e2a62dcf103ce2d0851099fc61cd868d65ddbef78c`
- negative/malformed OBJ: `9457954284cac1d68e23627e3ff734c0c591b3a24086ce5aa3d0dbbfc22f01bc` /
`6dd508b5ba944c2d15e2889c9ad9a3693845145c3bf6c9bf7df992081c915864`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `785f593271058098704498cb0a7c948305087f1a83bf8f29b6e6fb9fe9341926`
## Next Task
`M12-07C`: Web-to-desktop OBJ round-trip and loss report.
## Rollback
Remove the multi/negative OBJ generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07A as the queue tail and move the machine queue back to M12-07B. No parity ledger rollback
is required.

55
docs/status/M12-07C.md Normal file
View File

@@ -0,0 +1,55 @@
# M12-07C Status
status: done
task: Web-to-desktop OBJ round-trip and loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded TypeScript OBJ protocol parses positive and negative indices, position/UV/normal streams,
objects/groups/faces, MTL `map_Kd`, and stable budgets; it serializes a deterministic Web OBJ/MTL pair
and emits a machine loss report for unbound texture origins. A Chromium Worker consumes the M12-07B
double-object fixture, then a new pinned Blender 5.2 process imports the Web output with split groups.
## Evidence
- `node --test web/tests/unit/obj-import.test.mjs` passed 3/3 for negative-index resolution,
deterministic serialization, bound/unbound texture loss, malformed face arity, and index range.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5460 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/obj-web-roundtrip.spec.ts` passed 1/1 in Chrome
150. Browser output has 2 objects, 6 positions/UVs, 2 normals, 2 faces, 2 materials; bound texture
loss is zero and missing texture loss contains two `OBJ_TEXTURE_ORIGIN_UNRESOLVED` warnings.
- The test writes the browser OBJ/MTL and texture to an isolated directory, invokes pinned Blender
`wm.obj_import`, and compares 2 objects, 2 triangles, UVMap presence, and one material per object.
- `node tools/web/check-obj-web-roundtrip.mjs` passed the exact golden and artifact hash gate:
`obj-web-roundtrip-ok objects=2 triangles=2 lossWarnings=2 desktopExact=true next=M12-07D`.
- `npm --prefix web run typecheck`, Python compile, and `git diff --check` passed. Package hash remains
frozen; OBJ Web capability is still bounded and does not change N-023 parity.
## Artifact Hashes
- parent manifest: `785f593271058098704498cb0a7c948305087f1a83bf8f29b6e6fb9fe9341926`
- protocol: `e7240af65e0d90f3ee690a4e3f391416fe4744ac6c46edc8ac0d72386857cab9`
- Worker: `bf1fcc60ec318cf6c2747d44f4af741b46f284cf5f5307e142f0ab6d50b14302`
- desktop importer: `9f1eb4ab679255a0f1f596696e8befc33a4e30c0cbe6ea423e2aaa0314cec22d`
- checker: `9d53014f4b89f786c516ebe8d300030c2728e4a36a86a5ef136b2769a12ac96b`
- unit/Chromium: `485a669be5de8e370e9b5a3239357b028ba61ca5c4076819cd46aed52a5c210a` /
`93785b4017ba14b007926b0f82442f8ae5968f242a2a762e5f5dc77d36110f5b`
- report: `45eaffc9c2e50c84b557d13ebbe9f4f53b63e19e00bc69b272491ef6366dff81`
- fixture OBJ/MTL/PNG: `4ed3dced8445b03754cd3916ae2e8cf0dff85e6a5882f1c6f0a4a4e4c5251f6a` /
`80338f569c67a8b1616515ba878ffc72b26e93ef2e8c361131023fb14f132f5f` /
`44e4fd08bdda8403908349e2a62dcf103ce2d0851099fc61cd868d65ddbef78c`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `0c639954900b1fcc3b8285d0f4c0ecfa5807df6cde6d1f2cd3b59c4636d71674`
## Next Task
`M12-07D`: split STL binary and ASCII capability declarations.
## Rollback
Remove the OBJ protocol, Worker, desktop importer, unit/E2E tests, checker, report, manifest, and this
status entry. Restore M12-07B as the queue tail and move the machine queue back to M12-07C. No parity
ledger rollback is required.

47
docs/status/M12-07D.md Normal file
View File

@@ -0,0 +1,47 @@
# M12-07D Status
status: done
task: split STL binary and ASCII capability declarations
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_stl_export` now generates binary and ASCII STL from the same selected
two-triangle mesh using identical axis, scale, unit, evaluation, and modifier settings. The report
keeps `STL_BINARY/ascii_format=false` and `STL_ASCII/ascii_format=true` as separate variants; it does
not infer the format from the `.stl` extension or claim Web parsing/import support.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-stl-capability-fixtures.py -- tests/files/web/m12_stl_capability_v1
tests/golden/M12-07D/capability-report.json` generated a 184-byte binary STL with two 50-byte
triangle records and a 213-byte ASCII STL with two facets/six vertex lines.
- `node tools/web/check-stl-capability-fixtures.mjs` matched runtime identity to M12-05A, validated
both independent encodings, regenerated the report/files byte-for-byte in a fresh directory, and
returned `stl-capability-fixtures-ok binaryTriangles=2 asciiFacets=2 deterministic=true next=M12-07E`.
- Package hash remains frozen. This enabling task does not change N-023 parity or expose an STL UI
route.
## Artifact Hashes
- parent manifest: `0c639954900b1fcc3b8285d0f4c0ecfa5807df6cde6d1f2cd3b59c4636d71674`
- generator: `8310104e66f246b32ac7cb4619e7f4da109baf2ece39ea670cbb6d33bd88c8b8`
- checker: `b2ad901eaa9701436cf7bcc8aa4e40d1b2d6eda7c6c44a0af830347a37cc9ca8`
- desktop report: `29c7d2a6e6764440c99eec25bb5760c7e0880839691757fb3e607ed4f5050013`
- binary/ASCII fixtures: `50161172cd12e4240067064db6f80e74b2df69c475e3e34154e9d0523928c1ca` /
`a463a5add8be070fb67b34f00ef6e7b46025aed31fa429d4a033d75a11cf0113`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `bbc78e47f389562e7d648bf49c9b3bf8a08aaa36e914589a6eab0a1f6e72748d`
## Next Task
`M12-07E`: STL normal, unit, degenerate-triangle, and trailing-byte parity.
## Rollback
Remove the STL capability generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07C as the queue tail and move the machine queue back to M12-07D. No parity ledger rollback
is required.

60
docs/status/M12-07E.md Normal file
View File

@@ -0,0 +1,60 @@
# M12-07E Status
status: done
task: STL normal, unit, degenerate-triangle, and trailing-byte parity
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded STL protocol requires an explicit binary/ASCII variant and positive unit scale. It parses
facet normals and vertices, applies the scale, removes zero-area triangles the same way as Blender's
validated import, and rejects binary payload after the declared triangle table with
`STL_TRAILING_BYTES`. Desktop Blender accepts that trailing fixture as an empty mesh, so the report
records `STRICTER_WEB_BLOCK` rather than claiming exact parity for that edge case.
## Evidence
- The deterministic edge generator derived a one-degenerate-triangle binary and a four-trailing-byte
binary from M12-07D. Pinned Blender 5.2 was probed at unit scales 1 and 0.001 and against both edge
files; it preserves normals, scales world bounds by 1000, removes one degenerate triangle, and
accepts the trailing fixture as an empty mesh.
- `node --test web/tests/unit/stl-import.test.mjs` passed 2/2 for binary/ASCII normals, explicit unit
scaling, degenerate removal, trailing-byte rejection, and invalid scale.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5463 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/stl-edge-parity.spec.ts` passed 1/1 in Chrome
150. Normal comparison is exact, Web/Desktop unit ratio matches within Float32 tolerance, and both
retain one triangle after degenerate removal.
- `node tools/web/check-stl-edge-parity.mjs` passed:
`stl-edge-parity-ok normals=exact unitRatio=1000 degenerate=removed trailing=STRICTER_WEB_BLOCK next=M12-07F`.
- Typecheck and `git diff --check` passed. The stricter trailing-byte policy leaves N-023 full parity
blocked and does not expose an STL UI route.
## Artifact Hashes
- parent manifest: `bbc78e47f389562e7d648bf49c9b3bf8a08aaa36e914589a6eab0a1f6e72748d`
- fixture generator/desktop probe: `018013347642603c21237ebb023bdc7a4e338f5a3f875fea536a996eb121e716` /
`b3d6ea197ef77b5a14f60f5e6b43d4392e943ff5d56acf73915507fc9a4161b7`
- protocol/Worker: `87eec72e2b8aa7ad0b168ca0ee8c4016c941f56f5f1ac53aa5fe71d0832f1dd8` /
`d714f1f3a218a2226dd349aea81c6c54efa6246de1c4fe51aaa9f5c352ef44fc`
- unit/Chromium/checker: `4af52833486421c017f3af2b833b0776e60a6ab57ed66fea2161cf9674f4b243` /
`121d348250e26d29ad966f7427bbef9da77de2098e2e305827b11aae52002c5c` /
`b5ed7fbb41bb46fba982d5726cb8c3eaecf360b772a01d6337c309b1c4a4f535`
- fixture/desktop/Web reports: `545463a984356d6635cbaae3865d13fe95bd2d841c394ac9ddff496c95d46f18` /
`2d3028a3b7d97f39654cff5fcef1d0c1c71e9f2d08e3e29c2e926651ed3860f1` /
`e0686cc9be3b68e564651207443e0ebf3e3b0eb3d07a32915b03f44b1908357b`
- degenerate/trailing fixtures: `c120bb0f218819eb89a3607c0b4f8fafd9afb599402e3b21deaa3b2be143e7d0` /
`0a30aab6db1588722067000e2a08c3c6206a8ed5b7531caa0b082723700a3681`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `19a9f460d1b939c9504dadd364cb87dab3b1769b0599035e2d2b51b47091e034`
## Next Task
`M12-07F`: STL Web-to-desktop round-trip and material-loss report.
## Rollback
Remove the STL edge fixtures, probes, parser, Worker, tests, reports, checker, manifest, and this status
entry. Restore M12-07D as the queue tail and move the machine queue back to M12-07E. No parity ledger
rollback is required.

51
docs/status/M12-07F.md Normal file
View File

@@ -0,0 +1,51 @@
# M12-07F Status
status: done
task: STL Web-to-desktop round-trip and material-loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The STL Web path now serializes the bounded parsed triangle result back to deterministic binary STL.
The loss report explicitly records STL's lack of material slots as
`STL_MATERIAL_UNSUPPORTED`; it never silently claims material preservation. A Chromium Worker output
is imported by a fresh pinned Blender 5.2 process and compared by triangle count and facet normals.
## Evidence
- `node --test web/tests/unit/stl-export.test.mjs` passed 1/1 for binary header/table serialization
and explicit material-loss warning.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5467 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/stl-web-roundtrip.spec.ts` passed 1/1 in Chrome
150. Browser output is 184 bytes/2 triangles; Blender reopens 2 polygons/2 triangles with exact
normals; warning code is `STL_MATERIAL_UNSUPPORTED`.
- `node tools/web/check-stl-web-roundtrip.mjs` passed:
`stl-web-roundtrip-ok triangles=2 normals=exact materialLoss=1 desktopExact=true next=M12-07G`.
- Typecheck and `git diff --check` passed. The STL material loss remains machine-visible and STL UI
route/parity stays bounded.
## Artifact Hashes
- parent manifest: `19a9f460d1b939c9504dadd364cb87dab3b1769b0599035e2d2b51b47091e034`
- protocol/Worker: `3b9c409de9fb3eaea34f82c1ddd466670d2b478845d8ff6af3c4e44cb4e04a52` /
`1da8b8281cf8ebf9ccf5fd2f42da8ed5886001ab83daba8d9fcd88980257af87`
- desktop importer: `c4cbff52ff2e7cecba7aeab47e865975955da23a0e1e8ff885ece56b894558d5`
- unit/Chromium/checker: `f06af242df80ec26d06e92b749449cfebaf909476198ff825207cdd4b9484102` /
`2e979dcd030f5316fcbe28e2c19b1c99fe5d111e849d3fc1d2ea316d2159032b` /
`093de04bf80b0909eee56ea590e04e7aa4749168e2e49615c62ab39ddc0d16cf`
- report: `0495c645b4280f6e7821f0ba02010e25d4accbc552e3cd7c58e052607799040e`
- source fixture: `50161172cd12e4240067064db6f80e74b2df69c475e3e34154e9d0523928c1ca`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3cbbcb541ee123da0ef8916ac2ca8805680d539bbf8db3b4a8d331aec418148c`
## Next Task
`M12-07G`: PLY ASCII/binary little-endian capability declarations.
## Rollback
Remove the STL export/loss protocol, Worker, desktop importer, tests, checker, report, manifest, and
this status entry. Restore M12-07E as the queue tail and move the machine queue back to M12-07F. No
parity ledger rollback is required.

53
docs/status/M12-07G.md Normal file
View File

@@ -0,0 +1,53 @@
# M12-07G Status
status: done
task: PLY ASCII and binary little-endian capability declarations
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_ply_export` now has two independently declared capability variants for
the same selected two-triangle mesh: `PLY_ASCII` and `PLY_BINARY_LITTLE_ENDIAN`. The report binds
the export settings, source/operator anchor, runtime identity, header semantics, and byte hashes;
the variant is never inferred from a shared `.ply` extension. This enabling task freezes desktop
capability only and does not expose a Web PLY parser or import route.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-ply-capability-fixtures.py -- tests/files/web/m12_ply_capability_v1
tests/golden/M12-07G/capability-report.json` generated an ASCII PLY with four vertices/two faces
and a binary little-endian PLY with the same four vertices/two faces. Both headers explicitly carry
their independent encoding declarations and Blender export settings are recorded in the report.
- `node tools/web/check-ply-capability-fixtures.mjs` matched every runtime identity field to the
pinned M12-05A inventory, validated the `ascii` and `binary_little_endian` variants, checked the
vertex/face element counts and artifact hashes, regenerated both files in a fresh temporary
directory, and passed byte-for-byte determinism:
`ply-capability-fixtures-ok ascii=ascii binary=binary_little_endian vertices=4 faces=2 deterministic=true next=M12-07H`.
- `python3 -m py_compile tools/web/generate-ply-capability-fixtures.py` and
`node --check tools/web/check-ply-capability-fixtures.mjs` passed. The package hash remains
frozen and N-023 parity remains blocked; no PLY Web UI route was exposed.
## Artifact Hashes
- parent manifest: `3cbbcb541ee123da0ef8916ac2ca8805680d539bbf8db3b4a8d331aec418148c`
- generator: `581cd84057357e3a87997cf9c07d5d5633209648ac11e44611782eb254a38ebd`
- checker: `5280d6e57b7a722ea881e27b792c6082c5113c1577ac0e87f87cc87fdf59516c`
- desktop report: `26b1ce83334b41778cef5ce2a1f2c4d34254f63d7c7573cb3fb550f93ddeabb2`
- ASCII/binary little-endian fixtures: `63646cab9bf6ccecb23092e5e24d04df1e0a690c866127c72a35791e99262331` /
`e40fbb494b8b147c555a0fc06eb191415406bb9a6c061acf6befd8464c8c41a5`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `87df9c12f9c6eacf63051b70e9bb2eb43ebd1e5c4487b3512c45adb94cbb82ea`
## Next Task
`M12-07H`: PLY vertex/face/color/custom-property mapping and unknown-property loss report.
## Rollback
Remove the PLY capability generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07F as the queue tail and move the machine queue back to M12-07G. No parity ledger
rollback is required.

62
docs/status/M12-07H.md Normal file
View File

@@ -0,0 +1,62 @@
# M12-07H Status
status: done
task: PLY vertex/face/color/custom property mapping and unknown property loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production `ply-import` protocol now accepts explicitly declared ASCII and binary
little-endian PLY. Vertex position, normal, RGBA color, numeric custom properties, face
indices, and numeric face properties are mapped into a bounded canonical document. Unsupported
vertex/face list properties and unknown elements are skipped with deterministic
`PLY_UNKNOWN_PROPERTY`/`PLY_UNKNOWN_ELEMENT` loss warnings; mapped fields remain available.
The worker serializes the canonical document to bounded ASCII PLY for desktop validation.
This task does not expose a general PLY file-picker route or claim full PLY attribute parity.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-ply-mapping-fixtures.py -- tests/files/web/m12_ply_mapping_v1
tests/golden/M12-07H/mapping-report.json` generated deterministic ASCII and binary
little-endian fixtures containing four vertices, two faces, RGBA colors, and two numeric
custom vertex attributes. A derived ASCII fixture contains an unsupported list property.
- `node tools/web/check-ply-mapping-fixtures.mjs` matched pinned Blender 5.2 runtime identity,
artifact hashes, field counts and a fresh byte-for-byte regeneration:
`ply-mapping-fixtures-ok vertices=4 faces=2 colors=rgba custom=2 unknown=PLY_UNKNOWN_PROPERTY deterministic=true next=M12-07I`.
- `node --test web/tests/unit/ply-import.test.mjs` passed 3/3. It covers both encodings,
mapped values, unknown-property loss, serialization/reopen, and format mismatch blocking.
- `UPDATE_PLY_MAPPING_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5472
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/ply-web-roundtrip.spec.ts` passed 1/1. Production Chromium Worker parsed both
encodings, reported unknown loss, serialized ASCII, and pinned Blender 5.2 re-imported the
result with exact vertex/face/position counts and mapped custom/color attributes.
- `npm --prefix web run typecheck`, `node --check tools/web/check-ply-mapping-fixtures.mjs`,
and Python compile checks passed.
## Artifact Hashes
- protocol: `058a3263fde553637840a4e9ad4e8e9d923eb52c250f8000317c7f43a228881d`
- worker: `f6bf5e39e83286d7b257bbdce88f4d7fa027c64651da9765567788b5cf298c71`
- generator: `ffc051eccfc6973ee00cc791cdbd641fcce308b4083741e3e6ae82291d9347b7`
- checker: `2b055dbc705830848efdf4d8db8543a3ccc684de1f258732bcafefa86cf65c3a`
- desktop importer: `6edbc6e401a1a902dcfd11c4d767e8c8620d694e40eb4ca29dd8479f9c55ef37`
- unit/e2e: `b03a5f4b4b2a974fa26e653763470b92d1433c5d352ae09ab5492b841e6e5e1f` /
`2cadebc89057655d78e9b520bb6adf9debb27c6d783cd002efee08d269636fb9`
- desktop mapping report: `8a02fc9e364ed79e50ef00897affa9ab63808d3cb3cdabd00fdb8ee4c26ec18a`
- Chromium/desktop round-trip report: `1ca9d3b7870fcc8c9e3c9bbbd90ef48bd13bbc9ae0462312c9482f24f05f13ec`
- ASCII/binary/unknown fixtures: `acaa369c17252d4d089a2e3064d0c1fcdfdb2d066759ed160adf7869d3e859d5` /
`d0fc195fd1a101c42ac984a2382bccdddb7d0bf60dd618e9f637c964f1b30b9e` /
`a994c7126f235d0067ce4af35f8b0c6699cc83073e2a37e982edd45ece459f33`
## Next Task
`M12-07I`: PLY big-endian, malformed list, and oversized count stable blocking.
## Rollback
Remove the PLY mapping protocol, worker, fixture generator/checker, fixtures, reports, tests,
package script, and this status entry. Restore M12-07G as the queue tail and move the machine
queue back to M12-07H. No parity ledger rollback is required.

49
docs/status/M12-07I.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-07I Status
status: done
task: PLY big-endian, malformed list, and oversized count stable blocking
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
PLY admission now fails closed for unsupported big-endian input, truncated/malformed list data,
and element counts above the bounded 65,536 record budget. The production parser returns stable
codes `PLY_FORMAT_UNSUPPORTED`, `PLY_DATA_TRUNCATED`, and `PLY_IMPORT_BUDGET_EXCEEDED: vertex`;
the Worker does not publish a partial document. No big-endian route or unbounded PLY import is
claimed.
## Evidence
- `node tools/web/generate-ply-negative-fixtures.mjs` generated deterministic big-endian,
malformed-list, and oversized-count fixtures. `node tools/web/check-ply-negative-fixtures.mjs`
regenerated them in a fresh temporary directory and passed:
`ply-negative-fixtures-ok cases=3 bigEndian=PLY_FORMAT_UNSUPPORTED malformed=PLY_DATA_TRUNCATED oversized=PLY_IMPORT_BUDGET_EXCEEDED deterministic=true next=M12-07J`.
- `node --test web/tests/unit/ply-negative.test.mjs` passed 2/2 for all three stable error paths.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5478 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/ply-negative.spec.ts` passed 1/1. The
production Worker returned the exact expected error for each case and never returned `ok=true`.
- `npm --prefix web run typecheck`, Node syntax checks, and `git diff --check` passed.
## Artifact Hashes
- protocol: `058a3263fde553637840a4e9ad4e8e9d923eb52c250f8000317c7f43a228881d`
- generator/checker: `9c09707bdfe73ba467bbfbf61ed3846fb59fd33ab5563a3a62c8032722ff6938` /
`b1d047d4cb1fa15dff7821687e7028ad073fdc62d4c76f60a2656732c0ec5e2b`
- unit/e2e: `60439f9e6bc221df8866956bf926816a347e85828b5a93deb26ee23015cf449a` /
`6509a29d6842f3423d4dfcc40dbd52a959a5efa7ee1121143dce06e5bbc4a460`
- report: `fbe2830d1b19294ea98eea66c3e00125bc0809a4bb8a750612939cbe1f5acca9`
- fixtures: `cda92943a3690529fbb3463d328b6796ac0d07e19139450556f7411fc1f031e3` /
`a6a576b7a04d919b540520a6f43a89c089f0d706a17fd8b390711fff6b8b03df` /
`fcd99e0838025429420a47466251cf80e638d2b5816ad14d5aa696364525bb`
## Next Task
`M12-07J`: three-format cancellation, OOM, Worker restart, and small-file recovery.
## Rollback
Remove the count guard, negative fixture generator/checker, fixtures, report, tests, manifest,
and this status entry. Restore M12-07H as the queue tail and move the machine queue back to
M12-07I. No parity ledger rollback is required.

50
docs/status/M12-07J.md Normal file
View File

@@ -0,0 +1,50 @@
# M12-07J Status
status: done
task: three-format cancellation, OOM, Worker restart, and small-file recovery
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
OBJ, STL, and PLY now share a schema-1 recovery receipt. Each bounded production Worker run
binds format, input hash, base/candidate revision, Worker generation, output hash, temporary bytes,
live requests, published result count, and commit state. Cancellation clears temporary state and
publishes no result; over-budget/OOM input returns `IO_FORMAT_OOM`; a generation-2 rerun and a
generation-3 small-file run reproduce the generation-1 output hash. This is recovery evidence for
the bounded format workers, not a general file-picker or full Blender IO claim.
## Evidence
- `node --test web/tests/unit/io-format-recovery.test.mjs` passed 2/2 for cancellation/OOM cleanup,
commit identity, generation recovery, and stale-generation blocking.
- `UPDATE_IO_FORMAT_RECOVERY_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5492
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/io-format-recovery.spec.ts` passed 1/1. The report covers OBJ, STL, and PLY separately:
three cancellations, three OOM budget faults, three Worker-generation restarts, and three small
recovery commits; all output SHA-256 values are stable.
- A second run without report update passed against the same golden, proving deterministic operation
IDs and receipt output. `node tools/web/check-io-format-recovery.mjs` passed:
`io-format-recovery-ok formats=OBJ,STL,PLY cancelled=3 oom=3 restart=3 smallRecovery=3 deterministic=true next=M13-01A`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- protocol: `7e352539e3300969c7409c34d6056eb6ad31055431ffce84b1b0a459c335480a`
- worker/testing adapter: `63b78fbf25132cad28147ef68731f2cd212a26c96b464fdec349a13ebaa1174f` /
`cfcebb6ec38936a66983957b0dede716871cfbfbea3cb53cddc16f3e24fb19b0`
- unit/e2e: `aaed1f2abe4789b084c8a6a60bcce8595d38220d7e6678a93924cd05c5716b4f` /
`5c1750fa408e1297fc43f2e5749be3e9ac08a16b86265d22f0f06053f52b3bd7`
- checker: `6ef6bc4a168f8675a4933a06c296f61076b9ea64cec25b295e961a9b610ab1a2`
- report: `35d4fe10d8a4fa84d6e05a85f20ca50975d93a86df41e73c7bbc5875edc4fc70`
## Next Task
`M13-01A`: begin the next machine-queued milestone task.
## Rollback
Remove the IO recovery protocol, worker, adapter, tests, checker, report, manifest, and this
status entry. Restore M12-07I as the queue tail and move the machine queue back to M12-07J. No
parity ledger rollback is required.

47
docs/status/M13-01A.md Normal file
View File

@@ -0,0 +1,47 @@
# M13-01A Status
status: done
task: inventory Text, Python Console, autorun, driver expression, handler, and add-on entry points
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 now has a machine-readable scripting entry inventory covering three Text
datablocks, Python Console operators, a module-autorun request, one driver expression, 39 handler
groups, and four add-on operators. The report records the entry source and default Web policy:
Text is metadata-only, while Console, autorun, driver expressions, handlers, and add-on operations
are `DENY`. This task only inventories entry points; it does not execute script text or open a
browser scripting route.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-script-entry-inventory.py -- tests/files/web/m13_script_entry_v1
tests/golden/M13-01A/entry-inventory.json` created a fixture with internal/external Text,
`use_module` autorun metadata, and a driver expression without executing user code.
- `node tools/web/check-script-entry-inventory.mjs` matched pinned runtime identity, policy and
semantic inventory, then regenerated the report in a fresh directory. Blender's `.blend` save
contains runtime save bytes that may differ between runs, so determinism is asserted on the
inventory and fixture byte length; the checked-in fixture hash remains bound in the manifest.
Output: `script-entry-inventory-ok texts=3 console=3 autorun=1 drivers=1 handlers=39 addonOps=4 deterministic=true next=M13-01B`.
- `python3 -m py_compile tools/web/generate-script-entry-inventory.py`, Node syntax check and
`git diff --check` passed.
## Artifact Hashes
- generator: `b72667493cfe9957161ef3fb9814180e0cfad5f8aaa1c60c9b6f132e915f3d6f`
- checker: `68478f15de4d63ed175e6b580761fd478b1fe9bccbfcaeee82218d13063dfa51`
- report: `e024995c53f01beaf725f281f74a6e5ec6018a53435da61a66f5e58a9e50973c`
- fixture: `bd6375d02908bfcc57ff7cdeec3f9827bfc4336d1e46e165c5fbbf4d04f19645`
- manifest: `d4a305033343ef5fb1ffc073617b59d9012f64b80ecb233e743fb0789a8b4893`
## Next Task
`M13-01B`: read script metadata on `.blend` open without executing arbitrary content.
## Rollback
Remove the generator, checker, fixture, report, manifest, and this status entry. Restore M12-07J
as the queue tail and move the machine queue back to M13-01A. No parity ledger rollback is required.

41
docs/status/M13-01B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-01B Status
status: done
task: read script metadata on `.blend` open without executing arbitrary content
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The real `script_scene.blend` open path reads all three Text sources, verifies source bytes and
SHA-256, preserves read-only metadata, and keeps every source `executionStatus=BLOCKED`. A
`use_module` autorun request remains `SCRIPT_POLICY_DENIED`; no Python Console, driver, handler,
or add-on code executes during open. This task does not add a script execution route.
## Evidence
- `node tools/web/check-script-open-metadata.mjs` ran the production WASM Main reader against the
real fixture and passed `script-open-metadata-ok blend=opened textMetadata=read sourceHash=verified execution=DENY autorun=DENY next=M13-01C`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5495 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/script-open-metadata.spec.ts` passed 1/1.
Chromium opened the fixture through `WebEngineClient`, saw three read-only blocked sources and
the explicit autorun denial.
- `npm --prefix web run typecheck` and `git diff --check` passed. The checker emits the deterministic
report `tests/golden/M13-01B/open-metadata-report.json` bound to the fixture hash.
## Artifact Hashes
- checker: `66396d5c9a5294021ae077bb162278c74d46de8b52ac8a444a5de4f6d84cfe05`
- e2e: `df6412cda113c830996e08c3d66a035dc1ac309e392f5946a762d11121b1926c`
- report: `f92470e57c048452134664f7f6208e50b6f087dbcbc33369e6b882c51813990c`
- fixture: `2b8fbdb05419e1e61d64777998d6a3b2562f726c17f548cd1852efc723e1a037`
## Next Task
`M13-01C`: default-deny autorun, register, install, and driver execution policy codes.
## Rollback
Remove the checker, report, manifest, e2e test, and this status entry. Restore M13-01A as the
queue tail and move the machine queue back to M13-01B. No parity ledger rollback is required.

39
docs/status/M13-01C.md Normal file
View File

@@ -0,0 +1,39 @@
# M13-01C Status
status: done
task: default-deny autorun, register, install, and driver execution policy codes
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting manifest parser and execution gate reject autorun/register/install/driver execution
requests with stable policy codes. The current bounded contract returns `SCRIPT_POLICY_DENIED` for
autorun, `DRIVER_EXECUTION_BLOCKED` for driver expressions, `ADDON_INSTALL_BLOCKED` for add-on
install/registration, and `SCRIPT_SANDBOX_UNAVAILABLE` even for a correctly signed script when no
isolated sandbox exists. No local eval or script execution is enabled.
## Evidence
- `node --test web/tests/unit/script-policy-codes.test.mjs` passed 1/1 and asserts all three denied
request codes plus the approved-key sandbox gate.
- `node tools/web/check-script-policy-codes.mjs` passed:
`script-policy-codes-ok autorun=SCRIPT_POLICY_DENIED driver=DRIVER_EXECUTION_BLOCKED addon=ADDON_INSTALL_BLOCKED sandbox=SCRIPT_SANDBOX_UNAVAILABLE next=M13-01D`.
- `npm --prefix web run typecheck`, Node syntax checks and `git diff --check` passed. The report and
manifest bind the transpiled production protocol source hashes.
## Artifact Hashes
- checker: `22588c2198bc8c425ab8e104e8559f0053654ae778aaea3783ec7d54822bc8f4`
- unit: `b5a52b8e707963545f1cd71f1a148fa9c9b9d1e4b4c5f51c87d33f8bf3777430`
- report: `956db548ee71688a4b89c9a993259d3e57129cd4abe9efd1b9397b3e30b1bf84`
## Next Task
`M13-01D`: ensure UI exposes no direct-eval bypass around the scripting policy.
## Rollback
Remove the checker, unit test, report, manifest and this status entry. Restore M13-01B as the queue
tail and move the machine queue back to M13-01C. No parity ledger rollback is required.

36
docs/status/M13-01D.md Normal file
View File

@@ -0,0 +1,36 @@
# M13-01D Status
status: done
task: UI direct-eval bypass gate
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production app, Workers, and protocol TypeScript sources contain no direct `eval(` or
`new Function(` bypass. The scan covers 176 non-vendor `.ts/.tsx` files and records the only
declared scripting policy entry points: `gateScriptExecution`, `gateServerScriptJob`, and
`parseScriptSourceInventory`. Execution remains `DENY`; this static gate does not claim a sandbox.
## Evidence
- `node tools/web/check-script-ui-bypass.mjs` passed:
`script-ui-bypass-ok scanned=176 violations=0 policyEntrypoints=3 report=8e234e128b90036548ab709b86b063de404250da2c5c0a6e25e28969b5cd5c73 next=M13-01E`.
- `git diff --check` passed. Vendor-generated Emscripten/Three.js sources are outside the scan;
no application or protocol source is allowed to introduce a direct eval constructor.
## Artifact Hashes
- checker: `f34cb64891c2b22bc3da353f6b864ba3e558d3c286cf716bcb778d9a542cb3d9`
- report: `6b050092088508ebd5d769d95a2e66f0cd4020c97f3407724a19b9707f51f6dd`
- manifest: `6b28688b3ebcce5629bcfc437d4ca903d0b1e053b32a796690ee4e021726c75b`
## Next Task
`M13-01E`: preserve Text data and unknown script sources through save/reopen.
## Rollback
Remove the checker, report, manifest, and this status entry. Restore M13-01C as the queue tail and
move the machine queue back to M13-01D. No parity ledger rollback is required.

41
docs/status/M13-01E.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-01E Status
status: done
task: preserve Text data and unknown script sources through save/reopen
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production WebEngine path opens `script_scene.blend`, saves it, starts a new engine Worker,
and reopens the saved bytes. All three Text sources compare exact by metadata and source SHA-256;
they remain read-only and `BLOCKED`, including the `use_module` autorun request. No source is
rewritten or executed. This does not claim arbitrary script execution or add-on support.
## Evidence
- `UPDATE_SCRIPT_SAVE_REOPEN_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5498
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/script-save-reopen.spec.ts` passed 1/1. A second run without report update on port 5497
also passed against the same deterministic report.
- `node tools/web/check-script-save-reopen.mjs` passed:
`script-save-reopen-ok sources=3 exact=true blocked=true savedBytes=490191 next=M13-01F`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- checker: `7fc9a370cb472636e2699565cb21a1450e3cc8a2c90ffdcdff96533b344afa7c`
- e2e: `481f78f3a0cce923b67ab14436cc23cbcd2ce66725de29dc874fea4fb5801227`
- report: `0f6869a8ec8342ed87649312d2872ab2c172cbf12d6be81bb0b770ebcbe8a398`
- manifest: `889a4e06f7e8c0ea55b3ca4baa9fe85dccbe97053e497a45e3d364ce2b70a7c6`
- fixture: `2b8fbdb05419e1e61d64777998d6a3b2562f726c17f548cd1852efc723e1a037`
## Next Task
`M13-01F`: malicious Text, driver, handler, and embedded-module fixtures.
## Rollback
Remove the checker, e2e test, report, manifest, and this status entry. Restore M13-01D as the
queue tail and move the machine queue back to M13-01E. No parity ledger rollback is required.

44
docs/status/M13-01F.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-01F Status
status: done
task: malicious Text, driver, handler, and embedded-module fixtures
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Pinned Blender 5.2 generated a malicious fixture containing four source bodies: OS command text,
driver import, handler subprocess, and an embedded `register()` module. Chromium opened the file
through the production Main reader and kept every source read-only/`BLOCKED`; the embedded module
returned `SCRIPT_POLICY_DENIED`. No filesystem marker or execution path is exposed by the test.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-malicious-script-fixture.py -- tests/files/web/m13_malicious_script_v1
tests/golden/M13-01F/malicious-report.json` generated four deterministic source hashes and one
`use_module` request.
- `node tools/web/check-malicious-script-fixture.mjs` passed:
`malicious-script-fixture-ok sources=4 module=1 execution=BLOCKED fixtureSha256=7b1921931afc5bb74a2b73e90b175017c583ea878cdbb66f131718b2d8cd23b5 next=M13-02A`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5499 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/malicious-script.spec.ts` passed 1/1.
- `git diff --check` passed.
## Artifact Hashes
- generator: `013285befeb59de21a887cefd377adf8cf53ff1c785b28a9c87d29f76f092731`
- checker: `36608da893ae59e2e03856a62866ea6e7c349ec4a63200f042b2329e5f61caa9`
- e2e: `98fbde6728ddf55cce5262522197a5b4db1dfce618e52259bf0b0c9e0e9165f2`
- report: `a628b73411d6f9a761f659ae28867ea9b0c0df30d47668353278b70d4b44180c`
- fixture: `7b1921931afc5bb74a2b73e90b175017c583ea878cdbb66f131718b2d8cd23b5`
- manifest: `9a0b7c4097b3755365a9fb92b4848e6ac2ddd36ee2c7e9df3cb8808ce247cf3d`
## Next Task
`M13-02A`: bounded script manifest limits.
## Rollback
Remove the generator, checker, fixture, report, manifest, e2e test, and this status entry. Restore
M13-01E as the queue tail and move the machine queue back to M13-01F. No parity ledger rollback is required.

49
docs/status/M13-02A.md Normal file
View File

@@ -0,0 +1,49 @@
# M13-02A Status
status: done
task: bounded script manifest limits
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting manifest parser now requires an explicit `sourceByteLength` and
`module=false` for every script. It limits script count, aggregate source bytes, dependency count,
permission count and per-field execution budgets; canonicalizes entry/dependency paths within the
project; and rejects duplicate dependencies, unsafe paths, module execution, unknown permissions
and all budget overflow. The parser remains fail-closed and does not execute script content.
## Evidence
- `node --test web/tests/unit/script-manifest-budgets.test.mjs` passed 4/4 bounded positive and
negative cases.
- `WEB_TEST_PORT=5513 npm --prefix web run test:script-manifest-budgets` passed unit 4/4 and the
production Chromium Worker test 1/1. The browser Worker returned the same canonical paths,
aggregate byte count and stable policy/budget errors as the Node protocol test.
- `node tools/web/check-script-manifest-budgets.mjs` passed:
`script-manifest-budgets-ok accepted=2 totalSourceBytes=256 blocked=6 deterministic=true next=M13-02B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`,
`npm --prefix web run build`, `npm --prefix web run test:scripting-isolation`, and
`git diff --check` passed. The existing isolation gate still reports approved-key
`SCRIPT_SANDBOX_UNAVAILABLE` and does not enable execution.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `8d8eae67fa6915f0337850e15247baf01f0abde0b3362fbb120f0b448f1a4cf5`
- checker: `b3457324d72ab233cd17a142ea19fac6a0d024dd95de7b8fb5d26810437fb0d2`
- unit: `6ce7847a0b745ba4081e4332d012e0b7f86e4906c71c95bdeda8c39977a630ee`
- e2e: `1ef4fd4caaeb1fa3d832fc8881823d5284755372575eab186c751f408dc9314c`
- report: `860672fe844b7969ca376d4b2708771189d1767efa819f7b97667d8a26438d3a`
- manifest: `7148e0387dadffdb55e94e80dc30cfd5cdd40ebe990d06378e90c376d36ebd51`
## Next Task
`M13-02B`: canonical serialization fixes the signature input.
## Rollback
Remove the M13-02A protocol fields, checker, unit/Chromium tests, worker, report, manifest and this
status entry. Restore M13-01F as the queue tail and move the machine queue back to M13-02A. No parity
ledger rollback is required.

52
docs/status/M13-02B.md Normal file
View File

@@ -0,0 +1,52 @@
# M13-02B Status
status: done
task: canonical script manifest serialization
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now exposes `canonicalizeScriptingManifest` and
`serializeScriptingManifest` as the single canonical signature-input path. Script, permission and
dependency arrays are sorted with locale-independent code-unit ordering; unknown fields are removed
by the parser; canonical JSON has sorted object keys and no whitespace; and security-relevant fields
such as source byte length, source hash, permissions, paths, budgets and policy flags remain in the
serialized input. Schema changes and source declaration mutations produce a different or rejected
input. No signature is accepted and no script is executed by this task.
## Evidence
- `node --test web/tests/unit/script-manifest-canonical.test.mjs` passed 2/2. It proves order
invariance, unknown-field dropping, security-field binding and schema rejection.
- `WEB_TEST_PORT=5514 npm --prefix web run test:script-manifest-canonical` passed unit 2/2 and
production Chromium Worker 1/1.
- `node tools/web/check-script-manifest-canonical.mjs` passed:
`script-manifest-canonical-ok equal=true bytes=1923 unknownDropped=true schemaMutation=blocked next=M13-02C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`, `npm --prefix web run build`,
`node tools/web/check-script-manifest-budgets.mjs`, `node tools/web/check-status-consistency.mjs`
and `git diff --check` passed. The M13-02A artifact manifest was refreshed to the current protocol
hash after this additive canonical API change, and its checker was rerun successfully; no prior
behavior or parity status was changed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `de27fdcd6d16e27a07806ac609f908edfdb7a93d653676174cdd5e06ffa394af`
- checker: `5ed344cab6428ae5538a450171ba40c73ff738666515492298e30aaed1394f56`
- unit: `33eae0f3ad2ae7243c9ce2835ab8e42186f65f574ab682099766f1d0f4c481f6`
- e2e: `5342301165ae82a01b46f5fed0cc0ec34b9813a6ecbc8032900d90b89628e064`
- report: `5f4bc0b098ea65de47f1255d30130376d74260e2b912bcd0e28354171fbd07df`
- parent manifest: `7148e0387dadffdb55e94e80dc30cfd5cdd40ebe990d06378e90c376d36ebd51`
- manifest: `605c656780a206a0d3b81d06b0294108b488a62d2b709e886884a2973c6cb091`
## Next Task
`M13-02C`: signer identity, key rotation, revocation and timestamp policy.
## Rollback
Remove the canonical serializer exports, checker, unit/Chromium tests, worker, report, manifest and
this status entry; restore M13-02A as the queue tail and move the machine queue back to M13-02B. No
parity ledger rollback is required.

51
docs/status/M13-02C.md Normal file
View File

@@ -0,0 +1,51 @@
# M13-02C Status
status: done
task: signer identity, key rotation, revocation and timestamp policy
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now has a versioned trust-policy schema for signer identity and key
lifecycles. It validates ED25519 public-key identity, publisher ownership, active/revoked status,
not-before/not-after windows, revocation timestamps, same-publisher rotation predecessors and
acyclic rotation chains. `maxClockSkewMs` binds policy timestamps to an explicit bounded window.
`resolveScriptSigner` only returns `ELIGIBLE` with `cryptographicVerification=REQUIRED`; revoked,
expired, not-yet-valid, missing and publisher-confused keys remain structured `BLOCKED` results.
This task does not verify signatures or enable script execution.
## Evidence
- `node --test web/tests/unit/script-trust-policy.test.mjs` passed 3/3. It covers valid active
rotation, revoked predecessor, invalid/cross-publisher/cyclic rotation, revocation metadata,
public-key format and timestamp failures.
- `WEB_TEST_PORT=5516 npm --prefix web run test:script-trust-policy` passed unit 3/3 and production
Chromium Worker 1/1.
- `node tools/web/check-script-trust-policy.mjs` passed:
`script-trust-policy-ok active=key:new revoked=REVOKED crossPublisher=SCRIPT_POLICY_DENIED policyExpired=POLICY_EXPIRED crypto=REQUIRED next=M13-02D`.
- `npm --prefix web run typecheck` passed; M13-02A and M13-02B checkers were rerun after the
additive protocol change and passed. No parity ledger or execution route changed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `c6e206b29e7cacc3e23e2ac12a3d523a9c0b16ff29759126dab13c8665547421`
- checker: `0e55ce20d142f2bcbc5ce9c6fb955ef2771d284dff636c79da3f59a33b8b0aeb`
- unit: `59ac77bcc1086e0a0e914cb77d647db5d34c7160202e7aad52948b7277769551`
- e2e: `614091bda15367090bc78a6f465fb10d02d0aa08775b5088699b12e2490034d2`
- report: `0f59f733920edbbe5cb799e5f50ff31d19e55ced98e7a890828f6337a237e4bd`
- unit: `aac3ff0a1c7ae27e35112614bedabc02bb248882ec9b0b52d65f9794d06830d8`
- parent manifest: `605c656780a206a0d3b81d06b0294108b488a62d2b709e886884a2973c6cb091`
- manifest: `89745daca88371335f4bd56982791266461082066c6c1345056fbc697bb7e6a2`
## Next Task
`M13-02D`: signature only approves declared content and source hash changes invalidate it.
## Rollback
Remove the trust-policy schema, parser/resolver, checker, unit/Chromium tests, worker, report,
manifest and this status entry; restore M13-02B as the queue tail and move the machine queue back to
M13-02C. No parity ledger rollback is required.

46
docs/status/M13-02D.md Normal file
View File

@@ -0,0 +1,46 @@
# M13-02D Status
status: done
task: signature verification binds declared content
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`verifyScriptManifestSignature` now verifies the canonical per-script manifest input with the
trusted ED25519 key. The input includes the declared source SHA-256 and all policy-relevant fields,
while excluding only the signature field itself. A source hash or signature mutation therefore
returns `SCRIPT_SIGNATURE_INVALID`; revoked or otherwise ineligible keys return
`SCRIPT_POLICY_DENIED`. Verification remains a policy gate and does not enable script execution.
## Evidence
- `node --test --test-name-pattern=M13-02D web/tests/unit/script-trust-policy.test.mjs` passed the
M13-02D case (1 passed, 3 unrelated cases skipped).
- `WEB_TEST_PORT=5520 npm --prefix web run test:script-signature` passed the focused Node case and
production Chromium Worker E2E (1/1).
- `node tools/web/check-script-signature.mjs` passed:
`script-signature-ok verified=SCRIPT_SIGNATURE_VERIFIED sourceHashChanged=SCRIPT_SIGNATURE_INVALID revoked=SCRIPT_POLICY_DENIED next=M13-02E`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`, `npm --prefix web run build` and
`git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `f4e8ff45d06efcfa9e634ef28e654241d70554ed05dfe9c3fecd9f6eef166ce0`
- checker: `2d6e7b403dd6d401eb1a41978016b40bd1fb86120464e09f185de4445c177fa4`
- unit: `aac3ff0a1c7ae27e35112614bedabc02bb248882ec9b0b52d65f9794d06830d8`
- e2e: `8a882fc8fa2c0c4e2eab3660810cec0f60d2f7475f62a1bb406fc3b2bdf60882`
- report: `957daf8e5899714cc5ce253b1f0fb2b258f1cc966238fff31e2626f8f56feb3a`
- manifest: `c6b79a77e4b7ffe5f4a9ba785a30305f9cf6e86caf89b38a4b303a86ab662a31`
## Next Task
`M13-02E`: permission default-minimization and unknown-permission blocking.
## Rollback
Remove the M13-02D checker, report, manifest, status entry and focused package command; restore
M13-02C as the queue tail and move the machine queue back to `M13-02D`. No parity ledger rollback
is required.

42
docs/status/M13-02E.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-02E Status
status: done
task: permission default-minimization and unknown-permission blocking
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`resolveScriptPermissions` now grants an empty set by default and only grants an explicitly
requested permission when it is already declared by the script manifest. Unknown, duplicate or
undeclared requests return `SCRIPT_POLICY_DENIED`; manifest declarations still reject unknown
permissions during parsing. This task adds no execution capability.
## Evidence
- `node --test web/tests/unit/script-permission-policy.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5521 npm --prefix web run test:script-permission-policy` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-permission-policy.mjs` passed:
`script-permission-policy-ok defaultGranted=0 declared=READ_MAIN escalation=SCRIPT_POLICY_DENIED unknown=SCRIPT_POLICY_DENIED next=M13-02F`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `5df074e676542475009a4980fecaf3fdde009d149de84b9ca146647fb6aa1c02`
- checker: `169ab096295e08c5a630ef09d814da6ce742efd7a7143ff9a17984b4ca20593a`
- unit: `43bb6796616f3f92d71b51ef2a119a4e263864121a03356764e4b9c9241c4043`
- e2e: `dc13412a44f277bbe68315da0d38a2c4aa520d7489c81e7c908f9768c0547b7e`
- report: `8dc41e75620ba5bcb08d0edc52c3994e4f4dbc37ad3633757634bf10fe97b252`
- manifest: `691376d3cd33d3cd339b7195034abaf89cc02fba7e740c40ff051c4496400eef`
## Next Task
`M13-02F`: replay, key-confusion, expiry and multi-signature negative cases.
## Rollback
Remove `resolveScriptPermissions`, the focused worker/unit/E2E/checker, report, manifest, status
entry and package command; restore M13-02D as the queue tail and move `nextTask` back to `M13-02E`.

42
docs/status/M13-02F.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-02F Status
status: done
task: signature replay, key-confusion and expiry negative cases
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The signature gate now has an independent negative-case matrix covering missing keys, expired and
not-yet-valid keys, publisher/key confusion, and a signature copied to a different script. Every
case remains fail-closed with `SCRIPT_POLICY_DENIED` or `SCRIPT_SIGNATURE_INVALID`; no execution
route is added. Canonical script ordering remains accepted when the script's own signature matches.
## Evidence
- `node --test web/tests/unit/script-signature-negative.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5522 npm --prefix web run test:script-signature-negative` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-signature-negative.mjs` passed:
`script-signature-negative-ok missing=SCRIPT_POLICY_DENIED expired=SCRIPT_POLICY_DENIED notYetValid=SCRIPT_POLICY_DENIED swapped=SCRIPT_SIGNATURE_INVALID next=M13-03A`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `49b289110a6533fcd1a29ad78be00792fd3c0d251c6027bae0440f5daba929a1`
- checker: `35f2e6727aef5e6ea2e2623e2effa6ea0356faaf66d417976db7f5bbe671a38c`
- unit: `8b9c8d63c97fce07299622b9ad261791a97bb91a6ed340e72c24c55e685978bd`
- e2e: `26c52ef67d6b1ea2994d92637826994e98e5234e042049f8d69a905f5cdb3309`
- report: `d23a2ae5613b2442ad79420aa344ebfe3767d10ac19b3ea30a62afcccd3a167c`
- manifest: `283673b21e6c9b89dc6ecb7007f3cecf28d53a84ec84f3f8b52373c055538a74`
## Next Task
`M13-03A`: sandbox capability scope with no DOM, host-worker, OPFS, IndexedDB or network access.
## Rollback
Remove the M13-02F negative-case worker, tests, checker, report, manifest, status entry and package
command; restore M13-02E as the queue tail and move `nextTask` back to `M13-02F`.

42
docs/status/M13-03A.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-03A Status
status: done
task: sandbox capability scope
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting protocol now defines a versioned all-deny sandbox scope. DOM, host-worker,
OPFS, IndexedDB and network capabilities must each be explicitly `false`; any enabled, missing or
unknown scope version is rejected with a stable policy/protocol error. This is a capability contract
only: script execution remains disabled and no sandbox implementation is claimed.
## Evidence
- `node --test web/tests/unit/script-sandbox-scope.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5523 npm --prefix web run test:script-sandbox-scope` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-scope.mjs` passed:
`script-sandbox-scope-ok dom=SCRIPT_POLICY_DENIED hostWorker=SCRIPT_POLICY_DENIED opfs=SCRIPT_POLICY_DENIED indexedDB=SCRIPT_POLICY_DENIED network=SCRIPT_POLICY_DENIED execution=DISABLED next=M13-03B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `27058fbb602791cbe6691fa14b3bc9c3d6cdea79641ba9c72fe18b6226d2a651`
- checker: `ad26ea3b078e480ba8f99cbf8dbd0d9b135c7605f4a3958d24845b7f5f8b0f43`
- unit: `a15da2e645d2d681c7e9ac1380f6b224d196d1d2e78d20f1bacad01e138753d4`
- e2e: `49930747e6663f79b61093706318b72e59388d79e3e1cc105bc1571693326667`
- report: `ba5784c751d5a347f38aa522ffcbed270d38fb474f0f10a2d06ea501d0234021`
- manifest: `76a7ce0fd3a38fb770c9cedccbd05ed566b931caa1782fdae898d3b66c3a20bf`
## Next Task
`M13-03B`: fixed CPU, wall-time, memory, message and output-byte budgets.
## Rollback
Remove the sandbox scope parser, focused worker/tests/checker, report, manifest, status entry and
package command; restore M13-02F as the queue tail and move `nextTask` back to `M13-03A`.

41
docs/status/M13-03B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-03B Status
status: done
task: sandbox CPU, wall, memory, message and output budgets
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now parses bounded CPU, wall-time, memory, message and output-byte budgets.
Each field has a fixed maximum and all overflow or schema drift returns `SCRIPT_BUDGET_EXCEEDED` or
`PROTOCOL_MISMATCH`. The budget is a contract only; execution remains disabled.
## Evidence
- `node --test web/tests/unit/script-sandbox-budget.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5524 npm --prefix web run test:script-sandbox-budget` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-budget.mjs` passed:
`script-sandbox-budget-ok cpu=SCRIPT_BUDGET_EXCEEDED wall=SCRIPT_BUDGET_EXCEEDED memory=SCRIPT_BUDGET_EXCEEDED message=SCRIPT_BUDGET_EXCEEDED output=SCRIPT_BUDGET_EXCEEDED execution=DISABLED next=M13-03C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `ed836a032b33f54154fdd36f9f6e99ee43ca1755ea0dd8326474a13300ec965e`
- checker: `ab10d1d32c20022c848be4b33e1be846168a9ca4cf22ac932ea000001e9e2391`
- unit: `caa40fc58a73aa4d433285c94009e5436a29fbcb6b4e18b74b27c49fd0b07490`
- e2e: `8be77fd55e76149bfe2e0e449d81a62707ebfa430514936808ec4805fc96e07c`
- report: `4355710e07e95cbb0f96a82fdefca3607f363d3aea9ba89c332e8a4708b7bed2`
- manifest: `b61978c22cdfffe81b812e2eea788d52326f9f0ebb4540e77f86dc9e19ff21dd`
## Next Task
`M13-03C`: host calls use explicit allowlist and structured parameters.
## Rollback
Remove the sandbox budget parser, focused worker/tests/checker, report, manifest, status entry and
package command; restore M13-03A as the queue tail and move `nextTask` back to `M13-03B`.

43
docs/status/M13-03C.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-03C Status
status: done
task: explicit host-call allowlist and structured parameters
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting protocol now accepts only five host-call names: `READ_MAIN`, `READ_ASSET`,
`WRITE_MAIN`, `WRITE_ASSET` and `SUBMIT_SERVER_JOB`. Each request has a version, request/script IDs,
permission binding and call-specific structured parameters. Unknown calls, permission confusion,
unknown fields, unsafe paths and malformed payloads fail closed. Parsed calls remain
`execution=DISABLED`; no host operation is invoked.
## Evidence
- `node --test web/tests/unit/script-host-call.test.mjs` passed 3/3.
- `WEB_TEST_PORT=5525 npm --prefix web run test:script-host-call` passed unit 3/3 and production
Chromium Worker E2E 1/1.
- `node tools/web/check-script-host-call.mjs` passed:
`script-host-call-ok accepted=5 blocked=4 structured=true execution=DISABLED next=M13-03D`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `b26a37f20e829172bb70fbe9b9e3a194923818127cccbe8bbc55f6d994be55e8`
- checker: `e90042f4eefd9e89da6d1cead87ca1cb9db9b3bd65ba8028593e093903577e2e`
- unit: `e7679cd902c75504204d528343e4fa6be316d1c56c02b2871a67637aa847a1ec`
- e2e: `7b17a7da440aee07895101efb8e1eb13bfbebbe54e955bde09299f6b33d6aaf9`
- report: `afb140a3aecff1de52c4363e7cd0ce476b0c9140ffdc016ec13a085049f6dd1a`
- manifest: `54318c45b11dd1707fecf78b0637257158102ea1dbb88d4d442e33b77df2cdbf`
## Next Task
`M13-03D`: sandbox crash/timeout terminates the job without changing Main revision.
## Rollback
Remove the host-call parser, focused worker/tests/checker, report, manifest, status entry and package
command; restore M13-03B as the queue tail and move `nextTask` back to `M13-03C`.

46
docs/status/M13-03D.md Normal file
View File

@@ -0,0 +1,46 @@
# M13-03D Status
status: done
task: sandbox crash/timeout isolation
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The sandbox job termination receipt now converts crash, wall-time timeout and cancellation into
stable fail-closed statuses. Every terminated receipt keeps `mainRevisionAfter` equal to
`mainRevisionBefore`, publishes no result, releases temporary bytes, and remains
`execution=DISABLED`; a result received after termination is rejected with
`SCRIPT_SANDBOX_LATE_RESULT`.
The Chromium test starts a production Worker that throws for the crash case and a production Worker
that would publish a delayed result for the timeout case. The host observes the crash, terminates the
timeout Worker before its delayed message, and confirms no late message arrives.
## Evidence
- `node --test web/tests/unit/script-sandbox-isolation.test.mjs` passed 3/3.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5532 npm --prefix web run test:script-sandbox-isolation` passed unit 3/3 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-isolation.mjs` passed:
`script-sandbox-isolation-ok crash=SCRIPT_SANDBOX_CRASHED timeout=SCRIPT_SANDBOX_TIMEOUT revisionUnchanged=true late=SCRIPT_SANDBOX_LATE_RESULT next=M13-03E`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `8c810ee7c8bd15d83ecfb4981068f947536bfe8c9e63b906861f42b8465722da`
- checker: `e5c0c3c7cd500c269ae43a1a9eb05589e82aad28199ab4f11ad1167b486f6937`
- unit: `47986f93638fdc18b817b03222484f4691dc294185040eaebac8e1f386bc1549`
- e2e: `2c16c42f09827a0c0100ef2cc6295ca6bc96933ed7475e08b1fa195d7940c141`
- report: `4af91cdb21101039b379136c7559b46df55f4f5ab5478c05c1c57cd6e1624d2a`
- manifest: `8066013f3d356ba438c36d1f1ea1cf692dbb4f60b086f552072e36b783a96d42`
## Next Task
`M13-03E`: cancellation after termination must not publish a late message or cache.
## Rollback
Remove the isolation Worker additions, focused tests/checker, report, manifest and this status entry;
restore M13-03C as the queue tail and move `nextTask` back to `M13-03D`.

45
docs/status/M13-03E.md Normal file
View File

@@ -0,0 +1,45 @@
# M13-03E Status
status: done
task: sandbox cancellation result gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Cancellation now has an explicit terminated-job receipt. The receipt preserves the Main revision,
publishes no result, releases temporary bytes and remains `execution=DISABLED`. The production
Chromium Worker schedules a late message containing a cache key; the host cancels and terminates it
before publication, then observes a bounded late window with zero messages and zero cache writes.
Late results supplied after cancellation are rejected with `SCRIPT_SANDBOX_LATE_RESULT`.
This task does not claim Worker/port/timer disposal or same-session recovery; those remain M13-03F/G.
## Evidence
- `node --test web/tests/unit/script-sandbox-cancellation.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5533 npm --prefix web run test:script-sandbox-cancellation` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-cancellation.mjs` passed:
`script-sandbox-cancellation-ok status=CANCELLED late=SCRIPT_SANDBOX_LATE_RESULT lateMessages=0 cacheWrites=0 next=M13-03F`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `0feb70c8c491cc24ebfe6c3e267b92522d616b6f260efcecfa57cf489d0742c0`
- checker: `b6fbe7102b7d0808673931c66797f8976e79b21bd4c32e429f21832c6090708e`
- unit: `374cc87f66bd42226b750e387663ef8c86bef92348fa7cbc6ed7f0027945204d`
- e2e: `b233d9cafa1f70798ec19d76ca936abb610681522264a12237f532eb98e09fca`
- package: `6499a70fc4a93c925053ddf5009c74d9c10754b443afc9d58e898fe20d7f1b05`
- report: `066d9f19716b8229f2cf7755ec3009a3edef942ebab5f70159bec7f2afbaf71f`
- manifest: `0cdf625e6bd3ed7aca43318a3b04353cb806c51cfa4cf3c5dae9a65a0eae2e69`
## Next Task
`M13-03F`: dispose Worker, MessagePort, timers, abort controllers and buffers to zero.
## Rollback
Remove the cancellation Worker, focused tests/checker, report, manifest, package command and this
status entry; restore M13-03D as the queue tail and move `nextTask` back to `M13-03E`.

44
docs/status/M13-03F.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-03F Status
status: done
task: sandbox resource disposal gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The sandbox Worker now owns an explicit disposal receipt. Both `MessagePort` endpoints, the timer,
`AbortController`, transferable buffer, pending request and cache reference are observed before
disposal and are all zero after the first dispose. A second dispose is accepted and reports
`idempotent=true`; the cleared timer produces no late message. Script execution remains
`DISABLED`, and this task does not claim same-session recovery or server isolation.
## Evidence
- `node --test web/tests/unit/script-sandbox-dispose.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5534 npm --prefix web run test:script-sandbox-dispose` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-dispose.mjs` passed:
`script-sandbox-dispose-ok ports=0 timers=0 abortControllers=0 buffers=0 pending=0 cacheReferences=0 idempotent=true next=M13-03G`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `f3d9f667c3809cfad0f52bc6028d93e36e25c4b639fb6081c9c933fbad0ebc0a`
- worker: `2a074b05d301c4083e60534eb9452aabf5d95aea0ab316fa657441ef4bcd5c96`
- checker: `6549bd10f588281d23c4bea705fd164252c9e3f44d8f4b93c893a2c410907135`
- unit: `6e00aa6286aae0eabc1345c04c7628dcc9acb32d51c1c27436a0e1b4c170b64c`
- e2e: `b240d92c90e0d81272cd9cb3c0eb4e7d77102ce2e49ad05c761f763d1812b18e`
- package: `0f06cd7ccdeed4213b6cb956aecf94e60dceff811ad8c3a2e239397685cfc1bf`
- report: `2dbd3e79939b500c0fc83216c51f258b88ead42a667ed1a6da755e893d7f73c6`
- manifest: `96abc7c7613ef4c18c64b84ffb8420c39369f9e4733bd1fa4d7d9ee9e53d6f89`
## Next Task
`M13-03G`: recover a small script in the same session with a new Worker generation while keeping
the Main revision/source hash stable and extending the audit hash chain.
## Rollback
Remove the dispose protocol, Worker, focused tests/checker, report, manifest, package command and
this status entry; restore M13-03E as the queue tail and move `nextTask` back to `M13-03F`.

43
docs/status/M13-03G.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-03G Status
status: done
task: same-session sandbox recovery and audit continuity
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
A denied script request can be resumed in the same session after a Worker generation change from 4
to 5. The Main revision remains 11, and the source and canonical manifest hashes remain stable.
Two default-deny audit entries use distinct request IDs, sequence 1/2, and a continuous
`previousEntrySha256 -> entrySha256` chain. Replay and source-hash tampering are rejected. This task
does not enable Python execution or claim Blender server isolation.
## Evidence
- `node --test web/tests/unit/script-sandbox-recovery.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5535 npm --prefix web run test:script-sandbox-recovery` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-recovery.mjs` passed:
`script-sandbox-recovery-ok generation=4->5 revision=11 sourceStable=true manifestStable=true sequence=1,2 chain=true replay=SCRIPT_MANIFEST_INVALID tamper=SCRIPT_MANIFEST_INVALID next=M13-04A`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `8034faded657d49e1376ea42051bc302a090b485024a9ff3781e46aa82638b64`
- worker: `7b02331c375d4fb7dbadadd179f0ab9a0e336c8b95fabb071c06e67f3e7b3fe4`
- checker: `612015a3fca44bae0f0b78e622f044a5297ed8aa3a0efc774a40f0d47ddbdc9e`
- unit: `69a2d34e38d591043ff62b2d305bd9aae684ecebd9ecba718580d77318931226`
- e2e: `73176e513f115ba917be74f62a5deb8fe2918fafa8a84c9294e80d2a86b8f1ed`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `9057b3f49c3bb15cf53d638ada4bd2743949d3914173cd3799414489d584111d`
- manifest: `5cd365eeebbd6a7f56f380af103b66f2beb11eb49cb6db6adb49972b572cf2ec`
## Next Task
`M13-04A`: create an unpredictable one-shot directory for each real Blender server job.
## Rollback
Remove the recovery protocol, Worker, focused tests/checker, report, manifest, package command and
this status entry; restore M13-03F as the queue tail and move `nextTask` back to `M13-03G`.

44
docs/status/M13-04A.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-04A Status
status: done
task: server job one-shot directory
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The server-side job allocator creates an unpredictable `0700` directory below a configured absolute
root for each request. Directory names do not contain the request ID, two concurrent jobs receive
distinct directories, and successful or failed cleanup removes the directory exactly once. Repeated
cleanup is idempotent. This task does not claim read-only source mounts, process limits or Blender
execution.
Browser E2E is not applicable: this is a Node server filesystem boundary. The checker uses real
temporary directories and `fs.stat`/`fs.rm` calls.
## Evidence
- `node --test web/tests/unit/server-job-isolation.test.mjs` passed 2/2.
- `npm --prefix web run test:server-job-directory` passed unit 2/2 and the independent checker.
- `node tools/web/check-server-job-isolation.mjs` passed:
`server-job-directory-ok allocated=2 cleaned=2 unique=1 requestIdsHidden=1 mode=0700 residual=0 idempotent=1 next=M13-04B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `3aa5678a2c2769e4db5bb8f5c755b97e23045c4106e5636459748ab9b41929cd`
- checker: `b8d0e741144f742946246370bd35820d806686fb00dc0b040c925cf16f2179da`
- unit: `b1ac3324332180f7b3522f135520e7b5dace334dc461c92f2bce48fbcba2e147`
- package: `0c2633da831e7ca10cf74797650353b6dfb1507ed5957688d34bc97f9a6dd193`
- report: `07ed66fe0b2e1f1bbdba1cfb1089b052a5961d38f761bfcf79d8362980d2d502`
- manifest: `fd2407a7b9fefe67e2d77ed844e6c2ca17cdc4a746857a5825a38ff02ab664e3`
## Next Task
`M13-04B`: source read-only mount and independent writable output directory.
## Rollback
Remove the directory allocator, focused tests/checker, report, manifest, package command and this
status entry; restore M13-03G as the queue tail and move `nextTask` back to `M13-04A`.

41
docs/status/M13-04B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-04B Status
status: done
task: server source read-only and output isolation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Each allocated server job now gets a `source/` directory and a separate `output/` directory. The
source directory is `0555` and the staged `.blend` is `0444`; a source overwrite fails with
`EACCES`. The output directory is `0700` and accepts result bytes. Cleanup temporarily restores
the source directory permission so the one-shot job directory can be removed without residue.
This task does not claim OS/container CPU, memory or process limits.
## Evidence
- `node --test web/tests/unit/server-job-isolation.test.mjs` passed 3/3.
- `npm --prefix web run test:server-job-workspace` passed unit 3/3 and the independent checker.
- `node tools/web/check-server-job-workspace.mjs` passed:
`server-job-workspace-ok sourceDir=0555 sourceFile=0444 sourceWrite=EACCES outputDir=0700 outputWrite=OK distinct=1 residual=0 next=M13-04C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `3aa5678a2c2769e4db5bb8f5c755b97e23045c4106e5636459748ab9b41929cd`
- checker: `9490c2eeb9980073fc1fe77fdba1fb6e4ef528de8eb666d9eaf1fb582ba658c2`
- unit: `b1ac3324332180f7b3522f135520e7b5dace334dc461c92f2bce48fbcba2e147`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `650a643cc92617d068cb96d8bd4303429ef169ea89e3d4cb63e3ce5e2428e6d2`
- manifest: `9bc906b9e4c9751229f03271ef45a5925122b89b15bfe775591775f121ce1a4c`
## Next Task
`M13-04C`: enforce CPU, memory, process, file, wall-time and output budgets at the server boundary.
## Rollback
Remove the workspace protocol additions, focused tests/checker, report, manifest, package command and
this status entry; restore M13-04A as the queue tail and move `nextTask` back to `M13-04B`.

43
docs/status/M13-04C.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-04C Status
status: done
task: server job resource budget gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server jobs now have fixed CPU, memory, process, file, wall-time and output-byte limits. Budget
parsing rejects undeclared fields and out-of-range values. A usage receipt is marked
`enforced=true` only when every measured value is within its corresponding limit; each of the six
over-limit cases returns `SERVER_JOB_BUDGET_EXCEEDED` and remains `execution=DISABLED`.
This is the resource contract and usage gate. OS/container enforcement is proven by the later real
process task and is not claimed here.
## Evidence
- `node --test web/tests/unit/server-job-resource-budget.test.mjs` passed 2/2.
- `npm --prefix web run test:server-job-resource-budget` passed unit 2/2 and the independent checker.
- `node tools/web/check-server-job-resource-budget.mjs` passed:
`server-job-budget-ok cpu=bounded memory=bounded process=bounded files=bounded wall=bounded output=bounded overages=6 execution=DISABLED next=M13-04D`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `9746f0aef9dd76411320792dee1213c03755a3c03a87bbc4cbf88d4324c728d6`
- checker: `5599f4e25fc3ceca18e04be322450a4dc5bb6ce9c72c3abe9f1afc9c81851ff8`
- unit: `05212b2aa639f4c37e37e1cac0597d9b367a1280e519240f073762394914dc63`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `76ba684966bf7e680b0ebfc630ae9e080f04dd6daa6dd744bbb22dcff43f8eb1`
- manifest: `d00fff709b57909ec418ff0e476dca97281fc39456f674c63b51248377fc6ab2`
## Next Task
`M13-04D`: default-deny network policy with explicit declared-origin admission.
## Rollback
Remove the resource budget protocol, focused tests/checker, report, manifest, package command and
this status entry; restore M13-04B as the queue tail and move `nextTask` back to `M13-04C`.

24
docs/status/M13-04D.md Normal file
View File

@@ -0,0 +1,24 @@
# M13-04D Status
status: done
task: server job network policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Server jobs default to `DENY`. Only an explicitly declared canonical HTTPS or loopback origin is
`ALLOWED`; missing, undeclared, credential-bearing, path-bearing, public HTTP and invalid origins
return `SERVER_NETWORK_DENIED` or `SERVER_NETWORK_POLICY_INVALID`. Execution remains `DISABLED`.
Evidence: `node --test web/tests/unit/server-job-network-policy.test.mjs` 2/2;
`npm --prefix web run test:server-job-network-policy` passed; checker output
`server-job-network-ok default=DENY declaredOrigin=ALLOWED missing=SERVER_NETWORK_DENIED undeclared=SERVER_NETWORK_DENIED execution=DISABLED next=M13-04E`;
typecheck, lint and `git diff --check` passed.
Artifact hashes: protocol `0dc3698383fbfa511bebfeca41504c7c04a8302d47168cfae94f01f2a11a316c`,
checker `6f3e9cd9f988313863345f392036e6dbb522102c969197034800f419e497ad92`, unit
`c0ba10ccd2fb6ec8878a1b4a54bc6a12e49d35818566e0d55ef307779e8c8b77`, report
`37bcba2666e8c76c2e07d23e285737004affbb0372ec6dd84bb6802dba551527`, manifest
`11ce246597e3321b346ed4fed00edba22708d97250163d332d7ba8a003d8849a`.
Next task: `M13-04E`, fixed Blender background/factory-startup runtime identity.

22
docs/status/M13-04E.md Normal file
View File

@@ -0,0 +1,22 @@
# M13-04E Status
status: done
task: pinned Blender server startup
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Pinned Blender 5.2.0 LTS now passes a real server preflight using only `--background`,
`--factory-startup`, the fixed `tools/web/server-job-startup.py`, and a fixed business argument.
The structured receipt confirms background mode, runtime version and argv. Execution remains
`DISABLED`; this task does not claim result publication.
Evidence: `node tools/web/check-server-job-startup.mjs` output
`server-job-startup-ok blender=5.2 background=1 factory=1 userPrefs=0 fixedScript=1 execution=DISABLED next=M13-04F`;
typecheck, lint and `git diff --check` passed. Artifact hashes: startup
`c8c5b5a7a7880d4df9477a94a98e54e328baf582ade649807067f988484e1f12`, checker
`66b2e25efe0e7455348e8f488cd0f6ebef07f916fcf6541680e7d18e4f69ab10`, report
`c67d2972e584782d03479dbdb36dae0976074978f4ce9a48e41e7ad5aea66089`, manifest
`a24ea87bcf305bc15d8ae70b2abd03aa16ffbd6b127d5e9da9da23617d7201cc`.
Next task: `M13-04F`, bounded and redacted stdout/stderr.

40
docs/status/M13-04F.md Normal file
View File

@@ -0,0 +1,40 @@
# M13-04F Status
status: done
task: bounded and redacted server stdout/stderr
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server job output is normalized through a production receipt before publication. Credentials, bearer/basic
tokens, secret headers and Unix/Windows/file URL paths are replaced; UTF-8 output is truncated at fixed
stdout/stderr byte budgets with an explicit marker. The receipt records original/emitted bytes, redaction
count and truncation state. Server execution remains `DISABLED`; process cancellation and result publication
are separate tasks.
## Evidence
- `npm --prefix web run test:server-job-output-redaction` passed 3/3 unit tests and the independent checker.
- Checker output: `server-job-output-ok stdoutTruncated=1 stderrTruncated=1 redactions=6 totalBounded=1 execution=DISABLED next=M13-04G`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `a24ea87bcf305bc15d8ae70b2abd03aa16ffbd6b127d5e9da9da23617d7201cc`
- protocol: `5a58e7080324b399905c6a20a313225153ba94c75a55d21c4bbdd957ae4a2462`
- checker: `5c2db9d3313484bb68ac65822828467b3f99cb03e8374935757cfcb4b4ed908d`
- unit: `4ae6266bce22f84e73113b93a590a0c32d9452e748003af251a602024d0c6db5`
- package: `52781eb2650133b43271889a22ce38023e611641da15411d31698c6cfc0ce19c`
- report: `cb6e3ed8d6cc0a69b333b6bff3199593bdfbae14fa7fa700dcb12e9e9cea519a`
- manifest: `b5b4b26183dc48ebcae009e49999010d9b60d512f5daa4674a0aff0577d6602c`
## Next Task
`M13-04G`: cancel Blender process tree and clean the one-shot directory.
## Rollback
Remove the output receipt protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04E` as the queue tail.

38
docs/status/M13-04G.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04G Status
status: done
task: server process-tree cancellation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Real server jobs now run in a detached process group on POSIX and are cancelled as a tree. The cancellation
path sends SIGTERM to the group, escalates to SIGKILL after the grace window, waits for the group to exit,
and performs one idempotent job-directory cleanup. Windows uses `taskkill /T /F`. The receipt reports the
actual signal path, cleanup count and orphan count. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-cancellation` passed 2/2 real-process unit tests and the checker.
- Checker output: `server-job-cancel-ok state=CANCELLED tree=SIGTERM_GROUP cleanup=1 orphan=0 residual=0 execution=DISABLED next=M13-04H`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `b5b4b26183dc48ebcae009e49999010d9b60d512f5daa4674a0aff0577d6602c`
- protocol: `74fbbac806f34904bc9cb8e40eaf386cb60d44d978973950f1809262d311ec95`
- checker: `751ecafc642595d0de69b618e223cbff49d414f2958fc371371e4a668d66a8cc`
- unit: `39ac445ff51a9bfe249363204cf2edca906b16bf67ab1f8321166b440eba8629`
- package: `ca092a9a1d48ac41dc20f978bb26c8268adde9f7602a06459c7df8c2cb2d4cc7`
- report: `61f5c3ad315f94bac48e58627fcc46015c173dd9f303d5914acb8dbbe93caa97`
## Next Task
`M13-04H`: map timeout/OOM/non-zero exit/signal to stable error codes.
## Rollback
Remove the process control protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04F` as the queue tail.

38
docs/status/M13-04H.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04H Status
status: done
task: stable server process fault codes
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Timeout, bounded-memory OOM, signal termination and non-zero exit are converted to stable server error
codes. Classification precedence is cancellation, timeout, OOM, signal, then non-zero exit. Failed receipts
keep the base/current revision equal, set `publish=false`, and expose no internal process details. Execution
remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-fault-codes` passed 3/3 unit tests and the checker.
- Checker output: `server-job-faults-ok timeout=SERVER_JOB_TIMEOUT oom=SERVER_JOB_OOM signal=SERVER_JOB_SIGNAL exit=SERVER_JOB_EXIT_FAILED revisionPreserved=1 publish=0 execution=DISABLED next=M13-04I`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `7103a25ec7eb4a1c7f0d9f7acfb5ed30da32c87d512d6f9d53e081db275f7b89`
- protocol: `858360b4468a7b6cf796fc83a1627ba18626b61a0799f83531de996ea374519b`
- checker: `cb67246ef3df111525ca5e14af0546154ea2beee930b9840ad4ac7e2ebbb91ec`
- unit: `3551e28d78e5069c3d97eabcacac824bf142f54fdcb3ad4904668909af1cc545`
- package: `77bae66fd3885e36d2ead6f261754724144e5f51fafc5ccad9863dfc8e5ab548`
- report: `01999232f926496909fc9ef072e19aadb688822d3f9d7e03b42871ac5d54a0f6`
## Next Task
`M13-04I`: verify source/settings/build/output hashes before OPFS commit.
## Rollback
Remove the fault classifier, unit/checker, report, manifest, package command and this status entry; restore
`M13-04G` as the queue tail.

38
docs/status/M13-04I.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04I Status
status: done
task: server result hash binding and atomic OPFS handoff
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server output publication requires request identity plus source, settings and Blender build SHA-256 values
to match the expected request. Output bytes are staged, read back, atomically renamed to the request result
path, and read back again before a committed receipt is returned. Tampered output, identity drift, partial
stage and quota failures remain unpublished. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-result-binding` passed 2/2 unit tests and the checker.
- Checker output: `server-job-result-ok source=bound settings=bound build=bound output=verified tamper=blocked quota=blocked atomic=1 execution=DISABLED next=M13-04J`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `ba530ddff6e6fdd84057444ce757fad05a30d825a5915abebe2d5910a689af7f`
- protocol: `ecf3bddef53e2766dcc055ec027b04c14e3d884132c7fdea476663617364ad86`
- checker: `b0fbffd2937ab20e72d337bb5ff63ccf188ccf8a939d8ccc8b4878d80c9a4a19`
- unit: `c5538798aa6263b8a1c20270a019f8b4fb8b176b141a6411b72aad21a457bfd0`
- package: `5d269d4e5ff4385d919c0ee33f996dcb814e3e415da25dbf3b4dbdc3312fbe24`
- report: `ec63faeba35a641a22c3b3a69757bd37e8e9acaa1dda11a64faf7bed80439784`
## Next Task
`M13-04J`: idempotent request retry and conflicting-result isolation.
## Rollback
Remove the result-binding protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04H` as the queue tail.

38
docs/status/M13-04J.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04J Status
status: done
task: server request idempotency and conflict isolation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`projectId/requestId` is now an idempotency key. An exact retry verifies and reuses the existing result;
different output or source/settings/build identity returns a stable conflict and cannot overwrite the bound
result. Different requests use separate result and receipt files. Concurrent duplicate requests share one
in-flight submission and resolve as one commit plus one reuse. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-idempotency` passed 3/3 unit tests and the checker.
- Checker output: `server-job-idempotency-ok first=COMMITTED retry=REUSED conflict=BLOCKED isolated=1 concurrent=REUSED execution=DISABLED next=M13-05A`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `f9658954d3dbd0cd1edd696c10f6a1b880bb3288c91a39a47ca84c4496046a97`
- protocol: `15eca7550964c9985e26a22a7900d3f3aa69fdef35fe5962b48a8f55ebba5863`
- checker: `02247ffda07c095373642a7fa22268bb9f5ac181d41571f7fff685812976d3c4`
- unit: `6ee08e67cd8493e856f67309bd6562316eca42ef52dd4a9aad3a15efdc4b6b41`
- package: `5b47e94cf828fc9d3021019eed9922eb67815aba5416266d8c967c7cb5bd96ba`
- report: `31f95a8cc1c4792303986b8b5987ab02fc11a77ab25fd76b31c02d1ed1b104d1`
## Next Task
`M13-05A`: CSP denies inline script, eval, data script and undeclared origins.
## Rollback
Remove the idempotency protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04I` as the queue tail.

45
docs/status/M13-05A.md Normal file
View File

@@ -0,0 +1,45 @@
# M13-05A Status
status: done
task: CSP default-deny policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deployment contract now requires one CSP on every response: same-origin default/script/worker/connect
sources, no inline or eval execution, no data/blob script source, and object/base/frame embedding denied.
The Vite source, entry HTML, production source tree and built JS/HTML are scanned for dynamic code and data
scripts. The deployment HTTP checker verifies the policy on normal, missing and entry responses. Resource-
specific Worker/WASM/font/image/media rules remain in M13-05B.
## Evidence
- `npm --prefix web run test:csp-policy` passed.
- `node tools/web/check-deployment-contract.mjs` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed; built output was scanned by the CSP checker.
- Checker output: `csp-policy-ok inline=DENY eval=DENY dataScript=DENY undeclaredConnect=DENY responses=3 execution=DISABLED next=M13-05B`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `d230ae49dbf38cd9e95e7379a1a49332e478d3d23b3638730d2ec6167204c368`
- contract: `3f2b0b10c5a5698be2adda61af80cfb9cb9291fb9797994bfa66a77b7b511eeb`
- deployment server: `a5734ce9760f65cf5bade8cc209454d39fa963ad7dfaf20653728a9d7a57b04c`
- contract checker: `5e2d80f5c1377420f4779291fa73c206741ed415e751e79ce5edae7ba039febf`
- CSP checker: `f97ab074da860e3f8489e520c8bb5932f858409136ef25cca56247bb1310340d`
- index: `16b7691b191127f84c5143e23aecdfc203dc9e279d34cb270b37631fcbd5f856`
- Vite: `fd160c685ed780738e2b37ce9a32e5d4718e11a2875e12d86ddad310213abaf3`
- package: `5b47e94cf828fc9d3021019eed9922eb67815aba5416266d8c967c7cb5bd96ba`
- report: `9c7c64bb021161a1165a7c089ccf3f4897877635914260f6f0b0da119a5036fb`
## Next Task
`M13-05B`: verify resource-specific CSP for Worker, WASM, font, image and media paths.
## Rollback
Remove the CSP contract/checker changes, report, manifest, package command and this status entry; restore
`M13-04J` as the queue tail.

31
docs/status/M13-05B.md Normal file
View File

@@ -0,0 +1,31 @@
# M13-05B Status
status: done
task: resource-specific CSP policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deployment contract now separates same-origin policy for Worker, WASM, font, image and media
resources. Chromium loaded same-origin Worker, WASM, image and media resources, and rejected data-image,
blob-Worker and cross-origin connect attempts. WASM uses only the explicit `wasm-unsafe-eval` source
expression; JavaScript `eval` remains denied. Resource responses and 404 responses carry the same policy.
## Evidence
- `npm --prefix web run test:csp-resource-policy` passed the HTTP resource matrix and Chromium browser gate.
- `node tools/web/check-deployment-contract.mjs` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
## Next Task
`M13-05C`: production/build/test dependency inventories.
## Rollback
Remove the resource-specific CSP/MIME changes, checker, report, manifest, package command and this status;
restore `M13-05A` as the queue tail.

27
docs/status/M13-05C.md Normal file
View File

@@ -0,0 +1,27 @@
# M13-05C Status
status: done
task: production/build/test dependency inventories
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Evidence
`web/package.json` and `web/package-lock.json` are parsed as the only dependency sources. Deterministic
transitive closures contain production=3, build=135 and test=6 packages; every package is classified and
records its path, version, resolved URL and lockfile integrity. A fresh regeneration is byte-identical.
- `npm --prefix web run test:dependency-inventory` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
## Next Task
`M13-05D`: severity gates and documented dependency exceptions.
## Rollback
Remove the inventory generator/checker, report, manifest, package command and this status; restore
`M13-05B` as the queue tail.

18
docs/status/M13-05D.md Normal file
View File

@@ -0,0 +1,18 @@
# M13-05D Status
status: done
task: dependency severity gates and exceptions
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The severity policy is machine-readable: BLOCKER/HIGH block, MEDIUM requires review and LOW is tracked.
Exceptions require a non-empty owner, non-expired ISO date, reason and alternative control. Production
inventory has zero findings and zero exceptions, while four negative/positive exception cases are checked.
- `npm --prefix web run test:dependency-severity-policy` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
Next task: `M13-05E`, SBOM/license/source-offer binding.

13
docs/status/M13-05E.md Normal file
View File

@@ -0,0 +1,13 @@
# M13-05E Status
status: done
task: SBOM/license/source-offer and archive binding
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The supply-chain checker binds SPDX 2.3 to the lockfile and notices hashes, verifies the corresponding
source offer and source archive contents, checks top-level archive SHA256SUMS, and records the current
commit. Binary/source archive validators also pass independently; script execution remains disabled.
Next task: `M13-05F`, malicious input matrix.

14
docs/status/M13-05F.md Normal file
View File

@@ -0,0 +1,14 @@
# M13-05F Status
status: done
task: malicious input matrix
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The production blend loader rejected five malformed blend cases. Existing production protocol tests
rejected malformed image previews, fonts, media cache manifests, shader node graphs, script manifests and
GLB inputs; archive metadata rejected six ZIP/TAR traversal, link, duplicate and bomb cases without
extraction. All matrix categories are stable reject paths and execution remains disabled.
Next task: `M13-05G`, fuzz crash minimization and regression capture.

37
docs/status/M13-05G.md Normal file
View File

@@ -0,0 +1,37 @@
# M13-05G Status
status: done
task: fuzz crash minimization and regression capture
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deterministic runner replays 16 mutations in each of the blend, image, font, node-graph and script
manifest domains using seed `1511506142`. Every case returns one structured `ACCEPTED` or `REJECTED`
receipt; a non-zero runner exit first writes a replayable corpus sample. This run completed 80 cases with
zero crashes and an empty minimized corpus. Script execution remains disabled.
## Evidence
- `npm --prefix web run test:fuzz-regression` passed.
- Checker output: `fuzz-regression-ok seed=1511506142 cases=80 crashes=0 corpus=0 execution=DISABLED next=M13-05H`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `34043df0515f4b422a2b265d38978dd3c7f21acd12753c99f9a50f9b23f8bd60`
- runner: `a4d5d1b743b454705b1c3a257f1f36d1fea8abd77442e11fb1fec9e2905a3f79`
- checker: `55c8fa3776b22eb3f2e2ffd1629f0092384df30ef3913699a1ba93b283d641d8`
- package: `1feb509789d7f06019390bd86197bb9851cd520fd9fe310d1e29bfc3d2ef3f18`
- report: `5eb4a5469732697be7910fded3ce34cf2898735f767d94c1abbe0dd264bcc0d9`
## Next Task
`M13-05H`: fuzz corpus replay and release-boundary exclusion.
## Rollback
Remove the fuzz runner/checker, report, manifest, package command and this status entry; restore
`M13-05F` as the queue tail.

30
docs/status/M13-05H.md Normal file
View File

@@ -0,0 +1,30 @@
# M13-05H Status
status: done
task: script audit record integrity
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting audit protocol now has an independent integrity gate. Two default-deny audit
records are validated with strictly increasing ISO timestamps, contiguous sequence numbers, unique request
IDs, canonical entry digests and a continuous previous-entry hash chain. Replay, time reversal, sequence
mutation, entry digest mutation and chain mutation all return `SCRIPT_MANIFEST_INVALID`; execution remains
disabled.
## Evidence
- `npm --prefix web run test:script-audit-integrity` passed 2 unit tests and the checker.
- Checker output: `script-audit-integrity-ok entries=2 sequence=1,2 requestIds=unique time=ordered chain=true replay=SCRIPT_MANIFEST_INVALID tamper=3 execution=DISABLED next=M14-01A`.
- `git diff --check` passed.
## Next Task
`M14-01A`: freeze the current Chromium release, engine and archive hashes.
## Rollback
Remove the audit integrity checker/unit, report, manifest, package command and this status entry; restore
`M13-05G` as the queue tail.

32
docs/status/M14-01A.md Normal file
View File

@@ -0,0 +1,32 @@
# M14-01A Status
status: done
task: Chromium, engine and archive identity freeze
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The Chromium baseline is frozen at `150.0.7871.128`. The checker resolves and hashes the actual browser
executable, validates every single/pthread engine resource against `engine-manifest.json`, and validates
both release archives against the regenerated `RC_MANIFEST.json` and `SHA256SUMS.txt`. Execution remains
disabled.
## Evidence
- `npm --prefix web run release:offline` passed deterministic binary/source rebuild twice.
- `node tools/web/create-rc-manifest.mjs && node tools/web/check-rc-manifest.mjs` passed.
- `npm --prefix web run test:chromium-freeze` passed with browser `150.0.7871.128`, two engine variants,
and two archive bindings.
- `npm --prefix web run typecheck` passed; execution remains `DISABLED`.
- `git diff --check` passed.
## Next Task
`M14-01B`: Firefox capability probe using the frozen field set.
## Rollback
Remove the Chromium freeze checker, report, manifest, package command and this status entry; restore
`M13-05H` as the queue tail.

21
docs/status/M14-01B.md Normal file
View File

@@ -0,0 +1,21 @@
# M14-01B Status
status: done
task: Firefox capability probe
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Firefox `153.0` was probed against the rebuilt production assets with COOP/COEP isolation. WASM, Worker,
OPFS, IndexedDB, WebGL2, OffscreenCanvas and cross-origin isolation passed. WebGPU is explicitly
`BLOCKED/WEBGPU_UNAVAILABLE`; it does not change the Chromium-only release claim.
## Evidence
- `npm --prefix web run test:firefox-capability` passed.
- Checker output: `firefox-capability-ok version=153.0 wasm=PASS,worker=PASS,opfs=PASS,indexedDB=PASS,webgl2=PASS,webgpu=BLOCKED,offscreen=PASS,isolation=PASS execution=DISABLED next=M14-01C`.
- `git diff --check` passed.
## Next Task
`M14-01C`: WebKit capability probe with the same fields.

21
docs/status/M14-01C.md Normal file
View File

@@ -0,0 +1,21 @@
# M14-01C Status
status: done
task: WebKit capability probe
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
WebKit `26.5` was probed against the rebuilt production assets with COOP/COEP isolation. WASM, Worker,
IndexedDB, WebGL2, OffscreenCanvas and isolation passed. OPFS and WebGPU are explicitly blocked; the
result does not change the Chromium-only release claim.
## Evidence
- `npm --prefix web run test:webkit-capability` passed.
- Checker output: `webkit-capability-ok version=26.5 wasm=PASS,worker=PASS,opfs=BLOCKED,indexedDB=PASS,webgl2=PASS,webgpu=BLOCKED,offscreen=PASS,isolation=PASS execution=DISABLED next=M14-01D`.
- `git diff --check` passed.
## Next Task
`M14-01D`: probe identity and GPU/OS adapter recording.

33
docs/status/M14-01D.md Normal file
View File

@@ -0,0 +1,33 @@
# M14-01D Status
status: done
task: probe identity and GPU/OS adapter recording
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production Chromium probe records observed browser identity, OS kernel/runtime identity,
hardware concurrency, WebGL2 vendor/renderer/version, WebGPU adapter identity, and cross-origin
isolation. WebGPU is recorded as `BLOCKED/WEBGPU_ADAPTER_UNAVAILABLE` in this headless environment;
the result does not claim WebGPU support. The report is bound to the exact worker/WASM asset hashes
used by the probe and carries a canonical identity SHA-256.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:probe-identity` passed twice (one report-generation run and one frozen
report verification run).
- Checker output: `probe-identity-ok version=151.0.7922.34 os=linux/x64 webgl2=PASS,webgpu=BLOCKED identity=3c6f898e1b6ffd39862505b8e7dde8fd29369204e1670a013859f74ccaf1c1eb execution=DISABLED next=M14-01E`.
- `git diff --check` passed.
## Next Task
`M14-01E`: Chromium WebGPU fail-closed boundary. Firefox and WebKit are excluded by the project
Chromium-only iron rule.
## Rollback
Remove the probe checker, report, manifest, package command and this status/task entry; keep
`M14-01C` as the queue tail.

29
docs/status/M14-01E.md Normal file
View File

@@ -0,0 +1,29 @@
# M14-01E Status
status: done
task: Chromium WebGPU fail-closed boundary
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Chromium routing was checked against the production render protocol. A bounded Eevee request using
WebGPU returns `BLOCKED/WEBGPU_RENDERER_UNAVAILABLE` when no bundled adapter is available, while the
same bounded request using WebGL2 remains `READY/WEB_LOCAL_BOUNDED`. This task does not launch Firefox
or WebKit.
## Evidence
- `npm --prefix web run test:chromium-webgpu-boundary` passed.
- Checker output: `chromium-webgpu-boundary-ok webgpu=BLOCKED/WEBGPU_RENDERER_UNAVAILABLE webgl2=READY execution=DISABLED next=M14-04A`.
- `git diff --check` passed.
## Next Task
`M14-04A`: Chromium GPU/memory budget device tier selection.
## Rollback
Remove the Chromium boundary checker, report, manifest, package command and this status/task entry;
restore `M14-01D` as the queue tail.

25
docs/status/M14-04A.md Normal file
View File

@@ -0,0 +1,25 @@
# M14-04A Status
status: done
task: Chromium GPU/memory budget device tier selection
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added a bounded device-budget selector driven only by the real Chromium M14-01D identity report.
The observed SwiftShader renderer and unavailable WebGPU adapter select `CONSERVATIVE`; untrusted,
missing, or fallback adapters cannot expand budgets. Fixed `CONSERVATIVE`, `BALANCED`, and `HIGH`
limits are explicit and unknown tiers fail closed. Firefox/WebKit are excluded by the iron rule.
## Evidence
- `npm --prefix web run test:chromium-device-budget` passed: 3 unit tests plus the production identity
report checker.
- Checker output: `chromium-device-budget-ok tier=CONSERVATIVE reason=UNTRUSTED_ADAPTER identity=3c6f898e1b6ffd39862505b8e7dde8fd29369204e1670a013859f74ccaf1c1eb execution=DISABLED next=M14-04B`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04B`: Chromium DPR 1/1.5/2/3 canvas and raycast consistency.

26
docs/status/M14-04B.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04B Status
status: done
task: Chromium DPR 1/1.5/2/3 canvas and raycast consistency
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Shared viewport DPR and CSS-bounds NDC helpers now drive the main-thread and Offscreen viewport
boundaries. Chromium production verification ran at device scale factors 1, 1.5, 2 and 3; the
declared renderer cap of 2 was applied, backing dimensions matched the browser canvas, CSS dimensions
remained `679x321`, and the same center raycast selected the same object at every scale.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-dpr-consistency` passed: 2 protocol tests and 4 real Chromium
production contexts.
- Checker output: `chromium-dpr-ok dpr=1,1.5,2,3 css=679x321 selection=stable execution=DISABLED next=M14-04C`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04C`: Chromium mouse/touch/pen pointer identity and cancellation contract.

26
docs/status/M14-04C.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04C Status
status: done
task: Chromium mouse/touch/pen pointer identity and cancellation contract
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The main-thread and Offscreen viewport paths now record a shared pointer observation for mouse,
touch, and pen input. Pointer identity, pressure, tilt, button/buttons and `pointercancel` are
preserved with bounded values; unknown pointer types and invalid IDs fail closed. Chromium production
events verified down/cancel pairs for all three pointer types. Firefox/WebKit are excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-pointer-contract` passed: 2 protocol tests and real Chromium
mouse/touch/pen down/cancel events.
- Checker output: `chromium-pointer-ok types=mouse,touch,pen cancel=PASS execution=DISABLED next=M14-04D`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04D`: Chromium IME composition guard for incomplete operators.

26
docs/status/M14-04D.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04D Status
status: done
task: Chromium IME composition guard for incomplete operators
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added an explicit IME composition state machine and connected it to the App global shortcut gate.
Composition start/update records pending text and blocks operator shortcuts; composition end clears
the block without dispatching an incomplete operator. A real Chromium page dispatched composition
events and `G`; UI revision remained unchanged during composition. Firefox/WebKit are excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-ime-guard` passed: 2 protocol tests and real Chromium
compositionstart/update/keydown/compositionend events.
- Checker output: `chromium-ime-ok composing=BLOCKED_OPERATOR shortcut=G revision=0 execution=DISABLED next=M14-04E`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04E`: Chromium US/non-US/dead-key/modifier keymap fixture.

26
docs/status/M14-04E.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04E Status
status: done
task: Chromium US/non-US/dead-key/modifier keymap fixture
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added a versioned keyboard observation contract preserving layout character (`key`), physical key
(`code`), location, repeat, composition state, dead-key identity and modifier flags. Chromium
production events verified US, non-US character, dead-key and modifier fixtures. Firefox/WebKit are
excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-keymap-fixture` passed: 2 protocol tests and 4 real Chromium
keyboard fixtures.
- Checker output: `chromium-keymap-ok fixtures=US,NON_US,DEAD_KEY,MODIFIER observations=4 execution=DISABLED next=M14-04F`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04F`: Chromium touch modal cancel, two-finger navigation and single pen Main commit.

View File

@@ -1,7 +1,8 @@
# N-023 Asset、Library 与 IO
状态:`BLOCKED`asset catalog、来源/许可证元数据、真实 Main library inventory、库依赖与
IO 安全门已落地;Append/Link/Override Main、非 GLB 本地导入和跨桌面重导入未实现)
IO 安全门已落地;bounded Append Main 及其 canonical persistence 已完成Link/Override Main、
非 GLB 本地导入和跨桌面重导入仍未实现)
## 完整对标盘点基线
@@ -91,8 +92,35 @@ M12-03D 已把同一 source-hash-bound closure 送入 WASM Worker 的 authoritat
link/append context 递归导入 Object、Mesh、Material 和 packed ImageMain commit 前核对 source
locator、root、closure 与 base revision四个 ID 均无 `ID.lib`/override、映射为可写 `LOCAL_MAIN`
并只产生一个新的 SceneIR revision。stale revision 与 local ID collision 在 Main mutation 前阻断,
失败路径回滚完整 history state。该项只证明单 transaction Main appendundo/redo/save/reopen 与
desktop canonical report 的联合一致性仍由 M12-03E 验证。
失败路径回滚完整 history state。
M12-03E 已在同一 Chromium/WASM Main 路径完成联合持久化门append 只推进一个 revisionundo
移除 Object/Mesh/Material/Image 四个 closure IDredo 恢复同一 canonical graphsave/reopen 后
再次读取的依赖边、geometry、UV、material slot 和 packed image Float32 pixel hash 与 M12-03C
desktop report 精确一致。图像比较只对 Blender bottom-up `Image.pixels` 与 Canvas top-down row
做规范化;当前 SceneIR 缺省的 `Image.colorSpace` 使用 desktop sRGB semantic default若字段出现
则必须匹配,不放宽其它字段。该证据仍不覆盖 Link/Override 或完整 N-023 IO parity。
M12-03F 已用独立 Blender 5.2 desktop fixture 冻结 LINK 语义。只链接一个 Object rootMesh、
Material 和 packed Image 依赖随 source library 保留;四个 ID 的 `library` 均为
`m12_link_source.blend``isLibraryOverride=false`,并映射为 `SOURCE_LIBRARY/readOnly=true`
target 保存并重开后 stable mapping、依赖边、geometry/UV/material slot 和 packed image Float32
pixel hash 不变。该 enabling evidence 仍不开放 linked writer 或声明完整 Link parity。
M12-03G 已为 linked Object/Mesh/Material/Image writer 建立统一 fail-closed gate。object transform、
mesh geometry/material slot、material property/image node 和 packed image data 六类操作在
`SOURCE_LIBRARY/readOnly=true` context 下全部返回 `LINKED_DATA_MUTATION_BLOCKED`,且
`recoverable=false`stale revision 先返回 `REVISION_CONFLICT`未知字段、operation 和 owner
substitution 也在 Main 前阻断。M12-03H 又将 reload 限定为匹配 source library generation/revision 的
单一 linked snapshot 替换stale、跳代、重复 identity 和 source substitution 均不发布新状态。该项仍不
实现 relocate、override 或 LINK Main transactionM12-03I 的 missing-library placeholder 仍是有界
reference-preservation 证据,不是完整资源恢复。
M12-04A-J 又冻结 declared source-origin admission、canonical project path、path/origin safety、
symlink/hardlink resolution、metadata-first read、entry/total/path/range/conflict budget 与 cancellation
rollback。取消、quota 和 OOM 的部分 staging 都会清零并保持 committed revision/SHA-256 不变,
同一 storage instance 可继续提交小 archive6 个恶意 ZIP/TAR fixture 又进入确定性长期回归。
该组有界证据仍不实现完整 archive decoder、fuzz 或 N-023 全域 parity。
## 已验证切片
@@ -101,8 +129,30 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
缺许可证和哈希不匹配会拒绝。
2. N-023-A/B部分catalog 与 library dependency 图做确定性拓扑检查并返回 load order
content-addressed index 报告 `LOCAL_BOUNDED`OPFS 只在运行时 API 存在时报告 `PROBE_REQUIRED`
3. N-023-C现有 GLB 导出与 USD semantic analysis 可放行;GLTF/OBJ/PLY/STL、
USD/Alembic 实际导入保持 `IO_FORMAT_UNSUPPORTED`,库 mutation 需要真实 Main。
3. N-023-C现有 GLB 导出与 USD semantic analysis 可放行;M12-05A 已从 pinned Blender
5.2 runtime 生成 GLTF/GLB/OBJ/STL/PLY/USD/Alembic operator/build inventory但没有把清单
当作执行 receiptM12-05B 仅放行已有 bounded GLB local export其余 import/export local/server
route 均保持 `BLOCKED`M12-05C 又让 UI registry 只消费 matrix 声明且 runtime 可执行的 route
文件选择器仅接受 `.blend`operator search 隐藏 blocked/undeclared 组合M12-05D 再用
pinned Blender 5.2 runtime receipt 在执行前确认 operator registered/build option/RNA identity
M12-05E 又要求 source/settings/runtime 三重 hash 与 parent inventory identity且不从扩展名推断能力
M12-06A 已由同一 pinned runtime 生成五个独立 Mesh/PBR/UV/skin/animation GLB fixture并用
semantic report 与逐字节二次生成固定输入基线M12-06B 又由生产 Web parser 在 Node 与
Chromium Worker 对 topology/attributes/materials/nodes/animations 做 exact canonical 比较;
M12-06C-G 又完成 Main persistence、loss report、desktop re-import、negative budget 和双向取消/
Worker restart/真实 OPFS quota 恢复M12-07A 又冻结 pinned Blender OBJ 单 Mesh position/
normal/UV/material-group 输入M12-07B 又冻结 OBJ 双对象/负索引/相对纹理来源/坏 face 负例;
M12-07C 已完成 bounded Web-to-desktop OBJ round-trip 与 texture-origin loss report
UV/skin mismatch、GLB import UI route 和 OBJ Web route 仍保持阻断M12-07D 已冻结 Blender
STL binary/ASCII 两个独立 runtime variantM12-07E 又对标 normal/unit/degenerate/trailing
trailing 保持 stricter Web blockM12-07F 又完成 STL Web-to-desktop round-trip/material loss
reportSTL Web route 仍保持阻断M12-07G 又冻结 PLY ASCII 与 binary little-endian 两个
独立 desktop capability variantM12-07H 又完成 bounded PLY vertex/face/color/custom property
mapping 与 `PLY_UNKNOWN_PROPERTY` loss reportM12-07I 又让 big-endian、坏 list、超大 count
在 Worker 中稳定 fail-closedM12-07J 又完成 OBJ/STL/PLY cancellation/OOM/restart/small recovery
但 PLY Web route 仍保持阻断;
GLTF/OBJ/PLY/STL、USD/Alembic 实际导入仍保持 `IO_FORMAT_UNSUPPORTED`
库 mutation 需要真实 Main。
4. N-023-A/B部分预览字节先验 SHA-256 和 byte length再校验 PNG signature/尺寸;
WebP 仅在 RIFF/WEBP 容器签名正确时进入后续解码门,不从元数据伪造预览内容。
5. N-023-E项目路径、外部 URI、archive entry 数量/单项/总量、压缩展开比率均有边界。
@@ -110,9 +160,11 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
packed/external 状态、只读标志和 archive-parent dependency1024 library/每库 1024 dependency、
重复 ID、缺依赖、依赖环与项目外路径由 SceneIR 再校验。缺外部库字节时返回
`LINKED_LIBRARY_RESOURCE_REQUIRED`,不从路径伪造 SHA-256 或声称已加载。
7. N-023-Earchive 结构门):除 traversal 与展开比预算外,重复规范路径、文件/目录前缀冲突、
累计压缩/解压字节和声明源长度不一致均拒绝;`planIOArchiveRanges` 按路径生成确定性、安全整数
compressed offset 计划。它为后续流式解包提供边界,不代表已有 ZIP decoder。
7. N-023-Earchive 结构门):symlink/hardlink 在写前解析到临时根ZIP central directory/TAR
manifest 必须先读entry/total/path、展开比、重叠 range、重复路径与文件/目录前缀冲突均拒绝。
取消会删除真实 staging、保持 committed identity 且发布数为零quota/OOM 部分写入也会清零,
并允许同一 storage instance 恢复小 archive。三类 ZIP 与三类 TAR 恶意二进制 fixture 确定性
重建、验证真实容器 metadata 后全部 fail-closed这些门不代表已有 ZIP/TAR decoder。
8. N-023-ENanoVDB range 基础件):`.nvdb` manifest 要求连续、32-byte 对齐、逐块 hash
HTTP source 只接受与 manifest 精确一致的 `206 Content-Range`,并按块校验后消费;临时错误重试、
稳定 ETag/If-Range、response-body 偏移续传、错位/短响应拒绝均已完成。OPFS 原子
@@ -125,11 +177,16 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
## 仍然阻断
- N-023-BAppend undo/redo/save/reopen、Link/Library Override、reload/relocate 和完整真实 Main
parityM12-03D 的单 transaction append 已有独立证据,但不解除本项阻断。
- N-023-Blinked relocate、missing-library recovery、Library Override 和完整真实 Main parity
M12-03D/E 已证明 bounded Append 的单 transaction 与 desktop canonical persistenceM12-03F/G/H/I
已冻结 desktop LINK source-library/read-only contract、linked writer fail-closed 与
matching-generation reload、missing-reference preservation 和 desktop override ownership/property
fixture、单一 verified override writer、freshness gate、negative cases、三 lane command matrix 与
declared source-origin admission、canonical project-path normalization 与 path/origin security gate
但不解除本项阻断。
- N-023-C/DGLTF/OBJ/PLY/STL、USD/Alembic import/export/save/reopen/desktop reimport。
- N-023-E真实 zip decoder/fuzz、OPFS quota/recovery、license/source offer 发布审计和大文件
流式性能;archive 路径冲突、双向字节预算与确定性 range plan 已完成。
- N-023-E真实 ZIP/TAR decoder/fuzz、license/source offer 发布审计和大文件流式性能仍阻断;
archive link/metadata/budget/conflict/cancellation/quota/OOM 与恶意 fixture regression 已完成。
- N-023-EVDBGPU page resident LRU 已完成64 MiB1 GiB bundle 中断/内存性能门仍阻断。
## 验收
@@ -154,6 +211,13 @@ npm --prefix web run test:asset-preview-display
npm --prefix web run test:library-operation-inventory
npm --prefix web run test:library-operation-identity
npm --prefix web run test:library-main-append
npm --prefix web run test:library-link-safety
npm --prefix web run test:library-metadata-first
npm --prefix web run test:library-archive-budget
npm --prefix web run test:library-archive-conflicts
npm --prefix web run test:library-archive-cancellation
node --test web/tests/unit/library-archive-recovery.test.mjs
node tools/web/check-malicious-archive-fixtures.mjs
npm --prefix web run test:vdb
npm --prefix web run test:vdb-native
```

View File

@@ -25,13 +25,61 @@
8. N-025-E审计链至多 65,536 条拒绝审计按 sequence、前项 SHA-256 与 canonical
entry SHA-256 串联;读取时重新校验请求摘要和整条链,拒绝 requestId 重放、非递增 UTC
时间戳、内容篡改、断链与超预算日志。该链是内存/序列化协议,不声称已持久化发布审计。
9. M13-02A manifest gate每个 script 必须声明 `sourceByteLength``module=false`;解析器限制
脚本数量、总源码字节、依赖数量、权限数量与 allowlistcanonicalize 项目内 entry/dependency
path并拒绝重复依赖、模块执行、未知权限和所有预算溢出。Node unit 与生产 Chromium Worker
正负例、golden report 和 artifact manifest 已绑定。
10. M13-02B canonical signature input`canonicalizeScriptingManifest`
`serializeScriptingManifest` 是唯一规范入口locale-independent code-unit 排序所有可重排
数组,固定无空白 canonical JSONunknown fields 不进入签名输入order mutation、security
field mutation 和 schema drift 均由 Node/Chromium 与 golden report 验证。
11. M13-02C signer trust policy版本化 trust policy 绑定 ED25519 key/public-key、publisher、
active/revoked status、validity window、revocation timestamp、same-publisher rotation chain
和 bounded clock skewresolver 只返回 `ELIGIBLE/cryptographicVerification=REQUIRED`,不验签
不执行revoked/expired/mismatch/cycle/missing predecessor 全部 fail-closed。
12. M13-02D declaration-bound signature verificationcanonical per-script input 包含 source
SHA-256 和权限/预算/路径等声明,合法 ED25519 signature 才返回 `VERIFIED`source hash 或
signature 变化返回 `SCRIPT_SIGNATURE_INVALID`revoked signer 返回 `SCRIPT_POLICY_DENIED`
13. M13-02E permission minimization无显式请求时授予空集只有 manifest 已声明且请求的
permission 才能授予,未知、重复或未声明请求稳定返回 `SCRIPT_POLICY_DENIED`
14. M13-02F signature negative matrixmissing/expired/not-yet-valid key、publisher confusion
与跨脚本 signature swap 均稳定返回 `SCRIPT_POLICY_DENIED``SCRIPT_SIGNATURE_INVALID`
canonical ordering 不改变自身签名结果,且不开放执行入口。
15. M13-03A sandbox scope contractversioned scope 对 DOM、host Worker、OPFS、IndexedDB 和
network 五项能力逐项要求 `false`;启用、缺失或未知 schema 均 fail-closed执行仍禁用。
16. M13-03B sandbox budget contractCPU、wall-time、memory、message 和 output bytes 各有固定
上限;任一超限返回 `SCRIPT_BUDGET_EXCEEDED`,不创建或启用脚本执行器。
17. M13-03C host-call contract仅允许五个显式调用名每个调用使用结构化、调用专属参数
permission 必须来自 manifest 声明,未知字段、危险路径和未声明调用 fail-closed解析结果
保持 `execution=DISABLED`
18. M13-03D sandbox isolation真实 Chromium Worker crash/timeout 后 job receipt 分别返回
`SCRIPT_SANDBOX_CRASHED`/`SCRIPT_SANDBOX_TIMEOUT`Main revision 不变temporary/published
资源归零;终止后的迟到结果返回 `SCRIPT_SANDBOX_LATE_RESULT`,执行仍为 `DISABLED`
19. M13-03E cancellation gate取消 receipt 保持 Main revision 和 execution 状态,真实 Chromium
迟到窗口 `lateMessages=0``cacheWrites=0`,伪造迟到结果稳定返回 `SCRIPT_SANDBOX_LATE_RESULT`
20. M13-03F dispose gate真实 Chromium Worker 释放两端 `MessagePort`、timer、AbortController、
transferable buffer、pending request 和 cache reference首次和重复 dispose 均返回零资源,
且迟到 timer 消息为 0。
21. M13-03G same-session recoveryWorker generation 4->5 后 Main revision/source hash/manifest hash
保持不变;两条 default-deny audit entry 的 request ID、sequence 和 previous hash chain 连续,
replay/source tamper 均返回 `SCRIPT_MANIFEST_INVALID`
22. M13-04A server job directory gate每个 job 获得随机 `0700` one-shot directoryrequest ID 不
进入目录名;成功/失败清理后无残留且重复清理幂等。
23. M13-04B source/output isolationsource directory/file 为 `0555/0444`,真实写入返回 `EACCES`
output directory 为 `0700` 且可写,清理会先恢复 source directory 权限并无残留。
24. M13-04C server resource budgetCPU、memory、process、file、wall 和 output 六类限制有固定
上限;每类超限均返回 `SERVER_JOB_BUDGET_EXCEEDED`bounded receipt 标记 `enforced=true`
执行仍为 `DISABLED`
25. M13-04D server network policy默认 network `DENY`;显式声明的 HTTPS/loopback origin 才可
`ALLOWED`missing/undeclared/unsafe origin 均为 `SERVER_NETWORK_DENIED`
## 仍然阻断
- N-025-B/C签名验证密钥管理、无网络 CPython/native sandbox、server Blender job 和
output hash 提交。
- N-025-D/E真实 GPU/native window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、
审计日志持久化和发布门;本地请求级审计凭证已完成,不代表隔离执行完成。
- N-025-D/E真实 server isolation、真实 GPU/native
window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、审计日志持久化和发布门;本地
请求级审计凭证与 crash/timeout receipt 已完成,不代表隔离执行完成。
## 验收