Skip to content

Settlement

The two workflows that catch the repository up to itself. Settle derives every pending routine operation from committed state — drifted distributed sessions, unapplied @Transfer sessions, and the month's PU batch — and applies them in one run. Map checkup sweeps the Mapa catalogue, HEAD-probing the Margonem CDN for a newer render of each map. Both read the canonical settlement model; the examples use the fixture month 2026-07, whose only PU-bearing session is 2026-07-01, Eraster rozmawia z Tussalem, Anward.

Both capabilities — workflow.settle and workflow.map_checkup — sit in no role bundle: settle spans distribution, currency, and PU, so it resolves only through admin.all. A token holding the individual write capabilities is still refused. Every example runs against a live daemon — see how the reference is tested.

Routes

Method Path Cmdlet Cap Write
POST /workflows/settle Invoke-NerthusSettle workflow.settle
POST /workflows/map-checkup Invoke-NerthusMapCheckup workflow.map_checkup

Cap is the required capability ( = public, no token); Write () marks routes that pass the write gate; a in Cmdlet is reached directly, no wrapper. Paths are relative to /v1/api; the cross-cutting contract — middleware, envelopes, status codes — is on the API reference index.

Both routes always answer 200 with a per-item report (ok flags any failure) and honor ?dryRun=true. Neither workflow.settle nor workflow.map_checkup sits in a role bundle — each resolves only through admin.all. What counts as pending: Settlement; the CDN version sweep: Locations; the scheduled jobs: Set up pipelines.

Preview a settlement without applying

POST /v1/api/workflows/settle with ?dryRun=true returns the full report with applied: false and writes nothing — distribution, transfers, and PU are each derived and previewed. month is YYYY-MM; omit it and the previous calendar month is used.

POST /v1/api/workflows/settle?dryRun=true
Content-Type: application/json
Authorization: Bearer <token>

{ "month": "2026-07" }
await fetch("https://evocation.nerthus.pl/v1/api/workflows/settle?dryRun=true", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ month: "2026-07" }),
}).then((r) => r.json());

Response 200 (trimmed — every item carries, ok turns false on any failure):

{
  "month": "2026-07", "applied": false, "ok": true,
  "distribution": { "pending": 0, "items": [] },
  "transfers": { "pending": 0, "settled": 0, "items": [] },
  "pu": { "month": "2026-07", "status": "pending", "counted": 1, "echoed": 0 }
}

Rejected: malformed month

A month that is not YYYY-MM is 400, before any work is derived.

POST /v1/api/workflows/settle
Content-Type: application/json
Authorization: Bearer <token>

{ "month": "July" }
await fetch("https://evocation.nerthus.pl/v1/api/workflows/settle", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ month: "July" }),
}).then((r) => r.json());

Response 400:

{ "error": "month must be YYYY-MM, got 'July'" }

Rejected: the piecemeal capabilities are not enough

A token holding session.distribute, currency.write, and pu.award still cannot settle — the capability gate demands workflow.settle, which only admin.all carries. Here the bearer is a token minted with exactly those three write capabilities.

POST /v1/api/workflows/settle
Content-Type: application/json
Authorization: Bearer <token>

{ "month": "2026-07" }
// `scoped` holds only session.distribute + currency.write + pu.award — no workflow.settle.
await fetch("https://evocation.nerthus.pl/v1/api/workflows/settle", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${scoped}` },
  body: JSON.stringify({ month: "2026-07" }),
}).then((r) => r.json());

Response 403:

{ "error": "Forbidden", "required": "workflow.settle" }

Run the map checkup

POST /v1/api/workflows/map-checkup sweeps the active Mapa entities in a deterministic order, probing the CDN for a newer version of each @url. Because a real sweep reaches the network, the batch is resumable: maxMaps bounds one batch and cursor is its resume point (0 once the catalogue is exhausted). This call resumes past the tail of the catalogue, so the batch is empty — no probe is issued, scanned is 0, and cursor rewinds to 0 to signal the sweep is complete.

POST /v1/api/workflows/map-checkup?dryRun=true
Content-Type: application/json
Authorization: Bearer <token>

{ "maxMaps": 1, "cursor": 999 }
await fetch("https://evocation.nerthus.pl/v1/api/workflows/map-checkup?dryRun=true", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
  body: JSON.stringify({ maxMaps: 1, cursor: 999 }),
}).then((r) => r.json());

Response 200 (updated and failed carry any repainted or unreachable maps):

{ "applied": false, "total": 12, "scanned": 0, "skipped": 0, "updated": [], "failed": [], "budgetExhausted": false, "cursor": 0 }