Skip to content

The editing plane

Nerthus.Core (until cutover). This page describes the frozen system that runs today and is deleted at cutover. Replaced by: not yet written.

An editing session is a named set of pending lore changes, owned by one person and published as one act. It is not a buffer and not a per-file autosave: the hard case is one person touching a character's prose, a map alignment and an entity tag in one sitting and needing that to land as clean history rather than three tabs racing each other to git.

A pending edit is invisible because of where it lives.nerthus/staging/edits/, outside the four scan roots — and not because anything filters it out. The session model, the participation graph, the integrity walk, the PU ledger and the distribution fan-out cannot see one, and the model fingerprint does not move while somebody is typing.

Routes

Method Path Cmdlet Cap Write
POST /edits lore.edit
GET /edits/{eid} lore.edit
PUT /edits/{eid}/entries lore.edit
DELETE /edits/{eid}/entries/{n} lore.edit
DELETE /edits/{eid} lore.edit
POST /edits/{eid}/publish lore.edit

lore.edit is a capability of its own and not entity.write. entity.write authorises one - @tag: value line through a primitive that cannot express anything else; these routes accept arbitrary file text, which can rewrite a diary, empty a file, or put a session block where the model will not find it. A token reading entity.write would be lying about what it permits.

POST /edits/{eid}/publish additionally requires whatever its entries' kinds imply — location.override for a layout entry, entity.write for an entity one, docs.edit for a document one — so a narrator cannot reach a Council-level write by routing it through the editor. The route's own lore.edit is a floor, and the extra set is derived from the manifest rather than restated in the handler, so a kind added later cannot reach the route ungated.

The owner is the principal's Gracz and is never read from the body. A client that could name its own owner could author a commit as somebody else, in a repository the community clones.

Two paths are denied outright: nerthus.contributors.md, because editing it with a permission it grants is a loop and a namiestnik typo in it is unrecoverable through the tool that made it; and nerthus.ledger.md, because settlement output keeps its Council review through the sync service's merge-request rule.

The four staging writes have no dry run yet

?dryRun=true on POST /edits, PUT /edits/{eid}/entries, DELETE /edits/{eid}/entries/{n} and DELETE /edits/{eid} answers 400 DryRunUnsupported rather than a preview. Those four write only to the staging directory and a preview of them is real design work nobody has done; a refusal a caller can act on is better than a flag the handler ignores. It matters because the write gate's ReadOnly arm yields to a dry run, so a Write route that ignored the flag would perform its write on a read-only replica the moment the gate let it past.

POST /edits/{eid}/publish — the one route that touches lore — does honour ?dryRun=true, and that is the dialog a person confirms.

Publishing

The publish stages exactly the paths its manifest names and commits one per group, authored as the person who made the edit — <slug>@nerthus.pl, derived, set per invocation and never written into the clone's config. Two people whose names slug identically is a refusal, not a resolution.

It does not push. It commits and asks the sync tick to run now; the push, the rebase, the merge-request fallback and the retry all belong to the sync service, and a second path to origin would be a second set of its bugs.

A group that accepted a divergent propagation target goes out as a merge request. A mixed publish splits: the groups that overwrote nobody go direct to the default branch, and only the affected one waits for a reviewer. Such a publish announces nothing to the fleet, because no peer tracks the review branch — the person pressed a button, commits were made, and the fleet does not have them until somebody merges.

document — a second target kind

A document entry edits a file in another repository, named by an alias the host configures under editor.targets. It carries docs.edit, never lore.edit, and none of the lore machinery applies: no propagation, no announce, no model rebuild, and no sync-tick nudge. Its commit is local, and whoever owns that repository publishes it.