space-data-module-sdk 0.8.15 → 0.8.17

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 (130) hide show
  1. package/bin/space-data-module.js +24 -6
  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 +162 -0
  7. package/docs/conformance.md +20 -4
  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 +323 -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 +192 -0
  27. package/docs/families/estimation.md +158 -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 +347 -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 +97 -12
  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/provider-access-abi.md +25 -0
  65. package/docs/publication-submission.html +158 -0
  66. package/docs/publication-submission.md +78 -0
  67. package/docs/secrets-capability.html +206 -0
  68. package/docs/styles.css +860 -167
  69. package/docs/testing-harness.html +408 -0
  70. package/docs/tri-runtime-parity-gate.html +182 -0
  71. package/docs/tri-runtime-parity.html +203 -0
  72. package/include/orbpro/orbpro_estimation_abi.h +883 -0
  73. package/include/orbpro/orbpro_event_runner.h +951 -0
  74. package/include/orbpro/orbpro_events_abi.h +565 -0
  75. package/include/orbpro/orbpro_propagator_abi.h +75 -0
  76. package/package.json +13 -4
  77. package/schemas/orbpro/Estimation.fbs +244 -0
  78. package/schemas/orbpro/Events.fbs +501 -0
  79. package/schemas/orbpro/Propagator.fbs +136 -9
  80. package/schemas/orbpro/reference-frame-crosswalk.json +108 -0
  81. package/schemas/orbpro/reference-frame.lock.json +98 -0
  82. package/src/browser.js +13 -0
  83. package/src/conformance/estimationReference.js +81 -0
  84. package/src/conformance/estimationSuite.js +134 -0
  85. package/src/conformance/index.js +39 -2
  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 +38 -0
  91. package/src/generated/orbpro/propagator-abi.ts +67 -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/standards/sharedCatalog.js +7 -0
  124. package/src/transport/index.js +16 -0
  125. package/src/transport/records.js +1015 -3
  126. package/templates/estimation-module/README.md +24 -0
  127. package/templates/estimation-module/build.mjs +32 -0
  128. package/templates/estimation-module/package.json +12 -0
  129. package/templates/estimation-module/plugin-manifest.json +34 -0
  130. package/templates/estimation-module/src/reference_estimation.cpp +53 -0
@@ -41,31 +41,94 @@ attribute "abi_c_prefix";
41
41
  /// enum field. Writing these by hand is how padding bytes go stale.
42
42
  attribute "abi_c_helper_prefix";
43
43
 
44
- // !! FOUR INCOMPATIBLE `ReferenceFrame` VOCABULARIES CROSS THIS SEAM !!
45
- // This is the `orbpro.propagator` one. Its NUMERIC values are NOT
46
- // interchangeable with the others; translate by NAMED TOKEN at every seam.
44
+ // !! FIVE INCOMPATIBLE `ReferenceFrame` VOCABULARIES CROSS THIS SEAM, PLUS AN
45
+ // !! AXIS-TYPE VOCABULARY THAT IS NOT A ReferenceFrame AT ALL !!
46
+ // This is the `orbpro.propagator` one, and it is the ONE that crosses the ABI.
47
+ // The NUMERIC values below are NOT interchangeable with any of the others;
48
+ // translate by NAMED TOKEN at every seam.
47
49
  //
48
- // (A) orbpro.propagator (THIS) TEME=0 J2000=1 ICRF=2 ECEF=3 MCI=4 MCMF=5
50
+ // (A) orbpro.propagator (THIS) TEME=0 J2000=1 ICRF=2 ECEF=3 MCI=4 MCMF=5,
51
+ // then the appended axis roster at 6+
49
52
  // (B) orbpro.plugins ECI=0 ECEF=1 TEME=2 ICRF=3
50
53
  // (PropagatorState.fbs / "PRST" — the wire the compiled sgp4, hpop,
51
54
  // conjunction-assessment and sensor-shader modules already emit)
52
- // (C) Cesium.ReferenceFrame FIXED=0 INERTIAL=1
55
+ // (C) OrbPro engine ReferenceFrame.js — NINE members, not two:
56
+ // FIXED=0 INERTIAL=1 TEME=2 VVLH=3 ENU=4 NED=5 NEU=6 RIC=7 LVLH=8
57
+ // (verified on OrbPro 417320c5c5. The long-standing claim in this block
58
+ // that it was "Cesium.ReferenceFrame FIXED=0 INERTIAL=1" was stale, and
59
+ // stale in the direction that mattered: it hid seven live members.)
53
60
  // (D) ConjunctionCommon.fbs ECI=1
