Policy Not Prose
Never hard-code a decision's DATE or its AUTHOR into committed source, a comment, an XML doc comment, or documentation prose. State the rule; link to the policy record. The record carries the date and the name — once.
A rule written as "Maintainer, 2026-09-07: do it this way" embeds three different things in one sentence: the rule, when it took effect, and who decided. Only the first belongs in the place you are reading. The other two are data about the rule, and prose is the worst available store for them.
Why
Prose copies drift. The same decision gets restated in an AGENTS.md, two doc pages and a
skill. Change the decision and you must find all four; you will find three. The fourth goes on
instructing people for months, and it is indistinguishable from the live ones because they all look
equally authoritative.
Names go stale faster than rules. People change roles, hand over areas, and leave. The rule outlives the attribution, so a name in a comment converts a durable instruction into something that reads as gossip about a decision nobody can now ask about. It also invites the wrong question — "is this still true, or just what someone said once?"
Prose cannot be queried. "Which policies are in force, and since when?" is a reasonable thing to ask a system. If the answers live in sentences scattered across repos, there is no answer — only a grep and a guess. A register answers it in one read.
The shape
A policy is a record with five fields and a link:
| field | what it is |
|---|---|
| id | a stable slug — what other pages cite |
| value | the decision itself, in as few words as carry it |
| status | in force, or proposed when it was cited before it existed — the field the self-healing step below turns on |
| in force since | the date it started applying |
| set by | the role or identity that set it — a role where one exists |
Everything else — source, comments, AGENTS.md, docs, skills — states the rule and cites the id. No dates, no names.
- # A What's New entry is written per RELEASE, not per change (maintainer, 2026-09-20)
+ # A What's New entry is written per RELEASE, not per change — policy `whatsnew-cadence`
🚨 What this does NOT forbid
This rule is about policy markers and attributions, not about dates as such. A date that is evidence stays exactly where it is:
- a measurement — "the folder reached 1,292 entries, 662 in August"
- an incident — "on 2026-09-19 the observation window lapsed and nothing wrote a terminal state"
- a historical record — a migration note, a retired mechanism, a changelog entry
Those are facts about events, and an event without its date is not a fact. The test is simple: would this date need changing if the decision changed? If yes, it is a policy marker and belongs in the register. If no, it is evidence and belongs where it is.
For review
A diff that introduces a hard-coded policy date or a person's name into source, a comment, an XML doc comment or doc prose is a review finding. The fix is never to delete the information — it is to move it: add or cite a register entry, and leave a link behind.
The finding is self-healing — it never blocks
A reviewer who finds a hard-coded date or name does not hand back a chore. They run a two-step that always terminates:
- Look for a policy that already covers it in the register below. Found → replace the prose with the citation. Done, no issue, one line changed.
- Not found → file an issue to introduce the policy, add a
proposedrow to the register naming that issue, and cite it in place.
The citation is written first and the policy catches up. That is the whole trick: the text is never blocked on the policy existing, and the reviewer is never asked to settle a policy question in a review thread — which is the thing that turns a two-line finding into a three-day argument. Because step 2 adds the register row immediately, a citation never dangles; what is pending is the ratification, not the reference.
This is why the rule converges without a migration. Nobody sweeps the corpus, but every page that gets edited for its own reasons leaves behind one more citation and, where it was missing, one more policy. The register fills from actual traffic — the decisions people actually touch — rather than from an archaeology project, and the pages nobody edits are, by definition, the pages nobody is misled by.
File the issue and carry on. Do not stop the change you came to make in order to ratify a policy you just discovered was implicit — that is the incidental-findings rule, and it applies here exactly as it does everywhere else.
This is the hamster wheel, applied to policy. Triage → implement → test, with every step filing what it finds back into triage rather than absorbing it: the same loop, and the same reason. A change that stopped to ratify every implicit policy it brushed against would land late, review badly, and abandon what it set out to do. The exit has to be cheap or the wheel stops turning — so the exit here is one register row and one issue, and then you carry on with what you were doing.
🚨 Forward-only. No backward migration.
This rule applies to what is WRITTEN FROM NOW ON. It is not a licence to sweep the existing corpus, and a pull request whose purpose is to retrofit old pages is out of scope.
The existing prose is not a defect. It records decisions that were taken and communicated the way the house wrote at the time, it is accurate, and rewriting it would touch a large number of pages to change nothing a reader relies on — while burning the review attention that new work needs. A migration would also be the more dangerous edit, because mechanical rewriting of attributions is exactly the kind of change that quietly alters meaning in the one page nobody re-reads.
So a reviewer checks the direction of travel: does this diff ADD a hard-coded policy date or name? If it does, that is the finding. If it merely fails to remove existing ones, that is not. Old pages migrate only when they are being edited anyway for their own reasons, and only the lines already being touched.
The register
A row is in force once ratified, or proposed when a reviewer cited it before it existed —
a proposed row names the issue that will settle it, so the citation resolves from the moment it is
written.
| id | value | status | in force since | set by |
|---|---|---|---|---|
whatsnew-cadence |
A What's New entry is written per RELEASE, not per change. A merge updates its doc page and mints no dated file. | in force | 2026-09-20 | maintainer |
issue-taxonomy-scope |
Classification covers OPEN issues only. Closed issues are not classified, not counted, and appear in no query. | in force | 2026-09-20 | maintainer |
release-blocker-gate |
A release may not be cut while any sev:B or sev:H bug is open in the seven repositories that carry the taxonomy; sev:M and sev:L never gate a cut. Enforced by the release.cut standard in the Governance package. |
in force | 2026-09-20 | maintainer |
data-sync-approval |
Adding or widening the synchronisation of data needs a global admin's approval. | in force | 2026-09-20 | maintainer |
platform-backwards-compatibility |
Platform builds are backwards compatible within a major and a declared compatibility epoch — a ladder: a platform roll keeps the old plugin bytes (no rebuild, no re-seal) and plugins roll independently against the running platform. Compiled bytes are keyed on c<major>e<epoch>, never on a per-build identity (provenance only), and carry a platform range: floor (the producing build) ≤ running ≤ ceiling (open by default), else declined loudly naming both versions; platform assemblies bind whenever running ≥ compiled-against. Only a DECLARED break (an epoch or major bump in platform-compatibility.json, with a ceiling for the previous epoch) steps off the ladder and obliges a coordinated rebuild and seal; never seal or pin around a compatibility break — fix compatibility. Manual: Doc/Architecture/ModuleVersioning. |
in force | 2026-09-25 | maintainer |
version-shapes |
Exactly two version shapes: X.Y.Z-ci.<n> and clean X.Y.Z. No rc, preview or labelled line is ever minted. |
in force | 2026-09-07 | maintainer |
query-fanin-stall-terminal |
A query provider that neither emits, completes nor errors TERMINATES its merged query with a named error instead of hanging: the fan-in's Initial gate is a bound, not a wait. Every consumer that turns a mesh read into a decision reads that error as an availability failure — an access-control read fails CLOSED and reports that it could not be established, never denied and never granted. |
in force | 2026-09-21 | maintainer |
dynamic-content-type-registration-pass |
Every replica registers the content type of each already-baked dynamic NodeType it has not activated, in a PACED, REGISTRATION-ONLY pass after the boot's bake settles and OFF the readiness path: it loads the existing bytes and builds the configuration on a transient probe, and never compiles or writes a NodeType record. The cost is the ~13.5 s of assembly opening #1660 removed from boot, moved to that background pass. Never from a read seam. Mechanism: DynamicContentTypeRegistrar (MeshWeaver.Hosting); manual: Dynamic Content Type Registration. |
in force | 2026-09-25 | maintainer |
open-vocabulary-string-constants |
A vocabulary that is persisted, serialised, or extended by a module is a static class of const string named exactly as the enum would have been — never a C# enum. It stays OPEN: any other party may add its own values from its own constants class, so the platform's set is never treated as exhaustive. Consumers compare against constants and always carry a branch for a value this build does not know. |
in force | 2026-09-21 | maintainer |
thread-graceful-error |
Wherever user code is executed, innermost in a thread, it must gracefully error: every failure path ends in a stamped terminal state on the node. A failure the thread's own hub cannot stamp — because it is the hub that died — is observed, cleaned up and relaunched under a bound, and what a relaunch cannot fix is filed into bug triage. The relaunch/dispatch side is bounded by a configurable pool cap (maxConcurrentAgents, default 50) whose queue is a page, not a log. |
in force | 2026-09-20 | maintainer |
roll-migrates-first |
A schema change ships as a new image, and every roll runs that image's database migration FIRST — outside the portal, as its own run-once Job that must report succeeded — before the image moves. The operator half is hosting-migrate; the Roll plan calling it is the Plugins half. |
in force | 2026-09-21 | maintainer |
db-migration-planned |
A database schema change is planned before it merges, and every step is enforced by code. Every migration is EXPAND-ONLY: the previous image must run correctly against the new schema, because old pods keep serving until new pods are fully ready (maxUnavailable: 0). A destructive change ships as a two-release expand→contract pair. A pull request that bumps DbVersion.Latest declares Db-migration: V<N> — <kind>; <compat>; rolls migrate-first and passes a rehearsal against a real Postgres (MeshWeaver.Plugins). Every release publishes its ExpectedDbVersion (_releases/_db/<version>, OCI expectedDbVersion). Every roll path runs the target's migration Job before the image moves, or refuses naming both numbers; the operator's run.sh interlock enforces this for every plan, whatever Hosting generation composed it. One documented exception remains until its lane is fixed: the break-glass HelmRelease dispatch (Systemorph/Memex helm-release.yml) applies the migration Job alongside the Deployment; use Reconcile instead. Manual: Doc/Architecture/PlanningADatabaseMigration. |
in force | 2026-09-25 | maintainer |
first-admin-no-learning-path |
The instance's FIRST global administrator is seeded with no learning path (User.PinnedPaths empty); an ordinary new user is seeded with the four documentation sections. The learning path is a create-time SEED, never a value a later onboarding write re-imposes. |
in force | 2026-09-21 | maintainer |
first-sign-in-becomes-admin |
A provisioned instance with no HUMAN administrator sends an anonymous visitor to SIGN-IN, and the first person to complete onboarding is admitted without an invitation and becomes platform admin; every later person needs one. "Human administrator" is ONE rule, asked by every gate (onboarding page load, onboarding submit, entry page): an undenied Admin grant in Admin/_Access whose holder is not System, Anonymous or Public and has an Active mesh User node. So a grant SEEDED for someone who has not onboarded (Auth:GlobalAdmins, the image's own settings) does not block the first person. It is read entirely as System and fails closed (unreadable ⇒ administered). The image SHOULD seed no administrator, but today it still does: Memex.Portal.Distributed/appsettings.json carries Auth:GlobalAdmins: ["rbuergi"], so every instance of the current image holds that static grant until MeshWeaver.Plugins#2431 lands. The rule above keeps it from blocking the first person, because the holder has no User node on a fresh instance. Safe ONLY where sign-in is restricted to the owning organisation; an instance whose sign-in admits the public is provisioned with an administrator. Mechanism: AdministratorProbeService.HasHumanAdministrator + OnboardingAdmissions (MeshWeaver.Plugins#2430), FirstPersonBecomesAdminOnAFreshInstanceTest; the image seed goes in MeshWeaver.Plugins#2431; account in First-run setup on a provisioned instance. |
in force | 2026-09-27 | maintainer |
setup-secrets-three-valued |
The first-run setup dialog's secrets step shows a declared vault mapping whose object does not exist as its own state, missing, decided by the object's versions listing: 200 is exists, 404 is missing, anything else is not checked and never either answer. Missing rows sort first. |
in force | 2026-09-21 | maintainer |
platform-backwards-compatibility |
Platform builds within one major and one compatibility epoch are backwards compatible: plugin bytes built against platform N run UNCHANGED on platform N+1 — the ladder P1+p1 → P2+p1 → P2+p2 → P2+p3 → P3+p3, each step changing one side. Only a DECLARED epoch bump (src/MeshWeaver.Compiler/platform-compatibility.json, every broken member listed) breaks it; a plugin whose floor or producing platform is newer than the running one is declined loudly. Proven on every platform build, never assumed: the Platform compatibility … (ladder) check links the deployed plugin set against each platform pull request and hangs off the required check. |
in force | 2026-09-25 | maintainer |
cluster-upgrade-governed |
The AKS Kubernetes upgrade — control plane and every node pool — runs only as the governed UpgradeCluster Hosting/InstanceAction on the control instance, behind a mesh approval; never an ad-hoc az aks upgrade, az aks nodepool upgrade or kubectl. ONE approval covers the whole upgrade: control-plane minors chained one at a time, every pool upgraded once straight to the final version, the pool hosting the portals last, a health gate before each pool, and a stuck portal roll refuses it. Mechanism: hosting-aks-upgrade (operator), Hosting/ClusterUpgrade (MeshWeaver.Plugins — plan, approval, executor), the UpgradeCluster lane in Systemorph/Memex aks-ops.yml. |
in force | 2026-09-25 | maintainer |
module-sync-per-manifest-hash |
An instance ALWAYS syncs every module it has; nothing holds a whole Space or partition behind a per-identity seal. Each module is judged alone by the content hash (moduleVersion) in its manifest.lock: unchanged ⇒ nothing written; changed ⇒ it syncs to the incoming commit; a declared platform floor above the running platform ⇒ that one module is declined, loudly and by name, and holds no sibling. The seal decides only whether a NodeType ADOPTS prebuilt bytes or COMPILES from the synced source — never whether, or at which commit, sources arrive. Manual: Doc/Architecture/ModuleSyncPerManifestHash. |
in force | 2026-09-25 | maintainer |
init-timeout-retires-activation |
A hub that demand routing re-creates (WithReactivationOnDemand — every per-node hub) whose DataContext initialization TIMES OUT is disposed and logged at Error, never latched FAILED for the life of the process; the NEXT ACCESS re-creates it. No timer and no background retry: the parked backlog is answered terminally (ErrorType.Failed) so no re-ask latch retries on its own. A non-transient init FAULT keeps the latch. Mechanism: DataContext.SettleInitializationGate; account in What the DataContext Init Time-Box Bounds. |
in force | 2026-09-25 | maintainer |
dependent-suites-gate |
RETIRED — superseded by core-merge-never-blocked and one-promotion-gate. Was: a core change reached main only after MeshWeaver.Plugins' suites passed against the candidate, on every merge-queue entry, failing Consolidate test results on silence (measured cost: MeshWeaver#5807 green at 13:21Z, ejected 17:21Z on "did not answer within 42 min"). The advisory pull-request run and the verdict machinery remain; see One Promotion Gate. |
retired | 2026-09-25 → 2026-09-27 | maintainer |
core-merge-never-blocked |
A core pull request merges on core's OWN required checks. No required context, gate or merge-queue step waits on MeshWeaver.Plugins or any other repository; the dependent-suites run on a pull request is advisory (label dependent-suites, or a declared Pairs-with: Plugins counterpart). The merge queue on main stays off. Manual: One Promotion Gate. |
in force | 2026-09-27 | maintainer |
build-latest-green |
Every CI consumer and the image build take the NEWEST GREEN core main build (the resolver's newest set with a sealed platform trio — promoted, verified, baked — resolved by identity tag whether or not it is armed) together with MeshWeaver.Plugins main HEAD; a red core main falls back to the last green build, never forward into red. Plugins pull requests follow the newest set by default (the main-passed ceiling is opt-in, label platform:main-passed); the freeze variable MW_PLATFORM_REF stays for incidents. A burst of merges coalesces to one build of the newest heads; a run in flight is never cancelled. Manual: One Promotion Gate. |
in force | 2026-09-27 | maintainer |
one-promotion-gate |
The fleet rolls only to an ARMED set, and main-cd arm arms (the portal's <version> tag, the <line>-latest pointers, the release event) only the newest promoted set, newer than every armed one, whose MeshWeaver.Plugins dependent suites returned success for exactly its pair (refs/core-candidate/pair-<core7>-p<plugins7>: key, core commit, base, Plugins commit). A missing verdict waits, a red one is refused, a newer green one supersedes both; an override is a dispatch input carrying its reason. Platform delivery (promote, verify, bake, delivery-verdict) never waits on it. Every set is stamped with both commits (pair tag, promotion record, release event) so containment is answerable by ancestry. Manual: One Promotion Gate. |
in force | 2026-09-27 | maintainer |
paired-change-sets |
A change spanning core and MeshWeaver.Plugins is built and tested TOGETHER before either half merges: the core pull request declares Pairs-with: Systemorph/MeshWeaver.Plugins#<n>, the Plugins one Core-ref: Systemorph/MeshWeaver#<n>, and the dependent suites run against the core candidate plus the Plugins head. Merging stays per repository, core first and never waiting; the Plugins half goes green only once a green core build contains the core half (checked by ancestry). Manual: Paired Change Sets. |
in force | 2026-09-27 | maintainer |
content-neutral-push-keeps-run |
A push to a pull request that changes nothing the pull request AUTHORED — a merge of main, regenerated generated files — never cancels the run testing that content; the new head adopts its verdict. Only a push that changes the authored diff supersedes. Mechanism (MeshWeaver.Plugins): pr-supersede.yml + scripts/ci-change-set.py. |
in force | 2026-09-27 | maintainer |
self-update-record-authoritative |
When a deployment record declares the platform image's update policy (rendered as SelfUpdate__DefaultPolicy, with SelfUpdate__DefaultPattern), that declaration is AUTHORITATIVE: at every start the self-updater converges the instance's Admin/UpdatePolicy policy and pattern to it, touching no other field. With no policy declared the configuration only seeds a new node, and an existing node belongs to the instance's admin. Mechanism: UpdatePolicyNodeType.ConvergeToDeclaration (memex/Memex.Portal.Shared); account in Why the Fleet Stopped Rolling Itself. |
in force | 2026-09-28 | maintainer |
oauth-bounded-live-credentials |
The MCP OAuth token exchange keeps a BOUNDED number of live credentials per (user, client_id) — the N newest, N configurable as Mcp:OAuth:MaxLiveCredentialsPerClient, default 5 — and evicts the oldest beyond it, logging each eviction. Not one per client: processes of one installation share a client_id, and one-per-client made each new sign-in revoke every sibling session (#5074). Mechanism: OAuthCredentialEviction (Memex.Portal.Shared); manual: MCP Authentication. |
in force | 2026-09-25 | maintainer |
bake-gate-readiness-only |
A ROLL GATE — today the NodeType bake gate, nodetype_bake — holds READINESS only and never fails the startup probe. The startup probe proves only that the process booted; the gate's verdict is read by /ready alone, so a refusal stalls a roll (the pod stays alive, out of the Service) and never kills anything, and a restarted previous-image pod keeps serving. /health still runs and prints the gate; its status excludes it. The startup-critical checks (db_version, PostgreSql) stay on the startup probe; required_modules is a roll gate too (required-modules-readiness-only). Mechanism: ProbeEndpoints.RollGateTag + ServiceDefaults.TagRollGates, chart invariant 10b, RollGateReadinessOnlyTest; manual: The Bake Gate Only Stalls a Roll. |
in force | 2026-09-26 | maintainer |
required-modules-readiness-only |
The required-modules check (required_modules) is a ROLL GATE under the same rule as bake-gate-readiness-only: its Unhealthy verdict (a required module the image should ship is absent, or a present one did not install against this platform) stalls the roll and keeps the pod out of the Service, and never fails the startup probe or liveness. Its Degraded verdict (a store-delivered module not here yet) is a 200 and holds nothing, as before. /health still runs and prints it; its status excludes it. Core applies the tag by name, whatever the host's registration carries. Mechanism: ProbeEndpoints.RequiredModulesCheckName in ServiceDefaults.RollGateChecks, RollGateReadinessOnlyTest; manual: The Bake Gate Only Stalls a Roll. |
in force | 2026-09-26 | maintainer |
silos-pool-autoscaler-max |
The silos node pool (every portal) has its cluster-autoscaler maximum raised by one, 4 → 5, so a portal roll's surge pod is not left Pending while the public instance's KEDA scale-out holds its maximum. Node-pool bounds change only through the governed InfraDeploy action over Systemorph/Memex infra/estate.bicep — what-if first, then an approved deploy — never az aks nodepool update. Owed: the Memex change declaring the pool, the approved deploy, and the agentPools write grant for hosting-operator (the same Azure Kubernetes Service Contributor Role grant UpgradeCluster owes). |
proposed | — | maintainer |
governed-action-preflight |
A governed operation (a Hosting/InstanceAction) runs EVERY step under the system identity from its first step, and at PLAN time — before it parks for approval — verifies that each step is feasible: the rights it needs as system, and the scale bound of the mechanism each step uses. A step known to exceed its bound, or one the system identity cannot perform, is REFUSED AT PARK with the reason, never discovered partway through a destructive run. A whole-space deletion drops the partition as ONE teardown (PartitionTeardown.TearDownPartition), never a per-node recursive delete of its content. Manual: Partition Teardown → The direct teardown. |
in force | 2026-09-27 | maintainer |
severity-closes-on-verification |
A sev:B or sev:H issue closes on post-roll production verification of the running portal, never on the merge that lands its fix: a merge puts the fix on main, and what the label gates is whether the defect is gone from production. sev:M, sev:L, chore, enhancement and documentation issues close on a merge as before. Cited by the Closing keywords (no accidental close) gate, which refuses a body whose closing keyword targets an issue carrying either label. Ratification owed — filed for triage as rbuergi/Feedback/20260922-ratify-severity-closes-on-verification-policy, which carries the measurement that six merges closed a sev:H in the two days before the gate existed. |
proposed | — | — |
internal-code-review |
Pull requests are reviewed by the internal GLM-5.3 reviewer of the PR steward (MeshWeaver.Plugins Governance/PullRequestSteward), posting through the systemorph-com App; GitHub Copilot code review is retired from every repository. The steward reviews every in-scope, non-fork pull request and communicates only with global admins. Gate: check-review-answered.py accepts both reviewers until Copilot's rule is gone everywhere. |
in force | 2026-09-27 | maintainer |
secrets-write-only-entry |
No manual Key Vault access. Every secret the fleet uses is entered through a GUI in the app that owns it. The GUI is WRITE-ONLY: it sets or replaces a value, never reads or displays it back, and shows only status and a fingerprint. The vault has two identities: a READER (the pods' CSI identity: get only, per secret where the scope allows) and a WRITER (secret-writer: list, metadata, set, delete, recover, purge; never get), used only by the governed write path running as system. No human holds either. Mechanism: hosting-kv-set / hosting-kv-status / hosting-kv-state, the SetSecrets action; gate: check-manual-keyvault.py; manual: Secrets: Write-Only Entry, Split Identities. Owed: the secret-writer identity and its access policy (Systemorph/Memex infra/estate.bicep through an approved InfraDeploy), the reader narrowed to get, the Plugins status/lifecycle actions on the Deployments page, the Store payment-keys GUI, and the four operator steps that still read a value. |
proposed | — | maintainer |
governed-action-preflight |
A governed action (Hosting/InstanceAction) runs EVERY step with system credentials, and checks the rights and the scale each step needs at PLAN time, before it parks. A step that cannot complete (a right the system identity lacks, a volume a bound cannot cover) refuses the request at park, with the reason on the page. It never fails partway through a destructive run. Evidence: a DeleteSpace failed at its ninth step, on 31,138 per-node delete validations against a 25 s bound, after the space's grant and GitSync configuration had already been removed. Owed: the scale and rights pre-flight, in MeshWeaver.Plugins (in flight). Manuals: MeshWeaver.Plugins Hosting/AksOperationsViaActions, Hosting/DeleteSpaceAction. |
proposed | — | maintainer |
action-page-controls-and-queries |
An activity or action page is composed of platform UI controls in a real layout: cards, grids, and query controls that offer "show matching nodes". A SET of nodes is expressed as a mesh query (the top-level node plus scope:subtree), never as an enumerated listing dumped into a code control. The summary goes last. Owed: plan steps expressed as queries, in MeshWeaver.Plugins (in flight). Manual: MeshWeaver.Plugins Hosting/AksOperationsViaActions, "The run page". |
proposed | — | maintainer |
pr-babysitter-authority |
The fleet PR babysitter, the PR steward's heal/observe half, HEALS and never MERGES, and nothing irreversible runs unvalidated. Its deterministic pass only PROPOSES its one heal, with the evidence: a re-run of the failed jobs of a pull request whose every failing check died of infrastructure (runner, network, registry, artifact quota, or a stale review-gate verdict). Its validator agent approves or refuses each proposal against that evidence, with its reasoning. Only an approval runs: ONCE per head SHA, after the live head and the marker are re-checked, and behind a marker comment that carries the reasoning. It never merges, enables auto-merge, pushes, dequeues, approves a pull request or uses an administrator override. A waiting-for-platform pull request is read off its repository's label and re-run by that repository's own waker, never by the babysitter. Implementation owed: the validator's fail-closed EU enforcement (MeshWeaver.Plugins#2448) and the arming on the build instance (a governed Reconcile of its record). Shipped: MeshWeaver.Plugins#2439 (PrBabysitter, Hosting/PrWatch, agent pr-babysitter). Manual: MeshWeaver.Plugins Hosting/PrBabysitter. |
proposed | — | maintainer |
pr-babysitter-cadence |
The PR babysitter is event-driven, with a full fallback pass every 30 minutes. Its triggers are GitHub pull-request and check events and the arrival of a new sealed platform set. The events come from the ONE organisation webhook, and the control instance forwards them over the control lane. It runs on the BUILD instance only (opt-in configuration), one pass at a time. Implementation owed: as pr-babysitter-authority, plus the build instance's control-lane key, without which nothing is forwarded and the fallback pass is the only trigger. Shipped: core #5797 (forwarded events). |
proposed | — | maintainer |
code-review-eu-only |
Code review of pull requests — the PR steward's internal review and the PR-agent validator on the build instance — runs on GLM 5.3 through OpenRouter's EU endpoint https://eu.openrouter.ai/api/v1 ONLY, and FAILS CLOSED: a review that cannot run in the EU does not run. Mechanism (MeshWeaver.Plugins): the review model node Provider/OpenRouterEU/glm-5.3-review declares providerRouting (region EU; only Inceptron and Mistral; no fallbacks; zero data retention; no data collection), which makes it RESIDENCY-BOUND — reachable by node path only, credentialed only through its own provider (Provider/OpenRouterEU, which references the account key on Provider/OpenRouter rather than holding one), never substituted by another model, and refused before sending unless the endpoint is the EU host; OpenRouterProviderRoutingPolicy writes the pinned provider object onto every request. Governed setup: the standards pr.review-provider-eu.create and pr.review-model.bind. Owed: the two standards signed (the account is on OpenRouter's Business plan, which EU in-region routing needs), and the build instance's copy of the two nodes. Manual: MeshWeaver.Plugins Governance/PullRequestSteward § 6.2a. |
proposed | — | maintainer |
domain-config-apps |
Configuration and secrets live in the app that owns their DOMAIN — AI, Databases, Sign-in, Email, Payments, Integrations — never as ad-hoc panels or dialogs on the Deployment record page or elsewhere. A deployment's recorded shape is edited in the control instance's fleet app for that domain (/Hosting/{X}/Deployment/{id}: the record's block bound to the record, the domain's vault objects write-only, Apply files a governed Reconcile); what an instance changes about itself live is a tab of its own Admin app, under the same domain name. The record page links to the apps and carries no entry of its own. The AI domain's fleet app is named Models (/Hosting/Models; /Hosting/Ai redirects there). Owed: the six fleet apps (Models first) in MeshWeaver.Plugins Hosting/, and the record page's secret dialog and panels removed as each domain lands. Manual: Domain Configuration Apps. |
proposed | — | maintainer |
secret-actions-interim-actions-lane |
🚧 TRANSITIONAL. Until the secret-writer identity is provisioned AND every secret action runs in the in-cluster Job under it, the two VALUE-FREE secret actions — a generate-only SetSecrets (hosting-kv-set --generate, approved in the mesh like every SetSecrets) and a SecretStatus (hosting-kv-status, metadata only) — may run on the Actions executor (Systemorph/Memex aks-ops.yml) as hosting-operator (which holds get, list, set: the accepted interim risk is a writer that COULD read; the verbs never do and no value crosses the lane); each run says so on its node (writerIdentityNote). A pasted value and every lifecycle verb stay refused there, so a third-party-held secret has no write path until the exception ends. Manual: Secrets: Write-Only Entry → Interim: the value-free verbs on the Actions lane. Enforcement halves: the MeshWeaver.Plugins executor verdict (HostingOperator.ActionsLaneSecretVerdict, Plugins#2528, OWED until it is merged and rolled onto the control instance, when this row becomes in force) and the Memex aks-ops classifier (Memex#613, shipped). |
proposed | — | maintainer |
operations-instance-per-estate |
Every estate has the same shape, 1:1: exactly ONE operations instance, which holds BOTH the control role (the Deployments/* records, InstanceActions and their approvals, the signed inbox, triage, the fleet watch, the ops-lane dispatch) and the build role (the build queue, its scheduler and admission, the PR babysitter, build Jobs), plus any number of working instances. A separate build instance is retired through the generic migration, and the control role cuts over onto the instance the estate's records name as its operations instance; the cutover is decided. Exactly one inbox consumer per estate at every step. Owed: the build role's code and chart gaps G1–G10 (MeshWeaver.Plugins Hosting/OperationsInstance §7), then each estate's cutover acts (its records repository's cutover pull request). Manual: MeshWeaver.Plugins Hosting/OperationsInstance. |
proposed | — | maintainer |
Cited by: Release Process · The Self-Update Schema Wall · Issue Taxonomy and the Release Readiness Gate · Adding a Data Sync Needs a Global Admin · Thread Supervision · Access Control · Closing Keywords and Issue State · The Platform Compatibility Ladder · The Bake Gate Only Stalls a Roll · Deployment (AKS) · Secrets: Write-Only Entry, Split Identities.
🚨 A
proposedrow is not a weakerin force— it is an honest one. The first draft of this register listedrelease-blocker-gateasin forcewhile the standard that enforces it was still an unmerged pull request; the row was moved toproposednaming what was owed, and back toin forceonly once that standard had merged. That is the precise failure this page exists to prevent, committed in the page that defines the rule. If a row's mechanism does not exist yet, the row saysproposedand names what is owed.
Adding a policy here is cheap and reversing one is cheap. That is the point: a register entry can be changed in one place and every citation follows, which is exactly what a sentence copied into four files cannot do.