Skip to content

synapse-cdm 2.1.2

Choose a tag to compare

@github-actions github-actions released this 12 Sep 10:49
· 41 commits to main since this release

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 commit b69a267, 2026-09-09. The gate job's last step was
    pip-audit --strict over the installed environment; that environment holds the release
    candidate at the tree's own version, --strict turns a distribution the index cannot resolve
    into a failure, and the index cannot carry 2.1.0 until the publish job — 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 only synapse-cdm itself by name, and
    leaves every third-party line under --strict.
  • v2.1.1, on commit 4409115, 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 is refs/tags/v2.1.1, and no workflow in this repository can produce an analysis
    on a tag ref. The commit had two clean analyses on refs/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.geo carries Point, LineString, Polygon and their multi- forms,
    plus BoundingBox, VerticalPosition and VerticalExtent. A vertical position states its unit
    and its datum, because an altitude without a datum is a number and not a position.
  • Time. TemporalValidity and Period — 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
    on SourceRef so that a CDM object can say which bytes it came from.
  • Residual data. Residual and lossless.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.toml in the tree, and a CI job over the full
    history reachable from every push.
  • pip-audit --strict twice — over the environment and over the wheel's frozen closure — with
    exactly one distribution excluded by name, synapse-cdm itself, 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 --strict and no transitive dependency is excluded. Plus an
    npm audit at high over the documentation tree, with the two live advisory exceptions declared as
    files under security/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
    reports CURRENT: schemas vs models at 2.1.0.
  • A fourth console script, synapse. It is the one entry point not spelled cdm-*, because
    SOIF §19 fixes the command line it has to answer to. The three that existed are unchanged.
  • No runtime dependency changed. pydantic and jsonschema, as before. rdflib is a test
    extra and nothing under synapse_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.yml now 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-adapters

Adapter 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: 2GHSA-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.json records as priced, so format.version is 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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.json records both without naming the edition this implementation targets, so format.version is 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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.json records Edition 1.30 as available, and this adapter is written against 1.29
  • leftovers are parked in Entity.attributes / Event.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.json records that it "can change between deploys, and its info.version demonstrably does not move when it does", so v3 names 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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.version is 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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.int answers 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_basis saying so
  • leftovers are parked in Entity.attributes / Event.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.ElementTree and NOT with defusedxml, 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_bytes bounds 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.json records 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, so format.version is null rather than guessed
  • contact atoms only on ingest; CoT types outside a-.-... are out of scope
  • leftovers are parked in Entity.attributes / Event.payload under source_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.available is 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 in capabilities.limits with 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 in capabilities.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.ElementTree and NOT with defusedxml, 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_bytes bounds 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