61
+ // (E) foundation/frames `AxisType` (space-data-network-modules) — an
62
+ // ORIENTATION RULE roster, mirroring SDS `rfmAxisType`. It is not a
63
+ // ReferenceFrame and must never be numerically equated with one: a
64
+ // coordinate system is an axis set AND an origin, and this enum carries
65
+ // no origin.
54
66
  //
55
67
  // ECI==0, TEME==0 and FIXED==0 all collide, and ECEF is 1 in (B) but 3 here.
56
68
  // (B)'s values are frozen by compiled WASM artifacts in the field, so
57
69
  // collapsing (A) and (B) is a wire break, not a Wave-0 edit — see
58
- // graph/tasks/sdk-reference-frame-enum-unification.md. The reference pattern
59
- // for a correct seam is propagator.hpop/index.js createSourceFromState.
70
+ // graph/tasks/sdk-reference-frame-enum-unification.md, which also owns the
71
+ // (A)-vs-(C) inversion at 0/1. The reference pattern for a correct seam is
72
+ // propagator.hpop/index.js createSourceFromState.
60
73
  //
61
- // Ruling: graph/findings/official-harness-shapes.md §4.2 / §8.2
74
+ // The crosswalk between all of these is DATA, in
75
+ // schemas/orbpro/reference-frame-crosswalk.json, and
76
+ // scripts/check-reference-frame-uniqueness.mjs holds it to this enum.
77
+ //
78
+ // Ruling: graph/findings/official-harness-shapes.md §4.2 / §8.2; Janus consult
79
+ // 2026-08-30 (gmat-08-frames-and-state-representations).
80
+ //
81
+ // VALUES 0-5 ARE FROZEN AND ARE NEVER RENUMBERED. New members are APPENDED.
82
+ // ECEF/MCI/MCMF are body-bound legacy instances of the generic pair at 11/12 —
83
+ // ECEF is BODY_FIXED about the Earth, MCI is BODY_INERTIAL about Mars, MCMF is
84
+ // BODY_FIXED about Mars. They are retained, and the generic members are NOT a
85
+ // second spelling of them.
62
86
  enum ReferenceFrame : ubyte (abi, abi_c_name: "OrbProReferenceFrame", abi_c_prefix: "ORBPRO_FRAME_") {
63
87
  TEME = 0,
64
88
  J2000 = 1,
65
89
  ICRF = 2,
66
90
  ECEF = 3,
67
91
  MCI = 4,
68
- MCMF = 5
92
+ MCMF = 5,
93
+ /// Mean ecliptic and equinox of J2000. (The mean EQUATOR and equinox of
94
+ /// J2000 is J2000 = 1 and is not repeated here.)
95
+ MJ2000EC = 6,
96
+ /// Mean equator of date.
97
+ MOD = 7,
98
+ /// True equator of date.
99
+ TOD = 8,
100
+ /// Mean ecliptic of date.
101
+ MOE = 9,
102
+ /// True ecliptic of date.
103
+ TOE = 10,
104
+ /// Axes rotating with a named body, per its published rotation elements.
105
+ BODY_FIXED = 11,
106
+ /// Non-rotating axes on a named body's equator and prime meridian.
107
+ BODY_INERTIAL = 12,
108
+ /// Axes built from the relative geometry of two named objects. The three
109
+ /// live RTN triads — RIC, RSW and RTN — are THIS member with an axes spec,
110
+ /// not three members; so are LVLH and VVLH.
111
+ OBJECT_REFERENCED = 13,
112
+ /// Axes built by aligning one vector and constraining a second.
113
+ LOCAL_ALIGNED_CONSTRAINED = 14,
114
+ /// A named body's equatorial plane at the epoch.
115
+ EQUATOR = 15,
116
+ /// Solar-ecliptic magnetospheric (GSE).
117
+ GSE = 16,
118
+ /// Solar magnetospheric (GSM).
119
+ GSM = 17,
120
+ /// Local horizon axes at a surface site.
121
+ TOPOCENTRIC = 18,
122
+ /// Axes fixed by a body's spin axis and its direction to the Sun.
123
+ BODY_SPIN_SUN = 19,
124
+ /// Axes declared by a loaded ephemeris/orientation kernel.
125
+ SPICE_DEFINED = 20,
126
+ /// LEGACY, retained and NAMED rather than left implicit: mean equator of
127
+ /// date on the IAU-76/FK5 theory. Differs from MOD at the milliarcsecond
128
+ /// level; the two are not interchangeable.
129
+ MOD_FK5 = 21,
130
+ /// LEGACY, retained and NAMED: true equator of date on IAU-76/FK5.
131
+ TOD_FK5 = 22
69
132
  }
