synapse-cdm 2.1.2
synapse-cdm 2.1.2
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 | 2.1.2 |
| CDM version | 2.1.0 |
| SC-OES version | 0.1.0 |
| Adapter API version | 2.0.0 |
| manifest schema version | 1.2.0 |
Major changes
SOIF Part 1 — Foundation & Assurance, and this is the release that ships it. Part 1 is not a
format and not a semantic layer: it is the machinery that makes a claim about an adapter checkable
by somebody who did not write it. An adapter now describes itself in a published manifest; a
fifteen-check conformance suite runs over any adapter in the roster; an evidence record states what
was measured, on which commit, against which versions, with a digest of every fixture the run read;
and the CDM gains the geometry, time, route, quality, provenance and residual primitives an adapter
needs in order to say what it actually translated. Nothing is removed, renamed or narrowed, so a
2.0.0 consumer keeps working without doing anything.
If you are upgrading from 2.0.0 — which is what the index served until this release — read this
as the MINOR it is. Everything below is the arc from 2.0.0, because neither 2.1.0 nor 2.1.1 ever
reached anybody.
Why the number is 2.1.2 and not 2.1.0 or 2.1.1
Two tags were cut before this one, both were pushed, neither was published, and both stay where
they are. They were refused by two different steps of this project's own release pipeline, and
both refusals were the same shape: a step whose behaviour depends on the ref, executed for the
first time on a tag ref.
v2.1.0, on commitb69a267, 2026-09-09. Thegatejob's last step was
pip-audit --strictover the installed environment; that environment holds the release
candidate at the tree's own version,--strictturns a distribution the index cannot resolve
into a failure, and the index cannot carry 2.1.0 until thepublishjob — which needs the gate
that just failed. A gate that required the publication it was gating. The repair scopes both
audits to the release candidate's dependencies, excluding onlysynapse-cdmitself by name, and
leaves every third-party line under--strict.v2.1.1, on commit4409115, 2026-09-10. Step 15 passed — the repair worked — and step 16
of 17 refused it: the CodeQL gate asked for the code-scanning analyses of${GITHUB_REF}, which
on a tag push isrefs/tags/v2.1.1, and no workflow in this repository can produce an analysis
on a tag ref. The commit had two clean analyses onrefs/heads/main; the ref filter excluded
them. The repair makes the gate read the analyses of the commit it is gating, which is what
the step's own name had promised since it was written.
Neither tag is moved, deleted or recreated: each remains permanently attached to its commit as a
release tag that released nothing, and 2.1.2 is the corrective. PUBLICATION.md's ledger records
what was actually uploaded, and nothing in this file claims an upload that has not happened.
What the arc closed is the class and not the two instances. gates/release_ref_rehearsal.py
replays every ref-dependent release step — the tag guard, the tag-names-the-version condition, the
annotated-tag check, the CodeQL query, the five tag-derived versions and the Release name — against
a named tag and commit while that tag is still local, and it is a mandatory act between tagging and
pushing. Its last check refuses any future use of GITHUB_REF in the release workflow that its own
covered-uses table does not name, so the next ref-dependent step fails on a laptop rather than on a
pushed tag. Its own test now derives the tag it rehearses from PACKAGE_VERSION, so the rehearsal
does not become the next thing a version bump surprises.
Between v2.1.1 and this tag the distribution itself moves by two files — MIGRATIONS.md and
version.py. gates/bump_derivation.py derives PATCH over that arc with nothing unruled, and
2.1.2 is that floor.
Package version 2.1.2 · CDM schema_version 2.1.0. The two numbers are unequal, and that is
the ordinary case and not a signal: the schema moved on MIGRATIONS.md's table in the CDM round,
for optional primitives only; the package moved on version.py's table for the release; and then
the package moved twice more, two PATCHes the wire contract had no part in. They were level for one
day. synapse_cdm/version.py states the nine version axes and their independence in one place, and
tests/test_cdm_packaging.py sweeps the package for an assignment that would derive either number
from the other. A package at 2.1.2 does not mean SC-OES 2.1: SC_OES_VERSION is a third axis,
still 0.1.0 and still a Draft.
What changed on the wire, and what a 2.0.0 consumer must do
Nothing, and this is the release that says so with a gate rather than a promise. schema_version
moves 2.0.0 -> 2.1.0 and every addition behind it is an optional field or a model reached only
through one, so a 2.0.0 reader still reads a 2.1.0 object and a 2.0.0 object still validates against
the 2.1.0 models. The fourteen worked examples under spec/sc-oes/ are the witness: they still
declare schema_version 2.0.0 and they still validate.
What a producer gains is vocabulary, not obligation:
- Geometry.
synapse_cdm.geocarriesPoint,LineString,Polygonand their multi- forms,
plusBoundingBox,VerticalPositionandVerticalExtent. A vertical position states its unit
and its datum, because an altitude without a datum is a number and not a position. - Time.
TemporalValidityandPeriod— when an assertion is held to be true, as distinct
from when it was made. - Route and area.
Route,RouteLeg,Waypoint,Area. - Quality and provenance.
Quality,SourceHash,OperationalStatus, and seven added fields
onSourceRefso that a CDM object can say which bytes it came from. - Residual data.
Residualandlossless.classify(), which partitions every source leaf into
six categories and lets an adapter carry what the CDM has no field for instead of dropping it
silently.
packages/cdm/synapse_cdm/MIGRATIONS.md's 2.1.0 section carries the migration statement and the
derivation, entry by entry, and its 2.1.2 section carries this release's own record. There is no migration tooling, because there is nothing to migrate.
Adapter API v2, and every adapter now describes itself
ADAPTER_API_VERSION is 2.0.0 — the contract an adapter class is written against, additive over
v1 and renaming nothing. v2 adds four members: metadata, detect, validate_source and
capabilities. ARCHITECTURE.md §1 freezes it.
The visible half is the manifest. All fourteen adapters ship one under manifests/, validated
against schemas/manifests/adapter-manifest.schema.json at MANIFEST_SCHEMA_VERSION 1.2.0, and
python -m synapse_cdm.manifests --check reports CURRENT: manifests vs 14 shipped adapters at manifest schema 1.2.0. A manifest states the adapter's direction, its declared limits and where
each limit's number came from, its known limitations as structured records rather than sentences,
and what it does not support — so "this adapter handles that format" becomes a document a third
party can read without reading the code.
The Synapse Conformance Suite
python -m synapse_cdm.suite, also installed as synapse, runs fifteen checks, A through O,
over any adapter in the roster: identity, determinism, malformed input, parser robustness, resource
limits, streaming, temporal handling and the rest. Results come out as --format json and are
byte-identical across two sweeps of one tree, which is what makes them evidence rather than output.
SC-OES conformance is a separate and smaller thing and it is unchanged: python -m synapse_cdm.conformance, also cdm-conformance, reports five separately named dimensions with
PASS/FAIL/SKIP each, no aggregate score, and four exit codes a CI system can branch on. The
PNT Profile 0.1.0 remains the only profile with an executable rule of its own; against the
other six, dimension D is SKIP, which is a different fact from a failure and a different fact
again from a profile that does not exist. This work still creates no certification programme.
Evidence records
EVIDENCE_SCHEMA_VERSION 1.0.0, published as schemas/evidence/evidence.schema.json. synapse evidence generate --adapter X | --all writes one record per adapter: the manifest embedded whole,
the commit it was measured on, five version axes, the conformance report verbatim, the loss report,
and a SHA-256 of every fixture file the run read. synapse evidence verify <file> generates a NEW
record from the tree in front of it and compares field by field, masking only what is a measurement
of the run rather than of the tree — so reproducibility is a command and not an assertion. synapse badges derives shields.io endpoint files from those records and refuses to write one without a
record behind it.
The records are not in this distribution and not in the repository. They are produced by CI on
every run, uploaded, and attached to a release; each adapter's manifest declares
evidence.available: false until the release they are attached to exists. Thirty-nine
PROVENANCE.json records — one in every fixture directory a tracked test reads — say where the
fixture data came from.
Security, dependencies and the supply chain
SECURITY.md: the reporting path, and a parser-safety policy with declared limits on all
fourteen adapters.- Secret scanning on the platform,
.gitleaks.tomlin the tree, and a CI job over the full
history reachable from every push. pip-audit --stricttwice — over the environment and over the wheel's frozen closure — with
exactly one distribution excluded by name,synapse-cdmitself, because an audit that has to
resolve the release candidate against the index is a gate requiring the publication it gates.
Every third-party line stays under--strictand no transitive dependency is excluded. Plus an
npm audit at high over the documentation tree, with the two live advisory exceptions declared as
files undersecurity/exceptions/with an expiry each rather than as a flag on a command line.- CodeQL, and a gate that refuses a blocking alert.
- An SBOM in both SPDX and CycloneDX, built by the release pipeline over the clean-install
environment, plus a second tool's cross-check. - Build provenance: Sigstore attestation over the built artefacts, verified in the same run that
produced them.
What else moved
- The published schemas. All six regenerate from the models at
2.1.0, and two new ones join
them — the adapter manifest and the evidence record.git diff v2.0.0..HEAD -- schemas/is eight
files, 3915 insertions, 39 deletions.python -m synapse_cdm.schemas --check --out schemas
reportsCURRENT: schemas vs models at 2.1.0. - A fourth console script,
synapse. It is the one entry point not spelledcdm-*, because
SOIF §19 fixes the command line it has to answer to. The three that existed are unchanged. - No runtime dependency changed.
pydanticandjsonschema, as before.rdflibis a test
extra and nothing undersynapse_cdm/imports it. - No adapter was added or removed, and no adapter's translation was changed to make a
conformance verdict come out differently. - A release pipeline.
.github/workflows/publish.ymlnow runs six jobs in SOIF §50's order —
gate, build, attest, publish, release, witness — and the last three of them only on a tag.
Fourteen adapters, all harness-verified
python -m synapse_cdm.harness --adapter <name> --json, run over the roster with no --fixtures.
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 — a table missing an adapter tells a reader the roster is smaller than it is.
The roster did not move this arc, which is derived here rather than carried over: discover()
and roster() each return fourteen, the same fourteen names in the same two directions, and the
totals below were summed from the harness on this tree.
| Adapter | Direction | Fixture verdicts |
|---|---|---|
adsb |
bidirectional | 32 |
ais |
bidirectional | 22 |
cat021 |
bidirectional | 40 |
cat023 |
bidirectional | 34 |
cat034 |
bidirectional | 34 |
cat048 |
bidirectional | 82 |
cat062 |
bidirectional | 56 |
gmti |
bidirectional | 32 |
legion |
ingest | 6 |
pntmap |
ingest | 4 |
stanag4586 |
ingest | 24 |
stanag4609 |
bidirectional | 126 |
stanag4676 |
bidirectional | 34 |
tak |
bidirectional | 12 |
538 fixture verdicts, 0 failed across the fourteen adapters, against the published schemas.
The roster's totals are unmoved from 2.0.0: this release adds vocabulary and assurance machinery
over objects already translated, and no fixture. gates/wheel_install.py reports 1076 over the
same roster, which is these 538 run in each of two schema modes.
Published by CI over OIDC, as 1.1.0 through 2.0.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.
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. This release additionally attaches, to the GitHub Release itself,
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==2.1.2
python -m synapse_cdm.harness --list-adaptersAdapter status
14 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 | L4 | L3 | VERIFIED | CONFORMANT |
ais |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
cat021 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
cat023 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
cat034 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
cat048 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
cat062 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
gmti |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
legion |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
pntmap |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
stanag4586 |
1.0.0 | ingest | L3 | L5 | VERIFIED | CONFORMANT |
stanag4609 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
stanag4676 |
1.0.0 | bidirectional | L4 | L3 | VERIFIED | CONFORMANT |
tak |
1.0.0 | bidirectional | L4 | L3 | 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 |
| 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 |
| 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 findings at or above 7.0, gate green in this run
pip-audit, this release's run: 0 findings, strict, in this run- Security exceptions in force: 2 —
GHSA-5p2g-fcmc-qvqq.json,GHSA-w3rx-r6r6-pgpr.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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - 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
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 - no evidence RECORD is generated for this adapter: the harness produces verdicts, and the evidence record and its schema are owed by P4 (ARCHITECTURE.md §9).
evidence.availableis false for that reason and not because the checks do not run - 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 - 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 | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
ais |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat021 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat023 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat034 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat048 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
cat062 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
gmti |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
legion |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | SKIP | PASS | CONFORMANT |
pntmap |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | SKIP | PASS | CONFORMANT |
stanag4586 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
stanag4609 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
stanag4676 |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |
tak |
PASS | PASS | PASS | PASS | SKIP | PASS | PASS | PASS | PASS | PASS | PASS | PASS | SKIP | PASS | PASS | CONFORMANT |