Files
kane-diagnostics/docs/orchestrator/receiver-spec.md
2026-06-16 11:01:43 -04:00

5.9 KiB
Raw Permalink Blame History

Receiver Spec

Endpoint: POST /receive Contract version: 1.0 Status: design complete, not yet implemented

This is the single endpoint every Hubzilla addon on this node POSTs to. There is no per-addon route. The addon field in the envelope body determines how the orchestrator validates and stores the request.


Authentication

Every request must include:

X-Node-Token: {shared secret from /etc/civic-orchestrator/env_file}

A request with a missing or incorrect token is rejected with 401 before the body is parsed. See README.md for the trust model this implies — the token authenticates the node, not the specific addon.


Request Envelope — Common Fields

Every envelope, regardless of addon, must include:

Field Type Description
addon string One of vs01, dsc01, scn01. Identifies the record type and storage rule.
contract_version string Must be "1.0" for this spec version.
association_slug string URL slug of the association. Matches a key in that addon's config.json associations object.
association_channel_id string Hubzilla channel ID of the association, stored as string.
participant_id string The participant's Placekey (e.g. SASE1-22c-at-5sb-8hm-54v). This is the permanent, address-bound identifier — see README.md for why.
submitted_at string ISO 8601 timestamp of submission.
standing string One of public, participant, professional, operator. The access state at time of submission.

Anything beyond these common fields is addon-specific and described below.


vs01 and dsc01 — Overwrite-by-Placekey

Additional field

Field Type Description
fields object Keyed object of all field values for this submission. Keys match the field IDs defined in that addon's schema files.

Validation rules

  • fields must be present and non-empty.
  • The orchestrator does not validate individual field values against the VS or DSC schema files — that validation already happened on the Hubzilla side before the envelope was assembled. The orchestrator's job is to store what it receives, not to re-validate business rules it does not own a copy of.
  • If fields is missing entirely, reject with 400. An empty or malformed envelope is a bug on the sending side and should fail loudly, not be silently dropped or partially stored.

Storage behavior

Write (overwrite, not append) to:

/srv/civic-orchestrator/data/{addon}/{association_slug}/{participant_id}.json

The entire file is replaced with the new envelope on every write. No merge, no partial update, no history retained by the orchestrator.

Response

{ "status": "ok", "addon": "vs01", "participant_id": "SASE1-22c-at-5sb-8hm-54v", "stored_at": "2026-06-15T10:00:00+00:00" }

scn01 — Append-Only

Additional fields

Field Type Description
pinned_scenario_ids array of strings 13 scenario IDs from scenarios.json, deduplicated.
narrative string Free text.
vs_snapshot object The participant's full VS fields object at time of submission. Embedded, not referenced.
dsc_snapshot object The participant's full DSC fields object at time of submission. Embedded, not referenced.
g1_tx_hash string or null Optional. Transaction hash if a Ğ1 payment was made for this submission. May be null or absent. Absence does not invalidate the record — see README.md.

Validation rules

  • pinned_scenario_ids must have at least 1 and at most 3 entries.
  • narrative must be non-empty.
  • vs_snapshot and dsc_snapshot must both be present. A Scenario submitted without a snapshot of the participant's current VS and DSC understanding is rejected with 400 — this is the prerequisite enforced at the envelope level. (The Hubzilla addon enforces this before the form is even shown; the orchestrator enforces it again here as the backstop, per defense-in-depth, not as the primary gate.)
  • g1_tx_hash is never required for acceptance.

Storage behavior

Append the complete envelope as a new entry to the array at:

/srv/civic-orchestrator/data/scn01/{association_slug}/records.json

If the file does not exist, create it with a new array containing this one entry. Never overwrite or truncate existing entries. A write that would replace rather than append is a bug and must fail loudly rather than silently destroy prior records.

Response

{ "status": "ok", "addon": "scn01", "participant_id": "SASE1-22c-at-5sb-8hm-54v", "record_index": 14, "g1_tx_hash": null, "stored_at": "2026-06-15T10:00:00+00:00" }

record_index is the zero-based position of this entry in the association's records array, returned so the Hubzilla addon can display a confirmation reference if needed.


Error Responses

Code Condition
401 Missing or incorrect X-Node-Token.
400 Missing required common field, missing addon-specific required field, or unrecognized addon value.
500 Storage write failed (disk, permissions, JSON encode failure). The orchestrator must log the full envelope to a separate failure log before returning this — a failed write must never silently lose the submission.

Every error response includes a plain-language message field. No stack traces, no raw exception text.


What This Spec Does Not Cover

Ğ1 transaction broadcast and verification (signing happens in g1wallet, broadcast relay happens in g1wallet's spool, the orchestrator only records the resulting hash if one is provided — it does not initiate or verify the transaction itself). That flow is a separate, not-yet-built piece of work and will get its own contract addendum when it is built.

Operator manage/review read endpoints (GET routes for the orchestrator's stored data) are also out of scope for this version. This spec covers writes only.