70
133
 
71
134
  /// StateVector.flags is a BITFIELD carrying any OR-combination of these, so it
@@ -102,6 +165,70 @@ enum PropagatorSourceKind : ubyte {
102
165
  SDP8 = 12
103
166
  }
104
167
 
168
+ /// The negative return codes every propagator export shares.
169
+ ///
170
+ /// These were documented in docs/propagator-abi.md and declared NOWHERE, so
171
+ /// every module hand-typed them as literals and the contract lived only in
172
+ /// prose. A propagator that returns -1 for everything is unconformable — the
173
+ /// host cannot tell a bad entity index from an uninitialized module, so it
174
+ /// cannot place the failure on the degradation ladder — and the cheapest way
175
+ /// to end up there is having no names to return.
176
+ ///
177
+ /// VALUES ARE FROZEN. New classes are appended downward.
178
+ enum ErrorCode : byte (abi, abi_c_name: "OrbProPropagatorError", abi_c_prefix: "ORBPRO_PROP_") {
179
+ OK = 0,
180
+ /// No elements or ephemeris ingested yet.
181
+ NOT_INITIALIZED = -1,
182
+ /// Entity index at or beyond the entity count.
183
+ BAD_ENTITY_INDEX = -2,
184
+ /// The caller passed a null output pointer.
185
+ NULL_OUTPUT = -3,
186
+ /// Malformed or short input buffer.
187
+ BAD_INPUT = -4,
188
+ /// The solve failed to converge.
189
+ NOT_CONVERGED = -5,
190
+ /// The elements describe no closed orbit, or the result is not a number.
191
+ UNPHYSICAL = -6,
192
+ /// The ephemeris container is not one this module reads, or AUTO could not
193
+ /// identify it, or its declared frame has no member on the ReferenceFrame
194
+ /// roster.
195
+ UNSUPPORTED_FORMAT = -7,
196
+ /// The requested epoch lies outside every segment the loaded ephemeris
197
+ /// covers. A refusal, never a silent extrapolation: a caller cannot detect
198
+ /// an extrapolated state from the value alone.
199
+ EPOCH_OUT_OF_RANGE = -8
200
+ }
201
+
202
+ /// The container an ephemeris-driven propagator was handed on
203
+ /// `plugin_init_ephemeris`. A format is DATA, not identity: one ephemeris
204
+ /// provider reads every member below behind this discriminator rather than
205
+ /// shipping one artifact per container, because the interpolation, the time
206
+ /// scale handling and the frame rotation are shared and splitting them
207
+ /// re-creates the five-mirror drift this file exists to end.
208
+ ///
209
+ /// AUTO is the honest default: every container here is self-identifying in its
210
+ /// first bytes (`DAF/SPK ` / `NAIF/DAF`, the OEM version keyword, the STK
211
+ /// `stk.v.` banner, the SP3 `#d` line, the Code-500 fixed header block), so a
212
+ /// caller that does not know what it fetched says so rather than guessing. A
213
+ /// module that cannot identify the bytes returns UNSUPPORTED_FORMAT; it never
214
+ /// falls back to a default container.
215
+ ///
216
+ /// VALUES ARE FROZEN AND ARE NEVER RENUMBERED. New containers are APPENDED.
217
+ enum EphemerisFormat : ubyte (abi, abi_c_name: "OrbProEphemerisFormat", abi_c_prefix: "ORBPRO_EPHEM_FORMAT_") {
218
+ /// Identify the container from its own leading bytes.
219
+ AUTO = 0,
220
+ /// CCSDS Orbit Ephemeris Message, keyword-value notation.
221
+ CCSDS_OEM_KVN = 1,
222
+ /// NAIF Double Precision Array File carrying SPK segments.
223
+ SPK_DAF = 2,
224
+ /// Fixed-record binary ephemeris, 500-word logical records.
225
+ CODE500 = 3,
226
+ /// Ephemeris interchange text with a scenario epoch and typed data blocks.
227
+ STK_EPHEMERIS = 4,
228
+ /// Precise orbit product, revision d.
229
+ SP3_D = 5
230
+ }
231
+
105
232
  /// Orbital state vector — 64 bytes, 8-byte aligned. Mirrors
106
233
  /// `OrbProStateVector` in orbpro-integration/sdk/include/orbpro_propagator.h
107
234
  /// byte for byte:
