space-data-module-sdk 0.8.16 → 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.
- package/bin/space-data-module.js +24 -6
- package/docs/browser-wasmedge-isomorphic.html +1 -1
- package/docs/byo-wasm-quickstart.html +1 -1
- package/docs/conformance.html +10 -4
- package/docs/conformance.md +20 -4
- package/docs/events-abi.html +1 -1
- package/docs/families/analytics.html +1 -1
- package/docs/families/attitude.html +1 -1
- package/docs/families/behavior.html +1 -1
- package/docs/families/breakup.html +1 -1
- package/docs/families/conjunction.html +1 -1
- package/docs/families/data-source.html +7 -2
- package/docs/families/effects.html +1 -1
- package/docs/families/environment.html +1 -1
- package/docs/families/estimation.html +56 -54
- package/docs/families/estimation.md +155 -125
- package/docs/families/gnc.html +1 -1
- package/docs/families/maneuver.html +1 -1
- package/docs/families/obstruction.html +1 -1
- package/docs/families/propagator.html +16 -2
- package/docs/families/propulsion.html +1 -1
- package/docs/families/reentry.html +1 -1
- package/docs/families/rf.html +1 -1
- package/docs/families/scheduler.html +1 -1
- package/docs/families/sensor.html +1 -1
- package/docs/families/signature.html +1 -1
- package/docs/flatsql-host-contract.html +1 -1
- package/docs/flatsql-streaming-standard.html +1 -1
- package/docs/gpu-module-abi.html +1 -1
- package/docs/harness-family-matrix.md +7 -7
- package/docs/index.html +2 -2
- package/docs/isomorphic-pthreads.html +1 -1
- package/docs/isomorphic-sdn-runtime-plan.html +1 -1
- package/docs/language-runtime-matrix.html +1 -1
- package/docs/llms.txt +1 -1
- package/docs/module-bundle-runtime-plan.html +1 -1
- package/docs/module-publication-standard.html +1 -1
- package/docs/node-red-default-node-parity.html +1 -1
- package/docs/propagator-abi.md +52 -0
- package/docs/protect-and-sign.html +1 -1
- package/docs/protocol-installation.html +1 -1
- package/docs/provider-access-abi.md +25 -0
- package/docs/publication-submission.html +1 -1
- package/docs/secrets-capability.html +1 -1
- package/docs/testing-harness.html +1 -1
- package/docs/tri-runtime-parity-gate.html +1 -1
- package/docs/tri-runtime-parity.html +1 -1
- package/include/orbpro/orbpro_estimation_abi.h +883 -0
- package/include/orbpro/orbpro_propagator_abi.h +58 -0
- package/package.json +4 -2
- package/schemas/orbpro/Estimation.fbs +244 -0
- package/schemas/orbpro/Propagator.fbs +64 -0
- package/src/conformance/estimationReference.js +81 -0
- package/src/conformance/estimationSuite.js +134 -0
- package/src/conformance/index.js +39 -2
- package/src/generated/orbpro/propagator-abi.js +21 -0
- package/src/generated/orbpro/propagator-abi.ts +50 -0
- package/src/standards/sharedCatalog.js +7 -0
- package/templates/estimation-module/README.md +24 -0
- package/templates/estimation-module/build.mjs +32 -0
- package/templates/estimation-module/package.json +12 -0
- package/templates/estimation-module/plugin-manifest.json +34 -0
- package/templates/estimation-module/src/reference_estimation.cpp +53 -0
package/src/conformance/index.js
CHANGED
|
@@ -19,6 +19,8 @@ import path from "node:path";
|
|
|
19
19
|
|
|
20
20
|
import { loadPropagatorArtifact } from "./abiDriver.js";
|
|
21
21
|
import { computeVerdict, runPropagatorSuite } from "./propagatorSuite.js";
|
|
22
|
+
import { runEstimationSuite } from "./estimationSuite.js";
|
|
23
|
+
import { makeEstimationReferenceEvidence } from "./estimationReference.js";
|
|
22
24
|
|
|
23
25
|
export { ErrorCode, REQUIRED_ABI_EXPORTS } from "./abiDriver.js";
|
|
24
26
|
export {
|
|
@@ -34,14 +36,14 @@ export { runPropagatorSelfTest, formatSelfTestReport } from "./selfTest.js";
|
|
|
34
36
|
* never coerced — the ANALYSIS fallback was the namespace corruption the
|
|
35
37
|
* finding killed.
|
|
36
38
|
*/
|
|
37
|
-
export const CONFORMANCE_FAMILIES = Object.freeze(["propagator"]);
|
|
39
|
+
export const CONFORMANCE_FAMILIES = Object.freeze(["estimation", "propagator"]);
|
|
38
40
|
|
|
39
41
|
export class UnknownConformanceFamilyError extends Error {
|
|
40
42
|
constructor(family) {
|
|
41
43
|
super(
|
|
42
44
|
`no conformance kit for family "${family}" — kits exist for: ` +
|
|
43
45
|
`${CONFORMANCE_FAMILIES.join(", ")}. A family with no kit can never be CORE ` +
|
|
44
|
-
"(finding §5); maneuver
|
|
46
|
+
"(finding §5); maneuver remains Wave 2.",
|
|
45
47
|
);
|
|
46
48
|
this.name = "UnknownConformanceFamilyError";
|
|
47
49
|
this.family = family;
|
|
@@ -93,6 +95,23 @@ export async function runConformance(options) {
|
|
|
93
95
|
if (!CONFORMANCE_FAMILIES.includes(family)) {
|
|
94
96
|
throw new UnknownConformanceFamilyError(options.family);
|
|
95
97
|
}
|
|
98
|
+
if (family === "estimation") {
|
|
99
|
+
const evidence = options.evidence ?? JSON.parse(
|
|
100
|
+
await fs.readFile(path.resolve(options.evidencePath), "utf8"),
|
|
101
|
+
);
|
|
102
|
+
const evaluated = runEstimationSuite(evidence);
|
|
103
|
+
let artifact = evidence.artifact ?? null;
|
|
104
|
+
if (options.artifactPath) {
|
|
105
|
+
const artifactPath = path.resolve(options.artifactPath);
|
|
106
|
+
const artifactBytes = await fs.readFile(artifactPath);
|
|
107
|
+
artifact = {
|
|
108
|
+
path: artifactPath,
|
|
109
|
+
sha256: crypto.createHash("sha256").update(artifactBytes).digest("hex"),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { family, artifact, corpus: null, evidence: options.evidencePath ?? null, ...evaluated };
|
|
113
|
+
}
|
|
114
|
+
|
|
96
115
|
const artifactPath = path.resolve(options.artifactPath);
|
|
97
116
|
const artifactBytes = await fs.readFile(artifactPath);
|
|
98
117
|
const artifactSha256 = crypto
|
|
@@ -129,6 +148,24 @@ export async function runConformance(options) {
|
|
|
129
148
|
};
|
|
130
149
|
}
|
|
131
150
|
|
|
151
|
+
export { runEstimationSuite } from "./estimationSuite.js";
|
|
152
|
+
export { makeEstimationReferenceEvidence } from "./estimationReference.js";
|
|
153
|
+
|
|
154
|
+
export async function runEstimationSelfTest() {
|
|
155
|
+
const controls = [];
|
|
156
|
+
for (const [id, mutate] of [
|
|
157
|
+
["runtime-divergence", (e) => { e.runtime.threads["8"] = "different"; }],
|
|
158
|
+
["ekf-ukf-alias", (e) => { e.filter.ekfUkfCovarianceDifference = 0; }],
|
|
159
|
+
["covariance-placeholder", (e) => { e.invariants.actualOcmCovariance = false; }],
|
|
160
|
+
]) {
|
|
161
|
+
const evidence = makeEstimationReferenceEvidence();
|
|
162
|
+
mutate(evidence);
|
|
163
|
+
const report = runEstimationSuite(evidence);
|
|
164
|
+
controls.push({ id, caught: report.verdict === "FAIL" });
|
|
165
|
+
}
|
|
166
|
+
return { ok: controls.every((control) => control.caught), controls };
|
|
167
|
+
}
|
|
168
|
+
|
|
132
169
|
export function formatConformanceReport(report) {
|
|
133
170
|
const lines = [];
|
|
134
171
|
lines.push(`conformance ${report.family} — ${report.verdict}`);
|
|
@@ -47,6 +47,27 @@ export const StateFlags = Object.freeze({
|
|
|
47
47
|
HAS_COVARIANCE: 32,
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
+
export const ErrorCode = Object.freeze({
|
|
51
|
+
OK: 0,
|
|
52
|
+
NOT_INITIALIZED: -1,
|
|
53
|
+
BAD_ENTITY_INDEX: -2,
|
|
54
|
+
NULL_OUTPUT: -3,
|
|
55
|
+
BAD_INPUT: -4,
|
|
56
|
+
NOT_CONVERGED: -5,
|
|
57
|
+
UNPHYSICAL: -6,
|
|
58
|
+
UNSUPPORTED_FORMAT: -7,
|
|
59
|
+
EPOCH_OUT_OF_RANGE: -8,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const EphemerisFormat = Object.freeze({
|
|
63
|
+
AUTO: 0,
|
|
64
|
+
CCSDS_OEM_KVN: 1,
|
|
65
|
+
SPK_DAF: 2,
|
|
66
|
+
CODE500: 3,
|
|
67
|
+
STK_EPHEMERIS: 4,
|
|
68
|
+
SP3_D: 5,
|
|
69
|
+
});
|
|
70
|
+
|
|
50
71
|
export const ORBPRO_STATE_VECTOR = Object.freeze({
|
|
51
72
|
name: "StateVector",
|
|
52
73
|
cName: "OrbProStateVector",
|
|
@@ -53,6 +53,56 @@ export enum StateFlags {
|
|
|
53
53
|
HAS_COVARIANCE = 32,
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* The negative return codes every propagator export shares.
|
|
58
|
+
*
|
|
59
|
+
* These were documented in docs/propagator-abi.md and declared NOWHERE, so
|
|
60
|
+
* every module hand-typed them as literals and the contract lived only in
|
|
61
|
+
* prose. A propagator that returns -1 for everything is unconformable — the
|
|
62
|
+
* host cannot tell a bad entity index from an uninitialized module, so it
|
|
63
|
+
* cannot place the failure on the degradation ladder — and the cheapest way
|
|
64
|
+
* to end up there is having no names to return.
|
|
65
|
+
*
|
|
66
|
+
* VALUES ARE FROZEN. New classes are appended downward.
|
|
67
|
+
*/
|
|
68
|
+
export enum ErrorCode {
|
|
69
|
+
OK = 0,
|
|
70
|
+
NOT_INITIALIZED = -1,
|
|
71
|
+
BAD_ENTITY_INDEX = -2,
|
|
72
|
+
NULL_OUTPUT = -3,
|
|
73
|
+
BAD_INPUT = -4,
|
|
74
|
+
NOT_CONVERGED = -5,
|
|
75
|
+
UNPHYSICAL = -6,
|
|
76
|
+
UNSUPPORTED_FORMAT = -7,
|
|
77
|
+
EPOCH_OUT_OF_RANGE = -8,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The container an ephemeris-driven propagator was handed on
|
|
82
|
+
* `plugin_init_ephemeris`. A format is DATA, not identity: one ephemeris
|
|
83
|
+
* provider reads every member below behind this discriminator rather than
|
|
84
|
+
* shipping one artifact per container, because the interpolation, the time
|
|
85
|
+
* scale handling and the frame rotation are shared and splitting them
|
|
86
|
+
* re-creates the five-mirror drift this file exists to end.
|
|
87
|
+
*
|
|
88
|
+
* AUTO is the honest default: every container here is self-identifying in its
|
|
89
|
+
* first bytes (`DAF/SPK ` / `NAIF/DAF`, the OEM version keyword, the STK
|
|
90
|
+
* `stk.v.` banner, the SP3 `#d` line, the Code-500 fixed header block), so a
|
|
91
|
+
* caller that does not know what it fetched says so rather than guessing. A
|
|
92
|
+
* module that cannot identify the bytes returns UNSUPPORTED_FORMAT; it never
|
|
93
|
+
* falls back to a default container.
|
|
94
|
+
*
|
|
95
|
+
* VALUES ARE FROZEN AND ARE NEVER RENUMBERED. New containers are APPENDED.
|
|
96
|
+
*/
|
|
97
|
+
export enum EphemerisFormat {
|
|
98
|
+
AUTO = 0,
|
|
99
|
+
CCSDS_OEM_KVN = 1,
|
|
100
|
+
SPK_DAF = 2,
|
|
101
|
+
CODE500 = 3,
|
|
102
|
+
STK_EPHEMERIS = 4,
|
|
103
|
+
SP3_D = 5,
|
|
104
|
+
}
|
|
105
|
+
|
|
56
106
|
/** One field's placement inside an ABI struct. */
|
|
57
107
|
export interface AbiField {
|
|
58
108
|
readonly offset: number;
|
|
@@ -219,6 +219,13 @@ const sharedModuleCatalogEntries = [
|
|
|
219
219
|
fileIdentifier: "PRST",
|
|
220
220
|
source: "orbpro-propagator",
|
|
221
221
|
},
|
|
222
|
+
{
|
|
223
|
+
schemaCode: "ESTIMATION",
|
|
224
|
+
schemaName: "Estimation.fbs",
|
|
225
|
+
fileIdentifier: "$EST",
|
|
226
|
+
rootTypeName: "EstimationEnvelope",
|
|
227
|
+
source: "orbpro-estimation",
|
|
228
|
+
},
|
|
222
229
|
{
|
|
223
230
|
schemaCode: "ACCESSWINDOWREQUEST",
|
|
224
231
|
schemaName: "AccessWindowRequest.fbs",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Estimation reference module
|
|
2
|
+
|
|
3
|
+
This is the force-model-blind reference implementation for the fixed
|
|
4
|
+
estimation ABI. It demonstrates one covariance-form position update using an
|
|
5
|
+
`OrbProEstimationPropagatorSample` supplied by the caller. It never propagates
|
|
6
|
+
an orbit and never names a provider: production estimators obtain state and
|
|
7
|
+
STM samples from the caller-selected `plugin_propagate` /
|
|
8
|
+
`plugin_compute_stm` port.
|
|
9
|
+
|
|
10
|
+
The reference export is:
|
|
11
|
+
|
|
12
|
+
```c
|
|
13
|
+
int32_t orbpro_estimation_reference_position_update(
|
|
14
|
+
const OrbProEstimationConfig*,
|
|
15
|
+
const OrbProEstimationObservation*,
|
|
16
|
+
const OrbProEstimationPropagatorSample*,
|
|
17
|
+
OrbProEstimationState*);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
It accepts only a three-lane `POSITION_VECTOR` observation. That narrow shape
|
|
21
|
+
is deliberate: the reference proves ABI layout, covariance update, typed
|
|
22
|
+
refusal and deterministic bytes. The estimation conformance kit adjudicates
|
|
23
|
+
full modules against Orekit, Vallado, media, Monte-Carlo and runtime evidence.
|
|
24
|
+
It is not a second JS physics implementation.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { compileModuleFromSource } from "space-data-module-sdk/compiler";
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const root = fileURLToPath(new URL(".", import.meta.url));
|
|
10
|
+
const manifest = JSON.parse(await fs.readFile(path.join(root, "plugin-manifest.json"), "utf8"));
|
|
11
|
+
const source = await fs.readFile(path.join(root, "src/reference_estimation.cpp"), "utf8");
|
|
12
|
+
const propagatorHeader = await fs.readFile(
|
|
13
|
+
require.resolve("space-data-module-sdk/include/orbpro/orbpro_propagator_abi.h"), "utf8");
|
|
14
|
+
const estimationHeader = (await fs.readFile(
|
|
15
|
+
require.resolve("space-data-module-sdk/include/orbpro/orbpro_estimation_abi.h"), "utf8"))
|
|
16
|
+
.replace('#include "orbpro/orbpro_propagator_abi.h"', "");
|
|
17
|
+
const translationUnit = source
|
|
18
|
+
.replace('#include "orbpro/orbpro_propagator_abi.h"', propagatorHeader)
|
|
19
|
+
.replace('#include "orbpro/orbpro_estimation_abi.h"', estimationHeader);
|
|
20
|
+
const outputPath = path.join(root, "dist/isomorphic/module.wasm");
|
|
21
|
+
await fs.rm(path.join(root, "dist"), { recursive: true, force: true });
|
|
22
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
23
|
+
const result = await compileModuleFromSource({
|
|
24
|
+
manifest,
|
|
25
|
+
sourceCode: translationUnit,
|
|
26
|
+
language: "c++",
|
|
27
|
+
outputPath,
|
|
28
|
+
threadModel: manifest.threadModel,
|
|
29
|
+
});
|
|
30
|
+
if (!result.report?.ok) throw new Error(JSON.stringify(result.report?.issues ?? [], null, 2));
|
|
31
|
+
await fs.copyFile(path.join(root, "plugin-manifest.json"), path.join(root, "dist/plugin-manifest.json"));
|
|
32
|
+
console.log(`Built ${path.relative(root, outputPath)} with ${result.compiler}`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pluginId": "com.orbpro.estimation.reference",
|
|
3
|
+
"name": "Estimation ABI Reference",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Force-model-blind covariance update reference for the ratified estimation ABI.",
|
|
6
|
+
"pluginFamily": "analysis",
|
|
7
|
+
"capabilities": [],
|
|
8
|
+
"externalInterfaces": [],
|
|
9
|
+
"invokeSurfaces": ["direct"],
|
|
10
|
+
"runtimeTargets": ["browser", "wasmedge"],
|
|
11
|
+
"threadModel": "wasi-sequential",
|
|
12
|
+
"sequentialJustification": {
|
|
13
|
+
"kind": "inherently-sequential-algorithm",
|
|
14
|
+
"detail": "One six-state covariance update is order-dependent and small; callers parallelize independent tracks. The artifact still uses the sanctioned wasm32-wasip1-threads compiler lane."
|
|
15
|
+
},
|
|
16
|
+
"methods": [
|
|
17
|
+
{
|
|
18
|
+
"methodId": "abi_probe",
|
|
19
|
+
"displayName": "ABI Probe",
|
|
20
|
+
"description": "Returns success after the artifact has instantiated; estimation data uses the fixed direct export documented in README.md.",
|
|
21
|
+
"inputPorts": [],
|
|
22
|
+
"outputPorts": [],
|
|
23
|
+
"maxBatch": 1,
|
|
24
|
+
"drainPolicy": "single-shot"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"schemasUsed": [
|
|
28
|
+
{"schemaName": "Estimation.fbs", "fileIdentifier": "$EST", "rootTypeName": "EstimationEnvelope"}
|
|
29
|
+
],
|
|
30
|
+
"buildArtifacts": [
|
|
31
|
+
{"artifactId": "estimation-reference-isomorphic", "kind": "wasm", "path": "dist/isomorphic/module.wasm", "target": "browser,wasmedge"}
|
|
32
|
+
],
|
|
33
|
+
"abiVersion": 1
|
|
34
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#include "orbpro/orbpro_propagator_abi.h"
|
|
2
|
+
#include "orbpro/orbpro_estimation_abi.h"
|
|
3
|
+
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
|
|
7
|
+
#if defined(__wasm__)
|
|
8
|
+
#define ESTIMATION_EXPORT(name) __attribute__((export_name(name))) extern "C"
|
|
9
|
+
#else
|
|
10
|
+
#define ESTIMATION_EXPORT(name) extern "C"
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
extern "C" int abi_probe(void) { return 0; }
|
|
14
|
+
|
|
15
|
+
ESTIMATION_EXPORT("orbpro_estimation_reference_position_update")
|
|
16
|
+
int32_t orbpro_estimation_reference_position_update(
|
|
17
|
+
const OrbProEstimationConfig* config,
|
|
18
|
+
const OrbProEstimationObservation* observation,
|
|
19
|
+
const OrbProEstimationPropagatorSample* sample,
|
|
20
|
+
OrbProEstimationState* output) {
|
|
21
|
+
if (config == nullptr || observation == nullptr || sample == nullptr || output == nullptr) {
|
|
22
|
+
return ORBPRO_ESTIMATION_NULL_OUTPUT;
|
|
23
|
+
}
|
|
24
|
+
if (observation->kind != ORBPRO_MEASUREMENT_POSITION_VECTOR ||
|
|
25
|
+
observation->value_count != 3) {
|
|
26
|
+
return ORBPRO_ESTIMATION_BAD_INPUT;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
orbpro_estimation_state_init(output);
|
|
30
|
+
output->epoch[0] = sample->epoch[0];
|
|
31
|
+
output->epoch[1] = sample->epoch[1];
|
|
32
|
+
for (int axis = 0; axis < 6; ++axis) {
|
|
33
|
+
output->state[axis] = sample->state[axis];
|
|
34
|
+
for (int column = 0; column < 6; ++column) {
|
|
35
|
+
output->covariance[axis * 6 + column] = config->initial_covariance[axis * 6 + column];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (int axis = 0; axis < 3; ++axis) {
|
|
39
|
+
const double prior = output->covariance[axis * 6 + axis];
|
|
40
|
+
const double sigma = observation->sigma[axis];
|
|
41
|
+
if (!(prior > 0.0) || !(sigma > 0.0) || !std::isfinite(sigma)) {
|
|
42
|
+
return ORBPRO_ESTIMATION_BAD_INPUT;
|
|
43
|
+
}
|
|
44
|
+
const double measurement_variance = sigma * sigma;
|
|
45
|
+
const double gain = prior / (prior + measurement_variance);
|
|
46
|
+
output->state[axis] += gain * (observation->value[axis] - output->state[axis]);
|
|
47
|
+
output->covariance[axis * 6 + axis] = (1.0 - gain) * prior;
|
|
48
|
+
}
|
|
49
|
+
output->accepted_count = 1;
|
|
50
|
+
output->converged = 1;
|
|
51
|
+
output->estimator = ORBPRO_ESTIMATOR_EXTENDED_KALMAN_FILTER;
|
|
52
|
+
return ORBPRO_ESTIMATION_OK;
|
|
53
|
+
}
|