Settlement¶
Nerthus.Core (until cutover). This page describes the frozen system that runs today and is deleted at cutover. Replaced by: not yet written.
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. A full map sweep runs for minutes and answers only at the end, so Invoke-NerthusMapCheckup -ShowProgress renders a done/total bar from the route's mapcheckup:progress ticks (Server-Sent Events). 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.
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.
Response 400:
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.
// `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:
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), and maxMillis bounds the wall-clock time
one call may hold the daemon's thread. 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.
The size stage: ?dimensions=only|skip|both¶
A repaint changes what a map's render looks like, and it can change how big it is. The sweep
moves @url and refreshes @slug; the size stage measures the render behind it, with one
34-byte Range read on the connection the version check just opened
(Measuring a map).
| Value | Runs |
|---|---|
both (default) |
version probes, then a size read of every map whose @url just moved or that carries no @wymiary at all |
skip |
version probes only |
only |
size reads only, no version walk |
both is the default because the alternative is silent: without it, a repaint that resized a map
leaves a stale W x H on the block that nothing ever re-checks — the dimensions route skips any
map that already carries one — and four subsystems read that wrong number as measured. The gate
exists so the halves stay separable for CI and for debugging, not so the repair can be forgotten.
both is also what measures a catalogue that has never been measured. That pass belongs here, on
the fleet tick, where it already has a cursor that survives restarts and a
tick_budget_ms — not in a browser, which cannot hold a sweep that runs for minutes.
The report carries the size stage's work in measured[], beside the version stage's updated[].
Response 200 (updated and failed carry any repainted or unreachable maps):