ADR-0114: The Operating Model Arrives — Roles as Functions, Names as Words, People as This Instance's Decision¶
- Status: accepted (2026-08-11 — "go ahead with the realization wave", after his §7
refinement same morning; drafted from his accepted options round on
docs/planning/operating-model-arrival-options.md) - Date: 2026-08-11
- Deciders: Nicolas Burri ("In its current form it will be very hard to ever get a real project imported into a new system. I still think that importing users isn't the right call but roles we should reconsider. Is there an elegant way to match them with our own role model?")
- Relates to: ADR-0113 (the arrival import this completes), ADR-0096 (review policies — the workflow shapes that travel), ADR-0097 (the proposal-before-decision grammar, used a third time), ADR-0111 (staffing does not travel — restated untouched), ADR-0109 §4 (scope deletion undecided — §7 deliberately does NOT decide it), register #42.
Context¶
An ADR-0113 import delivers records and vocabulary but no operating model: no activated roles, no review policies. The imported project can be read forever and continued never — the first revision finds nobody who may author, review or release. The source's role definitions (permission bits) are meaningless across systems; the source's role functions — the places roles occupy in per-type workflows — are what ADR-0096 policies express, and a minimal permission set is derivable from them.
Decision¶
- The operating model travels as one unit (D1). The bundle carries, per document type, the workflow shape: the slot→role-name table (authors / reviewers / releasers / revise / revoke / cancel) and the four-eyes flag. Roles and policies arrive together or not at all — separately they are furniture and unexpressable respectively.
- The mapping preview (D2). The import preview proposes, per source role name, exactly one of: adopt an existing instance role (matched by FUNCTION — same slots occupied; name similarity is a hint, never the criterion), create it, or map it onto a lane-preset abstract slot. The operator confirms or edits every row; an unconfirmed row refuses at execute in the preview's own words. The confirmed mapping is recorded in the batch evidence and replayed verbatim on re-import.
- Created roles are minimal-by-function (D3). A created role receives exactly the permissions its slots require plus the VIEW/BASE_READ floor, listed in clear text in the preview. Every imported policy's grant set is complete in the ADR-0096 sense — every slot filled or explicitly denied.
- Naming: adoption takes the instance's word, creation keeps the source's (D4). Per-scope role labels (the ADR-0112 §2b pattern extended to role activations) are PARKED with a named trigger: a real project that must keep foreign role names beside same-function instance roles.
- Policy arrival runs on the governed surface (D5). Policies configure through CONFIGURE_REVIEW_POLICY as audited sub-acts inside the D1 cage; mapped/created roles are activated in the import-born scope. A type without a bundle shape arrives unconfigured and the setup-status dead-end check names it. An imported project is thereby READY-TO-STAFF: assign people, and the first revision walks the workflow the source defined.
- What still does not travel (D6, restated). Users and staffing (rosters are this instance's decisions; the §4 evidence artifact carries source staffing history), source permission bits, source role hierarchies. EXTERNAL persons never hold roles.
- Re-import of a FINALIZED import-born scope — decided by his refinement (2026-08-11:
"limit the deletion protection to the first change to a document, that is new release of
an existing doc or release of a new doc … I know there is a risk … I could live with
that (maybe show a warning, if there were any changes at all)"). A second, equally
narrow act —
dissolve-finalized-import— gated on IMPORT_PROJECTS at GLOBAL, permitted ONLY for an import-born scope whose trail contains no LOCAL release: no RELEASED (or direct-release) lifecycle event. The oracle is the arrival design's own trail-truth paying off — imported releases mint no lifecycle event, local releases always do, so "the first change to a document" is exactly derivable from the trail, state not paths. Below that boundary the operator may experiment freely with settings, roles, policies, staffing, even drafts, and still start over — the failure-recovery his play-test asked for. Everything short of a release WARNS instead of blocking: the act's confirmation returns a derived change inventory (drafts by whom, configuration acts, staffing acts since finalize — "these will be destroyed") and requires explicit confirmation naming the scope code, the destructive-act grammar. Two absolute refusals regardless: a LEGAL HOLD on anything in the scope, and the first local release — from that moment the scope is a working record system and dissolution is refused permanently (re-import then means a new scope or in-place configuration). The reasoning is the free-era logic institutionalized: until a local release exists, the SOURCE remains the authority of record and everything here is re-creatable from it. This is still not general scope deletion (ADR-0109 §4 stays undecided); the boundary comment rule carries over: never widen.
Clarification 1 (2026-08-11, same day — two consequences the integration proof surfaced)¶
- Many-to-one collapse semantics. When D2's mapping sends N source reviewer roles onto one instance role, the imported requirement is ONE approval of that role (minCount 1), never N: the source demanded one approval from each of N different roles and never N approvals of any single role. What the collapse loses is exactly the distinctness that stopped being expressible — and the operator chose that when they confirmed the mapping.
- Per-document bindings travel (D5 made literally true). The type policy carries the union as the honest default for NEW documents; each imported document walks under its OWN source binding (ADR-0064's per-document workflow groups, set at arrival; minCount 1 per bound reviewer role; documents the source left unattributed keep the type default). The proof's measure: without this, an imported SOP needed five distinct approvers where its source bound one.
Amendment 2 (2026-08-17): the TRUE NAME beats function evidence — D2's precedence, inverted¶
D2 fixed adoption's criterion as FUNCTION and reduced the name to "a hint, never the criterion". The PULSEMED arrival falsified that ordering for the case it matters most in, and Nicolas ruled the inversion on 2026-08-15 ("name-match beats function-match in the mapping preview; the PULSEMED constellation becomes its test").
What the live import showed. Both corpora carry ONE organization's role vocabulary, so
PULSEMED's PLE and MERIDIAN-QMS's PLE are the same role of the same company — but the two corpora
USE it differently. In MERIDIAN-QMS PLE appears only as an addressee, so it was minted with the read
floor and holds no live workflow slot; in PULSEMED it authors and reviews. Function matching
therefore rejected the real PLE on both of its conditions and offered the closest functional twin,
HOT — proposing to merge two distinct roles of one company. The operator overrode eleven such rows
by hand; that manual override is the argument.
Decision. A source role whose name is already a role in this catalog, character for character (case and punctuation aside), is proposed for ADOPTION of that role — before any function is examined, and whatever the function evidence would otherwise have said. Where no such name exists, D2's function match is unchanged and still answers.
Three properties keep this from being the shortcut D2 rightly banned:
- Only EXACT equality carries the new authority. Name SIMILARITY remains what D2 always made it — the last tie-break among functionally equal candidates. A "QMB Assistenz" still cannot displace the role this instance releases with.
- The identity IS the evidence. A name already in this catalog is not a resemblance; it is the word this installation already chose for a role. Function occupancy is evidence of how ONE corpus used a role, and two corpora of one organization legitimately use a role differently — so occupancy is the weaker signal exactly where the name is exact.
- Adoption still does not re-cut permissions (D4a). This is why the name rule may ignore
permission cover: a role people are already staffed in does not silently gain
CREATE_DOCUMENTbecause a second corpus arrived. The preview still prints what a CREATE would derive, so an operator who wants the source's authority says so at the confirm act.
It also removes a smaller dishonesty: the execute path has always adopted an existing role of the same name rather than colliding with it, so a preview that said CREATE for a name already in the catalog was describing something the act would not do. The preview and the act now agree. This amendment SUBSUMES the redo fallback the realization had added under §7 (a dissolved import leaves function-less roles behind); the redo is simply the commonest instance of "this name is already ours".
Rule 1b (2026-08-17, Nicolas on the three-option reprint: "Then a) please")¶
The paragraph above shipped as a NAMED CUT: a source role with no name here still received D2's
function proposal, so PULSEMED's PO — the one role of twelve this installation had never carried —
was still offered a merge into EIN, which the operator overrode by hand. Put to him as an open
question the same day, he closed it: the manual override becomes the default.
Decision. When a source role has NO name match in this catalog and the bundle's other roles resolved by name, the preview proposes CREATE rather than a function-match merge. The reasoning is rule 1's, one step out: when most of an arriving bundle resolves to this catalog by its own names, the vocabulary arriving is demonstrably this organization's own — and a name inside such a vocabulary that we have never carried names a role we DO NOT HAVE, not a synonym for one we do. Merging it into whichever role happens to do similar work is the same two-roles-into-one error rule 1 exists to prevent, arriving by the other door.
The threshold is a STRICT MAJORITY of the bundle's source roles resolving by exact name. The
one-hit alternative ("at least one sibling adopted by true name") was considered and rejected: the
premise is about a VOCABULARY, not a word. Role names here are short conventional abbreviations —
QMB, GL, TL — and one of them colliding with a role this installation happens to carry is
coincidence, not shared origin; under a one-hit threshold that coincidence would silently switch
function matching off for every other row in the bundle, a large behaviour change bought with the
thinnest possible evidence. A majority cannot be produced by a lucky collision and is stable under
adding one more role. PULSEMED, the case that earned the rule, resolves 11 of 12.
Because the evidence is a property of the BUNDLE rather than of a row, the mapping is now proposed
as a whole (ImportOperatingModel.proposeAll) instead of row by row.
What does not change: where the vocabulary is NOT already ours, a corpus whose names mean nothing here is exactly the corpus whose functions are the only evidence available, and D2 answers for every row as before — that gate is the whole point and is pinned by its own test. And this remains a PROPOSAL: an operator who wants the merge picks the role in the preview and confirms it. What changed is which answer they must override, not whether they may.
Consequences¶
- Bundle format grows a
roles+policiessection; for meridianqms the shapes come from the old loader's Johner configuration (already in the repo). - The thin client gains the mapping flow in CLI form: preview emits the proposed mapping as
a file; the operator edits/confirms; execute takes it back (
--mapping). The future import UI renders the same payload. - The #42b starter-role rider is superseded by this ADR; the #42e dead-end check ("no activated roles — nobody can ever be staffed") ships independently and stays.
- Retrofit: MERIDIAN-QMS + PULSEMED are re-imported through the new path once realized (§7 applies; nothing local has touched them beyond staffing/verifier acts, which do not block), exercising the mapping preview end to end — while everything is still free.
- Export-side bundling (LQMS→LQMS portability) remains its own future slice; this ADR fixes the arrival half's shape it will feed.