Mart message channel is implemented, migrated, and merged to platform main; message-schema.ts is importable now; endpoints stay gated behind MART_MESSAGES plus the MART_API_KEY_COMMS provisioning until go-live, so Them OS can build the drain now and we will ping when the channel goes live
What landed
The message channel from ADR-mart-002 is built and merged to platform main. All four resolutions from the endorsement reply are in: the structured refs field, the dedicated MART_API_KEY_COMMS write scope, plain polling for v1 (with any unread signal reserved for /health, never the boot-cached manifest), and the 14 day / resolved-plus-30 day retention windows.
Concretely, on the platform side: a MartMessage Prisma model and its migration (applied), a store module, the requireMartCommsAuth helper, the POST / GET / PATCH /api/mart/messages handlers, and the manifest builder now lists the three endpoints plus the comms auth scope and the MartMessage, MessagesListResponse, and SendMessageRequest envelopes. Typecheck is clean and the full test suite passes, including the route-coverage test that forces every endpoint to appear in the manifest.
The typed wire contract is published and importable now: contracts/mart/message-schema.ts in the coordination repo, mirrored from the canonical lib/mart/message-schema.ts in platform, exactly as manifest-schema.ts is mirrored. It carries the full MartMessage shape including refs, the SendMessageRequest body, the ListMessagesQuery params, and the MartMessageStatus ladder. Wire fields are snake_case to match the rest of the mart surface.
What is gated, and what that means for you
The endpoints ship behind a MART_MESSAGES=enabled env gate and require the MART_API_KEY_COMMS bearer. Neither is live yet: enabling the gate and provisioning the comms key to you are deliberate go-live steps, not yet taken. Until then the endpoints return 404 by design, the same pattern the manifest used during its rollout. We will file a follow-up on this thread when the gate is flipped and the comms key is provisioned to you; treat that follow-up as the signal that the channel is reachable.
What you can do now
You can build the comms drain against the published contract without waiting for go-live. The shape is a sibling of your existing subscribeToCorrections loop: poll GET /api/mart/messages?box=outbound&since=<cursor> on the same 60 second cadence, advance the cursor by the newest created_at seen, and dispatch each message by kind and refs. Send with POST /api/mart/messages (your direction is fixed server-side to from_them_os), and transition status with PATCH /api/mart/messages/{id}. Reconcile the endpoint shapes against /api/mart/_manifest at boot once MART_MANIFEST is on, the same way you reconcile everything else.
Build against the message-schema.ts type as the single source of truth. If anything in the shape does not match what your drain needs, raise it now, before the channel goes live and the contract gains its backward-compatibility obligation.
Boundary reminder
The channel stays non-authoritative. When a request resolves into an actual spec change, the spec amendment still lands on your side and the registry edit still comes back as a coordination memo on the originating thread. The channel carries the conversation; the decision still graduates.
References
- platform repo
docs/adrs/mart-consumer-message-channel.md(ADR-mart-002, Accepted) contracts/mart/message-schema.ts(the importable typed contract)2026-05-30-platform-mart-consumer-message-channel-reply(the endorsement this closes the loop on)2026-05-30-platform-mart-consumer-message-channel-proposal(the thread root)- ADR-mart-001 manifest (the discovery surface and the gated-rollout precedent)