space-data-module-sdk 0.8.14 → 0.8.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/bin/space-data-module.js +91 -0
  2. package/docs/_shell/consumer-assets.html +5 -0
  3. package/docs/browser-wasmedge-isomorphic.html +261 -0
  4. package/docs/byo-wasm-quickstart.html +226 -0
  5. package/docs/byo-wasm-quickstart.md +204 -0
  6. package/docs/conformance.html +156 -0
  7. package/docs/conformance.md +92 -0
  8. package/docs/emception-shared-memory-verdict.md +209 -0
  9. package/docs/events-abi.html +313 -0
  10. package/docs/events-abi.md +530 -0
  11. package/docs/families/analytics.html +178 -0
  12. package/docs/families/analytics.md +104 -0
  13. package/docs/families/attitude.html +157 -0
  14. package/docs/families/attitude.md +36 -0
  15. package/docs/families/behavior.html +157 -0
  16. package/docs/families/behavior.md +36 -0
  17. package/docs/families/breakup.html +157 -0
  18. package/docs/families/breakup.md +36 -0
  19. package/docs/families/conjunction.html +186 -0
  20. package/docs/families/conjunction.md +121 -0
  21. package/docs/families/data-source.html +318 -0
  22. package/docs/families/effects.html +157 -0
  23. package/docs/families/effects.md +36 -0
  24. package/docs/families/environment.html +170 -0
  25. package/docs/families/environment.md +73 -0
  26. package/docs/families/estimation.html +190 -0
  27. package/docs/families/estimation.md +128 -0
  28. package/docs/families/gnc.html +157 -0
  29. package/docs/families/gnc.md +36 -0
  30. package/docs/families/maneuver.html +209 -0
  31. package/docs/families/maneuver.md +206 -0
  32. package/docs/families/obstruction.html +191 -0
  33. package/docs/families/obstruction.md +96 -0
  34. package/docs/families/propagator.html +333 -0
  35. package/docs/families/propulsion.html +157 -0
  36. package/docs/families/propulsion.md +36 -0
  37. package/docs/families/reentry.html +157 -0
  38. package/docs/families/reentry.md +36 -0
  39. package/docs/families/rf.html +193 -0
  40. package/docs/families/rf.md +136 -0
  41. package/docs/families/scheduler.html +157 -0
  42. package/docs/families/scheduler.md +36 -0
  43. package/docs/families/sensor.html +157 -0
  44. package/docs/families/sensor.md +36 -0
  45. package/docs/families/signature.html +157 -0
  46. package/docs/families/signature.md +36 -0
  47. package/docs/flatsql-host-contract.html +176 -0
  48. package/docs/flatsql-streaming-standard.html +375 -0
  49. package/docs/gpu-module-abi.html +233 -0
  50. package/docs/harness-family-matrix.md +135 -0
  51. package/docs/index.html +216 -85
  52. package/docs/isomorphic-pthreads.html +228 -0
  53. package/docs/isomorphic-pthreads.md +84 -0
  54. package/docs/isomorphic-sdn-runtime-plan.html +274 -0
  55. package/docs/language-runtime-matrix.html +182 -0
  56. package/docs/llms.txt +86 -0
  57. package/docs/module-bundle-runtime-plan.html +146 -0
  58. package/docs/module-publication-standard.html +503 -0
  59. package/docs/node-red-default-node-parity.html +201 -0
  60. package/docs/propagator-abi.md +73 -21
  61. package/docs/protect-and-sign.html +181 -0
  62. package/docs/protect-and-sign.md +120 -0
  63. package/docs/protocol-installation.html +296 -0
  64. package/docs/publication-submission.html +158 -0
  65. package/docs/publication-submission.md +78 -0
  66. package/docs/secrets-capability.html +206 -0
  67. package/docs/styles.css +860 -167
  68. package/docs/testing-harness.html +408 -0
  69. package/docs/tri-runtime-parity-gate.html +182 -0
  70. package/docs/tri-runtime-parity.html +203 -0
  71. package/include/orbpro/orbpro_event_runner.h +951 -0
  72. package/include/orbpro/orbpro_events_abi.h +565 -0
  73. package/include/orbpro/orbpro_propagator_abi.h +17 -0
  74. package/package.json +15 -5
  75. package/schemas/orbpro/Events.fbs +501 -0
  76. package/schemas/orbpro/Propagator.fbs +72 -9
  77. package/schemas/orbpro/reference-frame-crosswalk.json +108 -0
  78. package/schemas/orbpro/reference-frame.lock.json +98 -0
  79. package/src/browser.js +13 -0
  80. package/src/conformance/abiDriver.js +225 -0
  81. package/src/conformance/index.js +151 -0
  82. package/src/conformance/propagatorSuite.js +526 -0
  83. package/src/conformance/selfTest.js +275 -0
  84. package/src/conformance/selfTestCorpus.js +68 -0
  85. package/src/conformance/twoBodyReference.js +132 -0
  86. package/src/generated/orbpro/events-abi.js +206 -0
  87. package/src/generated/orbpro/events-abi.ts +319 -0
  88. package/src/generated/orbpro/propagator/reference-frame.js +17 -0
  89. package/src/generated/orbpro/propagator/reference-frame.ts +91 -1
  90. package/src/generated/orbpro/propagator-abi.js +17 -0
  91. package/src/generated/orbpro/propagator-abi.ts +17 -0
  92. package/src/generated/spacedatastandards/plg/CCT.d.ts +94 -0
  93. package/src/generated/spacedatastandards/plg/CCT.d.ts.map +1 -0
  94. package/src/generated/spacedatastandards/plg/CCT.js +208 -0
  95. package/src/generated/spacedatastandards/plg/CCT.ts +281 -0
  96. package/src/generated/spacedatastandards/plg/CCTCategory.d.ts +98 -0
  97. package/src/generated/spacedatastandards/plg/CCTCategory.d.ts.map +1 -0
  98. package/src/generated/spacedatastandards/plg/CCTCategory.js +177 -0
  99. package/src/generated/spacedatastandards/plg/CCTCategory.ts +269 -0
  100. package/src/generated/spacedatastandards/plg/CCTCategoryRollup.d.ts +54 -0
  101. package/src/generated/spacedatastandards/plg/CCTCategoryRollup.d.ts.map +1 -0
  102. package/src/generated/spacedatastandards/plg/CCTCategoryRollup.js +106 -0
  103. package/src/generated/spacedatastandards/plg/CCTCategoryRollup.ts +144 -0
  104. package/src/generated/spacedatastandards/plg/PLG.d.ts +46 -2
  105. package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -1
  106. package/src/generated/spacedatastandards/plg/PLG.js +78 -5
  107. package/src/generated/spacedatastandards/plg/PLG.ts +90 -5
  108. package/src/generated/spacedatastandards/plg/capabilityClass.d.ts +181 -0
  109. package/src/generated/spacedatastandards/plg/capabilityClass.d.ts.map +1 -0
  110. package/src/generated/spacedatastandards/plg/capabilityClass.js +183 -0
  111. package/src/generated/spacedatastandards/plg/capabilityClass.ts +208 -0
  112. package/src/generated/spacedatastandards/plg/main.d.ts +4 -0
  113. package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -1
  114. package/src/generated/spacedatastandards/plg/main.js +4 -0
  115. package/src/generated/spacedatastandards/plg/main.ts +4 -0
  116. package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +40 -2
  117. package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -1
  118. package/src/generated/spacedatastandards/plg/pluginCategory.js +40 -2
  119. package/src/generated/spacedatastandards/plg/pluginCategory.ts +40 -2
  120. package/src/host/browserModuleHarness.js +8 -0
  121. package/src/host/wasiThreadHost.js +189 -14
  122. package/src/index.d.ts +18 -1
  123. package/src/testing/isomorphicHarness.js +233 -0
  124. package/src/transport/index.js +16 -0
  125. package/src/transport/records.js +1015 -3
