Help a user or agent write a small converter that publishes into
scenescape/external/{publisher_id}/{thing_type} with source_id equal to
{publisher_id} (publisher-centric; scenes bind separately).
Mandatory Reads (In Order)
Before writing or changing converter code or docs:
- This skill.
- User guide:
docs/user-guide/how-to-guides/publish-external-source-adapter.md - Canonical contract:
docs/user-guide/microservices/controller/data_formats.md(section External Source Input Message Format and its subsections). - When validating payloads against schema definitions:
controller/src/schema/metadata.schema.json(external_source,external_pose,external_detection). - If an example adapter already exists for the protocol or a close cousin, read
it before inventing a new layout:
tools/external_source_adapters/(for examplemavlink_to_external_source.py).
Architecture background (optional):
docs/adr/0016-unified-external-source-ingestion.md.
Hard Rule — No Contract Duplication
The field tables, required-field lists, pose-trust rules, identity/collision
guidance, rejection reasons, and full JSON examples are defined only in
data_formats.md (backed by the schema).
- Do not copy those tables, field lists, or examples into this skill, into generated code comments, or into new documentation pages.
- Cite the relevant
data_formats.mdanchors (or the how-to checklist) instead. - If the contract and a snippet appear to disagree, trust
data_formats.md/ the schema and fix the snippet.
Preferred Layout
- Put runnable example adapters under
tools/external_source_adapters/. - Keep protocol-specific dependencies in that directory's
requirements.txt(for examplepymavlink). Do not add them to core Scenescape runtime requirements unless the product explicitly adopts the protocol. - Follow the how-to's
SCENESCAPE_*environment-variable naming for source id, broker, MQTT auth, and root cert. Topic path usesSCENESCAPE_SOURCE_ID. - Reuse
scene_common.mqtt.PubSubandPubSub.DATA_EXTERNALrather than a one-off MQTT client, unless the user requires otherwise. - When adding or renaming an example adapter, update
tools/external_source_adapters/README.mdand add a See Also link from the how-to — do not paste the script intodata_formats.md.
Agent Checklist When Writing a Converter
- Publish to
external/{source_id}/{thing_type}with matching payloadsource_id. Do not put a scene uid in the topic path. Preferwgs84for mobile agents (geospatial auto-attach); useCONTROLLER_EXTERNAL_SOURCE_BINDINGSforscene-frame poses. - Choose a persistent
source_idand per-objectid(see Choosing asource_idindata_formats.md); never mint fresh UUIDs on each restart. - Map native observations into source-local
translation(metres) relative to the source origin described bypose. - Choose
reference_frame(wgs84vsscene) correctly; honorCONTROLLER_TRUSTED_POSITIONING_SOURCESforsceneposes. - Convert the source's native orientation (euler, DCM, etc.) into the
contract's quaternion
(x, y, z, w). Do not invent alternate rotation field shapes. - Use ISO 8601 UTC timestamps (
scene_common.timestamp.get_iso_timeis fine). - Pose-only sources (GNSS/attitude with no separate detections): either
publish
posewith an emptyobjectsarray (cache refresh), or report the platform itself as one object at[0, 0, 0]using the same persistent id assource_id— see Choosing asource_idindata_formats.md. Do not mint a second identity for "the vehicle." - Publish over authenticated MQTT with the Scenescape CA cert (see the how-to
skeleton using
scene_common.mqtt.PubSubandPubSub.DATA_EXTERNAL). - Keep credentials in environment variables or secret files — never hard-code and never ship default passwords.
- Do not add controller-side ID remapping, lookup caches, or identity allowlists; translation belongs in the adapter.
- Prefer linking readers to
data_formats.mdexamples over inventing new sample payloads.
Out of Scope (Refuse / Defer)
Do not implement or imply as part of an adapter task:
- Footprint handoff / overlap policy for the spatial binder (ADR 14 Future Work)
- Cross-source fusion or camera/external deduplication
- Per-source identity trust allowlists (identity is trusted by default with
collision detection — see
data_formats.md) - Changes to Scene Controller pose cache, identity registry, or schema unless the user explicitly requested a contract change
- Broker mTLS/ACL binding of credentials to publisher ids, or other trust-domain hardening beyond same-authority certs (ADR 14 Future Work)
- Promoting a protocol library into core Scenescape dependencies "for convenience"
Maintenance (Anti-Drift)
When the external-source contract changes:
- Update
controller/src/schema/metadata.schema.jsonand the External Source section ofdocs/user-guide/microservices/controller/data_formats.mdfirst. - Then only adjust broken links, checklist wording, or the how-to MQTT skeleton
in
docs/user-guide/how-to-guides/publish-external-source-adapter.mdand this skill. - If example adapters under
tools/external_source_adapters/break against the new contract, fix their mapping code and README pointers — still without copying field tables into the README. - Do not re-document fields here. This skill stays a thin procedure + pointer document.