@@ -0,0 +1,108 @@
1
+ {
2
+ "note": "Every ReferenceFrame-shaped vocabulary that crosses a seam with the orbpro.propagator ABI enum, and how each of its members maps ONTO that enum BY NAMED TOKEN. Numeric identity is never asserted across repositories: ECI==0, TEME==0 and FIXED==0 all collide, and ECEF is 1 in orbpro.plugins but 3 in the ABI. scripts/check-reference-frame-uniqueness.mjs holds this file and schemas/orbpro/Propagator.fbs to each other, and re-reads any listed source that is present on disk.",
3
+ "authority": "schemas/orbpro/Propagator.fbs :: enum ReferenceFrame",
4
+ "vocabularies": [
5
+ {
6
+ "id": "orbpro.plugins",
7
+ "description": "PropagatorState.fbs / \"PRST\" \u2014 the wire the compiled sgp4, hpop, conjunction-assessment and sensor-shader modules already emit. Its values are FROZEN by artifacts in the field; collapsing it into the ABI enum is a wire break, tracked as sdk-reference-frame-enum-unification.",
8
+ "repo": "space-data-network-modules",
9
+ "source": "propagator/sgp4/schemas/PropagatorState.fbs",
10
+ "members": {
11
+ "ECI": "ICRF",
12
+ "ECEF": "ECEF",
13
+ "TEME": "TEME",
14
+ "ICRF": "ICRF"
15
+ }
16
+ },
17
+ {
18
+ "id": "orbpro.engine",
19
+ "description": "The OrbPro engine's ReferenceFrame.js. NINE members, not the two this SDK's comment block claimed until 2026-08-30. FIXED/INERTIAL are INVERTED against the ABI's 0/1 \u2014 a live semantic difference, not a numbering accident \u2014 and reconciling that is sdk-reference-frame-enum-unification's job, not this crosswalk's. The four local orbital triads collapse onto OBJECT_REFERENCED with an axes spec.",
20
+ "repo": "OrbPro",
21
+ "source": "packages/engine/Source/Core/ReferenceFrame.js",
22
+ "members": {
23
+ "FIXED": "ECEF",
24
+ "INERTIAL": "ICRF",
25
+ "TEME": "TEME",
26
+ "VVLH": "OBJECT_REFERENCED",
27
+ "ENU": "TOPOCENTRIC",
28
+ "NED": "TOPOCENTRIC",
29
+ "NEU": "TOPOCENTRIC",
30
+ "RIC": "OBJECT_REFERENCED",
31
+ "LVLH": "OBJECT_REFERENCED"
32
+ }
33
+ },
34
+ {
35
+ "id": "orbpro.conjunction",
36
+ "description": "ConjunctionCommon.fbs, carried by the conjunction module.",
37
+ "repo": "space-data-network-modules",
38
+ "source": "analysis/conjunction-assessment/schemas/ConjunctionCommon.fbs",
39
+ "members": {
40
+ "UNKNOWN": null,
41
+ "ECI": "ICRF",
42
+ "ECEF": "ECEF",
43
+ "TEME": "TEME",
44
+ "ICRF": "ICRF"
45
+ }
46
+ },
47
+ {
48
+ "id": "modules.foundation.frames",
49
+ "description": "foundation/frames AxisType, mirroring SDS rfmAxisType. It is an ORIENTATION RULE roster and carries no origin, so it is not a ReferenceFrame; the mapping below is the axis half only, and a consumer still needs the RFMOrigin to have a coordinate system.",
50
+ "repo": "space-data-network-modules",
51
+ "source": "foundation/frames/src/axis_engine.hpp",
52
+ "members": {
53
+ "UNSPECIFIED": null,
54
+ "MJ2000EQ": "J2000",
55
+ "MJ2000EC": "MJ2000EC",
56
+ "ICRF": "ICRF",
57
+ "TEME": "TEME",
58
+ "MOD": "MOD",
59
+ "TOD": "TOD",
60
+ "MOE": "MOE",
61
+ "TOE": "TOE",
62
+ "BODY_FIXED": "BODY_FIXED",
63
+ "BODY_INERTIAL": "BODY_INERTIAL",
64
+ "OBJECT_REFERENCED": "OBJECT_REFERENCED",
65
+ "LOCAL_ALIGNED_CONSTRAINED": "LOCAL_ALIGNED_CONSTRAINED",
66
+ "EQUATOR": "EQUATOR",
67
+ "GSE": "GSE",
68
+ "GSM": "GSM",
69
+ "TOPOCENTRIC": "TOPOCENTRIC",
70
+ "BODY_SPIN_SUN": "BODY_SPIN_SUN",
71
+ "SPICE_DEFINED": "SPICE_DEFINED",
72
+ "MOD_FK5": "MOD_FK5",
73
+ "TOD_FK5": "TOD_FK5",
74
+ "ITRF": "ECEF"
75
+ }
76
+ },
77
+ {
78
+ "id": "modules.hpop.coords",
79
+ "description": "The HPOP propagator's internal chain vocabulary.",
80
+ "repo": "space-data-network-modules",
81
+ "source": "propagator/hpop/lib/coords_types.h",
82
+ "members": {
83
+ "TEME": "TEME",
84
+ "GCRF": "ICRF",
85
+ "ITRF": "ECEF",
86
+ "J2000": "J2000",
87
+ "ECEF": "ECEF",
88
+ "TOD": "TOD",
89
+ "MOD": "MOD"
90
+ }
91
+ }
92
+ ],
93
+ "rtnConvention": {
94
+ "abiMember": "OBJECT_REFERENCED",
95
+ "note": "The three live RTN triads collapse to ONE ABI member plus an axes spec. RIC, RSW and RTN name the SAME triad (x radial, z orbit normal, y completing); LVLH and VVLH are relabellings of it produced by naming a different primary. None of them is a separate ReferenceFrame, and adding a second RTN-named ABI member is a defect this check refuses.",
96
+ "aliases": [
97
+ "RIC",
98
+ "RSW",
99
+ "RTN",
100
+ "LVLH",
101
+ "VVLH",
102
+ "QSW",
103
+ "NTW",
104
+ "TNW",
105
+ "UVW"
106
+ ]
107
+ }
108
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "note": "The committed numbering of the ONE ReferenceFrame enum that crosses the ABI seam. scripts/check-reference-frame-uniqueness.mjs holds schemas/orbpro/Propagator.fbs to this file: values 0-5 are FROZEN and no member may ever be renamed, renumbered or removed. Appending a member means appending a row here in the same commit.",
3
+ "frozenThrough": 5,
4
+ "members": [
5
+ {
6
+ "name": "TEME",
7
+ "value": 0
8
+ },
9
+ {
10
+ "name": "J2000",
11
+ "value": 1
12
+ },
13
+ {
14
+ "name": "ICRF",
15
+ "value": 2
16
+ },
17
+ {
18
+ "name": "ECEF",
19
+ "value": 3
20
+ },
21
+ {
22
+ "name": "MCI",
23
+ "value": 4
24
+ },
25
+ {
26
+ "name": "MCMF",
27
+ "value": 5
28
+ },
29
+ {
30
+ "name": "MJ2000EC",
31
+ "value": 6
32
+ },
33
+ {
34
+ "name": "MOD",
35
+ "value": 7
36
+ },
37
+ {
38
+ "name": "TOD",
39
+ "value": 8
40
+ },
41
+ {
42
+ "name": "MOE",
43
+ "value": 9
44
+ },
45
+ {
46
+ "name": "TOE",
47
+ "value": 10
48
+ },
49
+ {
50
+ "name": "BODY_FIXED",
51
+ "value": 11
52
+ },
53
+ {
54
+ "name": "BODY_INERTIAL",
55
+ "value": 12
56
+ },
57
+ {
58
+ "name": "OBJECT_REFERENCED",
59
+ "value": 13
60
+ },
61
+ {
62
+ "name": "LOCAL_ALIGNED_CONSTRAINED",
63
+ "value": 14
64
+ },
65
+ {
66
+ "name": "EQUATOR",
67
+ "value": 15
68
+ },
69
+ {
70
+ "name": "GSE",
71
+ "value": 16
72
+ },
73
+ {
74
+ "name": "GSM",
75
+ "value": 17
76
+ },
77
+ {
78
+ "name": "TOPOCENTRIC",
79
+ "value": 18
80
+ },
81
+ {
82
+ "name": "BODY_SPIN_SUN",
83
+ "value": 19
84
+ },
85
+ {
86
+ "name": "SPICE_DEFINED",
87
+ "value": 20
88
+ },
89
+ {
90
+ "name": "MOD_FK5",
91
+ "value": 21
92
+ },
93
+ {
94
+ "name": "TOD_FK5",
95
+ "value": 22
96
+ }
97
+ ]
98
+ }
package/src/browser.js CHANGED
@@ -29,6 +29,19 @@ export {
29
29
  zeroWasmBytes,
30
30
  isSharedArrayBufferLike,
31
31
  } from "./host/browserModuleHarness.js";
