Reproduzierbarkeit & Herkunft
Kshana ist so gebaut, dass es reproduzierbar ist: Dieselben Eingaben ergeben dieselben Ergebnisse, und die Build-Artefakte lassen sich auf die Quelle zurückführen, die sie erzeugt hat. Dieses Dokument legt genau dar, was garantiert wird, was nicht, und wie die Garantien durchgesetzt werden.
Determinismus-Garantien#
Die Engine hat keine Wanduhr, keine Abhängigkeit vom Ausführungs-Thread und keine ungesäte Zufälligkeit. Jeder stochastische Prozess wird von einem Strom ChaCha8Rng getrieben, der durch den seed des Szenarios bestimmt und in fester Reihenfolge gezogen wird. Folgen:
| Eigenschaft | Garantiert | Durchgesetzt durch |
|---|---|---|
Dasselbe Szenario, dieselbe Maschine → byteidentisches result.json |
Ja | scripts/check-reproducible.sh (führt das Referenzszenario zweimal aus und vergleicht den SHA-256 (SHA: Secure Hash Algorithm)) |
| Dasselbe Szenario → identische Gütemaße Feld für Feld | Ja, je Plattform | tests/golden.rs legt jedes Gütemaß (FoM) für die vier Referenzszenarien fest |
Der Hash der Szenarioeingabe (scenario_hash) ist plattformunabhängig |
Ja | inhaltsadressierter SHA-256 des kanonischen Szenarios, festgelegt in tests/golden.rs |
| Eingabe-Fingerabdruck + Ausgabe-Struktur identisch über Betriebssysteme (OS) hinweg | Ja | tests/cross_platform_golden.rs legt je Szenario einen exakten SHA-256 fest (zehn Szenarien, je eine Datei .sha256 in tests/golden/), geprüft auf der CI-Matrix (kontinuierliche Integration) mit 3 Betriebssystemen |
| Ausgabe-Werte stimmen über Betriebssysteme hinweg überein (ubuntu/macOS/Windows) | Ja, bis auf 1e-6 | der CI-Job reproducibility-matrix führt golden.rs (1e-6), sgp4_verification.rs (2e-5 km) und determinism.rs auf allen drei Betriebssystemen aus |
| Ein Frame einer Navigationsnachricht für niedrige Erdumlaufbahnen (LEO) hat auf jeder Plattform und in jedem Build-Profil dieselben Bytes, den WebAssembly-(WASM-)Build eingeschlossen | Ja | src/portable_math.rs (jede transzendente Funktion und jede Normalabweichung der Art leo-navmsg läuft über das reine Rust-Crate libm); leo_navmsg::tests::the_encoded_frame_is_the_same_bytes_on_every_platform legt einen ganzen Frame ohne Plattformschranke fest |
| Gesäte Indexziehungen (Bootstrap-Resampling, Mischungen) sind auf 32-Bit- und 64-Bit-Zielen gleich | Ja | portable_math::uniform_index zieht immer als u64; festgelegt in portable_math::tests |
| Überall dieselbe Toolchain | Ja | rust-toolchain.toml legt den Kanal fest; scripts/check-toolchain.sh lässt den Build bei Abweichung scheitern; CI und Release legen dieselbe Version fest |
| Derselbe Abhängigkeitssatz | Ja | Cargo.lock ist eingecheckt, und cargo metadata --locked wird für die SBOM (Software-Stückliste) verwendet |
Jeder Befehlszeilenlauf schreibt außerdem einen Reproduzierbarkeitsnachweis in seinen Bericht (<scenario>.report.json und .report.html): die Engine-Version, den SHA-256 der Szenariodatei und des Ergebnisdokuments, den Seed, die Plattform und den genauen Befehl, den tests/advanced_report_cli.rs erneut ausführt, bis zu einem byteidentischen Ergebnis. Der Bericht selbst ist eine reine Funktion des Laufs: Zwei Läufe von scenarios/clock-holdover.toml schreiben dasselbe report.json Byte für Byte. Siehe REPORTS.md.
Der plattformübergreifende Vorbehalt (und wie die Goldens damit umgehen)#
Die numerischen Ergebnisse sind auf einer gegebenen Plattform bitidentisch, können sich aber zwischen Plattformen in den letzten Einheiten der letzten Stelle (ULP) unterscheiden. Die Ursache ist die Mathematikbibliothek der Plattform: sqrt, ln, exp und Verwandte müssen nach IEEE-754 (IEEE: Institute of Electrical and Electronics Engineers) nicht korrekt gerundet sein, sodass Linux (glibc, die GNU-C-Bibliothek), macOS und Windows jeweils ein anderes letztes Bit liefern können. Über einen langen Lauf summieren sich diese Unterschiede von ~1e-16 auf vielleicht ~1e-12 relativ.
Zwei Dinge machen diesen Unterschied in der letzten Stelle größer, als er anfangs ist, und beide sind gemessen statt angenommen. Ein adaptiver Integrator wählt seinen nächsten Schritt aus der Fehlerschätzung über eine fünfte Wurzel, sodass eine Einheit in der letzten Stelle die Schrittfolge ändert und die beiden Plattformen dann nur noch bis auf die Integrationstoleranz übereinstimmen. Ein iterativer Schätzer (eine Kleinste-Quadrate-Anpassung, ein Filter zur Bahnbestimmung) kann einen anderen Weg zur Konvergenz nehmen. Auf beidem aufgebaute Arten können sich zwischen Plattformen in einzelnen Feldern um mehr als 1e-6 unterscheiden; src/test_support.rs hält dasselbe Regime für die Unit-Tests fest.
Das Build-Profil spielt auf einer Maschine auf dieselbe Weise eine Rolle. Ein optimierter Build auf macOS fasst einen Sinus und einen Kosinus desselben Arguments zu einem einzigen Aufruf der kombinierten Routine des Systems zusammen, deren Sinus sich vom alleinstehenden sin im letzten Bit bei 379 von 200.000 Argumenten unterscheidet; ein nicht optimierter Build macht die beiden Aufrufe. Gemessen auf aarch64-macOS über die 138 Szenariodateien liefern ein Debug- und ein Release-Build derselben Quelle bei 102 byteidentische Ergebnisdokumente. Die übrigen 36 unterscheiden sich in den letzten Stellen: 28 innerhalb von 1e-6, eines (leo-ppp-convergence) um 2.8e-6 und sieben Kampagnen nur in den Digests ihrer Mitgliedsläufe; keines unterscheidet sich in einer Kennzeichnung, einer Zahl oder einem Urteil. Die obige Garantie der Byteidentität gilt daher für einen Build: dieselbe Binärdatei zweimal.
Die gesäten Normalziehungen sind eine dritte, viel seltenere Quelle: Der Sampler ruft in seinen seltenen Zweigen die Exponential- und Logarithmusfunktion des Hosts auf, und etwa eine von einer Million Ziehungen unterscheidet sich zwischen dem nativen und dem WASM-Build im letzten Bit.
Wo eine Ausgabe diskret ist, ist ein Unterschied in der letzten Stelle überhaupt nicht akzeptabel, und die Art wird stattdessen mit src/portable_math.rs statt mit der Host-Bibliothek berechnet. Die Art leo-navmsg ist die erste: Ihr binärer Frame besteht aus übertragenen Ganzzahlen, und dasselbe Szenario wurde einmal zu drei verschiedenen Frames kodiert: in einem Release-Build, in einem Debug-Build derselben Quelle und im Browser. Jetzt sind es in allen dreien dieselben Bytes.
Deshalb legen die Golden-Tests keinen einzelnen plattformübergreifenden Hash der Gleitkommaausgabe fest — das wäre fragil und würde ehrlich korrekte Builds auf einem anderen Betriebssystem scheitern lassen. Stattdessen:
tests/golden.rslegt jedes Gütemaß mit einer relativen Toleranz von1e-6fest — vier Größenordnungen enger als jede echte Regression (die einen Wert um ganze Prozent verschiebt), aber weit lockerer als das Jitter der Mathematikbibliothek (libm) zwischen Plattformen. Gitterbegrenzte Felder (Holdover-Sekunden) und Felder mit exakt null werden exakt festgelegt.scenario_hash— ein Inhalts-Hash der Eingaben — ist plattformunabhängig und wird exakt festgelegt.tests/cross_platform_golden.rslegt einen exakten SHA-256 fest, je Szenario intests/golden/eingecheckt, über die Projektion, die über Plattformen hinweg identisch ist: den Eingabe-Fingerabdruck plus die Ausgabe-Struktur (Feldnamen, Verschachtelung, Blatttypen, Array-Längen — festgelegt durch deterministische Gitterarithmetik, nie die Gleitkommawerte). Das fängt strukturelle Regressionen exakt ab, während die obigen Toleranzfestlegungen Wertregressionen abfangen.scripts/check-reproducible.sherzwingt byteidentische Ausgabe über zwei Läufe auf derselben Maschine (die Determinismus-Garantie).- Der CI-Job
reproducibility-matrixführt die vier obigen Tests (cross_platform_golden,golden,determinism,sgp4_verification) auf ubuntu-latest, macos-latest und windows-latest aus, sodass die plattformübergreifende Reproduzierbarkeit bei jedem Push festgestellt wird — die Struktur-/Eingabe-Goldens exakt, die Numerik bis auf 1e-6 und die SGP4-Zustände (Simplified General Perturbations 4) bis auf 2e-5 km — statt sich auf ein einziges Betriebssystem zu verlassen.
Wenn Sie die festgelegten Zahlen neu erzeugen müssen (z. B. nach einer beabsichtigten Modelländerung), führen Sie jedes Referenzszenario aus und kopieren Sie die ausgegebenen Gütemaßwerte in tests/golden.rs, und vermerken Sie die Änderung dann in CHANGELOG.md.
Software-Stückliste (SBOM)#
scripts/gen-sbom.sh gibt eine SBOM im Format CycloneDX 1,5 aus, die jedes Crate auflistet, das in einem Kshana-Artefakt ausgeliefert wird, mit seiner genauen Version, Quelle und Lizenz. Es ist ein abhängigkeitsfreier Generator auf Basis von cargo metadata --locked (er funktioniert also allein mit der Toolchain) und durchläuft den Auflösungsgraphen vom Paket kshana aus nur über normale und Build-Abhängigkeiten. Entwicklungsabhängigkeiten (reine Test-Crates wie sgp4) sind ausgeschlossen, weil kein Artefakt sie enthält.
Der Graph ist die Vereinigung der Feature-Mengen, mit denen die ausgelieferten Artefakte gebaut werden: der Standard-Build (Bibliothek und CLI, Befehlszeilenschnittstelle), --features python (das PyPI-Wheel, Python Package Index, dessen Kette pyo3 seine Fremdfunktionsgrenze ist) und --features wasm (das npm-Paket, das dieselbe SBOM in seinem Tarball mitführt). Plattformbedingte Abhängigkeiten für jedes Ziel sind eingeschlossen, da die Wheels für mehrere Betriebssysteme ausgeliefert werden und das npm-Paket auf WebAssembly zielt. Ein Dokument deckt alle drei Artefakte ab, daher ist es für jedes einzelne eine Obermenge. Derzeit listet es 107 Komponenten auf; die Zahl ist in tests/fixtures/reproducibility_software_assurance/ festgelegt. Der eigenständige Server kshana-mcp hat sein eigenes Manifest und wird von dieser SBOM nicht beschrieben.
Die Ausgabe ist deterministisch — derselbe Abhängigkeitssatz ergibt ein byteidentisches Dokument, einschließlich einer Seriennummer, die aus der sortierten Paketliste statt aus einem Zeitstempel abgeleitet wird.
Der Release-Workflow erzeugt die SBOM (kshana-sbom.cdx.json) und hängt sie an jedes getaggte Release an; der Publish-Workflow liefert sie außerdem neben den PyPI-Wheels und im npm-Paket aus.
Build-Herkunft#
Der Release-Workflow erzeugt eine SLSA-Attestierung (Supply-chain Levels for Software Artifacts) der Build-Herkunft (actions/attest-build-provenance), die jede Datei abdeckt, die er an das GitHub-Release anhängt: die Befehlszeilen-Binärdateien für jede Plattform, die Server-Binärdatei kshana-mcp, die SBOM, die Validierungszusammenfassung und SHA256SUMS. Ein Konsument kann mit gh attestation verify prüfen, dass die Artefakte vom Release-Workflow dieses Repositorys aus dieser Quelle gebaut wurden — und so die Lücke zwischen „hier ist eine Binärdatei“ und „hier ist eine Binärdatei, die ich auf ihre Quelle zurückführen kann“ schließen. Zum Beispiel für die SBOM von v0.28.0:
curl -sLO https://github.com/AshfordeOU/kshana/releases/download/v0.28.0/kshana-sbom.cdx.json
gh attestation verify kshana-sbom.cdx.json --repo AshfordeOU/kshana