Repository navigation
synapse-cdm 3.6.0
synapse-cdm 3.6.0
Rendered by synapse release-notes from the tree at this release's tag. Every
section below except major changes is a derivation; that one is quoted from
RELEASE_NOTES.md, which is written by a person. MIGRATIONS.md condition 4 is
unchanged by this file: it is still a person's, and this only makes the nine
mechanical fields impossible to mistype.
Versions
| axis | version |
|---|---|
| package version | 3.6.0 |
| CDM version | 3.2.0 |
| SC-OES version | 0.1.0 |
| Adapter API version | 3.1.0 |
| manifest schema version | 2.1.0 |
Major changes
The raster observation release. Between the 3.5.0 release of 2026-10-16 and this one, the tree
gained three adapter modules — grib2, cog and iem_n0q — and the registry moved from
twenty-seven to thirty. They read the gridded and raster halves of the public observation formats
3.5.0 began with: a GRIB edition 2 message (a model or analysis field, or a radar-derived
estimate), a Cloud Optimized GeoTIFF, classic GeoTIFF or GDAL VRT index (an elevation model or a
satellite band file, header-only), and an IEM NEXRAD N0Q radar composite PNG. Each becomes an
ENVIRONMENTAL_OBSERVATION Event carrying the gridded-field/1 or imagery-product/1 contract
3.5.0 published, or, for a GeoTIFF or VRT that states no time and is given none, an ANNOTATION
PlanObject. The two raster adapters share a standard-library codec, adapters/raster_codec.py
(the TIFF and GeoTIFF structure, block decoding and a PNG reader), and the offline host command
synapse-decode serves all three, cutting a GRIB2 file into its messages. Nothing on the wire
moved: SCHEMA_VERSION stays 3.2.0, no model, enum or published schema changed, and no golden of
an adapter that predates the arc moved by a byte. MIGRATIONS.md's 3.6.0 section is
the record of what the distribution carries.
If you are upgrading from 3.5.0, nothing you read or write changes. A 3.5.0 reader reads a
3.6.0 object unchanged, and version.compatible("3.2.0", "3.2.0") is the same answer it was. No
member of the Adapter contract moved, so an adapter subclass written against 3.5.0 keeps working.
synapse-decode gains three rows and a framer, and every invocation that worked against 3.5.0
works the same way: a host entry that declares no frame offset is handed exactly what it was.
Why the number is 3.6.0
The number is the derived floor: a MINOR from v3.5.0. gates/bump_derivation.py, run on the
landing commit before any number was typed, read "the arc since 3.5.0 derives MINOR with 0
unruled, so the next release is at least 3.6.0", and its --json reported the arc as {"kind": "MINOR", "number": "3.6.0", "unruled": []}. The floor comes from the public names the arc added and
from nothing removed — the three Adapter subclasses Grib2Adapter, CogAdapter and
IemN0qAdapter with their fixture sets, and the codec module raster_codec — and the units the
table cannot decide on its own, the host module's Hosted, HOSTED, decode and listing, each
of which gained something and kept what it had, are ruled MINOR in MIGRATIONS.md's 3.6.0 section,
which the gate reads and reports nothing unruled. Over the arc the gate's table decides 379
signals, 172 MINOR and 207 PATCH, and the four rulings decide the rest.
Package version 3.6.0 · CDM schema_version 3.2.0 · Adapter API 3.1.0 · manifest schema 2.1.0
· evidence schema 2.0.0. The first two are four MINORs apart, the fourth for the ordinary
reason: the surface grew and the contract did not. python -m synapse_cdm.schemas --check --out schemas reads CURRENT: schemas vs models at 3.2.0 and python -m synapse_cdm.manifests --check
reads CURRENT: manifests vs 30 shipped adapters at manifest schema 2.1.0.
ADAPTER_API_VERSION, MANIFEST_SCHEMA_VERSION and EVIDENCE_SCHEMA_VERSION did not move in this
arc. SC-OES, the Operational Ontology and the profile versions did not move: SC_OES_VERSION is
still 0.1.0 and still a Draft. synapse_cdm/version.py states the nine version axes and their
independence.
The raster adapters, and what they are measured to do
In FORMAT_COVERAGE.md's ordinal table grib2 is #29, cog #30 and iem_n0q #31. They were
registered twenty-eighth to thirtieth and carry ordinals one higher because ordinal 9 was issued to
a specification that has no adapter: the ordinal is not the roster count. All three are
ingest-only, residual: structured, and declare a path-bound preservation ledger.
| Adapter | Specification / profile | Direction | What ships |
|---|---|---|---|
grib2 |
GRIB edition 2 (WMO FM 92, WMO-No. 306, and the NCEP GRIB2 documentation, both cited by reference): grid templates 3.0 and 3.30, product templates 4.0 and 4.8, data representation templates 5.0, 5.3, 5.41 and 5.40 in reference form | ingest | one message → one ENVIRONMENTAL_OBSERVATION Event per field carrying gridded-field/1; the grib2 fixture set |
cog |
OGC GeoTIFF 1.1, OGC COG 1.0 and TIFF 6.0 (cited by reference), and GDAL's VRT index form, header-only | ingest | one file → one ENVIRONMENTAL_OBSERVATION Event carrying imagery-product/1 when a sensing time is stated or supplied, otherwise one ANNOTATION PlanObject; the codec raster_codec; the cog fixture set |
iem_n0q |
W3C PNG, Third Edition, and IEM's composite_n0q product (cited by URL) |
ingest | one composite → one ENVIRONMENTAL_OBSERVATION Event carrying gridded-field/1 at the caller's archive slot; the iem_n0q fixture set |
grib2 reads one GRIB edition 2 message, as its octets or its parsed twin, and writes one
Event per field: the reference time as observed_at, never a future valid instant, with its Code
Table 1.2 significance; the forecast's validity, an instant or Template 4.8's interval, as
validity.effective; the grid verbatim and a WGS84 footprint Polygon — a lat/lon grid's corners,
a Lambert conformal grid's outline converted point by point on the template's sphere; and the
values by reference, with a summary decoded from simple packing, complex packing with spatial
differencing and PNG. JPEG 2000 fields are read in reference form and their values declared
unsupported. A parameter is named, and its unit stated, only for the code-table rows its pin lists;
any other keeps its code. Bounds: 8 MiB a message, at most 16 fields and 2^25 grid points a message
(complex packing can describe a run of equal values in no octets at all), and a PNG field's rows
compared with a 64 MiB bound before they are inflated, each refused by name.
cog reads one classic GeoTIFF or Cloud Optimized GeoTIFF, or one GDAL VRT index, as its
octets or its parsed twin, header-only: every directory, the GeoKeys, GDAL's metadata and nodata
are kept in the residual, every block is checked to lie in the file, and one block, block 0 of the
full-resolution image, is decoded (none, LZW, Deflate or PackBits, with predictors 2 and 3) and
summarised in its stored values, inline when small. A file whose metadata states a sensing time,
or whose caller supplies one with its basis, becomes an Event; a file that names a sensed product's
processing clock and states no sensing time is refused unless the caller supplies one; any other
file is a PlanObject under the structured limitation no-source-time. The footprint comes from
EPSG:4326, EPSG:4269 (stated without a datum shift) or a WGS84 UTM zone, converted point by point;
every other system is refused, and a NAVD88 height datum is stated beside the values, never as an
ellipsoidal height. A VRT's sources are listed and never opened, and a remote one is refused by
name. Bounds: 256 MiB a file, a decoded block of at most 1 MiB, and at most 64 directories, 128
entries a directory, 1 MiB a value, 4 MiB of values in all and 65 536 VRT elements.
iem_n0q reads one IEM N0Q composite PNG, as its octets or its parsed twin. The grid is a
product constant the adapter declares — 12200 x 5400 cells of 0.005 degree in EPSG:4326 — and the
PNG's header is held to it before anything is inflated; the archive's world file is never read.
Palette index 0 is missing and index i is (i − 65) / 2 dBZ; the 65 880 000 values stay in the file by
reference, with a summary in dBZ. A PNG states no time, so observed_at is the archive file name's
five-minute slot, which the caller supplies with its basis; IEM's gentime text, a generation
clock, is carried verbatim as the product's version and never as a time. Bounds: 8 MiB a file, the
rows held to the constant grid's 65 885 400 octets under an 80 MiB bound, and, since this release,
at most 64 ancillary chunks and 1 MiB of their data octets in all, refused in the chunk walk before
anything is inflated.
What they refuse, by name. Every refusal is the adapter's own ValueError subclass —
Grib2Refused, CogRefused, IemN0qRefused — whose code names the rule and whose message never
quotes a value from the payload, asserted on 29 refused payloads under the three malformed/
directories (11 GRIB2 messages, 8 GeoTIFFs and 2 VRT indexes, 8 PNGs) and on inputs the tests
generate.
Where their behaviour comes from. The governing documents are cited by reference and never
carried: the NCEP GRIB2 pages and WMO-No. 306, OGC GeoTIFF 1.1, OGC COG 1.0 and TIFF 6.0, the W3C
PNG specification and IEM's pages, by their pin records. Every fixture is synthetic: the iem_n0q
set is written in pure Python by its builder, which writes its own DEFLATE stream; six GRIB2
messages and every malformed one by the grib2 builder's own encoder and seven by GDAL 3.13.3;
two VRT indexes by the cog builder and eight GeoTIFFs by GDAL 3.13.3. Each builder's --check
rebuilds what it writes byte for byte and, where GDAL is absent, holds the tool-written files to
their recorded digests and says so. No byte or value of a real collection is in the tree.
synapse-decode, three rows more
synapse-decode reads one local file through a registered adapter, as 3.5.0 shipped it, and now
serves the three: grib2 with a framer that cuts a GRIB2 file into its messages end to end and
hands each over with its ordinal, the octet it begins at and, when it is not the whole file, its own
digest — a gap, an edition 1 message or a length that disagrees is refused; cog, with the band
file's name, the granule and the role of a supplied instant (time=sensing_time or time=as_of)
as request parameters, the file read whole under its 256 MiB bound; and iem_n0q, with --at the
archive slot and --received-at required. A URL, an s3:// or a /vsicurl/ locator is still
refused by name; the exit codes are still 0, 2, 3 and 4, and no diagnostic quotes the input.
External interoperability is a separate conclusion, and it is NOT claimed
Each new adapter reads a public format from synthetic fixtures. That the translation of those
fixtures is implemented and checked is claimed; that a real file of each format translates is not,
because no real file is in this repository.
- The five evidence categories, as generated by
python -m synapse_cdm.evidence generate --adapter <name>on this tree for each of the three — the records themselves are generated,
gitignored, and attached by a Release rather than committed:internal_fixturePRESENT;
self_round_tripNOT_APPLICABLE, each being ingest-only;independent_expectedABSENT;
normative_schemaABSENT;independent_endpointABSENT. - Declared maturity is L3 and claim status VERIFIED for each, read from
manifests/<name>.json.
L4 is not declared: an ingest-only adapter has no round trip, and a rung passed vacuously is not a
rung declared. - The strict readings have met the documents and not yet a real file: the GRIB2 templates and
code-table rows read, Code Table 3.2's two sphere radii (which rest on GDAL 3.13.3's reading of the
table, recorded in the pin, rather than on a pinned copy of it), the GeoTIFF coordinate systems and
compressions read, and the N0Q product constant, itsgentimetext and the ancillary chunks a real
composite carries each stand as the stricter reading until a real file is read against them. - A values summary's domain is the producer's.
cogsummarises a window in its stored values,
with the file's scale and offset stated beside it;grib2andiem_n0qsummarise decoded values.
The observation-contracts page says so, and one domain for every producer is the contract
owner's to rule. evidence.availableistrueon the three from this release. Each landed declaringfalse
— "it becomes true at the first release that attaches them" — andtests/test_cdm_evidence.py
holds the field to the newest release tag's tree. The release commit flipped each, with a
limitation sentence that names no version, the form the five of 3.5.0 took:
.github/workflows/publish.ymlgenerates the records for every shipped adapter and attaches them
to the Release of the version it publishes.
The bridge, synapse-link16-bridge 1.1.0, on GitHub only
packages/link16_bridge/ holds the second distribution, synapse-link16-bridge, still 1.1.0
(import synapse_link16_bridge, command synapse-link16-bridge): nothing under it moved since
v3.5.0, and its runtime dependencies are still synapse-cdm 3.5.0 or later and below 4, and the
standard library.
It is part of the tag v3.6.0 and of the GitHub Release's source archives, and it is not part of
this wheel or of the package index: no second project is created there in this release, which is an
act for the account owner. It installs from the tag, after synapse-cdm from the index:
pip install synapse-cdm==3.6.0
pip install "synapse-link16-bridge @ git+https://github.com/Decent-Cybersecurity/synapsecommand-public@v3.6.0#subdirectory=packages/link16_bridge"Its workflow .github/workflows/gateway-bridge.yml runs its offline tests on every push to main
and to the release and arc branches.
What changed for a 3.5.0 consumer
- Three new adapter modules, three new fixture directories and the codec module
raster_codec;--list-adaptersreports thirty and the harness replays each new adapter with
--adapter <name>and no--fixtures. No other adapter's verdict moved. synapse-decodeservesgrib2,cogandiem_n0q, and lists a framed entry with the words
framed by message; every existing listing line and invocation is unchanged.- The wire contract is still 3.2.0. Every object this package writes is stamped
3.2.0, as at
3.5.0, except whatlink16_gateway's compatibility projection (cdm_schema="3.0.0") writes.
Thirty adapters at 3.6.0, all harness-verified
python -m synapse_cdm.harness --adapter <name> --schemas schemas, run over the roster with no
--fixtures on this tree, and every verdict read from the run. The table is the live registry,
and tests/test_cdm_release.py::test_the_release_notes_roster_table_is_the_registry requires both
directions to agree. On this tree python -m synapse_cdm.harness --list-adapters prints 30 adapters registered. Declared maturity and claim status are read from manifests/<name>.json.
| Adapter | Direction | Fixture verdicts | Declared maturity | Claim |
|---|---|---|---|---|
adsb |
bidirectional | 32 | L3 | VERIFIED |
ais |
bidirectional | 22 | L3 | VERIFIED |
cat021 |
bidirectional | 40 | L3 | VERIFIED |
cat023 |
bidirectional | 34 | L3 | VERIFIED |
cat034 |
bidirectional | 34 | L3 | VERIFIED |
cat048 |
bidirectional | 82 | L3 | VERIFIED |
cat062 |
bidirectional | 56 | L3 | VERIFIED |
gmti |
bidirectional | 32 | L3 | VERIFIED |
legion |
ingest | 6 | L3 | VERIFIED |
pntmap |
ingest | 4 | L3 | VERIFIED |
stanag4586 |
ingest | 24 | L3 | VERIFIED |
stanag4609 |
bidirectional | 126 | L3 | VERIFIED |
stanag4676 |
bidirectional | 34 | L3 | PROVISIONAL |
tak |
bidirectional | 12 | L3 | VERIFIED |
geojson |
bidirectional | 4 | L4 | VERIFIED |
geopackage |
ingest | 8 | L3 | VERIFIED |
c2sim |
bidirectional | 10 | L4 | VERIFIED |
aixm511 |
ingest | 10 | L3 | VERIFIED |
aixm52 |
ingest | 10 | L3 | VERIFIED |
dis7 |
bidirectional | 6 | L4 | VERIFIED |
tacticalapi |
ingest | 10 | L3 | VERIFIED |
link16_gateway |
bidirectional | 15 | L4 | PROVISIONAL |
readsb_trace |
ingest | 26 | L3 | VERIFIED |
nexrad2 |
ingest | 10 | L3 | VERIFIED |
ndbc_stdmet |
ingest | 8 | L3 | VERIFIED |
coops_csv |
ingest | 7 | L3 | VERIFIED |
airnow_hourly |
ingest | 8 | L3 | VERIFIED |
grib2 |
ingest | 26 | L3 | VERIFIED (new in the 3.6.0 arc) |
cog |
ingest | 20 | L3 | VERIFIED (new in the 3.6.0 arc) |
iem_n0q |
ingest | 8 | L3 | VERIFIED (new in the 3.6.0 arc) |
724 fixture verdicts, 0 failed across the thirty, against the published 3.2.0 schemas — the 670
that 3.5.0 shipped, every golden byte for byte as it was, plus 54 from the three new sets. The two readings the wheel gate takes,
its resources and harness checks, run on this tree from a directory outside the repository,
read 30 adapters, 754 fixture files and 30 adapters x 2 schema modes, 1448 fixture verdicts, 0 failed; gates/wheel_install.py takes the same readings off
the installed wheel in the release workflow. The lossless column reads PASS on every JSON
fixture and a stated SKIP on every non-JSON one, and FAIL on none, on a declared ledger for
pntmap, the five of the 3.1.0 arc, dis7, tacticalapi, link16_gateway, the five of the 3.5.0
arc and the three of this one, and on the value-presence heuristic, said so, for the other thirteen. The four L4 declarations
(geojson, c2sim, dis7, link16_gateway) rest on a ledger that reports no loss over a self
round trip under the adapter's declared tolerance; every other declaration is L3.
Nine schema files, regenerated from the models by python -m synapse_cdm.schemas and
byte-identical to the committed ones: entity, event, track, plan_object,
payload_gnss_interference and cdm_object under schemas/, manifests/adapter-manifest and
evidence/evidence and evidence/exercise beside them. None of the nine moved in this release:
the first six carry x-cdm-schema-version: 3.2.0, as at 3.5.0, and git diff v3.5.0 -- schemas/
is empty. The four observation contract schemas under schemas/observation/, generated by
python -m synapse_cdm.observation_contracts, and the three gateway schemas under
schemas/link16_gateway/, the handoff's, did not move either.
Published by CI over OIDC, as 1.1.0 through 3.5.0 were
No API token. .github/workflows/publish.yml builds on the tagged tree, gates that build with
gates/wheel_install.py --mutation-check, runs twine check --strict, checks that the tag names
the tree's PACKAGE_VERSION, and uploads those same files through PyPI Trusted Publishing after a
required reviewer approves the pypi environment. PUBLICATION.md ledger entry 6 records the
configuration, and entry 27 records the 3.5.0 upload. The workflow builds and uploads
synapse-cdm only; the bridge reaches the Release as source in the tag.
Artefacts
An sdist and a wheel, built once by the workflow, gated as that build, and uploaded as those same
files. Their SHA-256 digests are recorded in PUBLICATION.md's ledger together with the
workflow run that produced them. The GitHub Release additionally carries both SBOMs, the evidence
set, the conformance report, the witness record and these notes — so the evidence a claim rests
on is retrievable with the release rather than only as a workflow artefact with a retention
window.
They are deliberately not committed here, for the reason this file has given since 1.1.0. A digest
is a property of one build rather than of the tree: two builds of one tree have identical payloads
but differ in their generated metadata, so a digest written here before the tag would not be the
digest of the file PyPI serves, and one written after the tag could never be inside the tree the tag
names. 1.3.0 measured that the hard way — a local build and the published wheel came out at the
same byte count and were different files — so the digests to compare a download against are the
workflow's, never a rebuild's. Everything else in this document is readable off that tree, which is
what condition 4 of the release procedure asks for.
pip install synapse-cdm==3.6.0
python -m synapse_cdm.harness --list-adaptersAdapter status
30 adapters ship in this distribution. declared is the rung the
adapter's manifest claims; eligible is the rung this release's conformance
sweep allows it. A declared rung above an eligible one is a defect, not a note.
| adapter | version | direction | declared | eligible | claim | result |
|---|---|---|---|---|---|---|
adsb |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
airnow_hourly |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
ais |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
aixm511 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
aixm52 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
c2sim |
1.0.0 | bidirectional | L4 | L5 | VERIFIED | CONFORMANT |
cat021 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
cat023 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
cat034 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
cat048 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
cat062 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
cog |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
coops_csv |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
dis7 |
1.0.0 | bidirectional | L4 | L5 | VERIFIED | CONFORMANT |
geojson |
1.0.0 | bidirectional | L4 | L5 | VERIFIED | CONFORMANT |
geopackage |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
gmti |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
grib2 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
iem_n0q |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
legion |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
link16_gateway |
1.0.0 | bidirectional | L4 | L5 | PROVISIONAL | CONFORMANT |
ndbc_stdmet |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
nexrad2 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
pntmap |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
readsb_trace |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
stanag4586 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
stanag4609 |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
stanag4676 |
1.0.0 | bidirectional | L3 | L5 | PROVISIONAL | CONFORMANT |
tacticalapi |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
tak |
1.0.0 | bidirectional | L3 | L5 | VERIFIED | CONFORMANT |
Security status
| control | state |
|---|---|
| GitHub secret scanning | active |
| Secret-scanning push protection | active |
| Private vulnerability reporting | active |
| Secret scanning in CI (gitleaks) | active |
| No secret in the repository's history | active |
| Input bounds on every adapter | active |
| Parser-safety policy | active |
| Resource isolation of the conformance worker | active |
| Streaming input | not provided |
Verification of the integrity block |
not provided |
| Signed commits | active |
| Dependabot alerts and the dependency graph | active |
| Dependabot security updates | active |
| Dependabot version updates | active |
| Dependency review on pull requests | active |
| Python dependency audit | active |
npm dependency audit over docs/ |
active |
Pinned floors on transitive npm dependencies of docs/ |
active |
| CodeQL, with a gate that fails the build | active |
| SBOM, two formats | active |
| Build attestation, no long-lived key | active |
| Documented, time-bounded security exceptions | active |
| Secret-scanning non-provider patterns | not enabled in this round |
| Secret-scanning validity checks | not enabled in this round |
| Cryptographic signing of CDM objects | not provided |
| Defence against a producer asserting false semantics | not provided |
- CodeQL, this release's run: 0 result(s), 0 blocking at or above 7.0; gate exit 0 over 4 analysis file(s) of 4aee3f6
pip-audit, this release's run: No known vulnerabilities found; strict, over 43 third-party distribution(s), ignore-vuln flags in force: [--ignore-vuln GHSA-vfj7-8cjw-p6xm]- Security exceptions in force: 1 —
GHSA-vfj7-8cjw-p6xm.json
Known limitations
Stated by the adapters themselves, in their manifests. This is not a survey of what
the package cannot do; it is what each adapter says it does not do.
adsb
- the edition this adapter is written against is NOT STATED by any document in this repository — no pin record exists for RTCA DO-260x or ICAO Annex 10, both of which
fixtures/adsb/spec/adsb_terms.jsonrecords as priced, soformat.versionis null rather than guessed - DF17 and DF18 only; every other downlink format is out of scope
- a single frame carries no unambiguous position — the 17-bit CPR fields need a second frame of the opposite parity or a reference position, and no frame carries a time at all
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
airnow_hourly
- HourlyData and HourlyAQObs files are read; the forecast file (reportingarea.dat), the site file (monitoring_site_locations.dat), the API's responses and EPA AQS records are not, and nothing is joined from another file
- a HourlyData line states no position: it comes only from a caller's site table (a StationTable keyed by AQSID), else the site Entity's position is null; a HourlyAQObs line's Latitude and Longitude are its stated position, and its Elevation, whose datum the fact sheet does not state, stays in the residual
- a stamp is the GMT start of a one-hour period: validity.effective is [start, start + 1 h] and observed_at its end; the GMT offset (to local standard time) is never applied
- a HourlyAQObs AQI field is carried with the unit AQI under the fact sheet's definition, an index with no other unit; a concentration's unit is its own *_Unit field, verbatim
- a HourlyAQObs line stating neither an AQI nor a concentration is refused no-reading, and a HourlyData line with a blank value or unit is refused blank-value: the fact sheets say only valid data are reported, and the design record holds no such line
- AirNow's hourly files carry no per-value quality flag, so every contract states quality_flags_basis; the data are preliminary, and the AirNow Data Exchange Guidelines' terms bind the consumer, not this package
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
ais
- the edition this adapter is written against is NOT STATED by any document in this repository — the format has two publishers, ITU-R (M.1371) and NMEA (0183), and
fixtures/ais/spec/ais_terms.jsonrecords both without naming the edition this implementation targets, soformat.versionis null rather than guessed - message types 1, 2, 3, 4, 5, 18, 19 and 21 are in scope; every other type is named in FORMAT_COVERAGE.md with the reason it is out
- type 24 static data is out of scope, so a vessel's name and call sign arrive in no message this adapter reads
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
aixm511
- the five families are Airspace, AirportHeliport, Runway, RunwayDirection, Navaid and VerticalStructure, plus the Digital NOTAM event:Event (its own reading, limitation digital-notam-profiles); a feature of any other class (Unit, OrganisationAuthority, Route, Procedure …) becomes an Entity of type UNKNOWN carrying the GENERIC reading only — identity, interpretation, sequence and correction numbers, validTime, featureLifetime, the pinned simple properties the slice happens to state, and the ledger-bound complex elements (
CARRIED_ELEMENTS: location, ARP, a repeated availability — or a single one on the eleven NavaidEquipment classes NAV.UNS binds, whose time-slice types list it — activation, part, navaidEquipment, geometryComponent) carried source-verbatim at their block field — with every other property in the residual and no position or status, andvalidate_sourcenames it; a member that is not a feature at all (no aixm:timeSlice) is carried whole in the residual. Within a family only the pinned properties are typed (the implementation record lists them); the rest is residual - Digital NOTAM is read on the AIXM 5.1.1 + Event Schema 2.0.m combination only (Event 2.0.k and 2.0.l accept the same documents; 1.0 / 2.0.f / 2.0.j do not; no Event schema targets AIXM 5.2). The pinned scenario profiles are exactly RWY.CLS, ATSA.ACT, SAA.ACT and NAV.UNS at scenario version 2.0 of the Digital NOTAM Specification 2.0, which is a DRAFT ('in preparation', validated by implementation) and is never described as an approved final standard; an Event stating any other scenario is typed and carried with
profile_findingand no scenario rule is checked. The rule layer holds a bound slice to the rules it can be held to on its own — the binding rule (TEMPDELTA on a feature class the profile names) and the status rule (RWY.CLS.03, ER-01/ER-02, NAV.UNS.04) on the change's own structures; a structure carrying the REMARK 'Baseline data copy. Not included in the NOTAM text generation' (ATSA.ACT ER-04, SAA.ACT ER-06, NAV.UNS.08) restates the baseline and is kept, not judged — as findings, never repairs; the schema layer is normative_validation. NOTHING is resolved by this adapter: correction, cancellation, replacement and expiry are typed as the slice's own source assertion, and the resolved view at an instant issynapse_cdm.aixm_resolve, which takes explicit prior state. The event extension on a feature slice is read and not consumed (it stays in the residual at its position) - gml:ArcByCenterPoint, gml:CircleByCenterPoint, gml:Arc, gml:ArcString, gml:Circle, gml:CompositeCurve, gml:OrientableCurve, a CRS other than urn:ogc:def:crs:EPSG::4326 and urn:ogc:def:crs:OGC:1.3:CRS84, and a third dimension refuse the document by default with the element form and the source text named; under
Aixm511Adapter(unsupported_geometry='report')the slice is an Entity with the form named inattributes.aixmand no PlanObject. No arc is replaced by a chord and no circle by a polygon - an Airspace whose geometry components use UNION, INTERS or SUBTR, or whose BASE components state different vertical limits, is typed component by component and produces no PlanObject: the CDM Area is one volume and composing one would be a derivation the source did not state.
volume_projectionon the block says why;validate_sourcenames it - a vertical limit projects onto the CDM only where a VerticalUnit and a VerticalReference exist for it (FT/M against SFC/MSL/W84/STD, FL against STD); SM, a flight level against another reference, an unstated uom and the tokens UNL/GND/FLOOR/CEILING are carried typed with the reason they are not projected. Feet are never converted to metres and no datum is converted
- a time slice with no validTime instant of its own (§4.4.8's cancellation with nilReason='inapplicable', an absent validTime, an indeterminate begin) can be an Entity only under
Aixm511Adapter(as_of=AsOf(instant, basis)), whose instant becomesvalid_fromwith the basis insource.transformations; without it the document is refused naming the slice. Nothing is stamped with the clock or the epoch - a feature of a pinned family without a gml:identifier is refused: identity is derived from the UUID the feature carries across documents (Feature Identification and Reference 1.0 §2.1), and a document-local gml:id would make the same feature two entities in two documents
- xlink:href is resolved against the document and the caller's
referencestable, one hop, never over a network; a URL is classified and not fetched; unresolved references are kept with their property, href and form underattributes.aixm.referencesand listed inunresolved_references - Timesheets, activation and availability structures are carried as typed validity, never resolved to instants;
statuson an Entity is set only when the slice states exactly one such structure and it carries no timeInterval, so an unconditional status is never asserted from a scheduled one - positions carry
position_source: MANUAL— a surveyed, published coordinate is none of GNSS, INERTIAL or ESTIMATED — with the MSL elevation of an ElevatedPoint invertical(its uom kept, reference MSL by the model's own definition ofelevation) andalt_mNone because MSL is not height above the ellipsoid - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged.evidence.availableis true because 3.1.0 is the first release carrying this adapter and its pipeline generates the records for every shipped adapter and attaches them to thev3.1.0Release asevidence-3.1.0.tar.gz, retrievable by a third party; it says nothing about what the wheel contains, and a tag that released nothing carries this sentence to nobody - of §3.5's five resource limits this adapter enforces THREE —
max_input_bytesby the base class before decode and again bysecure_xmlbefore a parser exists,max_depthandmax_objectsin this module before any object is built — plus an element count the manifest schema has no field for. The other two are absent with their reasons incapabilities.limits.absent_because - XML is parsed with the standard library's expat through
secure_xmland NOT withdefusedxml, which is not a dependency of this package: a DOCTYPE is refused at its declaration before any entity is read, every entity reference other than the five predefined ones is refused, no external resource is fetched and XInclude is refused where it starts (tests/test_cdm_secure_xml.py). The tree isxml.etree.ElementTree's own, built through its TreeBuilder - this adapter reads AIXM 5.1.1 only: a document in the 5.1 or 5.2 namespace is refused at the root with its namespace named; AIXM 5.2 is a sibling adapter
aixm52
- the five families are Airspace, AirportHeliport, Runway, RunwayDirection, Navaid and VerticalStructure, with the AIXM 5.2 property groups pinned (the implementation record lists the 5.2 paths per family and the 5.1.1 → 5.2 differences); a feature of any other class (Unit, OrganisationAuthority, Route, Procedure …) becomes an Entity of type UNKNOWN carrying the GENERIC reading only — identity, interpretation, sequence and correction numbers, validTime, featureLifetime, the pinned simple properties the slice happens to state, and the ledger-bound complex elements (
CARRIED_ELEMENTS: location, ARP, a repeated availability, activation, part, navaidEquipment, geometryComponent) carried source-verbatim at their block field — with every other property in the residual and no position or status, andvalidate_sourcenames it; a member that is not a feature at all (no aixm:timeSlice) is carried whole in the residual. Within a family only the pinned properties are typed; the rest is residual — including the 5.2 AirspaceVolumenameandlocation, which ride in the component's verbatim source and are not typed - No Digital NOTAM Event schema exists for AIXM 5.2: every published Event Schema revision (5.1-e, 5.1.1-f/-j/-k/-l/-m) targets http://www.aixm.aero/schema/5.1.1/event or …/5.1/event, and the publisher states 'The current specifications for … Digital NOTAM are based on AIXM 5.1.1' (https://aixm.aero/page/aixm-52, read 2026-09-20). This adapter therefore reads NO Digital NOTAM: no Event feature, no scenario profile (
profilesis empty), noattributes.dnotamblock and no scenario rule; a member in the AIXM 5.1.1 Event namespace inside a 5.2 document is named byvalidate_source, carried whole in the residual and never typed. Digital NOTAM is the AIXM 5.1.1 adapter's (aixm511, limitation digital-notam-profiles), on the AIXM 5.1.1 + Event Schema 2.0.m combination only; nothing here claims that the same extension works with 5.2 - gml:ArcByCenterPoint, gml:CircleByCenterPoint, gml:Arc, gml:ArcString, gml:Circle, gml:CompositeCurve, gml:OrientableCurve, a CRS other than urn:ogc:def:crs:EPSG::4326 and urn:ogc:def:crs:OGC:1.3:CRS84, and a third dimension refuse the document by default with the element form and the source text named; under
Aixm52Adapter(unsupported_geometry='report')the slice is an Entity with the form named inattributes.aixmand no PlanObject. No arc is replaced by a chord and no circle by a polygon - an Airspace whose geometry components use UNION, INTERS or SUBTR, or whose BASE components state different vertical limits, is typed component by component and produces no PlanObject: the CDM Area is one volume and composing one would be a derivation the source did not state.
volume_projectionon the block says why;validate_sourcenames it - a vertical limit projects onto the CDM only where a VerticalUnit and a VerticalReference exist for it (FT/M against SFC/MSL/W84/STD, FL against STD); SM, a flight level against another reference, an unstated uom and the tokens UNL/GND/FLOOR/CEILING are carried typed with the reason they are not projected. Feet are never converted to metres and no datum is converted. An ElevatedPoint's
verticalDatumis free text in 5.2 (TextNameType) and is carried as the text stated - a time slice with no validTime instant of its own (§4.4.8's cancellation with nilReason='inapplicable', an absent validTime, an indeterminate begin) can be an Entity only under
Aixm52Adapter(as_of=AsOf(instant, basis)), whose instant becomesvalid_fromwith the basis insource.transformations; without it the document is refused naming the slice. Nothing is stamped with the clock or the epoch - a feature of a pinned family without a gml:identifier is refused: identity is derived from the UUID the feature carries across documents (Feature Identification and Reference 1.0 §2.1), and a document-local gml:id would make the same feature two entities in two documents. The gml:identifier a 5.2 «object» may carry is a property of that object, never an identity
- xlink:href is resolved against the document and the caller's
referencestable, one hop, never over a network; a URL is classified and not fetched; unresolved references are kept with their property, href and form underattributes.aixm.referencesand listed inunresolved_references - Timesheets, activation and availability structures are carried as typed validity, never resolved to instants;
statuson an Entity is set only when the slice states exactly one such structure and it carries no timeInterval, so an unconditional status is never asserted from a scheduled one - positions carry
position_source: MANUAL— a surveyed, published coordinate is none of GNSS, INERTIAL or ESTIMATED — with the MSL elevation of an ElevatedPoint invertical(its uom kept, reference MSL by the model's own definition ofelevation) andalt_mNone because MSL is not height above the ellipsoid - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged.evidence.availableis true because 3.1.0 is the first release carrying this adapter and its pipeline generates the records for every shipped adapter and attaches them to thev3.1.0Release asevidence-3.1.0.tar.gz, retrievable by a third party; it says nothing about what the wheel contains, and a tag that released nothing carries this sentence to nobody - of §3.5's five resource limits this adapter enforces THREE —
max_input_bytesby the base class before decode and again bysecure_xmlbefore a parser exists,max_depthandmax_objectsin the shared reader before any object is built — plus an element count the manifest schema has no field for. The other two are absent with their reasons incapabilities.limits.absent_because - XML is parsed with the standard library's expat through
secure_xmland NOT withdefusedxml, which is not a dependency of this package: a DOCTYPE is refused at its declaration before any entity is read, every entity reference other than the five predefined ones is refused, no external resource is fetched and XInclude is refused where it starts (tests/test_cdm_secure_xml.py). The tree isxml.etree.ElementTree's own, built through its TreeBuilder - this adapter reads AIXM 5.2 only: a document in the 5.1 or 5.1.1 namespace is refused at the root with its namespace named; AIXM 5.1.1 is the sibling adapter
aixm511, and the two share one reader under two profiles (aixm511.Profile)
c2sim
- an initialisation's Person, NonMilitaryOrganization, CommunicationNetwork, Overlay, CulturalFeature, EnvironmentalObject, GeographicFeature, non-Route map graphic, Action and PlanPhaseReference produce no canonical object: each is carried whole in every object's residual at its own path under
residual.data.MessageBodyand named byvalidate_source. The typed classes are ForceSide, Unit, the four Platform kinds and the Route map graphic - AcknowledgementBody, PlanBody, RequestBody, ObjectInitializationBody, SystemAcknowledgementBody and SystemCommandBody are refused by name: session and protocol state live in the exercise client (
examples/c2sim/exercise_client.py), never in the adapter - a ManeuverWarfareTask whose TaskActionCode is not MoveToLocation or HoldInPlace (decision D1) is refused with a diagnostic naming the two supported forms, on ingest and on egress; no other task is ever substituted
- ActivityObservation, ResourceObservation and SubjectTypeObservation are carried whole under
payload.c2sim.observations[].raw(typed: false); Health, Location and Name observations are typed - a SimulationTime instant is scenario seconds since the scenario epoch and resolves only against
C2simAdapter(exercise=ExerciseClock(epoch, basis)); a RelativeTime never resolves here. An Event whose observed_at would need an unresolved instant is refused, naming the form; a task's start and end times are carried typed either way - affiliation is read from the own side's stated ForceSideRelation only when
C2simAdapter(own_side=<uuid>)names it (FR, HO, NEUTRL; every other hostility code reads UNKNOWN with the code kept); without it every entity is UNKNOWN. Nothing is inferred from a name or a SIDC - elements and attributes outside the pinned vocabulary are preserved and listed on ingest but are not written back on egress, so an emitted document stays inside the schema the validator judges; a re-ingested round trip therefore lacks them, and the harness fixtures carry none
- the APP-6 SIDC string a source states is carried verbatim as a classification and never becomes
Entity.symbol, which is a 20-digit MIL-STD-2525D code; positions carryposition_source: ESTIMATED, the understating reading legion applies to a simulation's fixes, and their MSL or AGL height is kept inverticalunconverted withalt_mNone - egress of an Entity with no
attributes.c2simblock is refused: the schema needs a UUID, at least one EntityType and, for a Unit, an EchelonCode, and none of these is invented from the CDM's own fields - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged.evidence.availableis true because 3.1.0 is the first release carrying this adapter and its pipeline generates the records for every shipped adapter and attaches them to thev3.1.0Release asevidence-3.1.0.tar.gz, retrievable by a third party; it says nothing about what the wheel contains, and a tag that released nothing carries this sentence to nobody - of §3.5's five resource limits this adapter enforces THREE —
max_input_bytesby the base class before decode and again bysecure_xmlbefore a parser exists,max_depthandmax_objectsin this module before any object is built — plus an element count the manifest schema has no field for. The other two are absent with their reasons incapabilities.limits.absent_because - XML is parsed with the standard library's expat through
secure_xmland NOT withdefusedxml, which is not a dependency of this package: a DOCTYPE is refused at its declaration before any entity is read, every entity reference other than the five predefined ones is refused, no external resource is fetched and XInclude is refused where it starts (tests/test_cdm_secure_xml.py). The tree isxml.etree.ElementTree's own, built through its TreeBuilder
cat021
- ADS-B MOPS versions 0, 1 and 2 in full; version 3 (ED-102B / DO-260C) only partially, and mostly in the Reserved Expansion Field
- Edition 2.6 states on its own cover that it is not backwards compatible to Edition 2.1 or earlier, and this adapter does not read those editions
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
cat023
- the smallest specification pinned in this repository: nine data items, and nothing outside them is decoded
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
cat034
- the pinned edition is 1.29 and it is NOT the latest:
fixtures/cat034/spec/cat034_pin.jsonrecords Edition 1.30 as available, and this adapter is written against 1.29 - leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
cat048
- the Reserved Expansion field is carried verbatim and never interpreted: no edition of this category defines its contents
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
cat062
- the input is already the output of a fusion process, so the CDM objects this adapter emits carry judgements a tracker made and this adapter neither repeats nor re-decides
- items the specification marks implementation-dependent are parked verbatim and not interpreted
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
cog
- Array values are carried by reference — a locator, the shape and packing needed to open them, and a summary — and are not copied into the output.
- the twin's wire_hex is the file's octets, the input its dict form is decoded from; they are identified by SourceRef.source_hash when the caller gives it and are not copied into any object
- a DEM and a VRT state no instant, so the PlanObject carries no timestamp unless the caller supplies an as-of (
CogAdapter(as_of=InjectedTime(instant, basis))), which lands atvalidity.observed_atwith its basis insource.transformations. A band file whose metadata states a sensing time becomes an Event and is judged on it. The conformance suite's check J reads this id as the declared reason it may find no timestamp to judge - the values are read for one window only: block 0 of the full-resolution image (its north-west tile or first strip), clipped to the image, at most 1 MiB decoded; it is summarised in the stored values and carried inline when it holds at most 4096 cells (and, in an Event, when the file states its unit and no scale or offset). Every other block is checked to lie in the file and is not decoded; overview and mask directories are read as structure
- a footprint is converted from EPSG:4326, EPSG:4269 (NAD83, stated as WGS84 without a datum shift) and the WGS84 UTM zones only, and a vertical system only from EPSG:5703 (NAVD88 height); every other system, a user-defined one, a rotation and more than one tiepoint are refused by name. A height is never converted to the ellipsoid: the datum stays beside it in the residual
- classic TIFF only (BigTIFF refused by name); one sample a pixel; compression none, LZW, Deflate and PackBits (JPEG, LERC, ZSTD, LZMA, WebP and JPEG 2000 refused by name); predictors 1, 2 (integer samples) and 3 (Float32 and Float64); samples of 8, 16 or 32 bits signed or unsigned, Float32 and Float64
- a VRT is read as an index: its size, SRS, GeoTransform, metadata and simple or complex sources, listed and never opened; a remote source, a DTD, an entity and any other element (a derived band, a pixel function, an overview) are refused by name
- without
band_filean object's id derives from what the file states: its coordinate system, size, north-west corner, cell, sample type and sensing interval (a VRT's: its system, size, corner, cell and source count), followed by the caller'ssource_hashdigest when it gives one. With neitherband_filenorsource_hash, two band files of one granule that share a grid and a sensing time share an id; a caller that holds several bands of a granule passesband_file(andgranule_id) orsource_hash - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
coops_csv
- a response echoes none of the request's datum, units, time zone or interval, and the CSV form not its station: they are the caller's required CoopsRequest, and a JSON response naming another station is refused
- time_zone lst_ldt is refused by name (DECISIONS L-11): daylight-saving local time needs a time-zone database; gmt is read as UTC, and lst with the caller's declared standard-time offset
- the CSV form of water_level, air_pressure and wind and the JSON form of water_level are read; every other product, and the JSON form of air_pressure and wind, whose record keys the design record does not hold, are refused
- the request's units (metric or english) is every value's unit, verbatim under the request parameter's namespace; no unit string is derived from it, and wind's degrees direction is the one value with a unit of its own
- a blank field is refused blank-value: the design record does not hold how the API writes a missing sample, so this module neither reads a blank as a sentinel nor drops the reading
- wind's second Direction column, the compass point, is text and not a measurement; it stays in each Event's residual row
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
dis7
- Entity State subset only: protocol version 7, PDU type 1, protocol family 1. Every other PDU type, protocol family and DIS version is refused, and no network transport, capture file or multi-PDU datagram is read
- no IEEE certification is claimed, and acceptance under this subset is not validation of every reserved bit of the standard
- the IEEE 1278.1-2012 text was not consulted: the layout authority is open-dis-python (https://github.com/open-dis/open-dis-python, BSD-2-Clause) at commit 732b6655bb47e34ccc73722eefe0f4706fd0032f. A comparison with it exists as an opt-in test and an exercise report; no report ships in the distribution
- the state instant is supplied by the caller with its basis; the DIS timestamp is preserved and never converted. Affiliation is UNKNOWN for every force ID, and velocity is projected only for dead reckoning algorithms 2 to 5
- egress replays the original octets of an unchanged Entity only; a fresh or edited Entity is refused
fixture_instancesupplies the packaged fixtures' context (sessionunnamed, synthetic, the vectors' state instant and basis) and refusessynthetic=False. The harness and the conformance suite construct through it, so their verdict is defined for the packaged fixtures only; PDUs from another exercise need a caller-built adapter- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
geojson
GeometryCollectionis refused, not translated:geo.pykeeps it out of the CDM union deliberately (a heterogeneous geometry has no single semantics for a consumer), so a feature carrying one refuses the whole document. The RFC's other six geometry types are all carried- a GeoJSON text whose top-level object is a geometry (RFC 7946 §3 permits it) is refused: it has no id and no properties to carry, so nothing identifies it. Wrap it in a Feature
- a geometry whose
coordinatesarray is empty is refused. RFC 7946 §3.1 lets a processor read it as a null geometry; this adapter does not turn a stated geometry into an absent one silently - a
crsmember at any level is refused. RFC 7946 §4 removed it; a document carrying one follows the 2008 specification, and no legacy profile is implemented here. Projected coordinates are never relabelled as WGS84 - an empty FeatureCollection translates to no object, which is what it carries; its collection-level members then have no object to ride in and the preservation ledger reports them LOST for that document. Stated here so the empty result is never read as a filtered one
- RFC 7946 states no instant for a Feature or a FeatureCollection, so no object carries a timestamp unless the caller supplies an as-of context (
GeojsonAdapter(as_of=AsOf(instant, basis))), which lands atvalidity.observed_at(PlanObject) orvalid_from(Entity) with its basis insource.transformations. The conformance suite's check J reads this id as the declared reason it has no timestamp to judge bboxat every level is kept verbatim in the residual and is NOT projected to a canonicalBoundingBox:PlanObjectcarries bounds only inside anArea, andgeo.BoundingBoxrefuses an antimeridian-crossing box (west > east) by construction. Every bbox is noted insource.transformations, the antimeridian case as such- egress accepts
PlanObjectandEntity(an entity'spositionbecomes a Point, or a null geometry when it has none); anEventor aTrackis not compatible with the geo-object profile and egress refuses it rather than choosing a geometry for it - egress under the exchange profile refuses a source property already named
sc:...rather than overwriting it; thesc:keys of a re-ingested exchange document are ordinary source properties on ingest (this adapter never reads its own export keys back as canonical meaning), so such a document exports under the generic profile only - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged.evidence.availableis true because 3.1.0 is the first release carrying this adapter and its pipeline generates the records for every shipped adapter and attaches them to thev3.1.0Release asevidence-3.1.0.tar.gz, retrievable by a third party; it says nothing about what the wheel contains, and a tag that released nothing carries this sentence to nobody - of §3.5's five resource limits this adapter enforces THREE —
max_input_bytesandmax_depthby the base class before decode, andmax_objects(the feature count) in this module before any object is built — plus a position count the manifest schema has no field for. The other two are absent with their reasons incapabilities.limits.absent_because
geopackage
- only GeoPackage 1.4.0 (
user_version10400,application_idGPKG) is read; any otheruser_version, and the GP10/GP11 application ids of 1.0 and 1.1, are refused as unsupported with the value reported. Earlier versions are not implemented and are not silently accepted - a selected layer's SRS must be WGS 84 by DEFINITION — EPSG:4326, OGC:CRS84 or EPSG:4979, judged on the WKT's root, datum, ellipsoid and authority; an 'undefined' definition (srs_id 0 or -1), a projected CRS or any other datum refuses the package with the declaration reported. Nothing is reprojected and no other CRS is relabelled
- M ordinates are refused, never dropped and never read as height: a layer declaring m = 1 or m = 2 is inventoried as unsupported content (refused if selected by name), and a row carrying an XYM or XYZM geometry, or an envelope with an M range, refuses the package
- GeometryCollection, the non-linear extension types (CircularString, CompoundCurve, CurvePolygon, MultiCurve, MultiSurface, Curve, Surface) and ExtendedGeoPackageBinary (flag X = 1) are outside the profile: a layer declared with such a type is inventoried as unsupported; a row of a GEOMETRY column carrying one refuses the package
- raster tiles, gridded coverages, attributes-only tables and views are inventoried as unsupported content in every object's
residual.data.package.inventoryand are never read; a mixed package translates its selected vector layers only and every object says so - a container whose SQLite header says WAL mode (write/read version 2) is refused as WAL-dependent, because its committed content may be in a
-walfile the octets do not include;wal_checkpointed=Trueis the caller's assertion that the file was checkpointed, recorded on every object - a GeoPackage states no observation time;
gpkg_contents.last_changeis the table's last-edit stamp and is carried as package metadata, never as a row's time. No object carries a timestamp unless the caller supplies an as-of context (GeopackageAdapter(as_of=AsOf(instant, basis))), which lands atvalidity.observed_at(PlanObject) orvalid_from(Entity) with its basis insource.transformations. The conformance suite's check J reads this id as the declared reason it has no timestamp to judge - a Z ordinate is carried as the third coordinate element with the meaning the package declares and no other: under EPSG:4979 the SRS declares ellipsoidal height in metres; under EPSG:4326 or CRS84 the SRS declares no vertical axis and the value's datum and unit are undeclared — carried as sent, not asserted as height above the ellipsoid
- ingest only:
from_cdmis the base class's refusal (NotImplementedError), the manifest advertises no egress, and no GeoPackage is ever written. The cross-format path is the GeoJSON adapter's export (examples/geopackage_to_geojson) - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged.evidence.availableis true because 3.1.0 is the first release carrying this adapter and its pipeline generates the records for every shipped adapter and attaches them to thev3.1.0Release asevidence-3.1.0.tar.gz, retrievable by a third party; it says nothing about what the wheel contains, and a tag that released nothing carries this sentence to nobody - of §3.5's five resource limits this adapter enforces THREE —
max_input_bytesandmax_depthby the base class before decode, andmax_objects(the row count) in this module before any row is fetched — plus a per-value size, a coordinate count and an output estimate the manifest schema has no field for. The other two are absent with their reasons incapabilities.limits.absent_because
gmti
- the Controlled Extension FIELD DEFINITIONS are not implemented and cannot be: AEDP-4607's §L.4, which is where their field tables belong, reads "(TO BE PROVIDED)" in the promulgated Edition A Version 1
- the standard itself declines to specify error handling (§2.2), so a malformed packet's treatment is this adapter's decision and is documented at the site rather than cited
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
grib2
- Array values are carried by reference — a locator, the shape and packing needed to open them, and a summary — and are not copied into the output.
- a Template 5.40 field's values are a JPEG 2000 codestream this module does not decode (DECISIONS U-02: no decoder outside the standard library): Sections 0 to 6 are read, Section 7 is checked to open with a codestream's SOC and SIZ markers, and the contract states the field by reference with no summary
- the twin's wire_hex is the message's octets, the input its dict form is decoded from; they are identified by SourceRef.source_hash when the host injects it and are not copied into any object
- exactly one GRIB2 message per call, as its octets or as its twin; a file of several messages, a gzip around one and an index file are not taken. synapse-decode unwraps a gzip and cuts a file into its messages, each with its ordinal and the octet it begins at
- grid templates 3.0 and 3.30 (north-pole-centred, LaD a standard parallel, a spherical earth), product templates 4.0 and 4.8 (one time range), data representation templates 5.0, 5.3 (orders 1 and 2) and 5.41 (8- and 16-bit greyscale) are read; every other template, a predefined grid or bitmap, a quasi-regular grid, coordinate values after Section 4, a second Section 2 or 3, a scanning mode other than the i and j directions and a grid across 180 degrees are refused by name, as is GRIB edition 1
- a parameter's name and unit and a surface's unit are stated only for the Code Table 4.2 and 4.5 rows this module lists, each with the file it was read from (GDAL's table files, its NCEP local table for NCEP's local rows, and NSSL's MRMS table for MRMS's); any other parameter keeps its discipline.category.number code with no unit, any other surface its code with no value, and a row whose unit column states a code's meanings (CFRZR) names the parameter and states no unit
- the contract's level is the first fixed surface; a layer's second surface stays in the Event's residual with every other Template 4.x octet
- Event.geometry is the outline of the grid POINTS, not of the cells around them: a lat/lon grid's corner points, a Lambert grid's edge points converted with the spherical inverse, at most 16 segments an edge and rounded to 10^-6 degree
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
iem_n0q
- Array values are carried by reference — a locator, the shape and packing needed to open them, and a summary — and are not copied into the output.
- the grid is the IEM N0Q product constant — 12200 x 5400 cells of 0.005 degree in EPSG:4326, the archive's world file read as the centre of the north-west cell, so the outline runs from 126.0025 W 50.0025 N to 65.0025 W 23.0025 N — and the .wld beside an archive PNG is not read: a PNG of any other size, bit depth or colour type is refused. Which registration IEM means is not stated on its pages; the half-cell reading is this module's
- a PNG states no observation time: observed_at is the archive file name's slot (UTC, minutes divisible by five), the composite's nominal time, which the caller supplies with its basis (
IemN0qAdapter(slot=InjectedTime(instant, basis))); no radar's scan time is recoverable from the image. The tEXt gentime chunk is IEM's generation clock and is carried verbatim as product_version.production_time_verbatim, never as a time - index i is read as (i - 65) / 2 dBZ, so index 255 is 95.0 dBZ; IEM's composite documentation captions the ramp as -32 to 90 dBZ while its raster catalogue's table ends at 95, and the formula's value is emitted, not either page's ceiling
- an object's id derives from the slot, followed by the caller's
source_hashdigest when it gives one: IEM re-publishes a slot's file under the same name, and without the digest two files of one slot share an id - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
legion
- a VENDOR API rather than a ratified standard:
fixtures/legion/spec/openapi_pin.jsonrecords that it "can change between deploys, and its info.version demonstrably does not move when it does", sov3names the endpoint family and not a frozen edition - ingest only — this adapter does not emit Legion documents and never acquires one: no HTTP client, no token, no cursor, no base URL
- only the resources the pinned OpenAPI document names are in scope
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
link16_gateway
- the wire form is SC Link16 Gateway 1.0.0, an interface defined in this repository: a provisional internal profile bound to no normative document. Green gates prove agreement with that profile only
- no JREAP C or Link 16 bytes, frames or J-series words are parsed or produced, and no native interoperability, radio participation, encryption, accreditation or certification is claimed. The native boundary lives outside this package and refuses with BLOCKED_EXTERNAL_EVIDENCE until a normative profile, independent byte vectors and a peer test exist
- exactly one report per call, as UTF-8 JSON octets or as a dict; a stream, NDJSON, a list, text and the contract's lifecycle notices are refused (JSON_INVALID or SCHEMA_INVALID)
- duplicate keys, a byte order mark, invalid UTF-8 and non-finite number literals are refused on octets only: a dict was parsed by its caller, who already lost them. The runtime bridge always passes octets
- the contract's 1 MiB of UTF-8, depth 32 and 10 000 JSON value nodes are enforced here as LIMIT_EXCEEDED; past the manifest's 1 MiB and 64 containers the base class refuses first with InputTooLarge and InputTooDeep
- SENSOR and UNKNOWN are CDM 3.1.0 members of PositionSource. Under
cdm_schema="3.0.0"a report with either method yields an Entity with position null and no Track, marked POSITION_NOT_PROJECTED_CDM3, the report kept whole in the residual; every other report projects in full. The conformance suite judges the default projection only - a height stated as HAE in feet becomes metres (x 0.3048) in both
verticalandalt_m, departing from the description ofPosition.vertical(never converted), becausealt_mmay stand only beside an HAE vertical in metres; the feet stay in residual.data.report. No other datum or unit is converted, andalt_mis null for each of them - the report's eight identity tokens project to the CDM's four: FRIENDLY, HOSTILE and NEUTRAL as they are, and UNKNOWN, PENDING, ASSUMED_FRIEND, SUSPECT and OTHER to UNKNOWN. The token stays in residual.data.report and is not written into
attributes, which the contract forbids, although the Affiliation enumeration's own description says finer wording is kept there kinematics.observed_athas no home on the CDM's Kinematics and stays in residual.data.report; the Track's sample time isposition.observed_at, andvalid_fromiseffective_at, neverreceived_atEntity.symbolis null: no symbol profile is defined for this contract, andconfidence,valid_toandattributesstay unset too- the conformance suite builds this adapter without an ExportContext, so its egress evidence (check E) is mirror reconstruction of the same report; export mode is judged by this adapter's own tests, and
docs/docs/cdm/link16-gateway.mdxis its contract. Neither mode transmits anything - every packaged fixture is synthetic and labelled so; none is a capture and none is a native byte vector. The six reports of the engineering handoff are carried byte-identical, and its six projections are kept under reference/ as a semantic oracle
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains - of the five resource limits the manifest has fields for, two are declared with their bases —
max_input_bytesandmax_depth— and three are absent with their reasons incapabilities.limits.absent_because; inside them the contract's own depth 32 and node bound of 10 000 are enforced as LIMIT_EXCEEDED
ndbc_stdmet
- exactly one stdmet file per call (a realtime, monthly or yearly historical file), as its octets or its parsed twin; a yearly .txt.gz is unwrapped by synapse-decode --container gzip. Other NDBC data types (.spec, .cwind, .ocean and the rest) are not this adapter's and their headers are refused
- a stdmet file states neither its station nor the station's position (research-station-text F03): the station identifier is the caller's station_id argument, and the position comes only from a caller's StationTable, else the Entity's position is null. Nothing is joined from activestations.xml or another file
- MM is read as missing only in a realtime file (a header with PTDY), and a run of 9s only in a historical file at the width research-station-text F02 observed for its column (WVHT, DPD, APD and TIDE 99.00, MWD 999, VIS 99.0, WTMP 999.0). Any other run of 9s in a historical file is refused undocumented-sentinel, and so is a real reading of that shape in a column whose sentinel width is not documented (a 999.0 hPa pressure, a 99 degree wind direction): the widths for WDIR, WSPD, GST, PRES, ATMP and DEWP are not established, so this module refuses rather than guesses. MM in a historical file is refused
- the year is the width its header column names (four digits under #YY and YYYY, two under YY), and a two-digit year is read only as 98, 1998: the YY layout is recorded in a 1998 file only (research-station-text F01), so any other two-digit year is refused undocumented-year rather than given a century
- a file with no units line (before 2007) states no unit, so each value is an Absence of cause unit_unknown and the number stays in the Event's residual row; nothing assumes the unit a later file states
- each row is one instant, observed_at and both ends of validity.effective; the averaging windows the measurement descriptions give for a column (WSPD over eight minutes, PTDY over three hours) are not stated as intervals
- NDBC's text files print no per-value quality flag (NDBC T80-10, December 2023), so every contract states quality_flags_basis instead of flags
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
nexrad2
- Array values are carried by reference — a locator, the shape and packing needed to open them, and a summary — and are not copied into the output.
- the twin's wire_hex is the volume's octets, the input its dict form is decoded from; they are identified by SourceRef.source_hash when the host injects it and are not copied into any object
- exactly one Archive II volume file per call, as its octets or as its twin; a real-time chunk (the _chunks bucket's records), a gzip or tar around the volume and an _MDM sidecar are not taken. synapse-decode unwraps a gzip or a named tar member before the adapter sees the volume
- message 1 (the legacy radial, pre-Build 10), message 29 (model data, the _MDM record) and a radial whose Compression Indicator is 1 (bzip2) or 2 (zlib) are refused by name and not decoded; an archive version other than 06 or 07 is refused
- the metadata record's messages (15, 32, 13, 18, 3, 5, 2) and the RDA status messages (2) among the radials are framed and counted by type in the site Entity's residual, not decoded; the VCP is read from each radial's VOL block, not from message 5
- Event.geometry is the radar site's point, not the area a sweep covers: no gate or beam geometry is computed, and the gates' ranges are the contract's first_gate_range and gate_interval
- every range ICD 2620002Y Tables XVII-A, -B, -E, -F and -H state for a field this module reads is a validation rule, so a volume a lenient reader would take can be refused; Table XVII-I's data ranges are not rules (they are a moment's typical values, note 20), so a moment's gate codes are converted with each radial's own scale and offset and the summary is not range-checked (narrowed 2026-10-16, the 3.5.0 release); a data block or moment the ICD does not name is refused, not skipped (note 9 recommends skipping it); spare and reserved octets are not read except the moment block's Reserved word, which is carried
- the VOL block's ZDR Bias Estimate Weighted Mean is carried as the Integer*2 it is stated as: the ICD's note 33 on its scaling is not in the design record, so no unit is stated for it
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
pntmap
- no document in this repository DEFINES the PNTMAP alert payload — FORMAT_COVERAGE.md carries no PNTMAP section — so there is no edition to name and
format.versionis null; the licence class rests on the payload being first-party rather than on a licensing sentence about the format - ingest only: this adapter does not emit PNTMAP alerts
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
readsb_trace
- exactly one readsb trace file per call, as its gzip octets (one gzip member) or as the decompressed document in a dict; a day archive, a tar part, a list of traces and JSON text are not taken. synapse-decode takes one tar member by name
- nothing is joined across files: a flight across UTC midnight is two files, two Tracks and one entity_id, and a new-leg flag is decoded as data and nothing is split on it. A Track's and its Event's ids derive from the address and the first and last instants, so two files of one airframe spanning the same two instants (two readsb instances' copies of one day, or a copy holding more points between them) give one track_id and one event_id: the id names the airframe's window, not the file, and files with different spans are different Tracks. Stitching, merging and leg-splitting are fusion's
- TrackSample holds a position and an instant only, so a point's ground speed, element 5, flags, vertical rate, aircraft object, source, geometric altitude and rate, IAS and roll stay in the Entity's residual (
residual.data.trace[i], sample i's point as stated), with the readings taken from them inattributes.readsb_samples, arrays keyed by the same index; only the last point's speed, track and vertical rate reach Entity.kinematics - a barometric altitude is carried as Position.vertical in feet against BARO and never as alt_m; only a geometric altitude reaches alt_m, converted from feet (x 0.3048). When element 3 is barometric, element 10's geometric altitude stays in the residual
- the database fields r, t, desc, ownOp and year are carried verbatim in the residual and read for nothing; no packaged fixture states them, because every registration mark is a claim about a real allocation, so the shipped set is readsb's database-less form
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains
stanag4586
- Edition 4 is current (promulgated as AEP-84 Edition A) and is NOT implemented: FORMAT_COVERAGE.md records that
nso.nato.intanswers HTTP 403 on every route tried, that the mirror carrying this family lists exactly Editions 2 and 3, and that the commercial distributors holding Edition 4 serve it paywalled and DRM-wrapped. No sentence here claims an Edition 3 decoder reads an Edition 4 feed - ingest only: this adapter does not emit DLI
- whether the 5-octet millisecond timestamp steps at a leap second is not stated by the document, and every object carries
attributes.time_basissaying so - leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
stanag4609
- ST 0601.14 is the authoritative tag table; ST 0601.19 is pinned as CONTEXT ONLY and is never a source of tag semantics here
- a length-divergent item's original octets are carried verbatim so that egress is byte exact, which means this adapter reproduces a defect rather than correcting it
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces ONE —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5). The other four are still absent, each with its own reason incapabilities.limits.absent_because; a depth, object-count, decompression or wall-clock bound is not enforced here today
stanag4676
- Edition A (the STANAG 4676 Edition 1 generation) is read for the edition delta and is never a basis: Edition B §2.1.1.1 declares the two incompatible
- the binary encoding of AEDP-12.1 Annex F is not implemented
- leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces TWO —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5), andmax_depth, declared the same way and refused byparse_documentimmediately after the XML parse and before either reader recurses into the tree (2026-09-16). The other three are still absent, each with its own reason incapabilities.limits.absent_because; an object-count, decompression or wall-clock bound is not enforced here today - XML is parsed with the standard library's expat (
pyexpatinto anxml.etree.ElementTreetree,parse_document's_parse_xml) and NOT withdefusedxml, which is not a dependency of this package (M's F5.5 ruling, round P5). Since F05 (2026-09-20) an EXTERNAL entity reference FAILS the parse at the reference and parameter-entity parsing is off, so an external DTD subset is never requested — both set on the parser rather than read off its defaults — but an INTERNAL entity IS expanded, and what stops an entity bomb is libexpat's own input-amplification limit rather than anything in this package. That protection belongs to the RUNTIME's expat build (2.4.0 and later, on by default), so a deployment on an older expat loses it without this package changing;max_input_bytesbounds the document either way. tests/test_cdm_parser_safety.py reads the linked version and takes every one of these readings rather than asserting them - the XML element names this adapter reads and writes are a PROVISIONAL internal profile (
binding: provisional-internal-profile): AEDP-12's UML attribute names bound through one table (ELEMENT_NAMES) in no namespace, because the normative XSD is distributed through NATO national representatives (Ed B §B.5) and is not held here. Reader and writer agreeing through that table proves the profile is self-consistent, not that it is the standard's binding; FORMAT_COVERAGE.md marks every NITS row· provisionalfor the same reason. The verified normative binding is a separate, explicit mode (SYNAPSE_CDM_NITS_BINDING=normative) that validates every document read or emitted against the authorised schema through the local-resource hookSYNAPSE_CDM_NITS_XSD_DIRand FAILS BLOCKED_EXTERNAL_EVIDENCE without it — it never falls back to the profile, and no shipped fixture, golden or evidence record was produced under it
tacticalapi
- reads the two read-side responses of the BlueForceTracking service, GetBlueForcesResponse and SubscribeBlueForceEventsResponse, and nothing else: every other message of the contract (own pose, situation objects, every request, the write-side blue-force messages) and every type outside it is refused
unsupported-message-type, naming the two. Ingest only; no encoder exists - the unit of ingest is one response wrapped in google.protobuf.Any (bytes) or its twin (dict), because a serialized message does not name its own type. gRPC framing, calls, sessions, stream bookkeeping and keep-alive timing are not read and not held: the caller receives each message and hands it over, and a stream is a sequence of calls
- written against rheinmetall.tactical_api.v0 at upstream commit 58661c9 (2026-09-01), which has no tag or release; the embedded field table is generated from protoc's descriptor of those pinned files. A field a later revision adds is carried as an unknown field; a new upstream commit is a new pin and a new adapter version, never a silent update
- the contract places the point on the WGS 84 ellipsoid and states no angular unit for latitude_coordinate and longitude_coordinate; they are read as decimal degrees, inferred from every other angle in the contract, not stated by it
- point_location.course is in degrees with no stated north reference, and
Kinematics.course_degmeans degrees true: a course in [0, 360) is mapped tocourse_degwith the north reference ASSUMED true, an assumptioncourse_basisstates on every Entity it is applied to (R5, ruled 2026-10-06). A course outside that range, 360 included, is not mapped and not normalised; it stays in the typed block andvalidate_sourcenames it Entity.symbolis set only from a MIL-STD-2525D numeric code (catalog SYMBOL_CATALOG_MIL2525_D, first set 1 000 000 000 to 9 999 999 999, second set 0 to 9 999 999 999), unrewritten. Every other symbol — another catalog, the string form, a set out of range — is carried in the typed block unconverted and named byvalidate_source; no symbol is derived from the affiliation (R4, ruled 2026-10-06)- proto3 writes no scalar holding its default, so an unset coordinate pair and 0°N 0°E are the same bytes and a false bool reads as an unset one. A geo_point with neither coordinate on the wire yields no position, one with a single coordinate on the wire reads the other as 0.0 and
position_basissays so, andblue_force_typeflags that are not true giveentity_typeUNKNOWN, never a person or a unit. Likewise a Timestamp holding seconds 0 and nanos 0 (1970-01-01T00:00:00Z) is what a default-constructed one serialises to, so neither point_location.location_time nor last_contact_time holding it is read as a source time: the next choice stands, the basis says the zero Timestamp was passed over,validate_sourcenames it, and its text stays in the typed block - encodings a lenient protobuf parser accepts and repairs are refused by name: a singular field twice, two members of one oneof, a named field with another wire type, an int32 or enum varint outside 32 bits, a bool other than 0 or 1, a varint whose tenth octet sets bits past the 64th, a tag written in more than five octets, and a field the well-known types Any, Timestamp, StringValue and DoubleValue do not define. Nothing is repaired
- the read side marks no time field mandatory:
valid_fromandobserved_atcome from point_location.location_time, else last_contact_time, else the receipt instant from the injected clock, a zero Timestamp being passed over (proto3-zero-indistinguishable), andvalid_from_basisandobserved_at_basissay which. The CDM renders instants to the millisecond; the source text stays whole in the typed block. A deleted element gets novalid_to: the contract says only that the blue force is no longer present (R6, ruled 2026-10-06) - no TacticalAPI server, client or captured message has been exercised. Every payload is synthetic, and every one starts as protoc's own encoding of a text source against the pinned files; none was written from scratch by hand. Fourteen are protoc's bytes unchanged. Seven were changed afterwards by the fixture builder: three have hand-encoded fields appended, and four refusal payloads are protoc's bytes after one byte surgery each. protoc's own readings of the payloads are the only independent oracle
- the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run, and the release pipeline generates the records for every shipped adapter and attaches them to the GitHub Release of the version it publishes.evidence.availableis true because every published distribution that carries this adapter has that Release, so its records are retrievable by a third party; it says nothing about what the wheel contains - of the five resource limits this adapter enforces three —
max_input_bytes,max_depthandmax_objects, each an implementation cap declared with its basis and refused before any object is built — plus two the manifest has no field for, declared besidemax_objects:MAX_UNKNOWN_FIELDS(65 536 carried unknown fields per input) andMAX_CARRIED_COPY_CHARS(16 777 216 characters of compact JSON text, with ASCII escaping, of the message-level data carried across all the Entities and Events of one message, each copy counted).max_decompressed_bytesandmax_parse_secondsare absent, each with its reason incapabilities.limits.absent_because
tak
- the CoT schema edition this adapter is written against is NOT STATED by any document in this repository —
fixtures/tak/spec/tak_terms.jsonrecords the Base-Event Schema's own version as its publisher states it, which is a reading of that page and not a statement that this implementation targets it, soformat.versionis null rather than guessed - contact atoms only on ingest; CoT types outside
a-.-...are out of scope - leftovers are parked in
Entity.attributes/Event.payloadundersource_extras(lossless.residual()), not in the origin-identifying container ARCHITECTURE.md §5 gives to P3 — the Part 1 stance that section rules for the adapters already shipped - the evidence RECORD for this adapter is not IN the distribution:
evidence/is untracked and unpackaged, CI generates the set on every run and the release pipeline attaches it to the GitHub Release.evidence.availableis true because the records for 2.1.2 are attached to thev2.1.2Release and retrievable by a third party, and it says nothing about what the wheel contains - of §3.5's five resource limits this adapter enforces TWO —
max_input_bytes, declared incapabilities.limitswith its basis beside it and refused before decode by the base class (round P5), andmax_depth, declared the same way and refused by this module immediately after the XML parse and before anything recurses into the tree (2026-09-16). The other three are still absent, each with its own reason incapabilities.limits.absent_because; an object-count, decompression or wall-clock bound is not enforced here today - XML is parsed with the standard library's
xml.etree.ElementTreeand NOT withdefusedxml, which is not a dependency of this package (M's F5.5 ruling, round P5). An EXTERNAL entity is not resolved and an external DTD is not fetched — the parser never reads the external subset — but an INTERNAL entity IS expanded, and what stops an entity bomb is libexpat's own input-amplification limit rather than anything in this package. That protection belongs to the RUNTIME's expat build (2.4.0 and later, on by default), so a deployment on an older expat loses it without this package changing;max_input_bytesbounds the document either way. tests/test_cdm_parser_safety.py reads the linked version and takes every one of these readings rather than asserting them
Conformance summary
Checks A–O of the Synapse Conformance Suite over every
shipped adapter, from this release's own sweep.
| adapter | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | result |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
adsb |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
airnow_hourly |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
ais |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
aixm511 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
aixm52 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
c2sim |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat021 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat023 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat034 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat048 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat062 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cog |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
coops_csv |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
dis7 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
geojson |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | SKIP | SKIP | PASS | CONFORMANT |
geopackage |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
gmti |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
grib2 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
iem_n0q |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
legion |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | SKIP | PASS | CONFORMANT |
link16_gateway |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
ndbc_stdmet |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
nexrad2 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
pntmap |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | SKIP | PASS | CONFORMANT |
readsb_trace |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
stanag4586 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
stanag4609 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
stanag4676 |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
tacticalapi |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
tak |
PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |