The semantic layer
The API calls behind the semantic layer.
On this page
Part of the HTTP API reference.
Route: #/semantic → drawSemantic.
The access decision for this screen:
Reading it is open, and deliberately so: the last time a screen was gated on the permission that changes it, nobody could find the screen and it may as well not have existed. Saving is behind
SEMANTIC_EDIT, and the button says so rather than the page disappearing.
The order of calls
GET /api/semantic/yaml- On pressing Check:
POST /api/semantic/yaml/plan - On pressing Save:
POST /api/semantic/yaml - On unlocking a field:
DELETE /api/semantic/lock/{ref}/{code}
GET /api/semantic/model, POST /api/semantic/compile,
GET /api/semantic/history and GET /api/semantic/history/{save_id} exist and
no screen calls them; see the final section.
GET /api/semantic/yaml — the layer as YAML
No parameters, no permission check.
Cached by _derived under semantic_yaml — 4.52s on ten million assets.
Refusal: 503 "Reading a semantic model needs the pyyaml package. pip
install pyyaml".
Docstring: "The layer as Cube-shaped YAML, plus the fields a paste would not touch."
Response
{
"yaml": "cubes:\n - name: orders\n …",
"locks": [ // the fields a paste will NOT overwrite
{"ref": "orders", "code": "revenue",
"field": "Description", // the attribute's name
"by": "r.iyer",
"when": "3 Feb 2026"} // strftime("%-d %b %Y")
],
"saved_at": "2026-02-03T…", // the last save, or null
"saved_by": "r.iyer", // or null
"note": "Added the churn metric." // or null
}
A lock is created by PUT /api/assets/{uid}/attributes/{code} on every write
(see Screen 4). "A lock is not a refusal. It decides who wins a disagreement,
and the screen that would lose says so before saving rather than afterwards."
POST /api/semantic/yaml/plan — what saving it would do
No permission check. "Writes nothing." Always rolled back.
Body: {"yaml": "<the whole document>"}.
Refusal: 400 with semantic_io.CannotRead's own sentence.
Response: the plan shape (p.as_dict), as described in Conventions.
POST /api/semantic/yaml — apply it
Permission: SEMANTIC_EDIT — "save the semantic model".
Body
| Field | Type | Notes |
|---|---|---|
yaml |
string | the whole document |
note |
string | stripped, null when empty; shown as note on the next read |
Docstring: "Apply the YAML. Refused whole if anything in the plan blocks it."
Refusals: 400 from semantic_io.CannotRead (and the transaction is
rolled back first); 409 with " ".join(p.blockers) when the plan is not
safe.
Response: the plan shape, committed.
DELETE /api/semantic/lock/{ref}/{code}
Permission: SEMANTIC_EDIT — "unlock a field", naming
"<ref>.<code>" in the refusal.
Docstring: "Let the YAML win this field from now on."
Response: {"unlocked": 1} — how many lock rows went.