@@ -0,0 +1,228 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="description" content="space-data-module-sdk is the enforced source of truth for isomorphic" />
7
+ <title>Isomorphic pthreads — Space Data Module SDK</title>
8
+ <link rel="stylesheet" href="./styles.css" />
9
+ <!-- SDN_CONSUMER_ASSETS_START -->
10
+ <link rel="stylesheet" href="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.c3f68d1cfd88478f10d836a5e829d1dfc6a10157972cf0f7d4d319d0636f2cc4.css" integrity="sha384-fICuhN4I9xqOK1F5vGGzl26opuO+xQIvTZXMSV76lWTBiQ6AfzztMGLLDw8yRT8i" crossorigin="anonymous">
11
+ <script defer src="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.f611e7e151a3b5c38384272f8894a4c6634f0a29bf925b0e02e0e27f8db0bfff.js" integrity="sha384-R+QqsKoWJIS7iWrtPmgJ49DVnb1hSGjZokupbLInJd1PLp8RwQhtF/hnaerc33ci" crossorigin="anonymous" data-sdn-wallet-public-client="v1"></script>
12
+ <script defer src="https://static.spacedatanetwork.org/assets/sdn-stack-nav/1.0.0/sdn-stack-nav.52fde607eee38ffa116188201f50258ed50bd18c9f06c1af9678f763147a8fe5.js" integrity="sha384-dgeojhJ8vTszHXIbv7O7nZcEzqD10oUYYJjBmPrV7+kLQEUlXLQD4ek5Q7HOFiO5" crossorigin="anonymous" data-nav-style-url="https://static.spacedatanetwork.org/assets/sdn-stack-nav/1.0.0/sdn-stack-nav.36a36359ce18322185e9ff179f88175bab67d5ad84a14d9c08a54f2ff27267e7.css" data-nav-style-integrity="sha384-c4M8Fg+kYaeOYYtJVr7jJsde24IhSWkWaRyAOHEZU9jozhRck089aw+mnHwxymds" data-wallet-client-url="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.f611e7e151a3b5c38384272f8894a4c6634f0a29bf925b0e02e0e27f8db0bfff.js" data-wallet-client-integrity="sha384-R+QqsKoWJIS7iWrtPmgJ49DVnb1hSGjZokupbLInJd1PLp8RwQhtF/hnaerc33ci" data-wallet-style-url="https://static.spacedatanetwork.org/assets/hd-wallet-ui/2.0.28/sdn-wallet-public-client.c3f68d1cfd88478f10d836a5e829d1dfc6a10157972cf0f7d4d319d0636f2cc4.css" data-wallet-style-integrity="sha384-fICuhN4I9xqOK1F5vGGzl26opuO+xQIvTZXMSV76lWTBiQ6AfzztMGLLDw8yRT8i" data-wallet-client-id="sdn-module-sdk-pages-v1" data-wallet-callback-uri="https://digitalarsenal.github.io/space-data-module-sdk/wallet-callback.html" data-wallet-registry-sha256="e1ce6fe903c9700484a8a87d96581c8cad97063dabf63030b4518a31a3bdaa93"></script>
13
+ <!-- SDN_CONSUMER_ASSETS_END -->
14
+ </head>
15
+ <body>
16
+ <a class="skip-link" href="#main">Skip to content</a>
17
+ <sdn-stack-nav active="module-sdk"></sdn-stack-nav>
18
+ <header class="site-header">
19
+ <a class="site-brand" href="./">Space Data Module SDK</a>
20
+ <nav class="header-links" aria-label="Site">
21
+ <a href="./byo-wasm-quickstart.html">Quickstart</a>
22
+ <a href="./conformance.html">Conformance</a>
23
+ <a href="https://github.com/DigitalArsenal/space-data-module-sdk">GitHub</a>
24
+ <a class="stack-button" href="#stack">Stack</a>
25
+ </nav>
26
+ </header>
27
+ <div class="shell">
28
+ <nav class="sidebar" id="sidebar" aria-label="Documentation">
29
+ <h2>Start here</h2><ul>
30
+ <li><a href="./index.html"><span>Harness family matrix</span></a></li>
31
+ <li><a href="./byo-wasm-quickstart.html"><span>BYO-wasm quickstart</span></a></li>
32
+ <li><a href="./conformance.html"><span>Conformance kit</span></a></li>
33
+ <li><a href="./protect-and-sign.html"><span>Protect and sign</span></a></li>
34
+ <li><a href="./publication-submission.html"><span>Publication and listing</span></a></li>
35
+ </ul>
36
+ <h2>Dynamics</h2><ul>
37
+ <li><a href="./families/propagator.html"><span>Propagator</span><span class="tag tag-shipped">shipped</span></a></li>
38
+ <li><a href="./families/maneuver.html"><span>Maneuver</span><span class="tag tag-experimental">experimental</span></a></li>
39
+ <li><a href="./families/propulsion.html"><span>Propulsion</span><span class="tag tag-planned">planned</span></a></li>
40
+ <li><a href="./families/attitude.html"><span>Attitude</span><span class="tag tag-planned">planned</span></a></li>
41
+ <li><a href="./families/gnc.html"><span>GNC</span><span class="tag tag-planned">planned</span></a></li>
42
+ </ul>
43
+ <h2>Environment and interaction</h2><ul>
44
+ <li><a href="./families/rf.html"><span>RF</span><span class="tag tag-designed">designed</span></a></li>
45
+ <li><a href="./families/sensor.html"><span>Sensor</span><span class="tag tag-planned">planned</span></a></li>
46
+ <li><a href="./families/signature.html"><span>Signature</span><span class="tag tag-planned">planned</span></a></li>
47
+ <li><a href="./families/environment.html"><span>Environment</span><span class="tag tag-planned">planned</span></a></li>
48
+ <li><a href="./families/obstruction.html"><span>Obstruction</span><span class="tag tag-designed">designed</span></a></li>
49
+ </ul>
50
+ <h2>Event physics</h2><ul>
51
+ <li><a href="./families/breakup.html"><span>Breakup</span><span class="tag tag-planned">planned</span></a></li>
52
+ <li><a href="./families/reentry.html"><span>Reentry</span><span class="tag tag-planned">planned</span></a></li>
53
+ <li><a href="./families/conjunction.html"><span>Conjunction</span><span class="tag tag-designed">designed</span></a></li>
54
+ <li><a href="./families/effects.html"><span>Effects</span><span class="tag tag-planned">planned</span></a></li>
55
+ </ul>
56
+ <h2>Estimation, data and logic</h2><ul>
57
+ <li><a href="./families/estimation.html"><span>Estimation</span><span class="tag tag-experimental">experimental</span></a></li>
58
+ <li><a href="./families/data-source.html"><span>Data source</span><span class="tag tag-shipped">shipped</span></a></li>
59
+ <li><a href="./families/analytics.html"><span>Analytics</span><span class="tag tag-experimental">experimental</span></a></li>
60
+ <li><a href="./families/scheduler.html"><span>Scheduler</span><span class="tag tag-planned">planned</span></a></li>
61
+ <li><a href="./families/behavior.html"><span>Behavior</span><span class="tag tag-planned">planned</span></a></li>
62
+ </ul>
63
+ <h2>Runtime contract</h2><ul>
64
+ <li><a href="./events-abi.html"><span>Event locator ABI</span></a></li>
65
+ <li><a href="./module-publication-standard.html"><span>Module publication standard</span></a></li>
66
+ <li><a href="./browser-wasmedge-isomorphic.html"><span>Browser / WasmEdge isomorphism</span></a></li>
67
+ <li><a href="./isomorphic-pthreads.html" aria-current="page"><span>Isomorphic pthreads</span></a></li>
68
+ <li><a href="./tri-runtime-parity.html"><span>Tri-runtime parity</span></a></li>
69
+ <li><a href="./tri-runtime-parity-gate.html"><span>Tri-runtime parity gate</span></a></li>
70
+ <li><a href="./testing-harness.html"><span>Testing harness</span></a></li>
71
+ <li><a href="./language-runtime-matrix.html"><span>Language and runtime matrix</span></a></li>
72
+ </ul>
73
+ <h2>Host surfaces</h2><ul>
74
+ <li><a href="./flatsql-host-contract.html"><span>FlatSQL host contract</span></a></li>
75
+ <li><a href="./flatsql-streaming-standard.html"><span>FlatSQL streaming standard</span></a></li>
76
+ <li><a href="./secrets-capability.html"><span>Credential lanes</span></a></li>
77
+ <li><a href="./protocol-installation.html"><span>Protocol installation</span></a></li>
78
+ <li><a href="./gpu-module-abi.html"><span>GPU module ABI</span></a></li>
79
+ <li><a href="./module-bundle-runtime-plan.html"><span>Module bundle runtime</span></a></li>
80
+ <li><a href="./isomorphic-sdn-runtime-plan.html"><span>Isomorphic SDN runtime</span></a></li>
81
+ <li><a href="./node-red-default-node-parity.html"><span>Node-RED node parity</span></a></li>
82
+ </ul>
83
+ </nav>
84
+ <main class="doc" id="main">
85
+ <h1>Isomorphic pthreads</h1>
86
+ <p><code>space-data-module-sdk</code> is the <strong>enforced source of truth</strong> for isomorphic pthreads module artifacts. When a module is compiled for the pthreads thread model, the SDK guarantees two things that used to be optional and unchecked:</p>
87
+ <ol>
88
+ <li>The final link <strong>cannot omit</strong> the thread-enabling flags, and it targets the <strong>wasi-threads</strong> toolchain (not Emscripten's browser Web-Worker model).</li>
89
+ <li>The emitted <code>.wasm</code> is <strong>parsed and validated</strong> to be a real wasi-threads artifact. A module that claims pthreads but does not emit the wasi-threads contract <strong>fails the compile</strong> — it does not ship.</li>
90
+ </ol>
91
+ <p>The goal is one compiled <code>.wasm</code> that threads in <strong>both</strong> the browser (via <code>SharedArrayBuffer</code> + a wasi-threads Worker shim) and WasmEdge (via wasi-threads), mirroring the <code>analysis/conjunction-assessment</code> module's <code>std::thread</code> workers.</p>
92
+ <h2 id="why-wasi-threads-and-not-emscripten--pthread"><a class="anchor" href="#why-wasi-threads-and-not-emscripten--pthread" aria-hidden="true">#</a>Why wasi-threads and NOT Emscripten <code>-pthread</code></h2>
93
+ <p>This is the load-bearing decision. Emscripten's <code>-pthread</code> — even with <code>-s STANDALONE_WASM=1</code> — emits the <strong>browser-only</strong> thread model:</p>
94
+ <ul>
95
+ <li>it imports <code>env.__pthread_create_js</code> and <code>env._emscripten_*</code> mailbox / <code>postMessage</code> hooks (a JS Web Worker protocol), and</li>
96
+ <li>it has <strong>no</strong> wasi thread-spawn contract.</li>
97
+ </ul>
98
+ <p>That artifact <strong>cannot spawn threads under WasmEdge</strong> — there is no JS runtime to satisfy those imports; instantiation fails on the unknown imports, and stubbing them would require host-side thread orchestration (which is separately forbidden). It has shared memory and atomics, but those are <strong>necessary, not sufficient</strong>: a browser-only Emscripten build has them too.</p>
99
+ <p>WasmEdge's actual thread mechanism is <strong>wasi-threads</strong>: the guest imports <code>wasi.thread-spawn</code> and exports <code>wasi_thread_start</code> over an imported shared memory. Compiling with <code>clang --target=wasm32-wasip1-threads -pthread</code> (wasi-sdk / wasi-libc + wasi-runtimes threads sysroot) produces exactly that contract, which threads under WasmEdge and loads in the browser through a wasi-threads shim.</p>
100
+ <p><code>-mthreads</code> is likewise never used — it is a MinGW driver flag, invalid for the wasm target.</p>
101
+ <h2 id="thread-models"><a class="anchor" href="#thread-models" aria-hidden="true">#</a>Thread Models</h2>
102
+ <p><code>ModuleThreadModel</code> (see <code>src/compiler/compileModule.js</code>):</p>
103
+ <ul>
104
+ <li><code>single-thread</code> — portable, no shared memory, no atomics. Default for <code>runtimeTargets: [&quot;browser&quot;]</code> and <code>[&quot;browser&quot;, &quot;wasmedge&quot;]</code>. Built with Emscripten (emception, in-process).</li>
105
+ <li><code>emscripten-pthreads</code> — the isomorphic threaded model (the enum value string is historical; it now compiles to a <strong>wasi-threads</strong> artifact, not an Emscripten Web-Worker build). Default for <code>runtimeTargets: [&quot;wasmedge&quot;]</code>. Built with the wasi-threads toolchain.</li>
106
+ </ul>
107
+ <p><code>resolveThreadModel({ manifest, threadModel })</code> resolves the model; an explicit <code>threadModel</code> option always wins over <code>runtimeTargets</code> inference.</p>
108
+ <h2 id="1-enforced-flags-non-bypassable"><a class="anchor" href="#1-enforced-flags-non-bypassable" aria-hidden="true">#</a>1. Enforced Flags (non-bypassable)</h2>
109
+ <p>The pthreads final link routes through one flag-assembler (<code>buildCompilerArgs</code> in <code>src/compiler/compileModule.js</code>, backed by <code>PTHREAD_FINAL_LINK_FLAGS</code> in <code>src/compiler/pthreadArtifactGuard.js</code>). For the pthreads model it <strong>always</strong> carries the wasm-ld / clang flags:</p>
110
+ <div class="codeblock"><pre><code>-pthread -matomics -mbulk-memory -Wl,--import-memory -Wl,--shared-memory -Wl,--max-memory=2147483648</code></pre></div>
111
+ <p>plus the toolchain args resolved by <code>src/compiler/wasiThreadsToolchain.js</code> (<code>--target=wasm32-wasip1-threads --sysroot=… -resource-dir=…</code>). Object files are compiled <code>-matomics -fno-exceptions -pthread</code> (the wasi-threads libc++ is built without exceptions, so throwing code otherwise fails to link).</p>
112
+ <p><code>buildCompilerArgs</code> asserts its own output (<code>assertPthreadFlagsPresent</code>) so a future edit that removes a mandated flag fails loudly. There are deliberately <strong>no</strong> Emscripten <code>-s</code> settings here — those produce the browser-only build.</p>
113
+ <p>The toolchain is resolved with sensible defaults and env overrides (<code>SDN_WASI_CLANG</code>, <code>SDN_WASI_CLANGXX</code>, <code>SDN_WASI_TARGET</code>, <code>SDN_WASI_SYSROOT</code>, <code>SDN_WASI_RESOURCE_DIR</code>). If a wasi-threads sysroot is unavailable, the pthreads compile fails with a clear, actionable error.</p>
114
+ <h2 id="2-validated-artifact-the-part-that-matters-most"><a class="anchor" href="#2-validated-artifact-the-part-that-matters-most" aria-hidden="true">#</a>2. Validated Artifact (the part that matters most)</h2>
115
+ <p>After the final <code>.wasm</code> is emitted, <code>compileModuleFromSource</code> calls <code>assertPthreadArtifact(wasmBytes)</code> for the pthreads model. It parses the wasm and REJECTS the compile unless ALL of the following hold:</p>
116
+ <ul>
117
+ <li><strong>Shared memory</strong> — an imported or declared memory with the shared limits flag (<code>flags &amp; 0x02</code>, i.e. <code>0x03</code>/<code>0x07</code>).</li>
118
+ <li><strong>Atomics usage</strong> — the code section is walked with a real instruction decoder that counts genuine <code>0xFE</code>-prefixed atomic instructions. This is <strong>not</strong> a byte scan: a naive scan for <code>0xFE</code> false-positives on <code>i32.const</code> / LEB128 / memory-offset immediates (memory load/store opcodes <code>0x28</code>–<code>0x3E</code> carry a memarg). <code>target_features</code> is honored when present.</li>
119
+ <li><strong>wasi thread-spawn import</strong> — <code>wasi.thread-spawn</code> (the host contract WasmEdge invokes to spawn a guest thread).</li>
120
+ <li><strong><code>wasi_thread_start</code> export</strong> — the entry a host calls to run a spawned thread.</li>
121
+ <li><strong>No Emscripten thread hooks</strong> — the artifact must NOT import <code>env.__pthread_create_js</code> or the <code>env._emscripten_*</code> mailbox/postMessage hooks. Their presence means it is a browser-only Web-Worker build and it is rejected.</li>
122
+ </ul>
123
+ <p>Shared memory + atomics <strong>alone</strong> are necessary but insufficient (the browser-only Emscripten build has both), which is exactly why the wasi-threads contract check exists. The analysis is returned on the compilation result as <code>result.threadFeatures</code> (<code>{ hasSharedMemory, usesAtomics, atomicInstructionCount, hasWasiThreadSpawnImport, hasWasiThreadStartExport, emscriptenThreadHooks, isIsomorphicPthreads, … }</code>).</p>
124
+ <p><code>analyzeWasmThreadFeatures(wasmBytes)</code> and <code>assertPthreadArtifact(wasmBytes)</code> are exported from <code>src/compiler/index.js</code> (and the package root) for reuse by downstream validators, deploy gates, and tests.</p>
125
+ <p>Note that the wasi-threads contract (thread-spawn import + <code>wasi_thread_start</code> export) appears only when the module <strong>actually spawns threads</strong> — the linker pulls in that machinery on demand. A module declared <code>emscripten-pthreads</code> that never spawns a thread will therefore fail this guardrail; such a module should use the <code>single-thread</code> model instead.</p>
126
+ <h2 id="guest-link-symbol-namespacing-collision-proof-metadata-authoritative"><a class="anchor" href="#guest-link-symbol-namespacing-collision-proof-metadata-authoritative" aria-hidden="true">#</a>Guest-link symbol namespacing (collision-proof, metadata-authoritative)</h2>
127
+ <p>For monolithic flow composition, each module also emits a <strong>guest-link</strong> wasm object whose exported method symbols are namespaced by a per-plugin prefix so that independently-built modules can be linked together with <code>wasm-ld -r</code> without symbol clashes. <code>guestLinkSymbolPrefix(pluginId)</code> in <code>src/compiler/compileModule.js</code> produces that prefix as:</p>
128
+ <div class="codeblock"><pre><code>sdm_guest_&lt;full-lowercase-hex-of-pluginId-UTF8-bytes&gt;_</code></pre></div>
129
+ <p>The prefix uses the <strong>full</strong> hex encoding of the pluginId — it is <strong>not</strong> truncated. Hex encoding is injective, so distinct pluginIds always map to distinct prefixes. (A prior <code>.slice(0, 24)</code> truncation to 12 bytes collided real plugin ids that share a 12-byte stem — e.g. <code>com.orbpro.iss-source</code> and <code>com.orbpro.intelsat-source</code> both collapsed to <code>hex(&quot;com.orbpro.i&quot;)</code> <code>636f6d2e6f726270726f2e69</code>, which would silently merge/clash their symbols at compose time.) Wasm symbol names have no meaningful length limit, so the full hex is always safe.</p>
130
+ <p>The emitted <code>symbolPrefix</code> and the per-method <code>methodSymbols</code> map are recorded in the guest-link <strong>metadata</strong> (<code>sds.guest-link</code>). <strong>That metadata is the sole authoritative source consumers read at compose time</strong> — <code>generateFlowTables</code> in <code>src/flow/flowCompiler.js</code> declares and calls <code>dependency.guestLink.metadata.methodSymbols[methodId]</code> and never re-derives the prefix from the pluginId. This keeps already-committed artifacts compatible: an object that shipped with a legacy (e.g. truncated) prefix still composes, because its own metadata carries the exact symbol names its object bytes define.</p>
131
+ <h2 id="3-compile-time-vs-runtime-an-honest-boundary"><a class="anchor" href="#3-compile-time-vs-runtime-an-honest-boundary" aria-hidden="true">#</a>3. Compile-Time vs. Runtime: an honest boundary</h2>
132
+ <p>Passing this guardrail proves the <strong>artifact</strong> is a valid wasi-threads shared-memory/atomics wasm. It does <strong>not</strong> prove that a given WasmEdge build actually spawns and runs guest threads.</p>
133
+ <blockquote><p><strong>Rule:</strong> Do not claim WasmEdge thread support until a real runtime invocation spawns threads and runs. Compile-time validation (wasi-threads contract + shared memory + atomics) is necessary but not sufficient; runtime thread-spawn verification is owned by the deploy/benchmark node, not by this SDK.</p></blockquote>
134
+ <p>Record any WasmEdge runtime limitation honestly. An artifact that validates here but only compiles — and does not instantiate/spawn threads under the target runtime — must be reported as such.</p>
135
+ <h2 id="4-integrators-the-browser-worker-anchor-required-when-you-bundle"><a class="anchor" href="#4-integrators-the-browser-worker-anchor-required-when-you-bundle" aria-hidden="true">#</a>4. Integrators: the browser worker anchor (REQUIRED when you bundle)</h2>
136
+ <p>The browser leg of the wasi-threads host runs each guest pthread on a pooled module <code>Worker</code>. That worker is a <strong>served asset</strong>, and the SDK cannot guess where your build published it.</p>
137
+ <p>By default the host anchors the worker to its own package layout:</p>
138
+ <div class="codeblock"><div class="codeblock-head">js</div><pre><code>new URL(&quot;./wasiThreadBrowserWorker.mjs&quot;, import.meta.url);</code></pre></div>
139
+ <p>That default is correct <strong>only when this source is served unbundled</strong> (Node, and plain dev servers). Any bundler inlines the host and rewrites <code>import.meta.url</code> to the <em>bundle's</em> URL — so the worker is requested next to your bundle, where it was never emitted, and the request 404s. This shipped: an engine artifact asked for <code>Build/CesiumUnminified/wasiThreadBrowserWorker.mjs</code> while the bucket served the chain under <code>js/vendor/space-data-module-sdk/src/host/</code>.</p>
140
+ <p><strong>If you bundle the host, pass the anchor.</strong> Two equivalent forms:</p>
141
+ <div class="codeblock"><div class="codeblock-head">js</div><pre><code>// A. Per-harness (or per-createWasiThreadSpawn) option.
142
+ await createBrowserModuleHarness({
143
+ wasmBytes,
144
+ // The directory YOUR build serves the SDK host chain from.
145
+ wasiThreadWorkerBaseUrl: &quot;js/vendor/space-data-module-sdk/src/host/&quot;,
146
+ });
147
+
148
+ // B. Process-wide, installed once by the host shim.
149
+ import { setBrowserWasiThreadWorkerBase } from &quot;space-data-module-sdk/browser&quot;;
150
+ setBrowserWasiThreadWorkerBase(&quot;js/vendor/space-data-module-sdk/src/host/&quot;);</code></pre></div>
151
+ <p>Resolution precedence, highest first — deterministic, and nothing else participates:</p>
152
+ <div class="table-wrap"><table><thead><tr><th>Source</th><th>Option / API</th></tr></thead><tbody><tr><td>1. Explicit worker file</td><td><code>browserWorkerUrl</code> / <code>wasiThreadWorkerUrl</code></td></tr><tr><td>2. Explicit directory</td><td><code>browserWorkerBaseUrl</code> / <code>wasiThreadWorkerBaseUrl</code></td></tr><tr><td>3. Process-wide base</td><td><code>setBrowserWasiThreadWorkerBase(base)</code></td></tr><tr><td>4. Packaged sibling</td><td><code>new URL(&quot;./wasiThreadBrowserWorker.mjs&quot;, import.meta.url)</code></td></tr></tbody></table></div>
153
+ <p>Rules that make this contract honest:</p>
154
+ <ul>
155
+ <li><strong>The anchor names a DIRECTORY that serves the WHOLE chain.</strong> <code>wasiThreadBrowserWorker.mjs</code> imports <code>./wasiThreadWorkerRuntime.js</code>. Staging the single <code>.mjs</code> next to your bundle does <strong>not</strong> work.</li>
156
+ <li><strong>A relative base resolves against the document</strong>; absolute URLs pass through unchanged.</li>
157
+ <li><strong>No consumer-side <code>location</code> sniffing.</strong> Forking worker resolution per consumer is not the contract; you already know your build's layout, so state it.</li>
158
+ <li><strong>No fetch-and-retry probe.</strong> Resolution never touches the network: Node never fetches, and browser thread count may not become a function of network timing.</li>
159
+ <li><strong>An unreachable worker fails LOUD.</strong> When the pooled path was requested (threads enabled + cross-origin isolated + shared memory) and the worker asset at the resolved anchor never loads, <code>createWasiThreadSpawn</code> <strong>throws</strong> <code>WasiThreadWorkerUnreachableError</code> naming the URL it tried. It does not drop quietly to one thread — a silent sequential fallback is how a deployment defect hid behind a passing gate as a pure performance loss.</li>
160
+ </ul>
161
+ <p>Genuine capability negotiation is unaffected and stays soft: a worker that loads and reports it cannot instantiate the module, a probe timeout, a non-isolated context, non-shared memory, or a 1-core host all still disable threading and let the guest run its proven sequential path (<code>wasi.thread-spawn</code> -&gt; <code>-1</code>).</p>
162
+ <h2 id="tests"><a class="anchor" href="#tests" aria-hidden="true">#</a>Tests</h2>
163
+ <ul>
164
+ <li><code>test/wasi-thread-bundled-consumer-anchor.test.js</code> — the <strong>bundled-consumer guardrail</strong>: the host source is run through esbuild into a directory that does not hold the worker chain (the published-bucket geometry), driven by a Worker mock that resolves URLs on the filesystem the way a browser resolves them against an origin. With no anchor the pooled path must throw <code>WasiThreadWorkerUnreachableError</code> (the silent sequential fallback is a HARD failure); with an explicit base — or the process-wide setter — the same bundle arms its pool and spawns threads. Also pins the precedence table and asserts the resolver neither fetches nor sniffs <code>location</code>.</li>
165
+ <li><code>test/wasi-thread-host-browser-pool.test.js</code> — warm-pool arming, short-circuit on the first not-ready, probe-deadline bound, idle reuse/teardown, and the fail-loud split between an unreachable worker asset and a negotiated fallback.</li>
166
+ <li><code>test/pthreads-artifact-guardrail.test.js</code> — flag-assembler invariants; a positive compile that emits a validated wasi-threads shared-memory/atomics wasm; a single-thread artifact rejected; a <strong>browser-only Emscripten <code>-pthread</code> artifact rejected</strong> (has shared memory + atomics but no wasi-threads contract); a shared-flag-stripped artifact rejected; and a false-positive guard proving the atomics decoder ignores <code>0xFE</code> immediates.</li>
167
+ <li><code>test/guest-link-symbol-prefix.test.js</code> — the guest-link prefix is the full injective hex of the pluginId; two previously-colliding ids now get distinct prefixes; fresh prefixes match the committed modules-branch artifacts byte-for-byte; and the compose path treats the guest-link metadata's <code>symbolPrefix</code> / <code>methodSymbols</code> as authoritative (never re-derived), keeping a legacy truncated-prefix artifact compatible.</li>
168
+ </ul>
169
+ <h2 id="see-also"><a class="anchor" href="#see-also" aria-hidden="true">#</a>See also</h2>
170
+ <ul>
171
+ <li><a href="./browser-wasmedge-isomorphic.html"><code>docs/browser-wasmedge-isomorphic.md</code></a> — the one-artifact browser + WasmEdge loading profile.</li>
172
+ <li><code>.claude/skills/wasmedge-pthreads/Skills.md</code> — the operating rules.</li>
173
+ <li><code>src/host/wasiThreadHost.js</code> — the isomorphic <code>wasi.thread-spawn</code> host: <code>createWasiThreadSpawn</code>, the browser worker anchor (<code>setBrowserWasiThreadWorkerBase</code>, <code>resolveBrowserWorkerUrl</code>), and <code>WasiThreadWorkerUnreachableError</code>.</li>
174
+ <li><code>src/compiler/pthreadArtifactGuard.js</code> — the flag list + wasm validator.</li>
175
+ <li><code>src/compiler/wasiThreadsToolchain.js</code> — the wasi-threads toolchain resolver.</li>
176
+ <li><code>src/compiler/compileModule.js</code> — <code>ModuleThreadModel</code>, <code>buildCompilerArgs</code>, <code>compileWithWasiThreads</code>, <code>resolveThreadModel</code>, <code>compileModuleFromSource</code>.</li>
177
+ </ul>
178
+
179
+ <p class="doc-footer">
180
+ Source of truth for this page:
181
+ <code>docs/isomorphic-pthreads.md</code>. Regenerate with
182
+ <code>npm run build:docs</code>.
183
+ </p>
184
+ </main>
185
+ <nav class="rail" aria-label="On this page"><h2>On this page</h2><ul><li><a class="depth-2" href="#why-wasi-threads-and-not-emscripten--pthread">Why wasi-threads and NOT Emscripten <code>-pthread</code></a></li>
186
+ <li><a class="depth-2" href="#thread-models">Thread Models</a></li>
187
+ <li><a class="depth-2" href="#1-enforced-flags-non-bypassable">1. Enforced Flags (non-bypassable)</a></li>
188
+ <li><a class="depth-2" href="#2-validated-artifact-the-part-that-matters-most">2. Validated Artifact (the part that matters most)</a></li>
189
+ <li><a class="depth-2" href="#guest-link-symbol-namespacing-collision-proof-metadata-authoritative">Guest-link symbol namespacing (collision-proof, metadata-authoritative)</a></li>
190
+ <li><a class="depth-2" href="#3-compile-time-vs-runtime-an-honest-boundary">3. Compile-Time vs. Runtime: an honest boundary</a></li>
191
+ <li><a class="depth-2" href="#4-integrators-the-browser-worker-anchor-required-when-you-bundle">4. Integrators: the browser worker anchor (REQUIRED when you bundle)</a></li>
192
+ <li><a class="depth-2" href="#tests">Tests</a></li>
193
+ <li><a class="depth-2" href="#see-also">See also</a></li></ul></nav>
194
+ </div>
195
+ <section id="stack" class="section" aria-labelledby="stack-title">
196
+ <div class="section-head">
197
+ <p class="eyebrow">SDN Stack</p>
198
+ <h2 id="stack-title">Connected sites</h2>
199
+ </div>
200
+ <div class="link-list">
201
+ <a href="https://spacedatastandards.org/">
202
+ <span>Standards</span>
203
+ <small>Canonical schemas, record contracts, and generated bindings.</small>
204
+ </a>
205
+ <a href="https://digitalarsenal.github.io/flatbuffers/">
206
+ <span>FlatBuffers</span>
207
+ <small>Binary encoding, schema tooling, and runtime documentation.</small>
208
+ </a>
209
+ <a href="https://digitalarsenal.github.io/flatsql/">
210
+ <span>FlatSQL</span>
211
+ <small>SQL-style queries over FlatBuffer-backed datasets and streams.</small>
212
+ </a>
213
+ <a href="https://spacedatanetwork.org/">
214
+ <span>SDN</span>
215
+ <small>Distributed publication, discovery, delivery, and marketplace infrastructure.</small>
216
+ </a>
217
+ <a href="https://digitalarsenal.github.io/space-data-module-sdk/" class="active">
218
+ <span>Module SDK</span>
219
+ <small>WASM module packaging, validation, and host compatibility tooling.</small>
220
+ </a>
221
+ </div>
222
+ </section>
223
+ <footer class="site-footer">
224
+ Space Data Module SDK — Apache-2.0. Every ABI page renders a Markdown
225
+ source in <code>docs/</code>; edit the Markdown, never the HTML.
226
+ </footer>
227
+ </body>
228
+ </html>
@@ -162,8 +162,88 @@ Record any WasmEdge runtime limitation honestly. An artifact that validates here
162
162
  but only compiles — and does not instantiate/spawn threads under the target
163
163
  runtime — must be reported as such.
164
164
 
165
+ ## 4. Integrators: the browser worker anchor (REQUIRED when you bundle)
166
+
167
+ The browser leg of the wasi-threads host runs each guest pthread on a pooled
168
+ module `Worker`. That worker is a **served asset**, and the SDK cannot guess
169
+ where your build published it.
170
+
171
+ By default the host anchors the worker to its own package layout:
172
+
173
+ ```js
174
+ new URL("./wasiThreadBrowserWorker.mjs", import.meta.url);
175
+ ```
176
+
177
+ That default is correct **only when this source is served unbundled** (Node, and
178
+ plain dev servers). Any bundler inlines the host and rewrites `import.meta.url`
179
+ to the *bundle's* URL — so the worker is requested next to your bundle, where it
180
+ was never emitted, and the request 404s. This shipped: an engine artifact asked
181
+ for `Build/CesiumUnminified/wasiThreadBrowserWorker.mjs` while the bucket served
182
+ the chain under `js/vendor/space-data-module-sdk/src/host/`.
183
+
184
+ **If you bundle the host, pass the anchor.** Two equivalent forms:
185
+
186
+ ```js
187
+ // A. Per-harness (or per-createWasiThreadSpawn) option.
188
+ await createBrowserModuleHarness({
189
+ wasmBytes,
190
+ // The directory YOUR build serves the SDK host chain from.
191
+ wasiThreadWorkerBaseUrl: "js/vendor/space-data-module-sdk/src/host/",
192
+ });
193
+
194
+ // B. Process-wide, installed once by the host shim.
195
+ import { setBrowserWasiThreadWorkerBase } from "space-data-module-sdk/browser";
196
+ setBrowserWasiThreadWorkerBase("js/vendor/space-data-module-sdk/src/host/");
197
+ ```
198
+
199
+ Resolution precedence, highest first — deterministic, and nothing else
200
+ participates:
201
+
202
+ | Source | Option / API |
203
+ | --- | --- |
204
+ | 1. Explicit worker file | `browserWorkerUrl` / `wasiThreadWorkerUrl` |
205
+ | 2. Explicit directory | `browserWorkerBaseUrl` / `wasiThreadWorkerBaseUrl` |
206
+ | 3. Process-wide base | `setBrowserWasiThreadWorkerBase(base)` |
207
+ | 4. Packaged sibling | `new URL("./wasiThreadBrowserWorker.mjs", import.meta.url)` |
208
+
209
+ Rules that make this contract honest:
210
+
211
+ - **The anchor names a DIRECTORY that serves the WHOLE chain.**
212
+ `wasiThreadBrowserWorker.mjs` imports `./wasiThreadWorkerRuntime.js`. Staging
213
+ the single `.mjs` next to your bundle does **not** work.
214
+ - **A relative base resolves against the document**; absolute URLs pass through
215
+ unchanged.
216
+ - **No consumer-side `location` sniffing.** Forking worker resolution per
217
+ consumer is not the contract; you already know your build's layout, so state
218
+ it.
219
+ - **No fetch-and-retry probe.** Resolution never touches the network: Node never
220
+ fetches, and browser thread count may not become a function of network timing.
221
+ - **An unreachable worker fails LOUD.** When the pooled path was requested
222
+ (threads enabled + cross-origin isolated + shared memory) and the worker asset
223
+ at the resolved anchor never loads, `createWasiThreadSpawn` **throws**
224
+ `WasiThreadWorkerUnreachableError` naming the URL it tried. It does not drop
225
+ quietly to one thread — a silent sequential fallback is how a deployment defect
226
+ hid behind a passing gate as a pure performance loss.
227
+
228
+ Genuine capability negotiation is unaffected and stays soft: a worker that loads
229
+ and reports it cannot instantiate the module, a probe timeout, a non-isolated
230
+ context, non-shared memory, or a 1-core host all still disable threading and let
231
+ the guest run its proven sequential path (`wasi.thread-spawn` -> `-1`).
232
+
165
233
  ## Tests
166
234
 
235
+ - `test/wasi-thread-bundled-consumer-anchor.test.js` — the **bundled-consumer
236
+ guardrail**: the host source is run through esbuild into a directory that does
237
+ not hold the worker chain (the published-bucket geometry), driven by a Worker
238
+ mock that resolves URLs on the filesystem the way a browser resolves them
239
+ against an origin. With no anchor the pooled path must throw
240
+ `WasiThreadWorkerUnreachableError` (the silent sequential fallback is a HARD
241
+ failure); with an explicit base — or the process-wide setter — the same bundle
242
+ arms its pool and spawns threads. Also pins the precedence table and asserts
243
+ the resolver neither fetches nor sniffs `location`.
244
+ - `test/wasi-thread-host-browser-pool.test.js` — warm-pool arming, short-circuit
245
+ on the first not-ready, probe-deadline bound, idle reuse/teardown, and the
246
+ fail-loud split between an unreachable worker asset and a negotiated fallback.
167
247
  - `test/pthreads-artifact-guardrail.test.js` — flag-assembler invariants; a
168
248
  positive compile that emits a validated wasi-threads shared-memory/atomics
169
249
  wasm; a single-thread artifact rejected; a **browser-only Emscripten `-pthread`
@@ -182,6 +262,10 @@ runtime — must be reported as such.
182
262
  - [`docs/browser-wasmedge-isomorphic.md`](./browser-wasmedge-isomorphic.md) —
183
263
  the one-artifact browser + WasmEdge loading profile.
184
264
  - `.claude/skills/wasmedge-pthreads/Skills.md` — the operating rules.
265
+ - `src/host/wasiThreadHost.js` — the isomorphic `wasi.thread-spawn` host:
266
+ `createWasiThreadSpawn`, the browser worker anchor
267
+ (`setBrowserWasiThreadWorkerBase`, `resolveBrowserWorkerUrl`), and
268
+ `WasiThreadWorkerUnreachableError`.
185
269
  - `src/compiler/pthreadArtifactGuard.js` — the flag list + wasm validator.
186
270
  - `src/compiler/wasiThreadsToolchain.js` — the wasi-threads toolchain resolver.
187
271
  - `src/compiler/compileModule.js` — `ModuleThreadModel`, `buildCompilerArgs`,