commits
The block had a missing [in] after [Odm.epoch_range seg] (running
the [let] phrase into [Printf.printf]) and referenced unbound
[segment] / [unix_timestamp]. Wrap each flow as a function ([report
path], [position_at ~segment ~unix_timestamp]), switch [Printf.printf]
to [Fmt.pr], and add [fmt] to the mdx libraries.
Remove libraries declared in '(libraries ...)' clauses but unreferenced
by any module in the same source tree, as flagged by 'monopam lint'
after the new Dead_lib detection landed. Touches 131 dune files across
~80 packages.
A few stanzas needed a positive correction instead of a pure removal:
- ocaml-git/bin/diag: depended on eio_main + bytesrw-eio for an
Eio_posix.run call site; the umbrella was overkill, switch to the
precise eio_posix package.
- ocaml-scaleway/lib, ocaml-s3/lib: scaleway.mli / s3.mli reference
Eio_unix.Stdenv.base; eio.unix is required and was missing.
- merlint/lib: pulled bytesrw + nox-opam.bytesrw to surface
Opam_bytesrw, used by rule e915 and lint helpers.
Stanzas where Dead_lib was a false positive (transitive dep needed
for module visibility, virtual-library impls) are left untouched —
e.g. helix.jx.jsoo for ocaml-globe/demo retains its (libraries ...)
entry because it provides the impl of the helix.jx virtual lib.
The READMEs all share the standard install/overlay snippet, but the
sh blocks lacked the "<!-- $MDX skip -->" directive. `dune test`
would shell out to `opam install` against the live switch, which
either prompts interactively or fails with a package conflict —
either way diffing as a test failure.
Bulk-add skip directives in front of every install/overlay block.
Also collapse the doubled "non-deterministic + skip" stack on three
READMEs (memtrace, ocaml-dpop, ocaml-pid1, ocaml-yaml, merlint) where
`skip` already implies the runtime is bypassed.
Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.
Object combinators: [Object.mem] -> [Object.member], [Object.opt_mem]
-> [Object.opt_member], [Object.case_mem] -> [Object.case_member]. The
sibling submodules [Object.Mem] / [Object.Mems] become
[Object.Member] / [Object.Members]. RFC 8259 §4 calls these
"name/value pairs, referred to as the members", so mirror the spec
name rather than the shortened [mem].
[Object.finish] -> [Object.seal]. "Seal" reads as "close the map, no
more members added", which is what the operation does.
Value constructors/queries: [Value.mem] (function) -> [Value.member];
[Value.mem_find] -> [Value.member_key]; [Value.mem_names] ->
[Value.member_names]; [Value.mem_keys] -> [Value.member_keys].
[type mem = ...] -> [type member = ...]; [type object'] still points
at [member list].
Downstream (~80 files across slack, sbom, stripe, sigstore, requests,
claude, irmin, freebox) updated via perl-pie. dune build clean,
dune test ocaml-json clean.
Follow up to the module rename: update the remaining callers that
still referenced [Err] (library [claude.ml{,i}], [client.ml], the test
driver [test.ml]), and fix one stray [^ e] string concatenation in
hermest's CLI that needed [Json.Error.to_string e] now that
[Json.of_string] yields a structured error.
Warning 69 (unused-field, mutable-never-assigned). Four independent
record fields were flagged as mutable but the code only mutates their
referents in place, never rebinds the record slot itself:
- ocaml-wal/lib/wal.ml: [t.file] (the Eio file resource; methods call
Eio.File.pwrite_all etc., the slot is set once at open time).
- ocaml-block/lib/block.ml: [Memory.state.data] (the backing bytes,
written via Bytes.blit_string; [Bytes.t] is already mutable).
- ocaml-sse/lib/sse.ml: [Parser.t.data_buf] (a Buffer.t, written via
Buffer.add_*; the slot never changes).
- ocaml-zephyr/lib/zephyr.ml: drop [mode : Read | Write] entirely —
set at open-time, read nowhere. The open_read / open_write
constructors already distinguish the two call shapes, so mode
tracking was redundant.
Previously the eight git-x subcommands sat flat at top level (split,
check, fix, verify, filter-paths, split-commit, drop-commit, reword),
with 'split' ambiguous between the subtree split and the per-directory
commit split.
Regrouped into two namespaces that mirror the object they act on:
git-x tree
split (was: git-x split)
add (new — inject a standalone history under a prefix)
drop (was: git-x filter-paths)
check (was: git-x check)
fix (was: git-x fix)
verify (was: git-x verify)
git-x commit
split (was: git-x split-commit)
drop (was: git-x drop-commit)
reword (was: git-x reword)
Each subcommand lives in cmd_<group>_<verb>.{ml,mli}; cmd_tree.ml and
cmd_commit.ml are the Cmd.group wrappers. git_x.ml registers just the
two groups.
'tree add' is a thin wrapper over Git.Subtree.add, which already
existed in the library but had no CLI exposure. It accepts a ref (e.g.
FETCH_HEAD after 'git fetch URL REF') and a --prefix, then builds a
subtree-merge commit with the current user's git config identity.
Log source names are updated to match (git-x.tree.split,
git-x.tree.fix). The cram test under test/cram/tree_split.t is
updated to use the new 'git-x tree split' invocation throughout.
Rename test_vectors.ml to test_oem.ml so it covers the OEM library
module (was missing test_oem.ml). Extract write_header/metadata/state/
spacecraft/covariance/maneuver helpers from to_string (was 79 lines).
Pull maneuver_of_table and consume_pair out of parse_maneuvers to drop
nesting depth from 5 to 3.
Generate .opam.template files with x-quality-* fields based on
detected package features:
- x-quality-build: has lib/ with .ml files
- x-quality-test: has test/ with .ml files
- x-quality-fuzz: has fuzz/ with .ml files
- x-quality-interop: has test/interop/ directory
- x-quality-cram: has test/*.t/ directories
These fields are picked up by dune's opam generation and will be
checked by merlint E910 for consistency.
Also: add fmt dep to ocaml-sse/lib/dune (Fmt.pf used without dep).
monopam quality — scans packages for quality features, caches by
git commit hash. 166 packages: build=163, test=162, fuzz=94,
interop=39, doc=42.
Standard vocabulary based on crates.io categories, erratique/opam
conventions, and monorepo domain coverage:
Org: org:blacksun
Domain: aerospace, codec, crypto, network, storage, git, merkle
Purpose: cli, test, bench, format, log, system
Protocol: ccsds, uslp, cop1, sdls, sle, atproto, tls, http, json, binary
Cross-cutting: eio, simulation, math, compression
Tags placed in dune-project (package ...) stanzas via (tags ...).
Propagated to .opam files by dune's opam generation.
112 files across the monorepo. Printf.sprintf → Fmt.str,
Printf.printf → Fmt.pr for consistent formatting library usage.
FSR (Frame Security Report) interop requires:
1. Crypto_Init_TM_Unit_Test() for SA setup
2. A full 1786-byte TM frame matching CryptoLib's config
3. Crypto_TM_ApplySecurity() to produce secured frame
4. Crypto_Get_FSR() to read the 32-bit FSR word
The TM frame must be copied from CryptoLib's own ut_tm_apply.c
HAPPY_PATH_CLEAR_FECF test (3572-char hex literal). Tracked
separately from the TC interop which is already working.
- Update .ocamlformat to 0.29.0 across all 591 files
- csvt: reuse single Buffer.t for field reads (no alloc per field)
- sexpt: Obj members decoded from stream into Dict, typed Variant GADT
- Reformat all source files for 0.29.0
Rice (CCSDS 121.0-B):
- Fix prediction error mapper per spec (modular arithmetic with
theta-based branching, matching libaec reference implementation)
- Fix select_k to use floor instead of round
- Add bounds check on decompress sample count
- All 11 tests + 4 fuzz tests pass
ODM consolidation (CCSDS 502.0-B):
- Merge OPM into ocaml-odm alongside OEM
- Access via Odm.Oem and Odm.Opm submodules
- Backward-compatible: Odm.of_kvn_string still works for OEM
ADM (CCSDS 504.0-B):
- Create ocaml-adm from ocaml-aem
- Access via Adm.Aem submodule (APM to be added)
ocaml-ccsds index:
- Meta-package with index.mld documenting the full protocol suite
- Organized by Blue Book / Green Book / Related Standards
- Links to CCSDS PDF specs for each standard
- Lists all implemented + not-yet-implemented specs
Add covariance_entry type with epoch, reference frame, and 21-element
lower triangle of 6x6 covariance matrix. Parse COVARIANCE_START/STOP
blocks including EPOCH, COV_REF_FRAME, and float rows. Previously
these blocks were silently skipped.
Test validates parsing against CCSDS sample04.oem covariance block:
correct epoch, frame, 21 elements, C11 and C66 values.
Replace manual Bytes.get/set in tml.ml with Wire.Codec for
TML PDU header (8 bytes) and context message body (12 bytes).
All 85 SLE tests pass.
- ocaml-rice: CCSDS 121.0-B lossless compression (Rice/Golomb)
- ocaml-udpcl: RFC 7122 UDP convergence layer for Bundle Protocol
- ocaml-erasure: CCSDS 131.5-B erasure correcting codes (GF(2^8))
- ocaml-short-ldpc: CCSDS 131.4-B short block-length LDPC
- ocaml-opm: CCSDS 502.0-B Orbit Parameter Message (KVN)
- ocaml-aem: CCSDS 504.0-B Attitude Ephemeris Message (KVN)
- ocaml-tdm: CCSDS 503.0-B Tracking Data Message (KVN)
- ocaml-rdm: CCSDS 508.1-B Re-entry Data Message (KVN)
Odm.vec3 is now Vec3.t (type alias via = Vec3.t = {x; y; z}).
Removes to_v conversion helpers from collision and cam interop tests.
odm now depends on vec3.
odm: Add Odm.position_at — queries position across all segments in one
call. No need to manually iterate segments or convert epochs.
collision: Add Collision.assess — one-call CDM risk assessment returning
Pc, miss distance, relative velocity, and risk level (Critical/High/
Watch/Low enum). encounter/pc_foster/pc_chan/pc_max remain available for
custom workflows.
cam: Add Cam.avoid — one-call CDM avoidance. Takes a CDM and time-to-burn,
returns the minimum maneuver to reduce Pc below threshold (default 1e-5).
Extracts conjunction geometry from CDM automatically.
Remove verbose MISSION-READY labels from test comments.
New packages:
- ocaml-tm-sync (131.0-B): TM randomizer (LFSR) with CCSDS PN
sequence test vector; RS/convolutional/LDPC/turbo stubs
- ocaml-proximity1 (211.0-B): Proximity-1 frame header Wire codec
with encode/decode and roundtrip tests
Tests with spec vectors (96 tests total):
- tm-sync: PN sequence from CCSDS 131.0-B-4 Annex B
- cltu: BCH(63,56) parity, CLTU/ASM sync parsers
- cop1: FOP-1/FARM-1 state machine transitions
- fsr: 32-bit FSR Wire codec with known bit patterns
- proximity1: frame header roundtrip for all frame types
- ccsds-time: CUC/CDS encode/decode with epoch constants
Tests that expose real gaps in our libraries when compared against GMAT:
ocaml-odm (2 FAIL):
- LEO interpolation midpoint: linear vs quadratic truth returns inf —
exposes precision bug in interpolate epoch conversion
- Molniya perigee interpolation: same issue at high-eccentricity perigee
ocaml-collision (1 FAIL):
- TCA precision: miss distance varies by 34 km in 10s at closest approach.
Step-based TCA finding is not mission-grade — need quadratic refinement.
ocaml-cam (new mission-ready tests, passing):
- Linear model (dv*dt) vs GMAT vis-viva SMA prediction (< 5% error)
- CAM evaluate internal consistency check
- Documents that linear along-track shift model is a first-order
approximation only — GMAT shows the real effect is an SMA change.
These failures are intentional — they document what needs to be fixed
before the libraries are mission-ready.
- ocaml-cltu: CLTU encoding/decoding (CCSDS 231.0-B) with BCH(63,56),
ASM sync markers (131.0-B), and stream sync parsers
- ocaml-cop1: COP-1 state machines (CCSDS 232.1-B) for FOP-1 (ground)
and FARM-1 (flight) with Eio service layer
- cltu-eio: CLTU/ASM send/recv over Eio flows
- cop1-eio: COP-1 service layer with Eio timer management
Each package README now mentions GMAT R2026a interop testing alongside
other test sources (Vallado, TraCSS, bradsease/oem).
ocaml-odm: 11 -> 24 tests. New tests exercise GMAT output edge cases:
- Scientific notation 1e-16 (near-zero Vz at LEO epoch)
- 5 orders of magnitude position range (Molniya 1e-12 to 4.6e+04 km)
- Trailing whitespace on INTERPOLATION_DEGREE metadata
- Space inside ORIGINATOR value
- NaN/inf rejection across all 16K+ state vectors
- Epoch monotonicity within segments
- Energy conservation (LEO, <1% drift over 7 days with drag)
- Vis-viva SMA consistency (Molniya, <2% drift with J2)
- GEO near-circular radius variation (<50 km)
ocaml-cam: fix multi-segment OEM handling — GMAT splits at impulsive
burn epoch. Tests now validate segment count, position continuity at
burn boundary, velocity discontinuity = 0.1 km/s, and orbit raising.
Application-layer chunking is custom, not CCSDS/RFC.
GMAT R2026a-generated OEM traces for LEO (ISS-like, 7 days, 20x20 gravity
+ MSISE90 drag), GEO (3 days), and Molniya (e=0.74, 2 days). 11 tests
validate OEM parsing, metadata, radius/velocity physical bounds, and epoch
ranges across all three orbit regimes.
- CLCW: remove hand-written bit manipulation, single codec for the
full 32-bit word with typed fields
- Space Packet: single full-packet codec (header + variable-length
data via Field.ref on data_length)
- TC: frame_codec with dependent-length data zone from header's
frame_length field
- AOS/TM/USLP: packed_frame type with Wire codec for header +
data zone capture for the variable-length trailing portion
- Remove all duplicate packed_header types where superseded
- Expose Wire.Codec field bindings for future zero-copy get/set
READMEs for all new packages. Fix missing docs (ocm, stix, globe),
naming (project_visible→visible, label_info→info, shader_kind→kind),
add .ocamlformat to csvt, add 11 KVN tests.
Rewrite SGP4 propagator ported from python-sgp4 with deep-space (SDP4)
satellite support including lunar/solar perturbations and resonance
handling. Add canonical Vallado verification vectors (33 satellites,
~700 test points from SGP4-VER.TLE + tcppver.out).
Also: ocamlformat reformatting across ocaml-respond, ocaml-odm,
ocaml-cdm, ocaml-requests, ocaml-spacedata; update root.opam deps.
ocaml-odm: 52 tests total (was 10)
- 10 v2.0 valid KVN samples from bradsease/oem
- 8 real orbit samples (LEO/MEO/GEO at 10s/20s/60s intervals)
- 22 invalid samples (crash safety)
- LEO altitude/velocity range checks
- GEO altitude/velocity range checks
- Covariance block skipping (COVARIANCE_START/STOP)
ocaml-cdm: Blue Book section 4 KVN + XML test vectors archived
OEM (Orbit Ephemeris Message) KVN parser with multi-segment support.
Parses state vectors (position, velocity, optional acceleration),
metadata (ref frame, interpolation, time system), and comments.
Test vectors: Mars Global Surveyor (Blue Book Fig 5.1, multi-segment
with trajectory correction maneuver), ISS single-segment, and
acceleration data. 10 tests, merlint clean.
Critical path for ssa.space: TraCSS ephemeris submission, CREAM
maneuver integration, and maneuver what-if analysis.
The block had a missing [in] after [Odm.epoch_range seg] (running
the [let] phrase into [Printf.printf]) and referenced unbound
[segment] / [unix_timestamp]. Wrap each flow as a function ([report
path], [position_at ~segment ~unix_timestamp]), switch [Printf.printf]
to [Fmt.pr], and add [fmt] to the mdx libraries.
Remove libraries declared in '(libraries ...)' clauses but unreferenced
by any module in the same source tree, as flagged by 'monopam lint'
after the new Dead_lib detection landed. Touches 131 dune files across
~80 packages.
A few stanzas needed a positive correction instead of a pure removal:
- ocaml-git/bin/diag: depended on eio_main + bytesrw-eio for an
Eio_posix.run call site; the umbrella was overkill, switch to the
precise eio_posix package.
- ocaml-scaleway/lib, ocaml-s3/lib: scaleway.mli / s3.mli reference
Eio_unix.Stdenv.base; eio.unix is required and was missing.
- merlint/lib: pulled bytesrw + nox-opam.bytesrw to surface
Opam_bytesrw, used by rule e915 and lint helpers.
Stanzas where Dead_lib was a false positive (transitive dep needed
for module visibility, virtual-library impls) are left untouched —
e.g. helix.jx.jsoo for ocaml-globe/demo retains its (libraries ...)
entry because it provides the impl of the helix.jx virtual lib.
The READMEs all share the standard install/overlay snippet, but the
sh blocks lacked the "<!-- $MDX skip -->" directive. `dune test`
would shell out to `opam install` against the live switch, which
either prompts interactively or fails with a package conflict —
either way diffing as a test failure.
Bulk-add skip directives in front of every install/overlay block.
Also collapse the doubled "non-deterministic + skip" stack on three
READMEs (memtrace, ocaml-dpop, ocaml-pid1, ocaml-yaml, merlint) where
`skip` already implies the runtime is bypassed.
Object combinators: [Object.mem] -> [Object.member], [Object.opt_mem]
-> [Object.opt_member], [Object.case_mem] -> [Object.case_member]. The
sibling submodules [Object.Mem] / [Object.Mems] become
[Object.Member] / [Object.Members]. RFC 8259 §4 calls these
"name/value pairs, referred to as the members", so mirror the spec
name rather than the shortened [mem].
[Object.finish] -> [Object.seal]. "Seal" reads as "close the map, no
more members added", which is what the operation does.
Value constructors/queries: [Value.mem] (function) -> [Value.member];
[Value.mem_find] -> [Value.member_key]; [Value.mem_names] ->
[Value.member_names]; [Value.mem_keys] -> [Value.member_keys].
[type mem = ...] -> [type member = ...]; [type object'] still points
at [member list].
Downstream (~80 files across slack, sbom, stripe, sigstore, requests,
claude, irmin, freebox) updated via perl-pie. dune build clean,
dune test ocaml-json clean.
Follow up to the module rename: update the remaining callers that
still referenced [Err] (library [claude.ml{,i}], [client.ml], the test
driver [test.ml]), and fix one stray [^ e] string concatenation in
hermest's CLI that needed [Json.Error.to_string e] now that
[Json.of_string] yields a structured error.
Warning 69 (unused-field, mutable-never-assigned). Four independent
record fields were flagged as mutable but the code only mutates their
referents in place, never rebinds the record slot itself:
- ocaml-wal/lib/wal.ml: [t.file] (the Eio file resource; methods call
Eio.File.pwrite_all etc., the slot is set once at open time).
- ocaml-block/lib/block.ml: [Memory.state.data] (the backing bytes,
written via Bytes.blit_string; [Bytes.t] is already mutable).
- ocaml-sse/lib/sse.ml: [Parser.t.data_buf] (a Buffer.t, written via
Buffer.add_*; the slot never changes).
- ocaml-zephyr/lib/zephyr.ml: drop [mode : Read | Write] entirely —
set at open-time, read nowhere. The open_read / open_write
constructors already distinguish the two call shapes, so mode
tracking was redundant.
Previously the eight git-x subcommands sat flat at top level (split,
check, fix, verify, filter-paths, split-commit, drop-commit, reword),
with 'split' ambiguous between the subtree split and the per-directory
commit split.
Regrouped into two namespaces that mirror the object they act on:
git-x tree
split (was: git-x split)
add (new — inject a standalone history under a prefix)
drop (was: git-x filter-paths)
check (was: git-x check)
fix (was: git-x fix)
verify (was: git-x verify)
git-x commit
split (was: git-x split-commit)
drop (was: git-x drop-commit)
reword (was: git-x reword)
Each subcommand lives in cmd_<group>_<verb>.{ml,mli}; cmd_tree.ml and
cmd_commit.ml are the Cmd.group wrappers. git_x.ml registers just the
two groups.
'tree add' is a thin wrapper over Git.Subtree.add, which already
existed in the library but had no CLI exposure. It accepts a ref (e.g.
FETCH_HEAD after 'git fetch URL REF') and a --prefix, then builds a
subtree-merge commit with the current user's git config identity.
Log source names are updated to match (git-x.tree.split,
git-x.tree.fix). The cram test under test/cram/tree_split.t is
updated to use the new 'git-x tree split' invocation throughout.
Rename test_vectors.ml to test_oem.ml so it covers the OEM library
module (was missing test_oem.ml). Extract write_header/metadata/state/
spacecraft/covariance/maneuver helpers from to_string (was 79 lines).
Pull maneuver_of_table and consume_pair out of parse_maneuvers to drop
nesting depth from 5 to 3.
Generate .opam.template files with x-quality-* fields based on
detected package features:
- x-quality-build: has lib/ with .ml files
- x-quality-test: has test/ with .ml files
- x-quality-fuzz: has fuzz/ with .ml files
- x-quality-interop: has test/interop/ directory
- x-quality-cram: has test/*.t/ directories
These fields are picked up by dune's opam generation and will be
checked by merlint E910 for consistency.
Also: add fmt dep to ocaml-sse/lib/dune (Fmt.pf used without dep).
Standard vocabulary based on crates.io categories, erratique/opam
conventions, and monorepo domain coverage:
Org: org:blacksun
Domain: aerospace, codec, crypto, network, storage, git, merkle
Purpose: cli, test, bench, format, log, system
Protocol: ccsds, uslp, cop1, sdls, sle, atproto, tls, http, json, binary
Cross-cutting: eio, simulation, math, compression
Tags placed in dune-project (package ...) stanzas via (tags ...).
Propagated to .opam files by dune's opam generation.
FSR (Frame Security Report) interop requires:
1. Crypto_Init_TM_Unit_Test() for SA setup
2. A full 1786-byte TM frame matching CryptoLib's config
3. Crypto_TM_ApplySecurity() to produce secured frame
4. Crypto_Get_FSR() to read the 32-bit FSR word
The TM frame must be copied from CryptoLib's own ut_tm_apply.c
HAPPY_PATH_CLEAR_FECF test (3572-char hex literal). Tracked
separately from the TC interop which is already working.
Rice (CCSDS 121.0-B):
- Fix prediction error mapper per spec (modular arithmetic with
theta-based branching, matching libaec reference implementation)
- Fix select_k to use floor instead of round
- Add bounds check on decompress sample count
- All 11 tests + 4 fuzz tests pass
ODM consolidation (CCSDS 502.0-B):
- Merge OPM into ocaml-odm alongside OEM
- Access via Odm.Oem and Odm.Opm submodules
- Backward-compatible: Odm.of_kvn_string still works for OEM
ADM (CCSDS 504.0-B):
- Create ocaml-adm from ocaml-aem
- Access via Adm.Aem submodule (APM to be added)
ocaml-ccsds index:
- Meta-package with index.mld documenting the full protocol suite
- Organized by Blue Book / Green Book / Related Standards
- Links to CCSDS PDF specs for each standard
- Lists all implemented + not-yet-implemented specs
Add covariance_entry type with epoch, reference frame, and 21-element
lower triangle of 6x6 covariance matrix. Parse COVARIANCE_START/STOP
blocks including EPOCH, COV_REF_FRAME, and float rows. Previously
these blocks were silently skipped.
Test validates parsing against CCSDS sample04.oem covariance block:
correct epoch, frame, 21 elements, C11 and C66 values.
- ocaml-rice: CCSDS 121.0-B lossless compression (Rice/Golomb)
- ocaml-udpcl: RFC 7122 UDP convergence layer for Bundle Protocol
- ocaml-erasure: CCSDS 131.5-B erasure correcting codes (GF(2^8))
- ocaml-short-ldpc: CCSDS 131.4-B short block-length LDPC
- ocaml-opm: CCSDS 502.0-B Orbit Parameter Message (KVN)
- ocaml-aem: CCSDS 504.0-B Attitude Ephemeris Message (KVN)
- ocaml-tdm: CCSDS 503.0-B Tracking Data Message (KVN)
- ocaml-rdm: CCSDS 508.1-B Re-entry Data Message (KVN)
odm: Add Odm.position_at — queries position across all segments in one
call. No need to manually iterate segments or convert epochs.
collision: Add Collision.assess — one-call CDM risk assessment returning
Pc, miss distance, relative velocity, and risk level (Critical/High/
Watch/Low enum). encounter/pc_foster/pc_chan/pc_max remain available for
custom workflows.
cam: Add Cam.avoid — one-call CDM avoidance. Takes a CDM and time-to-burn,
returns the minimum maneuver to reduce Pc below threshold (default 1e-5).
Extracts conjunction geometry from CDM automatically.
New packages:
- ocaml-tm-sync (131.0-B): TM randomizer (LFSR) with CCSDS PN
sequence test vector; RS/convolutional/LDPC/turbo stubs
- ocaml-proximity1 (211.0-B): Proximity-1 frame header Wire codec
with encode/decode and roundtrip tests
Tests with spec vectors (96 tests total):
- tm-sync: PN sequence from CCSDS 131.0-B-4 Annex B
- cltu: BCH(63,56) parity, CLTU/ASM sync parsers
- cop1: FOP-1/FARM-1 state machine transitions
- fsr: 32-bit FSR Wire codec with known bit patterns
- proximity1: frame header roundtrip for all frame types
- ccsds-time: CUC/CDS encode/decode with epoch constants
Tests that expose real gaps in our libraries when compared against GMAT:
ocaml-odm (2 FAIL):
- LEO interpolation midpoint: linear vs quadratic truth returns inf —
exposes precision bug in interpolate epoch conversion
- Molniya perigee interpolation: same issue at high-eccentricity perigee
ocaml-collision (1 FAIL):
- TCA precision: miss distance varies by 34 km in 10s at closest approach.
Step-based TCA finding is not mission-grade — need quadratic refinement.
ocaml-cam (new mission-ready tests, passing):
- Linear model (dv*dt) vs GMAT vis-viva SMA prediction (< 5% error)
- CAM evaluate internal consistency check
- Documents that linear along-track shift model is a first-order
approximation only — GMAT shows the real effect is an SMA change.
These failures are intentional — they document what needs to be fixed
before the libraries are mission-ready.
- ocaml-cltu: CLTU encoding/decoding (CCSDS 231.0-B) with BCH(63,56),
ASM sync markers (131.0-B), and stream sync parsers
- ocaml-cop1: COP-1 state machines (CCSDS 232.1-B) for FOP-1 (ground)
and FARM-1 (flight) with Eio service layer
- cltu-eio: CLTU/ASM send/recv over Eio flows
- cop1-eio: COP-1 service layer with Eio timer management
ocaml-odm: 11 -> 24 tests. New tests exercise GMAT output edge cases:
- Scientific notation 1e-16 (near-zero Vz at LEO epoch)
- 5 orders of magnitude position range (Molniya 1e-12 to 4.6e+04 km)
- Trailing whitespace on INTERPOLATION_DEGREE metadata
- Space inside ORIGINATOR value
- NaN/inf rejection across all 16K+ state vectors
- Epoch monotonicity within segments
- Energy conservation (LEO, <1% drift over 7 days with drag)
- Vis-viva SMA consistency (Molniya, <2% drift with J2)
- GEO near-circular radius variation (<50 km)
ocaml-cam: fix multi-segment OEM handling — GMAT splits at impulsive
burn epoch. Tests now validate segment count, position continuity at
burn boundary, velocity discontinuity = 0.1 km/s, and orbit raising.
- CLCW: remove hand-written bit manipulation, single codec for the
full 32-bit word with typed fields
- Space Packet: single full-packet codec (header + variable-length
data via Field.ref on data_length)
- TC: frame_codec with dependent-length data zone from header's
frame_length field
- AOS/TM/USLP: packed_frame type with Wire codec for header +
data zone capture for the variable-length trailing portion
- Remove all duplicate packed_header types where superseded
- Expose Wire.Codec field bindings for future zero-copy get/set
Rewrite SGP4 propagator ported from python-sgp4 with deep-space (SDP4)
satellite support including lunar/solar perturbations and resonance
handling. Add canonical Vallado verification vectors (33 satellites,
~700 test points from SGP4-VER.TLE + tcppver.out).
Also: ocamlformat reformatting across ocaml-respond, ocaml-odm,
ocaml-cdm, ocaml-requests, ocaml-spacedata; update root.opam deps.
ocaml-odm: 52 tests total (was 10)
- 10 v2.0 valid KVN samples from bradsease/oem
- 8 real orbit samples (LEO/MEO/GEO at 10s/20s/60s intervals)
- 22 invalid samples (crash safety)
- LEO altitude/velocity range checks
- GEO altitude/velocity range checks
- Covariance block skipping (COVARIANCE_START/STOP)
ocaml-cdm: Blue Book section 4 KVN + XML test vectors archived
OEM (Orbit Ephemeris Message) KVN parser with multi-segment support.
Parses state vectors (position, velocity, optional acceleration),
metadata (ref frame, interpolation, time system), and comments.
Test vectors: Mars Global Surveyor (Blue Book Fig 5.1, multi-segment
with trajectory correction maneuver), ISS single-segment, and
acceleration data. 10 tests, merlint clean.
Critical path for ssa.space: TraCSS ephemeris submission, CREAM
maneuver integration, and maneuver what-if analysis.