32
+ // The wasi-threads BROWSER WORKER ANCHOR. A bundling consumer MUST tell the SDK
33
+ // where its build serves the host worker chain from — `import.meta.url` inside a
34
+ // bundle points at the bundle, not at the package layout, and the worker 404s
35
+ // (fail-loud: WasiThreadWorkerUnreachableError). Either call
36
+ // `setBrowserWasiThreadWorkerBase(...)` once in the host shim, or pass
37
+ // `wasiThreadWorkerBaseUrl` to `createBrowserModuleHarness`.
38
+ export {
39
+ setBrowserWasiThreadWorkerBase,
40
+ getBrowserWasiThreadWorkerBase,
41
+ resolveBrowserWorkerUrl,
42
+ DEFAULT_BROWSER_WORKER_URL,
43
+ WasiThreadWorkerUnreachableError,
44
+ } from "./host/wasiThreadHost.js";
32
45
  // The runtime-target gate is reachable so a consumer can catch the refusal by
33
46
  // CLASS (`error instanceof RuntimeTargetError`) rather than by matching a
34
47
  // message string, and can ask the same question the loaders ask before it
@@ -0,0 +1,81 @@
1
+ /**
2
+ * A deterministic, non-physics reference receipt for exercising the
3
+ * estimation-family conformance evaluator. Real modules replace every value
4
+ * with measurements produced by their compiled WASM artifact. Keeping the
5
+ * evaluator's own known-good input here lets the negative controls prove that
6
+ * each required lane can fail without shipping a second JS estimator.
7
+ */
8
+
9
+ const reference = {
10
+ schemaVersion: 1,
11
+ family: "estimation",
12
+ artifact: { sha256: "reference-estimation-artifact" },
13
+ runtime: {
14
+ browser: { outputSha256: "reference-output" },
15
+ wasmedge: { outputSha256: "reference-output" },
16
+ threads: {
17
+ "1": "reference-output",
18
+ "2": "reference-output",
19
+ "4": "reference-output",
20
+ "8": "reference-output",
21
+ },
22
+ },
23
+ batch: {
24
+ positionAbsoluteErrorM: 0.25,
25
+ positionRelativeError: 4e-8,
26
+ covarianceRssRelativeError: 0.02,
27
+ residualRmsRelativeError: 2e-8,
28
+ rejectedExpected: [7, 19],
29
+ rejectedActual: [7, 19],
30
+ iterationCount: 4,
31
+ iterationCovarianceCount: 4,
32
+ iterationCovariancesSpd: true,
33
+ },
34
+ filter: {
35
+ positionErrorM: 0.65,
36
+ smootherPositionErrorM: 0.21,
37
+ smootherCovarianceMonotone: true,
38
+ neesMean: 6.02,
39
+ nees95Lower: 5.34,
40
+ nees95Upper: 6.70,
41
+ sncCovarianceGrowthRatio: 1.21,
42
+ dmcCovarianceGrowthRatio: 1.58,
43
+ ekfUkfCovarianceDifference: 0.08,
44
+ },
45
+ measurements: {
46
+ rangeMaxRelativeError: 6e-16,
47
+ rangeRateMaxRelativeError: 5e-16,
48
+ azElMaxRelativeError: 5e-16,
49
+ raDecMaxRelativeError: 5e-16,
50
+ lightTimeMagnitudeErrorM: 2e-10,
51
+ sagnacMagnitudeErrorM: 2e-10,
52
+ },
53
+ media: {
54
+ hopfieldSaastamoinenMaxRelativeError: 6e-5,
55
+ mariniMaxRelativeError: 7e-5,
56
+ p531PublishedPrecisionError: 0,
57
+ },
58
+ iod: {
59
+ gaussPrintedPrecisionError: 0,
60
+ laplacePrintedPrecisionError: 0,
61
+ gibbsPrintedPrecisionError: 0,
62
+ herrickGibbsPrintedPrecisionError: 0,
63
+ },
64
+ simulator: {
65
+ runs: 200,
66
+ stateInsideThreeSigmaFraction: 0.965,
67
+ recoveredNoiseSigmaRelativeError: 0.031,
68
+ },
69
+ invariants: {
70
+ covarianceSymmetric: true,
71
+ covariancePositiveDefinite: true,
72
+ residualOrthogonalityMax: 3e-11,
73
+ actualOcmCovariance: true,
74
+ },
75
+ };
76
+
77
+ export const ESTIMATION_REFERENCE_EVIDENCE = Object.freeze(reference);
78
+
79
+ export function makeEstimationReferenceEvidence() {
80
+ return structuredClone(reference);
81
+ }
@@ -0,0 +1,134 @@
1
+ /** Estimation-family conformance receipt evaluator. No physics lives here. */
2
+
3
+ import { computeVerdict } from "./propagatorSuite.js";
4
+
5
+ const pass = (id, tier, detail) => ({ id, tier, required: true, status: "pass", detail });
6
+ const fail = (id, tier, detail) => ({ id, tier, required: true, status: "fail", detail });
7
+
8
+ function check(checks, id, tier, condition, detail, failure = detail) {
9
+ checks.push(condition ? pass(id, tier, detail) : fail(id, tier, failure));
10
+ }
11
+
12
+ function finiteAtMost(value, limit) {
13
+ return Number.isFinite(value) && value <= limit;
14
+ }
15
+
16
+ function sameSet(left = [], right = []) {
17
+ const a = [...new Set(left)].sort((x, y) => x - y);
18
+ const b = [...new Set(right)].sort((x, y) => x - y);
19
+ return a.length === b.length && a.every((value, index) => value === b[index]);
20
+ }
21
+
22
+ export function runEstimationSuite(evidence) {
23
+ const checks = [];
24
+ const runtimeHashes = [
25
+ evidence?.runtime?.browser?.outputSha256,
26
+ evidence?.runtime?.wasmedge?.outputSha256,
27
+ evidence?.runtime?.threads?.["1"],
28
+ evidence?.runtime?.threads?.["2"],
29
+ evidence?.runtime?.threads?.["4"],
30
+ evidence?.runtime?.threads?.["8"],
31
+ ];
32
+ check(checks, "tier0/tri-runtime-byte-identity", "0",
33
+ runtimeHashes.every(Boolean) && new Set(runtimeHashes).size === 1,
34
+ "browser, WasmEdge and worker widths 1/2/4/8 emitted byte-identical results",
35
+ "missing or divergent browser/WasmEdge/thread-width output digests");
36
+
37
+ const batch = evidence?.batch ?? {};
38
+ check(checks, "tierA/batch-state", "A",
39
+ finiteAtMost(batch.positionAbsoluteErrorM, 1) &&
40
+ finiteAtMost(batch.positionRelativeError, 1e-3),
41
+ `absolute=${batch.positionAbsoluteErrorM} m relative=${batch.positionRelativeError}`,
42
+ "batch state exceeds 1 m absolute or 1e-3 relative");
43
+ check(checks, "tierA/batch-covariance", "A",
44
+ finiteAtMost(batch.covarianceRssRelativeError, 0.05),
45
+ `RSS position sigma relative error=${batch.covarianceRssRelativeError}`,
46
+ "batch covariance RSS differs from authority by more than 5%");
47
+ check(checks, "tierA/batch-residual-rms", "A",
48
+ finiteAtMost(batch.residualRmsRelativeError, 1e-6),
49
+ `residual RMS relative error=${batch.residualRmsRelativeError}`,
50
+ "batch residual RMS differs from authority by more than 1e-6 relative");
51
+ check(checks, "tierA/sigma-edit-set", "A",
52
+ sameSet(batch.rejectedExpected, batch.rejectedActual),
53
+ `exact rejected set [${batch.rejectedActual ?? []}]`,
54
+ "sigma editing rejected a different observation set");
55
+ check(checks, "tierC/batch-iteration-covariance", "C",
56
+ Number.isInteger(batch.iterationCount) && batch.iterationCount > 0 &&
57
+ batch.iterationCovarianceCount === batch.iterationCount &&
58
+ batch.iterationCovariancesSpd === true,
59
+ `${batch.iterationCovarianceCount}/${batch.iterationCount} iteration covariances are SPD`,
60
+ "batch iteration covariance history is missing, incomplete, or not SPD");
61
+
62
+ const filter = evidence?.filter ?? {};
63
+ check(checks, "tierA/filter-and-smoother-state", "A",
64
+ finiteAtMost(filter.positionErrorM, 1) &&
65
+ finiteAtMost(filter.smootherPositionErrorM, 0.5),
66
+ `filter=${filter.positionErrorM} m smoother=${filter.smootherPositionErrorM} m`,
67
+ "filter exceeds 1 m or RTS smoother exceeds 0.5 m");
68
+ check(checks, "tierC/smoother-covariance", "C",
69
+ filter.smootherCovarianceMonotone === true,
70
+ "smoothed covariance is no larger than filtered covariance at every epoch");
71
+ check(checks, "tierC/nees-100-run", "C",
72
+ Number.isFinite(filter.neesMean) && filter.neesMean >= filter.nees95Lower &&
73
+ filter.neesMean <= filter.nees95Upper,
74
+ `NEES mean=${filter.neesMean} band=[${filter.nees95Lower},${filter.nees95Upper}]`,
75
+ "100-run NEES lies outside the declared chi-square 95% band");
76
+ check(checks, "tierC/process-noise", "C",
77
+ Number.isFinite(filter.sncCovarianceGrowthRatio) && filter.sncCovarianceGrowthRatio !== 1 &&
78
+ Number.isFinite(filter.dmcCovarianceGrowthRatio) && filter.dmcCovarianceGrowthRatio !== 1,
79
+ `SNC ratio=${filter.sncCovarianceGrowthRatio} DMC ratio=${filter.dmcCovarianceGrowthRatio}`,
80
+ "SNC or DMC failed to change covariance growth");
81
+ check(checks, "tierC/ekf-ukf-not-aliased", "C",
82
+ Number.isFinite(filter.ekfUkfCovarianceDifference) && filter.ekfUkfCovarianceDifference > 0,
83
+ `covariance history distance=${filter.ekfUkfCovarianceDifference}`,
84
+ "EKF and UKF covariance histories are identical");
85
+
86
+ const measurement = evidence?.measurements ?? {};
87
+ for (const [name, key] of [["range", "rangeMaxRelativeError"],
88
+ ["range-rate", "rangeRateMaxRelativeError"], ["az-el", "azElMaxRelativeError"],
89
+ ["ra-dec", "raDecMaxRelativeError"]]) {
90
+ check(checks, `tierA/measurement-${name}`, "A", finiteAtMost(measurement[key], 1e-6),
91
+ `max relative error=${measurement[key]}`, `${name} exceeds 1e-6 relative`);
92
+ }
93
+ check(checks, "tierA/light-time", "A", finiteAtMost(measurement.lightTimeMagnitudeErrorM, 1e-6),
94
+ `magnitude error=${measurement.lightTimeMagnitudeErrorM} m`);
95
+ check(checks, "tierA/sagnac", "A", finiteAtMost(measurement.sagnacMagnitudeErrorM, 1e-6),
96
+ `magnitude error=${measurement.sagnacMagnitudeErrorM} m`);
97
+
98
+ const media = evidence?.media ?? {};
99
+ check(checks, "tierA/troposphere-hopfield-saastamoinen", "A",
100
+ finiteAtMost(media.hopfieldSaastamoinenMaxRelativeError, 1e-4),
101
+ `relative error=${media.hopfieldSaastamoinenMaxRelativeError}`);
102
+ check(checks, "tierA/troposphere-marini", "A",
103
+ finiteAtMost(media.mariniMaxRelativeError, 1e-4),
104
+ `relative error=${media.mariniMaxRelativeError}`);
105
+ check(checks, "tierB/ionosphere-p531", "B", media.p531PublishedPrecisionError === 0,
106
+ "P.531 table value reproduced to published precision");
107
+
108
+ for (const [name, key] of [["gauss", "gaussPrintedPrecisionError"],
109
+ ["laplace", "laplacePrintedPrecisionError"], ["gibbs", "gibbsPrintedPrecisionError"],
110
+ ["herrick-gibbs", "herrickGibbsPrintedPrecisionError"]]) {
111
+ check(checks, `tierB/iod-${name}`, "B", evidence?.iod?.[key] === 0,
112
+ "Vallado worked example reproduced to printed precision");
113
+ }
114
+
115
+ const simulator = evidence?.simulator ?? {};
116
+ check(checks, "tierC/simulator-coverage", "C",
117
+ simulator.runs >= 200 && simulator.stateInsideThreeSigmaFraction >= 0.95,
118
+ `${simulator.stateInsideThreeSigmaFraction} inside 3-sigma over ${simulator.runs} runs`);
119
+ check(checks, "tierC/simulator-noise-recovery", "C",
120
+ finiteAtMost(simulator.recoveredNoiseSigmaRelativeError, 0.05),
121
+ `noise sigma relative error=${simulator.recoveredNoiseSigmaRelativeError}`);
122
+
123
+ const invariants = evidence?.invariants ?? {};
124
+ check(checks, "tierC/covariance-spd", "C",
125
+ invariants.covarianceSymmetric === true && invariants.covariancePositiveDefinite === true,
126
+ "covariance is symmetric positive definite");
127
+ check(checks, "tierC/residual-orthogonality", "C",
128
+ finiteAtMost(invariants.residualOrthogonalityMax, 1e-6),
129
+ `max normalized normal-equation projection=${invariants.residualOrthogonalityMax}`);
130
+ check(checks, "tierC/ocm-covariance", "C", invariants.actualOcmCovariance === true,
131
+ "the emitted OCM carries the estimator covariance");
132
+
133
+ return { checks, verdict: computeVerdict(checks) };
134
+ }