# FEEDBACK — mgf-standard

> **Repo-scoped feedback queue** (rules FB-01..FB-04 / DOC-13). This is the
> channel for friction with **the standards, the federation contract, the
> library registry, the federation-process recipes, or the
> `mgf.standard` package** — everything this repo owns.

## Routing — file here when…

| Friction is about… | File at… |
|---|---|
| A standards **rule** (AP/CF/EH/LG/SC/TS/DP/DOC/…): wrong, missing, ambiguous, or a new rule is needed | **here** |
| The **federation contract** (`FEDERATION.md`): a duty is unclear / wrong / missing | **here** |
| The **library registry** (`MGF_LIBRARIES.md`) / its generator / the REL-13 gate | **here** |
| A **federation-process recipe** (cohort release, sibling rename, sync prompt, a template) | **here** |
| The `mgf.standard` package (resolver API, packaging) | **here** |
| `mgf-common` **library code or CLI** behaviour | [`mgf-common/FEEDBACK.md`](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/FEEDBACK.md) |
| A specific **sibling**'s API/behaviour | that sibling's `FEEDBACK.md` |

> **Routing migration note.** Historically, cross-cutting / standards-level
> papers went to `mgf-common/FEEDBACK.md`. With the standards extracted to
> this repo, standards / contract / registry papers now belong **here**.
> `FEDERATION.md §7` and the `mgf-fed agents` briefing are updated to
> match.

## Entry template

```
### PAPER-NN — <title>
- **Severity:** 🔴 Blocker | 🟡 Sharp edge | 🟢 Nice-to-have | 💭 Idea
- **Filed by:** <project / who> on <YYYY-MM-DD>
- **What hurts:** <the concrete friction>
- **Why it matters:** <impact / who it blocks>
- **Evidence:** <rule ID, file:line, commit SHA, version hit>
- **Suggested shape:** <what a fix might look like>
- **Status:** OPEN
```

`PAPER-NN` is a monotonic ID, per this repo.

---

## Open

### PAPER-118 — GUI-01 carve-out for shared Qt *brand-kit* libraries (`mgf-brand-qt`)

- **Severity:** 🟡 Sharp edge
- **Filed by:** vm-vmanager-app (desktop-UI redesign C10) on 2026-07-10
- **What hurts:** GUI-01 forbids ANY `mgf.*` library from importing PySide6 at
  module level. That is exactly right for domain libraries — but it also
  forbids the Qt analog of `mgf-brand-web`: a presentation-layer *kit* library
  (tokens, QSS builder, fonts, icons, brand widgets) that desktop consumers
  share. vm-vmanager-app has now built that layer app-local and kit-ready
  (`vmanager.gui.design`: a `design-system-is-kit-ready` import-linter
  contract forbids `vmanager.*`/`mgf.*` imports; the token/QSS core is
  additionally Qt-free), but extraction to `mgf-brand-qt` is blocked on the
  rule as written.
- **Why it matters:** three PySide6 consumers exist or are planned
  (vm-vmanager-app, hrb-app, figrecovery Phase 7 — whose REQUIREMENTS.md
  literally says "styled after VManager"). Without a sanctioned kit, each
  copies the design system — the exact drift `mgf-brand-web` was created to
  stop on the web.
- **Evidence:** GUI_CONSUMERS.md GUI-01; vm-vmanager-app `.importlinter`
  contract 5; `src/vmanager/gui/design/` (Qt-free `tokens.py`/`_mix.py`/
  `qss.py`; Qt only in `fonts/icons/theme/widgets`).
- **Suggested shape:** GUI-01 distinguishes *domain* libraries (Qt forbidden)
  from *UI-kit* libraries (Qt allowed, consumers import them only from their
  presentation layer — same discipline `mgf-brand-web` follows for CSS).
- **Status:** RESOLVED 2026-07-10 — founder-enacted: GUI-01 amended with the
  UI-kit carve-out (same commit); `mgf-brand-qt` extraction proceeds.

### PAPER-119 — Desktop visual-design guidance gap (a DESKTOP_BRAND recipe)

- **Severity:** 💭 Idea
- **Filed by:** vm-vmanager-app (desktop-UI redesign C10) on 2026-07-10
- **What hurts:** GUI_CONSUMERS.md §Non-scope declares visual design
  per-project, and no federation surface says what a Magogi *desktop* app
  should look like — the web has `mgf-brand-web`; desktop had nothing.
- **Why it matters:** vm-vmanager-app just derived the full translation
  (tokens→QPalette+QSS, chrome-vs-readout split, one-gold-per-view in Qt,
  self-theming widgets, reduced-motion via settings). The next adopter should
  read it, not re-derive it.
- **Evidence:** `vm-vmanager-app/docs/archive/2026/desktop-ui-redesign/`
  (docs 00–04 + 11 chunk records + verification/state-coverage.md).
- **Suggested shape:** a `docs/recipes/desktop-brand.md` pointing at the
  vm-vmanager-app design system as the reference implementation, graduating
  to a standard when `mgf-brand-qt` exists.
- **Resolution:** SHIPPED (recipe surface, 2026-07-10 sweep) — the paper's
  precondition was met the same day it became answerable: `mgf-brand-qt` 0.1.0
  entered the registry (PAPER-118 carve-out + REL-13 regen, PRs #205/#206) and
  the design core is already extracted into it (`mgf.brand_qt.{tokens,_mix,qss,
  theme,fonts,icons,motion,widgets/}` — verified on disk). Authored
  [`docs/recipes/desktop-brand.md`](docs/recipes/desktop-brand.md): the kit's
  module map, the five derived translation rules (tokens→QPalette+QSS ·
  chrome-vs-readout · one-gold-per-view · self-theming widgets ·
  reduced-motion-as-setting), the GUI-01 consumer discipline, the
  vm-vmanager-app archive as deep reference, and the adopt-in-a-new-consumer
  short path; indexed in `docs/recipes/README.md`. **Graduation stays open by
  design:** promote rules 1–5 to a DESKTOP_UI standard (EXTEND, founder) when
  the second consumer lands (hrb-app / figrecovery Phase 7 named).
- **Status:** SHIPPED (recipe; standard-graduation deliberately deferred to the second adopter)

> These five papers came out of a 2026-06-06 red-team of the federation-sync
> mechanism (simulating a sibling-repo agent handed only "run `mgf-common
> sync-prompt` and follow it") against three dimensions: (1) full resource
> access — always the latest, no guesswork; (2) full understanding + value
> capture — lessons + feedback never lost; (3) a recorded, resumable, multi-
> session plan. The **recipe-level** surface of each shipped the same day
> (federation-sync-prompt.md + the new lesson-learned template); the **binding
> rule / mgf-common CLI** parts remain OPEN below and are tracked in
> `pending-feedback/mgf-common.md` where they cross into mgf-common.

### PAPER-03 — `LESSON_LEARNED.md` as a first-class (eventually binding) artifact
- **Severity:** 🟡 Sharp edge
- **Filed by:** mgf-standard (red-team session) on 2026-06-06
- **What hurts:** The federation has no home for "the non-obvious thing I
  learned working in THIS repo that the next agent would otherwise rediscover."
  CHANGELOG records what shipped, FEEDBACK routes friction to *another* repo, a
  conformance ledger records rule state — none capture a local lesson. A core
  mgf value (never waste or duplicate effort) had no artifact behind it.
- **Why it matters:** Lessons live only in chat transcripts and evaporate; the
  same gotcha (e.g. the `VIRTUAL_ENV`/uv footgun) gets re-hit across sessions
  and repos.
- **Evidence:** `grep -r LESSON_LEARNED docs/` returns only prose
  (API_DESIGN.md:104); it is absent from the DOCUMENTATION.md required-docs set.
- **Suggested shape:** (a) ✅ SHIPPED recipe surface — new
  `docs/recipes/lesson-learned-md-template.md` + the sync prompt's PHASE-B
  LESSON-OUT step appends a dated entry at the repo root. (b) OPEN — promote to
  a binding **DOC-rule** in DOCUMENTATION.md (append a new id; update README
  Index of MUSTs + the FEDERATION required-docs list, DOC-18 ripple) and gate
  its presence in `mgf-fed catch-up`/`app-doctor --standards` (the CLI change is
  in `pending-feedback/mgf-common.md`). Stage it advisory-now / binding-later so
  the corpus isn't retro-failed before repos create the file.
- **Status:** ✅ SHIPPED as a SHOULD — **DOC-19** (v2.20) drafted + the §2.0.1 matrix / FEDERATION.md / What's-new ripple done (0.1.19). Deliberately staged as a SHOULD (kept OUT of the Index of MUSTs so it doesn't retro-fail every repo's ledger). The remaining step is the future **promotion to MUST** (Index of MUSTs + the `doctor --standards` presence gate = mgf-common PAPER-99), to run as a federation-sync wave once the file is broadly adopted.

### PAPER-04 — Durable cross-repo feedback outbox (`pending-feedback/`)
- **Severity:** 🟡 Sharp edge
- **Filed by:** mgf-standard (red-team session) on 2026-06-06
- **What hurts:** The sync prompt tells an agent to route cross-repo findings to
  the target's `FEEDBACK.md` but also that the federation is READ-ONLY ("never
  reach in"). Those two collided: the agent could neither write the paper nor
  keep it — findings degraded to a sentence in a final report that nobody
  relays. Value leaked exactly where the prompt claimed to capture it.
- **Why it matters:** A real bug found in a dependency, or a justified challenge
  to a standard, was lost unless a human happened to read the transcript —
  breaking "never lose value" and the "everything is up for evolution" value.
- **Evidence:** federation-sync-prompt.md GUARDRAILS (pre-fix) "routed to the
  right FEEDBACK.md — never reach in", with no writable destination.
- **Suggested shape:** ✅ SHIPPED recipe surface — a `pending-feedback/<target>.md`
  **outbox in the agent's OWN repo** (the one place it may write): the agent
  drafts a proper `feedback-md-template` paper there, the supervisor relays it
  into the target's `FEEDBACK.md`. OPEN — a short supervisor-side **relay
  recipe** (drain `pending-feedback/` → targets' FEEDBACK via `tea`/PR) and a
  decision on whether `pending-feedback/` presence/format is a binding
  convention or stays recipe-level.
- **Status:** SHIPPED (found already resolved on the 2026-07-10 sweep; the paper was never flipped) — both pending items landed 2026-06-13: the **binding decision** = **FB-05 promoted SHOULD→MUST** (README Index footer, "FB joins as the feedback-discipline family"; `DOCUMENTATION.md#FB-05`, v2.23) and the **supervisor-side relay recipe** = [`docs/recipes/feedback-relay.md`](docs/recipes/feedback-relay.md) + the `mgf-fed feedback` tool (shipped mgf-fed 0.3.0; `--check` is the no-silent-rot gate FB-05 names as its enforcement).

### PAPER-05 — "Latest" is ambiguous; sync can silently bind to a stale pin
- **Severity:** 🔴 Blocker (correctness of the core guarantee)
- **Filed by:** mgf-standard (red-team session) on 2026-06-06
- **What hurts:** The seams resolve the corpus from the version THIS project's
  pin RESOLVES TO — which may lag the latest release. Nothing asserted
  installed == latest, so an agent behind a stale ceiling (`mgf-common<0.47`
  while 0.47 is published) syncs to OLD standards and reports success. "I
  synced" silently meant "to whatever my stale pin resolved," not "to current."
- **Why it matters:** Directly undermines dimension 1 (always get the latest):
  a confident, green, WRONG sync.
- **Evidence:** prompt resolved "from the version THIS project pins" with no
  registry-vs-installed comparison; the live `catch-up` latest-check is an
  unwired TODO (project-state-handoff item #4).
- **Suggested shape:** ✅ SHIPPED prompt surface — STEP 0 **ASSERT-LATEST**:
  compare installed vs the Codeberg simple/REST index, and if the pin ceiling
  excludes the latest, record a REQUIRED pin-walk + FLAG rather than treat
  stale-as-current. OPEN — wire a real live-latest check into `mgf-common
  catch-up` (registry HEAD vs installed snapshot), routed in
  `pending-feedback/mgf-common.md`.
- **Status:** SHIPPED (status reconciled on the 2026-07-10 sweep — both halves had landed) — prompt guard shipped 0.1.18 (STEP 0 ASSERT-LATEST); the CLI half resolved as mgf-common PAPER-98 with a **recorded disposition that differs from the original ask, deliberately**: `catch-up` stays offline and ships a no-network snapshot-provenance advisory (so "green" states *what corpus it checked against*), while the live-latest comparison remains agent-side per the prompt guard (PR #9, commit `100b52e`). The stale-as-current failure mode is closed from both directions; nothing further is pending here.

### PAPER-06 — No ASK gate: the prompt over-weights autonomy on ambiguous calls
- **Severity:** 🟡 Sharp edge
- **Filed by:** mgf-standard (red-team session) on 2026-06-06
- **What hurts:** PHASE A ended "proceed autonomously" with no boundary for
  when to STOP and verify with the human. An agent could unilaterally mark a
  rule N/A, or apply an irreversible/cross-cutting fix, on a genuine judgment
  call — a silent conformance hole or an unsafe change with no checkpoint.
- **Why it matters:** Dimension 3 explicitly wants questions/verification when
  needed; wrong unilateral calls are the costly failure mode.
- **Evidence:** federation-sync-prompt.md (pre-fix) line "proceed autonomously"
  with no ask condition anywhere in PHASE B.
- **Suggested shape:** ✅ SHIPPED — a PHASE-B **ASK gate**: decide autonomously
  when clear, but stop and ask (recording the question in the plan's OPEN
  QUESTIONS first) on ambiguous applicability, irreversible/cross-cutting fixes,
  or rule conflicts. OPEN — decide whether to also encode it as a general
  agent-behaviour MUST in AGENTS.md.
- **Status:** SHIPPED (decision tail closed on the 2026-07-10 sweep, Court verdict recorded per AG-15) — the "encode as a general agent-behaviour MUST" question has been **answered by the corpus's own evolution** since filing: **AG-06** (risky/irreversible/shared-state ops MUST get explicit confirmation) + **AG-15**'s never-block protocol (record the open question, sensible default, mark dependents `INFERRED`, continue — bounded by the STOPPERS list) together encode the ASK gate's substance corpus-wide, and the sync prompt keeps the operational PHASE-B gate. A third, duplicate encoding would add surface without adding force — reviewed; no further rule needed.

### PAPER-07 — Plan ≠ ledger; no multi-session resume protocol
- **Severity:** 🟢 Nice-to-have
- **Filed by:** mgf-standard (red-team session) on 2026-06-06
- **What hurts:** The conformance ledger (state) doubled as the plan (sequence),
  with no sequenced steps, blockers, or open-questions section, and no
  instruction for resuming across sessions — a fresh session might redo PHASE A
  or, worse, assume the work was done.
- **Why it matters:** Big out-of-sync projects need multi-session work;
  dimension 3 wants the plan recorded and resumable.
- **Evidence:** prompt had only ⏳ ledger rows; `grep -i resume|session`
  returned no resume protocol.
- **Suggested shape:** ✅ SHIPPED — PHASE-A **A4 PLAN**
  (`docs/inprogress/<sync>-plan.md`, separate from the ledger, with ordered
  fixes + blockers + OPEN QUESTIONS) and an explicit **RESUME** step (re-run
  STEP 0 + ASSERT-LATEST; if corpus unchanged, continue ⏳ items). OPEN — decide
  whether the `<sync>-plan.md` location is a named convention worth a one-line
  rule.
- **Status:** SHIPPED (decision tail closed on the 2026-07-10 sweep, Court verdict recorded per AG-15) — the `docs/inprogress/<sync>-plan.md` location **stays recipe-level, deliberately**: the sync prompt is the only surface that creates these files and it already prescribes the path (the operative convention lives exactly where it is exercised); `docs/inprogress/**` is the established in-flight-work home and is explicitly a working surface (LOCK §1). A standalone one-line rule would duplicate the recipe without changing behavior — reviewed; no rule needed.

### PAPER-135 — Desktop GUI excellence has no rule home: a11y, measured perf, kit-adoption depth, and an observable-behavior test tier are all "per-project"

| Field | Value |
|---|---|
| Status | OPEN |
| Severity | 🟡 Sharp edge |
| Submitter | hrb-app (commit `96aeb42`) |
| Submitted | 2026-07-29 |
| Decision | pending |
| Decided on | — |
| Scheduled for | — |
| Shipped in | — |

- **Severity:** 🟡 Sharp edge
- **Filed by:** hrb-app (commit `96aeb42`) on 2026-07-29 — from the GUI round of its release review, as the reference desktop consumer.
- **What hurts:** the desktop GUI family (GUI-01..GUI-10) governs *architecture* — no Qt in libraries, don't block the main thread, settings-backed state, capability gating — and explicitly declares the rest out of scope: "Visual design / UX patterns (icons, layouts, colour choices, **accessibility checklists**). Those are per-project." The web family made the opposite call: **WUI-05** is a binding accessibility floor (one `h1`, skip link, visible focus indicator, `prefers-reduced-motion` honoured, honest empty states) and **WUI-07** puts enforcement in CI (palette-breach lint derived from the token layer, token-freshness gate, screenshot regression). Desktop has no analogue of either — no a11y floor, no measured performance budget, no statement that a GUI consumer should actually *use* the brand kit's vocabulary rather than hand-roll equivalent chrome, and no test tier that asserts observable behaviour.
- **Why it matters:** the gap is measurable in the reference consumer, and it points the wrong way — **full conformance with the desktop family coexists with every quality property being absent**. hrb-app was conformant against GUI-01..GUI-10 while: importing **4 names** from the brand kit (`apply_theme`, `EmptyState`, `StatusChipDelegate`, `STATUS_ROLE`) against a kit exporting 23 names from `mgf.brand_qt` plus 9 more from `mgf.brand_qt.widgets`; carrying **zero** `setAccessibleName` / `setAccessibleDescription` calls in the entire app; having no performance budget of any kind; and running a suite that could not see a dead button (it is scheduling a *planted*-dead-button self-test precisely because that capability is unproven). The adjacent lesson makes the point sharper: hrb-app's suite printed "215 passed" and died of SIGSEGV, and the green line was believed for weeks. Conformance that cannot see a widget with no accessible name, a 4-second cold start, or a button wired to nothing is measuring the wrong thing — and it is measuring it in the family that most needs the opposite.
- **Evidence:** the non-scope carve-out — `docs/standards/GUI_CONSUMERS.md:21-24`; the rule set it applies to — GUI-01..GUI-10 (ten rules, verified); the web analogues that exist — `docs/standards/WEB_UI.md:74` (WUI-05, the a11y floor) and `:76` (WUI-07, CI enforcement incl. screenshot regression). Reference-consumer measurements (hrb-app at `96aeb42`, 2026-07-29): kit imports — `grep` over `src/hrb_app` yields three import lines covering four names; accessible names — `grep -r "setAccessibleName\|setAccessibleDescription" src/hrb_app` → **0**; the app's own bar and its gaps — `hrb-app/docs/gui/HRB_GUI_STANDARD.md` §1 (a 22-row MUST table, G1..G22, whose columns are *MUST · What it means here · **Verified by** · Wave* — every MUST names the test that verifies it) plus §2 (five measured performance budgets: cold start ≤1.5 s to first paint, one model-update signal per poll tick, frame budget on a 5 000-node tree, event-storm debounce, quit ≤3 s with the collector down), §3 (an error-translation table), §5 (an a11y floor); the live gap ledger — `hrb-app/docs/gui/GUI_CONFORMANCE.md`; the test-tier evidence — `hrb-app/LESSON_LEARNED.md` (2026-07-29: "A test suite can print `215 passed` and then die of SIGSEGV; a piped tail converts exit 139 into exit 0") and `hrb-app/docs/inprogress/RELEASE_MASTERPLAN.md:136` (the planted-dead-button gate).
- **Suggested shape (A, recommended):** grow the GUI family rather than starting a new document — **GUI-11 kit-adoption depth** (a desktop consumer uses the brand kit's vocabulary for chrome it has an entry point for; hand-rolled equivalents are a declared variance, not a default); **GUI-12 desktop a11y floor** as the WUI-05 analogue (accessible names on interactive widgets, keyboard-complete operation, sane focus order, contrast via kit tokens in both themes, reduced-motion honoured and tested **both ways**); **GUI-13 measured perf budgets** in PF-01's shape (cold start, per-tick signal discipline, interaction frame budget, teardown), stated as regression-vs-baseline rather than absolute numbers so different apps can carry different bars honestly; and a **TESTING §6 desktop observable-behavior tier** (real input events, visible-text or pixel-delta assertions, dialog auto-answer) with `mgf-uitest-desktop` named as the reference harness once it exists — the WUI-07(c) screenshot-regression analogue. hrb-app offers `docs/gui/HRB_GUI_STANDARD.md` + `GUI_CONFORMANCE.md` + `GUI_ACCEPTANCE.md` as the draft evidence base, on the same second-consumer graduation path PAPER-119 defined (vm-vmanager-app is the other desktop consumer and derived an overlapping set independently — that convergence is the signal).
- **Suggested shape (B):** keep it per-project, but require every GUI consumer to **declare its own bar** in `docs/gui/` (the trio shape above) so the conformance audit at least sees the gap instead of reporting silence as success. Weaker, but it beats the current state, where "100% conformant" and "no a11y at all" are the same reading.
- **Cost if deferred:** every desktop consumer re-derives the bar (two have now done so independently), and the audit keeps reporting green on apps with zero accessible names and unmeasured startup. The a11y half is the one that compounds worst: retrofitting accessible names and focus order across a built UI is materially more expensive than requiring them while the widgets are being written — and it is the property an operator with a screen reader cannot work around.
- **Status:** OPEN

### PAPER-136 — DESKTOP_UI graduation trigger: PAPER-119's named second consumer has landed

| Field | Value |
|---|---|
| Status | OPEN |
| Severity | 🟢 Nice-to-have |
| Submitter | hrb-app (commit `96aeb42`) |
| Submitted | 2026-07-29 |
| Decision | pending |
| Decided on | — |
| Scheduled for | — |
| Shipped in | — |

- **Severity:** 🟢 Nice-to-have
- **Filed by:** hrb-app (commit `96aeb42`) on 2026-07-29.
- **What hurts:** nothing is broken — a precondition has been met and the paper that recorded it is closed, so nobody is watching for it. PAPER-119 shipped `docs/recipes/desktop-brand.md` and deliberately left graduation open: "promote rules 1–5 to a DESKTOP_UI standard (EXTEND, founder) when **the second consumer lands (hrb-app / figrecovery Phase 7 named)**". hrb-app adopted `mgf-brand-qt` on **2026-07-10** (merge `aa3a6db`, "adopt mgf-brand-qt — Magogi theme + doctor chips") and is deepening that adoption in its current GUI round. This entry exists to make the trigger visible and to request the founder-gated EXTEND.
- **Why it matters:** the five translation rules (tokens→QPalette+QSS · chrome-vs-readout · one-gold-per-view · self-theming widgets · reduced-motion-as-setting) are being followed as *recipe* by two independent consumers, which is exactly the state PAPER-119 said should convert them into a standard. Until they do, they are advisory — nothing audits them, and the third adopter's deviation is invisible. Filed as 🟢 because the substance already works; the ask is a status change with a real consequence (a rule the conformance audit can see).
- **Evidence:** PAPER-119's own graduation clause (this file, `:98-101`); the adoption commit `aa3a6db` (2026-07-10) plus the deepening round (`hrb-app/docs/gui/GUI_CONFORMANCE.md`, the live ledger against its 22-MUST bar); the kit's shipped module map (`mgf.brand_qt.{tokens,_mix,qss,theme,fonts,icons,motion,widgets}` — verified on disk); vm-vmanager-app as the deriving first consumer (`vm-vmanager-app/src/vmanager/gui/`, which now imports the extracted kit rather than its app-local copy — e.g. `gui/confirm.py:11`).
- **Suggested shape:** promote translation rules 1–5 into a `DESKTOP_UI.md` (or a DESKTOP_* rule family inside `GUI_CONSUMERS.md` if a second desktop document is unwanted), with the recipe kept as the worked reference and `mgf-brand-qt` named as the kit the rules are written against. Worth sequencing with PAPER-135: rules 1–5 are the *visual translation* half, and GUI-11..13 are the *quality floor* half — promoting them together gives desktop one coherent chapter instead of two half-answers. **Adjacent, routing question for the maintainer:** the kit's icon set is thin for hardware consoles — the 42 icons are navigation (9), actions (9), status (7) and a 17-glyph software-supply-chain domain set (`proof`, `manifest`, `artifact`, `ledger`, `chain`, `build`, `review`, `publish`, `kernel`, `forge`, `mesh`, `witness`, `registry`, `lock`, `key`, `terminal`, `chart`), with **no** `usb` / `pci` / `cpu` / `disk` / `network` / `power` / `lease` glyph, and `icon()` raises `ValueError` for any name outside the frozen set (`mgf-brand-qt/src/mgf/brand_qt/icons.py:85-87`), so a consumer cannot extend it locally either. That is brand-VALUE (glyph sources), so it likely belongs to `mgf-brand` rather than here or `mgf-brand-qt` — flagging it once, for the maintainer's routing call, rather than filing it three times.
- **Cost if deferred:** N/A (roadmap-shaped). The one real cost of waiting is that the trigger is now recorded on a **closed** paper, so if this entry is not carried, the next reader of PAPER-119 sees SHIPPED and moves on.
- **Status:** OPEN

### PAPER-128 — Three repos had NO `clone:` block at all — silently inheriting BOTH the OAuth flake and the WF-09 partial-clone 504

- **Severity:** 🟡 Sharp edge (two known, papered defects were being inherited by default, invisibly)
- **Filed by:** Court/CTO (the PAPER-109 rollout wave) on 2026-07-11
- **What hurts:** `mgf-hrb`, `mgf-test-supervisor` and `mgf-cost-watch` ship **no `clone:` section whatsoever**. They therefore use Woodpecker's **default** clone — which is (a) credential-injected from the short-lived OAuth token (**PAPER-109**), and (b) a **treeless partial clone**, the exact shape that intermittently 504s on Codeberg's lazy promisor tree-fetch and which **WF-09 / `partial: false` exists to prevent**. Both defects were being inherited **by omission**: nothing in the repo says "we opted out", because there is nothing there at all.
- **Why it matters:** the fleet believed `partial: false` was universal — it is in the canonical template, so every *generated* pipeline has it. But these three are bespoke or non-generated, so "we fixed that fleet-wide" was quietly untrue for them. **An absent block is the most invisible kind of drift: a grep for the wrong value finds nothing, and a grep for the right one finds nothing either.** This is the PAPER-120 class (bespoke pipelines don't inherit) in a form that is harder to see, because there is no line to be wrong.
- **Evidence:** `sed -n '/^clone:/,/^steps:/p' .woodpecker.yml` → **empty** for all three (on `origin/main`, 2026-07-11), while every generated member carries the explicit block. The same three were the only ones the PAPER-109 rollout could not patch by pinning an existing block.
- **Resolution:** SHIPPED (this wave) — each of the three now carries an explicit, hand-maintained `clone:` block with **both** fixes: the pinned `codeberg_clone_token` credential (PAPER-109) **and** `partial: false` (WF-09), with a comment saying why it is hand-maintained (PAPER-120).
- **Durable ask (relayed to mgf-fed):** the **gate floor** should assert `partial: false` and the pinned credential as **required clone properties** on every member — the `ci-command` check reads step *commands*, and a clone block is configuration, not a command, so it currently sails past. **A missing block must be a finding, not a silence.**
- **Status:** SHIPPED (instances); the gate-floor extension is relayed

### PAPER-129 — `mgf-cost-watch` and `mgf-website` are outside the registry too: they have pipelines, so nothing flags them

- **Severity:** 🟡 Sharp edge
- **Filed by:** Court/CTO (the PAPER-109 rollout wave) on 2026-07-11
- **What hurts:** PAPER-122 established that a repo outside `MGF_LIBRARIES.json` is invisible to every registry-scoped tool, and mgf-fed's new **`ci-ungoverned`** check closes that — **but only for repos with NO pipeline**. `mgf-cost-watch` and `mgf-website` are **also** non-members, and they **do** have pipelines — so they are *not* flagged, yet `mgf-fed scaffold` will not manage them either. They sit in a blind spot between the two checks: **governed enough to look fine, ungoverned enough to be skipped.** They were both missed by the PAPER-109 re-render (the generator simply does not know them) and had to be patched by hand.
- **Why it matters:** every future template change will silently skip them, exactly as this one did. That is the PAPER-120 failure mode again, but arising from *registry membership* rather than the exempt list — and it is quieter, because these repos have green pipelines that look entirely healthy.
- **Evidence:** `MGF_LIBRARIES.json` (37 members) contains neither `mgf-cost-watch` nor `mgf-website`; both have a committed `.woodpecker.yml` on `origin/main`; `mgf-fed scaffold <repo>` left both unchanged during the PAPER-109 wave (verified: the fix had to be hand-applied).
- **Suggested shape:** decide each repo's status **explicitly** — either register it (if it is a fleet artifact whose CI we own) or record it in a `[exempt].unmanaged` list with a reason — and have `drift-check` **fail on any cloned `mgf-*` repo that is neither a registry member nor explicitly exempted**, pipeline or not. Today the check only fires when a pipeline is *absent*; the real invariant is *"every repo we own is accounted for."*
- **Resolution:** RESOLVED by registration, piecemeal — every repo this paper (and PAPER-122) named is now a registry member: `mgf-brand` + `mgf-website` enrolled 2026-07-17 (`MGF_MEMBER.toml` / manifest parse), `mgf-cost-watch` enrolled 2026-07-24 (`MGF_MEMBER.toml`, `lang = "other"`, registry count 42 — the last holdout, which also gained the universal governance steps its cron-only pipeline never ran). The suggested *accounted-for invariant* was **not** built: `ci-ungoverned` stays deliberately narrow by recorded design (mgf-fed `ungoverned_repos` docstring — a pipeline-bearing non-member is out of drift-check's scope). Honest residual: a **future** cloned `mgf-*` repo with a pipeline but no registration would again be invisible until a human notices — the class is mitigated by there now being zero such repos, not closed by a check.
- **Status:** RESOLVED (instances; the invariant-check ask stands recorded above)

> **A note on method, recorded against my own work (2026-07-11).** While verifying PAPER-122 I used a membership check keyed on `name` — but registry entries are keyed on **`repo`**, so my check returned "not a member" for **every** repo, including the ones that are. It happened to agree with the (independently correct) agent finding about `mgf-brand`, so the conclusion stood — but **the verification was worthless, and I reported it as evidence.** A check that cannot fail proves nothing. Re-verified properly: `mgf-brand` is genuinely absent from the 37 members; `mgf-hrb`, `mgf-test-supervisor` and `mgf-standard` are present.

> **Renumbered on arrival (2026-07-14).** These two papers were filed on a branch as
> `PAPER-123` and `PAPER-124`. While that branch sat open, `main` grew its own — and
> entirely different — 123, 124, 125, 126 and 127. Merging the branch as written would
> have put **two different papers under each ID**, in a queue whose own spec says
> "`PAPER-NN` is a monotonic ID, per this repo." They are relanded here as **128** and
> **129**, with their evidence re-verified first-hand rather than trusted:
> - **PAPER-128's claim is now SHIPPED** — `mgf-hrb`, `mgf-test-supervisor` and
>   `mgf-cost-watch` all carry an explicit `clone:` block on `origin/main` today (the
>   PAPER-127 SSH rollout closed it).
> - **PAPER-129's claim still STANDS** — `mgf-cost-watch`, `mgf-website` and `mgf-brand`
>   are still absent from the 37-member registry.

### PAPER-130 — `REL-13` cannot see the only drift that matters: **main vs. the published artifact**. 28 of 30 distributions' version numbers are lies.

- **Severity:** 🔴 Blocker
- **Filed by:** Court/CTO (the 2026-07-14 full review) on 2026-07-14
- **What hurts:** `REL-13` (`mgf-fed registry --check`) compares a repo's **declared**
  version against the **registry's** version. Both said `0.4.10`, so it passed — while
  `mgf-alembic`'s `main` sat **28 commits past the `v0.4.10` tag**, still declaring
  `0.4.10`. **The published `0.4.10` and main's `0.4.10` were different code under the same
  number.** Nothing in the corpus checks main-vs-**tag** *content*, so nothing noticed.
- **Why it matters:** measured across the fleet, **28 of 30 distributions are in this
  state** (8–54 commits past their tag). Only `mgf-common` and `mgf-http` are honest — and
  `mgf-http` is precisely the one repo whose relicence reached users. That is not a
  coincidence; it is the proof. The consequences were all invisible:
  - **6 of 7 published wheels still shipped `License: MIT`** while `main` said Apache-2.0.
    The Foundation's relicence — recorded as *"done (51/0)"* — was true of `git main` and
    **false of anything installable. It had reached no consumer at all.** MIT carries no
    trademark carve-out and no patent grant, and grants already made under it cannot be
    retracted.
  - Four `FEEDBACK.md` papers marked **"✅ SHIPPED"** carried `Shipped in: next release`.
    That release never happened. A consumer reads the queue, concludes the fix is available,
    and `pip install` hands them a wheel without it.
  - **Eighteen leaves' published wheels still capped `mgf-common<0.50`** — a pin widened on
    `main` and never released. `uv` therefore **backtracked the entire federation's
    co-install to `mgf-common` 0.49.2**, and *that* stale cornerstone is why `mgf-fed`'s
    marker checker kept demanding `slow` (PAPER-131), flagging 24 conformant repos as broken.
    **One unreleased pin bump held the whole federation to the wrong cornerstone.**
- **Evidence:** `mgf/tools/verify_release_currency.py` (shipped with this paper) → **FAIL, 28
  distributions.** The published `mgf-alembic 0.4.10` wheel's metadata: `License: MIT`,
  `Requires-Dist: mgf-common<0.50`. After releasing `0.4.11`: `License: Apache-2.0`,
  `License-File: NOTICE`, `Requires-Dist: mgf-common<1.0,>=0.41` — verified by downloading
  the wheel from devpi.
- **Suggested shape:** a REL-family MUST — **a release gate that fails when `main` carries
  shipped-source changes past the tag matching its declared version.** Docs/CHANGELOG/CI
  changes are exempt; anything a consumer installs is not. Pair it with a metadata check:
  the licence in the latest published wheel MUST equal the licence on `main`.
  > **A fix that isn't released isn't shipped. A version that isn't published is a wish.**
- **Status:** 🟡 MOSTLY SHIPPED — **the corpus ask landed**: `REL-14` in `docs/standards/RELEASING.md` §2.4 (corpus v3.3.0, 2026-07-18), incl. the licence-parity half. **Re-verified by execution 2026-07-24, and the enforcing tool was itself wrong:** `verify_release_currency.py` reported **28** distributions, of which **26 were false positives** — the "changed" files were `fed-resources/` generated state, `scripts/`, `uv.lock` and governance docs, none of which reach a consumer's wheel (verified: every member packages `src/mgf` only). Fixed in the `mgf` workspace (`22dece4`); the gate now reports **4**, all genuine. A gate that cries wolf 26 times is how the real findings get ignored. **Two items remain, both tracked:** (1) the genuine drift — `mgf-fed-web` (v0.2.3) and `mgf-test-web` (v0.1.7) sit past their tags with `pyproject.toml` changes; this is drift the court itself created on 2026-07-23 walking the `mgf-fedres` pins forward without releasing, and it needs a bump + release. (2) REL-14 says "enforced by the **weekly** run" — **no such schedule exists**; the tool lives in the private `mgf` workspace, which has no pipeline. Wire it into the agent2 estate watcher (beside `devpi-export`) or strike the word "weekly".

### PAPER-131 — A checker that demanded a marker the standard had DELETED — and whose auto-fixer would have written it back into 24 repos

- **Severity:** 🔴 Blocker
- **Filed by:** Court/CTO (the 2026-07-14 full review) on 2026-07-14
- **What hurts:** `mgf-fed catch-up` kept its **own hand-copied duplicate** of the federation
  marker taxonomy. `mgf-common` 0.50.0 removed the deprecated `slow` marker per **TS-18** —
  whose migration note says plainly: *"drop the `slow` row from registered markers … under
  `--strict-markers` a leftover usage **fails collection, which is the loud migration
  signal**."* The fleet obeyed. **The checker did not follow**, so it demanded a marker the
  corpus had deleted, and flagged **24 of 40 repos as non-conformant FOR OBEYING THE
  STANDARD.**
- **Why it matters — it is worse than a false alarm.** `catch-up --apply` **writes** missing
  markers. Running the *documented remediation* would have **re-added the dead marker to all
  24 repos and then reported success.** In this very review, a careful reviewer read the
  checker's output and recommended exactly that. **The gate did not merely lie — it recruited
  a good engineer into spreading the lie, one keystroke from corrupting the fleet.** Its own
  message contained its refutation: the snippet it told you to paste read *"Deprecated.
  Removed in v2.0."*
  It was also **mislabelled TS-25** — which is *"flaky tests MUST be auto-quarantined"*, an
  entirely different rule — so anyone who followed the citation landed on the wrong page.
- **Evidence:** corpus TS-19 + §13.11 say **twelve** markers; `mgf.common.testing.MARKER_TIER`
  (which TS-19 names canonical) has **12**; `mgf-alembic`'s `pyproject.toml` registers exactly
  those **12**; `mgf-fed`'s `_CANONICAL_MARKER_DESCRIPTIONS` had **13**. `13 − 12 = slow`.
- **Suggested shape:** **the corpus should forbid a second copy of a canonical set.** Where a
  rule names a canonical mapping (TS-19 → `MARKER_TIER`), tooling MUST *derive* from it, not
  restate it. A copy of a truth is a second thing to forget. (Fixed in `mgf-fed`: the taxonomy
  is now derived from `MARKER_TIER`, the label corrected to TS-19, every hard-coded count
  removed — that literal `13` is *how* it drifted — and the tests, which hard-coded the
  taxonomy themselves and so **pinned the bug**, now derive it too.)
- **Status:** ✅ SHIPPED (corpus v3.3.0, 2026-07-18) — **DP-14 "Derive, never restate"** in `docs/standards/DESIGN_PRINCIPLES.md` §15, citing this paper by name, with an enforcement row and reviewer-checklist item. Tool half re-verified 2026-07-24: `mgf-fed`'s `_catch_up.py` imports `MARKER_TIER` from mgf-common at run time; its canonical set is 12 entries and is *identical* to `mgf.common.testing.MARKER_TIER` on disk — no hard-coded count, `slow` gone, and the TS-25 mislabel corrected to TS-19 throughout.

### PAPER-132 — Codeberg silently rate-limits **similarly-titled** PRs (~2/hour) — which is exactly the shape of every cohort release

- **Severity:** 🟡 Sharp edge
- **Filed by:** Court/CTO (the 2026-07-14 release wave) on 2026-07-14
- **What hurts:** opening a fleet-wide release wave (18 PRs, near-identical titles) fails
  with: `newIssue: "magogi-admin" posted 2 similarly named issues in the last hour: rate
  limited`. This is **not PAPER-110** — that is API *call volume*. This is a **content-similarity**
  anti-spam limiter, roughly **two similarly-titled PRs per hour**, and it is **undocumented**.
- **Why it matters:** a cohort release, a WF-13 re-render wave, a fleet-wide licence sweep —
  every one of them opens N PRs with deliberately uniform titles, because uniformity is the
  point. The federation's own recipes therefore *generate* the exact shape that trips this.
  And the failure is **silent**: the PR simply does not exist, and a driver script that does
  not check will merrily proceed as though it does.
- **Evidence:** 7 of 18 identical-title PRs were created before the limiter fired; the rest
  errored. **Re-issuing them with genuinely distinct titles succeeded immediately** (9 of 10).
- **Suggested shape:** the cohort-release + WF-13 recipes MUST require **per-repo distinct PR
  titles** (naming the repo and version), and any fleet driver MUST **verify each PR exists
  after creating it** rather than assuming success.
- **Status:** OPEN — **re-verified 2026-07-24: neither half shipped, and the one place the limiter IS
  mentioned is the wrong recipe.** The sole fleet-wide mention is a sub-bullet in
  `docs/recipes/activate-ci.md`, filed *under the PAPER-110 API-budget note* — conflating the HTTP-429
  call-volume limiter with this distinct similar-title one. `docs/recipes/cohort-release-wave.md` —
  the recipe that *generates* the failing shape — contains **zero** PR-title guidance, and
  `docs/recipes/codeberg-pr.md` still teaches a generic constant title (`feat(x): land the slice`),
  the exact anti-pattern, with no post-create existence check. **Founder-gated (corpus/recipes):**
  (1) cohort-release-wave Phase B gains a MUST for per-repo distinct titles naming repo + version,
  and verifying each PR exists after creation; (2) codeberg-pr's example title becomes repo-specific
  and the gotchas table gains the limiter; (3) move the activate-ci bullet out from under PAPER-110
  so the two limiters stop being conflated. The limiter itself was not re-probed — confirming it
  requires *creating* PRs, a write action out of a read-only verification's scope.

### PAPER-123 — Retired `mgf-*` artifacts are still live (and installable) on public PyPI — a silent-downgrade channel PKG-01 cannot close

> **⚠️ CORRECTED BY EXECUTION (Court, 2026-07-14). Do not act on this paper as originally
> written — its specifics are wrong in both directions, and the real hole is elsewhere.**
>
> - **It is 15 live, unyanked `mgf-*` distributions on public PyPI (240 files, 0 yanked), not
>   4.** Probed every registry name directly.
> - **`mgf-logship` is NOT "a squatter — not ours". It IS ours** (author `Bassam Alsanie`,
>   Homepage → our Codeberg, summary byte-identical to our `pyproject`). **There is no
>   adversary in the namespace today.** The paper invents one.
> - **The paper misses the actual channel: our own devpi index UNIONS public PyPI.**
>   `magogi/prod` has `bases: ['root/pypi']` with an empty `mirror_whitelist`. Proven:
>   `+simple/mgf-common/` on *our* index serves `mgf_common-0.44.5` whose **sha256 is
>   byte-identical to the public pypi.org wheel**, and `+simple/mgf-doc-standard/` returns
>   **HTTP 200, 10 files** — a package we renamed away from and **do not host**. Every
>   pipeline in the fleet resolves through that URL.
> - **~22 `mgf-*` names on public PyPI are unclaimed.** Because the private index has no
>   releases for them, devpi falls through to the mirror — so anyone who registers one gets
>   it served straight into our fleet. *That* is the dependency-confusion door, and it is
>   open now.
> - **All 15 relics are published under the OLD MIT licence** while the repos are Apache-2.0.
>   **The relicence is not complete while they stand** (see PAPER-130 — it had not reached
>   any consumer at all).
> - The paper's own proposed mitigation (`--frozen`) **does not protect the core ring**:
>   `mgf-fed`, `mgf-fedres` and `mgf-fed-web` have **no committed `uv.lock`**, so `--frozen`
>   is not even available to them.
>
> **Fix the paper first, then act.** The first move is a config change **on our own infra**
> that needs nobody's permission: sever `root/pypi` from `magogi/prod` (giving third-party
> deps their own explicit index), or make the mirror fall-through actually deny `mgf-*`.
> Then claim the ~22 unclaimed names as tombstones, and decide on yanking the 15 relics.

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | TelePlasma (rescue round S0/S1; commit `9016ae7`) |
| Submitted | 2026-07-10 |
| Severity | 🔴 Blocker |
| Federation paper | relayed by the supervisor from `TelePlasma/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🔴 Blocker
- **Filed by:** TelePlasma (2026-07-10 rescue round) — relayed 2026-07-12
- **What hurts:** PKG-01 forbids *resolving* `mgf-*` from pypi.org — but the
  pre-cutover uploads are still there and still installable: `mgf-common` up to
  0.44.5 (**55 releases / 110 files, 0 yanked**, last upload 2026-06-03 — the
  cutover day), plus `mgf-tele-teltonika`, the renamed-away `mgf-doc-standard`,
  and — not ours — an `mgf-logship` squatter (≤0.1.1). A rule that says "don't
  resolve from there" cannot stop a resolver that goes there *by accident*.
- **Why it matters:** demonstrated, not theorised. During TelePlasma's rescue
  round a credential-less re-resolve (`uv export` without `--frozen` — the CI
  step's own shape) silently swapped **all nine** `mgf-*` pins from the devpi
  versions to the stale pypi.org ones (mgf-common 0.46.3 → 0.44.5, and the rest
  of the tier) and rewrote `uv.lock`. No error, no warning. Any fresh machine, a
  mis-set CI secret, or a transitive-dep resolution can fall into the same hole,
  and the relics diverge further from the real packages every month — so the
  failure gets *quieter*, not louder.
- **Evidence:** `pypi.org/pypi/mgf-common/json`, re-checked at relay time
  (2026-07-12): 55 releases, 110 files, **0 yanked**; latest 0.44.5; last upload
  `2026-06-03T09:06`. Incident + fix: TelePlasma `9016ae7` (the CI pip-audit
  step that triggered it, now `--frozen`). Distinct from PAPER-112 (which is
  about the *prose* still describing Codeberg-PyPI) — this is about the
  *artifacts*.
- **Suggested shape:** a founder decision plus a one-time sweep — **yank** (or
  publish tombstone releases for) the pypi.org `mgf-*` relics; claim/park the
  squatted names where feasible; and make the pypi.org namespace state part of
  the distribution posture that is **checked, not assumed** (a PKG rule + a
  periodic check, in the spirit of REL-13 registry currency). Interim mitigation
  every repo can adopt today: `--frozen` on every CI `uv` verb (PAPER-125).
- **Status:** 🟠 STILL TRUE (external half is FOUNDER-GATED) — **re-verified 2026-07-24, and the
  paper's own "CORRECTED BY EXECUTION" note is itself partly wrong.** Confirmed still true: **15
  live, unyanked `mgf-*` distributions on pypi.org (240 files, 0 yanked), every one `License: MIT`
  while `main` is Apache-2.0**; `mgf-logship` is genuinely ours, not a squatter. **What the earlier
  note got wrong:** it claimed our devpi index mirror-serves packages we do not host, citing
  `mgf-doc-standard` and an `mgf-common` sha256 match — but `magogi/prod` hosts BOTH (7 stage files
  for the former; the sha match is a stage re-upload), and for every project the stage hosts, devpi
  prints the whitelist banner and serves **stage files only**. **The real door, proven:**
  `+simple/mgf/` on our index returns HTTP 200 with **no** whitelist banner and serves a third-party
  PyPI package straight through `root/pypi` — so a name devpi has never hosted resolves to public
  PyPI *through our own index*. **Exposure measured, and it is much narrower than it looks:** all
  **42/42 registry names are hosted on devpi**, so every one is stage-only and safe today. The risk
  is a name devpi has not yet hosted — a brand-new package pip-installed before its first publish, or
  a typo. **PKG-06's stated rationale is now false**: `PACKAGE_DISTRIBUTION.md` says the `mgf-*`
  prefix is "a private convention no public PyPI package uses" — 15 of them are public today.
  **Remaining: (a)** corpus edit striking that false rationale (founder-gated); **(b)** yank/tombstone
  the 15 MIT relics + claim high-value unclaimed names — external account action, a ⚖ package, never
  solo. Also now closed: the note's "`--frozen` isn't available to the core ring" — all three core
  repos commit `uv.lock`.

### PAPER-124 — PAPER-114 residue: the *merge moment* still runs PR + push pipelines concurrently (shared-workspace clobber, new costume)

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | TelePlasma (rescue round; Woodpecker repo 48 pipelines #22/#23) |
| Submitted | 2026-07-12 |
| Severity | 🟡 Sharp edge |
| Federation paper | relayed by the supervisor from `TelePlasma/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟡 Sharp edge
- **Filed by:** TelePlasma (rescue round) on 2026-07-12
- **What hurts:** PAPER-114's push-branch filter removed branch-push↔PR
  concurrency — but **merging a PR still spawns two pipelines at once**: the PR
  pipeline of the merged head and the push pipeline of the new `main`. Observed
  on TelePlasma: pipeline #23 (push) ran its steps in an **empty workspace after
  a successful clone** — `install` → "No `pyproject.toml` found in current
  directory or any parent directory"; `secret-scan` → "open `.gitleaks.toml`: no
  such file or directory"; `commit-trailers` and `frontend-lint` red the same
  way — while #22 (the PR pipeline for the same commit) ran beside it.
- **Why it matters:** every merge in the fleet rolls these dice, and the
  signature is maximally misleading — four unrelated steps "broken" at once,
  each with a plausible file-not-found. It costs a full diagnosis cycle each
  time it fires, and it reads as a bad commit: we nearly re-fixed already-correct
  code before spotting the concurrent sibling.
- **Evidence:** Woodpecker repo 48, 2026-07-12 — #22 (`pull_request`) and #23
  (`push`) on the same commit `2d6e474`; #23's `clone` step is **green**, then
  the empty-tree failures above; #24 (manual, solo, same commit) → full backend
  battery green. Same contention class as the exit-126 case PAPER-114 names.
- **Suggested shape:** (a) infra — per-pipeline isolated workspace volumes on the
  agents (Woodpecker workspace config; `mgf-cloud-provision`); or, at minimum,
  (b) a documented signature in the run-CI recipe ("multi-step *file not found*
  immediately after a merge = concurrency clobber; **re-run solo before
  diagnosing**"), and let the agent2 watcher flag concurrent same-repo pipelines.
  The fleet already pays for (b) in diagnosis time.
- **Status:** 🟡 PARTIALLY SHIPPED — the **mitigation** landed (`docs/recipes/run-ci.md` documents the signature + "re-run solo before diagnosing"), but the **durable fix did not**, and the condition still occurs: re-verified 2026-07-24 against the live Woodpecker API — 6 overlapping same-repo pipeline pairs on `mgf-fed` alone, the most recent 5 all push+tag running concurrently 13–40s apart on one agent (the release flow `git push` + `git push --tags` produces this deterministically). A live instance was hit this session: mgf-standard pipeline #374 (the #251 merge) died on `sbom` alone with no error output while the #252 pipelines ran beside it; the next pipeline over the same tree was green. **The remaining ask is one config line, not a corpus change:** `WOODPECKER_MAX_WORKFLOWS=1` per agent (fleet capacity stays 2 across the two agents), or per-pipeline workspace volumes, in `mgf-cloud-provision`'s `woodpecker-agent-cloud-init.yml` + `docker-compose.yml`, then re-provision.

### PAPER-125 — CI `uv` verbs without `--frozen` re-resolve and rewrite `uv.lock` mid-pipeline

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | TelePlasma (rescue round S0.3; commit `9016ae7`) |
| Submitted | 2026-07-10 |
| Severity | 🟡 Sharp edge |
| Federation paper | relayed by the supervisor from `TelePlasma/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟡 Sharp edge
- **Filed by:** TelePlasma (2026-07-10 rescue round) — relayed 2026-07-12
- **What hurts:** `uv export` / `uv run` **without `--frozen`** re-resolve the
  graph and rewrite `uv.lock` as a side effect. In an audit-shaped step
  (`uv export …` → `pip-audit`) the pipeline therefore mutates the very lockfile
  it is auditing; in a credential-less or misconfigured environment it composes
  with the still-live PyPI relics (PAPER-123) into a **silent downgrade** instead
  of a loud failure. Newer uv additionally emits the project itself (`-e .`)
  unless `--no-emit-project` is passed, which breaks `pip-audit` outright — so a
  step written against an older uv **rots silently** under a floating uv image.
- **Why it matters:** the failure product is a *wrong lockfile*, which is worse
  than a red build. TelePlasma's step carried this shape from its template era
  and was structurally red since 2026-06-06 with nobody knowing (its CI had never
  been registered — a separate finding). Any repo that copied the
  export-then-audit pattern carries the same latent hazard.
- **Evidence:** reproduced by execution 2026-07-10 — an un-frozen `uv export`
  swapped all nine `mgf-*` pins to the pypi.org relics and rewrote `uv.lock`
  (restored via `git restore`). Working reference shape, TelePlasma `9016ae7`:
  `uv export --frozen --no-emit-project` → strip private `mgf-*` (absent from the
  public advisory DB) → `pip-audit --strict --no-deps` (the lock already *is* the
  resolved graph). Note the canonical `templates/woodpecker/base.yml` has **no**
  `uv export` step today — so this is guidance-shaped, not a template bug.
- **Suggested shape:** a one-line WF-family rule (or a run-CI recipe note): every
  CI `uv` verb that must not re-resolve carries `--frozen`; audit-shaped exports
  add `--no-emit-project`; private `mgf-*` are stripped before a public-advisory
  audit. Cheap to state — and it closes the door PAPER-123's artifacts leave open.
- **Status:** ✅ SHIPPED (corpus v3.3.0, 2026-07-18) — **WF-14** in `docs/standards/WORKFLOWS.md` carries the ask verbatim (incl. `--no-emit-project` + the private-`mgf-*` strip); enforced by mgf-fed 0.16.0's `ci-uv-frozen` gate-floor check on every member, any language, exempt or not. Re-verified 2026-07-24: **0 of 42 registry members** carry an unfrozen CI `uv` verb. **Residual, tracked separately:** the four consumer-app repos (TelePlasma, vm-vmanager-app, figrecovery, hrb-app) are non-members, so `drift-check` never sees them and they still run unfrozen `uv run` — that is the PAPER-129 accounted-for-invariant gap, not a WF-14 gap.

### PAPER-126 — OB-02 is ambiguous for consumer applications: does the `mgf_` metric prefix bind an app's OWN domain metrics?

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | TelePlasma (rescue round S2.5 ledger audit; commit `474b635`) |
| Submitted | 2026-07-10 |
| Severity | 🟢 Nice-to-have |
| Federation paper | relayed by the supervisor from `TelePlasma/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟢 Nice-to-have
- **Filed by:** TelePlasma (2026-07-10 rescue round) — relayed 2026-07-12
- **What hurts:** OB-02 says "**Every** metric name MUST follow the federation
  convention `mgf_<domain>_<unit>_<aggregation>` … The `mgf_` prefix **isolates
  federation metrics** from third-party metrics in shared dashboards." For a
  consumer application's *own* domain metrics the two halves pull in opposite
  directions: TelePlasma emits `teleplasma.telemetry.records.ingested`
  (app-namespaced, dotted OTel form). Renaming those to `mgf_*` would put app
  metrics *into* the very namespace the rule exists to keep clean.
- **Why it matters:** every consumer app hits this on its first OB-02 ledger row,
  and CFM-03 completeness forces each of them to write *something*. Without a
  ruling, some will rename to `mgf_*` (polluting the federation namespace) and
  others will not (ledger inconsistency across the app tier).
- **Evidence:** `docs/standards/OBSERVABILITY.md` OB-02 (wording unchanged at
  corpus 0.1.62; re-checked at relay time 2026-07-12);
  `TelePlasma/src/teleplasma/observability/metrics.py:83-118` (the three app
  metrics); its ledger row deliberately holds at ⏳ pending this ruling rather
  than renaming speculatively (`docs/inprogress/MGF_STANDARDS_CONFORMANCE.md`
  §2.3).
- **Suggested shape:** a CLARIFY-class amendment — the `mgf_` prefix binds metrics
  emitted **by `mgf-*` libraries**; consumer applications use their own app prefix
  with the same `<domain>_<unit>_<aggregation>` grammar and the OB-03 canonical
  labels (`app` / `version` / `env`), which already disambiguate the same metric
  across consumers in a shared dashboard. One sentence in OB-02 closes it for the
  whole app tier.
- **Status:** OPEN — **re-verified 2026-07-24: OB-02's wording is byte-unchanged** at corpus 0.1.67
  ("**Every** metric name MUST follow …"), §2 gives only `mgf_*` examples, and the `README` summary
  row repeats the unqualified "Every metric name". Notably the OB-03 label block **already shows
  `app="hrb-app"`** — the very disambiguator the proposed ruling leans on — so the corpus is one
  sentence away from answering itself. Downstream is still visibly blocked: TelePlasma's conformance
  ledger keeps its OB-02/OB-03 row at ⏳, explicitly waiting on this rather than renaming
  speculatively. **Founder-gated, CLARIFY class, no MUST weakened:** append to OB-02 that the `mgf_`
  prefix binds metrics emitted **by `mgf-*` federation libraries**, and that a consumer application
  uses its own app prefix with the same `<domain>_<unit>_<aggregation>` grammar plus the OB-03
  canonical labels; mirror it in the README summary row and `rules.json`.

## Closed

### PAPER-02 — Umbrella-drain slices need a "verify the neutral surface" gate before declaring cross-repo
- **Severity:** 🟡 Sharp edge
- **Filed by:** vm-vmanager-app (Claude Code session) on 2026-06-04
- **What hurts:** When draining a consumer off a retiring umbrella, it is easy
  to MISCLASSIFY a slice. Two failure modes, both hit during the
  vm-vmanager-app providers drain:
  1. *False cross-repo:* `security_facts` was deferred as a 3-repo campaign
     (assumed it needed `domain_pid`/`libvirt_uri`/`network_xml` added across
     core/sdk/libvirt). It was fully **app-only**: `libvirt_uri` was already in
     app config; network isolation was already on `NetworkProfile.forward_mode`
     (`None` ⇒ isolated); and `domain_pid` was **never implemented on the real
     provider**, so the PID-derived facts were dormant no-ops — nothing to
     port. (PR #35.)
  2. *False app-only:* `storage` reads and `vm snap info` LOOK like a clean
     client repoint but are genuinely blocked by **thin observation contracts
     missing fields** — `PoolInfo` lacks `available_bytes`/`active`,
     `_SnapshotInfoContract` lacks `state`. Repointing naively would silently
     drop data.
- **Why it matters:** Misclassification either burns a cross-repo campaign on
  app-only work, or ships a data-losing slice against a too-thin contract.
  Recurs on every umbrella-consumer drain across the federation.
- **Evidence:** vm-vmanager-app PR #35 (security_facts, mapped cross-repo →
  shipped app-only); storage/snapshot-info deferred for real contract gaps.
- **Suggested shape:** Add a "drain slice classification" gate to the
  federation drain recipe. For each provider/umbrella call a slice removes,
  confirm BOTH: (a) the neutral SDK/contract value type actually carries every
  field the consumer *reads* (a same-named method is not enough), and (b)
  whether the legacy implementation even populates it in production — a
  never-implemented method is a dormant no-op, not a feature to preserve. Only
  after both checks fail may a slice be declared cross-repo-blocked.
- **Resolution:** Recipe shipped — [`docs/recipes/umbrella-drain.md`](docs/recipes/umbrella-drain.md):
  the **slice classification gate** is its centerpiece. Per removed
  provider/umbrella call, answer **Q-A** (does the neutral SDK/contract value
  type carry every field the consumer *reads* — fields, not a same-named
  method?) and **Q-B** (does the legacy actually *populate* it in production,
  or is it a dormant no-op?). Decision table: neutral type carries everything →
  app-only; missing field but legacy never populated it → app-only (drop the
  no-op); missing field that legacy genuinely produced → cross-repo-blocked
  (file the field gap to the sibling's FEEDBACK, name the field). Both
  vm-vmanager-app failure modes (false-cross-repo `security_facts`,
  false-app-only `PoolInfo`/`_SnapshotInfoContract`) are worked into it.
  Indexed in `docs/recipes/README.md`; cross-linked from `library-app-separation`
  / `codeberg-pr` / `cohort-release-wave`. Closed 2026-06-04.
- **Status:** CLOSED

### PAPER-01 — No documented CLI recipe for agents to open Codeberg PRs
- **Severity:** 🟡 Sharp edge
- **Filed by:** vm-vmanager-app (Claude Code session) on 2026-06-03
- **What hurts:** Landing a slice ends in a Codeberg (Forgejo) PR, but the
  federation had no documented or installed CLI for PR operations. `gh` is
  GitHub-only; `tea` (the Gitea/Forgejo CLI) was not installed. So an agent
  that finishes a green branch can `git push` but cannot open the PR — it can
  only hand back the `…/compare/main...<branch>` URL for a human to click.
- **Why it matters:** Every federation repo lands work as Codeberg PRs (e.g.
  vm-vmanager-app #27–#34). The missing tool wedges a manual step into an
  otherwise fully-automatable land-the-slice loop, across all repos and agents.
- **Evidence:** vm-vmanager-app `drain-providers-snapshot` slice — branch
  pushed, PR opened manually via the compare URL because no `tea`/`gh` was on
  PATH; remote `ssh://git@codeberg.org/magogi-admin/vm-vmanager-app.git`.
- **Suggested shape:** Adopt `tea` as the standard Codeberg CLI in a
  federation-process recipe: install (static binary → `~/.local/bin/tea`, from
  dl.gitea.com), a one-time `tea login add` with a scoped Codeberg token, and
  the canonical `tea pr create --base main --head <branch> --title … --body …`
  invocation (plus `tea pr merge`). Document it beside the existing
  land-the-slice / PR process so any agent can open and merge PRs directly.
- **Resolution:** Recipe shipped — [`docs/recipes/codeberg-pr.md`](docs/recipes/codeberg-pr.md):
  `tea` install, a **repository-scoped** Codeberg login (distinct from the
  `write:package` publish token — a package-only token `403`s on `pr create`),
  and the real flag surface (`tea pr create --base/--head/--title/`**`--description`**
  — note it's `-d`, not `gh`'s `--body`; some repos branch-protect `master`).
  Indexed in `docs/recipes/README.md`; cross-linked from the sync-prompt and
  cohort-release recipes. Merging stays the supervisor's call (WF-01 + release
  discipline). Closed 2026-06-04.
- **Status:** CLOSED

### PAPER-127 — Fleet CI clones died when the forge shed *anonymous* git traffic — the mechanism behind PAPER-109, and why SSH was the right permanent fix

| Field | Value |
|---|---|
| Status | ✅ RESOLVED ON ARRIVAL (2026-07-12) |
| Submitter | TelePlasma (rescue round S1.5; Woodpecker repo 48 pipelines #1–#3) |
| Submitted | 2026-07-10 |
| Severity | 🟡 Sharp edge |
| Federation paper | relayed by the supervisor from `TelePlasma/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟡 Sharp edge
- **Filed by:** TelePlasma (2026-07-10 rescue round) — relayed 2026-07-12, already closed by the PAPER-109 SSH wave; filed for the **mechanism + independent confirmation**, which the original PAPER-109 record did not carry.
- **What hurt:** during a multi-hour Codeberg degradation on 2026-07-10,
  **anonymous** git smart-HTTP returned 504/503 while *authenticated* requests
  answered in ~0.5 s. git/libcurl send credentials only **after** a 401
  challenge — which never arrived — so every Woodpecker clone failed for the
  duration even though valid credentials were present on the runner. PAPER-109
  recorded this failure class as a "credential-injection flake — restart the
  pipeline, don't investigate"; restarting cannot help while the forge's
  anonymous tier is shedding, because a fresh injection changes nothing about
  *when* credentials are offered.
- **Why the mechanism is worth recording:** it explains why SSH is not merely a
  workaround but the **correct permanent fix** — SSH authenticates inside the
  handshake and never touches the challenge-response path — and it retires the
  "restart it, don't investigate" folklore for this signature.
- **Evidence:** probed by execution from **both** the CI host (`195.15.241.48`)
  and a workstation, 2026-07-10: anonymous
  `GET …/TelePlasma.git/info/refs?service=git-upload-pack` → **504 in ~30 s**
  (later 503), same for `mgf-common`; the identical URL with `curl -u` → **200 in
  0.5 s**; the REST API → 200 throughout. Three consecutive Woodpecker pipelines
  (repo 48, #1–#3) died at `clone`. Recovery announced itself when the endpoint
  finally answered **401** (i.e. *challenged*) instead of timing out.
- **Resolution:** SHIPPED upstream as the PAPER-109 SSH-clone wave — `clone` over
  SSH with a read-only deploy key (mgf-standard#222; e.g. mgf-fed `a73fa4c`).
  TelePlasma adopted it 2026-07-12 (deploy key `ci-clone-2026-07-12`; PR #47,
  `d1739df`) and has cloned green over SSH since. Nothing further pending.
- **Status:** ✅ RESOLVED

---

## Plasma project feedback cohort — filed 2026-06-11 (PAPER-100..106)

External feedback from the **Plasma project** (Magogi Foundation), submitted as
`docs/inprogress/Plasma_To_Magogi_Feedback_Papers_v0_1.md` (staging ids P-A..P-G; bundle
review of v0.1.48). All seven re-verified against the live corpus on filing. Six shipped
same-day; PAPER-100 (the audit-spine gap) shipped in mgf-standard 0.1.50 — the full 218→258 re-baseline. **All seven now resolved.**

### PAPER-100 — Index of MUSTs omits 5 families + REL-10..13 (~40 binding rules); headline propagates the gap
- **Severity:** 🔴 Blocker
- **Filed by:** the Plasma project on 2026-06-11 (staging id P-A)
- **What hurts:** The *Index of MUSTs* lists 218 rows across 16 families, but the corpus ships 21 binding families. TM/PF/OB/NM/GUI have **zero** index rows and REL-10..13 are defined-yet-unindexed (~40 MUST-level rules). Verified live: index = 218; 0 rows for each of those families; 0 for REL-10..13.
- **Why it matters:** The Index is the audit spine — CFM-03 and `doctor --standards` gate ledger completeness against it. A project passes "complete" against an incomplete denominator (~40 binding rules never audited). The index's own maintenance note shows the manual same-commit discipline has lost this race before.
- **Evidence:** `docs/standards/README.md` Index (218 rows); `TIME.md` / `PERFORMANCE.md` / `OBSERVABILITY.md` (OB-11) / `NAMING.md` / `GUI_CONSUMERS.md` binding families; `RELEASING.md` REL-10..13.
- **Suggested shape:** Generate the Index + headline counts from the per-doc Rules boxes (`gen_rules_index.py` + a `rules.json` companion, `--check` CI staleness gate) — apply REL-13's own medicine to the index. Interim: manual refill of the 5 families + REL-10..13 + the headline, in one DOC-18 commit.
- **Fleet impact (why it was held OPEN):** expanding the audited set (218 → 258) re-baselines **every repo's §Z ledger** — a federation event requiring an explicit go-ahead, not a doc tweak. The go-ahead was given; executed in full this session.
- **Resolution:** SHIPPED (`mgf-standard` **0.1.50**, 2026-06-13) — the suggested shape, end to end, in four phases: (1) Index of MUSTs refilled **218→258** across 21 families; (2) `scripts/gen_rules_index.py --check` anti-drift gate + `rules.json` companion (REL-13's own medicine applied to the index) + `tests/unit/test_rules_index.py`; (3) **all 21 federation §Z ledgers re-baselined to 258** — forward-compatible, since `doctor --standards` reads the Index dynamically via `mgf.standard.read_standard`, so no fleet break until the release; (4) released `mgf-standard 0.1.50` — a fresh install ships `read_standard("README")` = 258 rows, so every doctor enforces 258 on pin-refresh; REL-13 GREEN + CURRENT. Runbook: `docs/archive/2026/PAPER-100-rollout.md`; seed helper `scripts/seed_ledger_rebaseline.py`. (Built on top, same court-intake spirit: **FB-05** + the `mgf-fed feedback` relay tool, closing the outbox-handling seam this review's filing implicitly exercised.)
- **Status:** SHIPPED

### PAPER-101 — README navigation text stale vs the docs it indexes (P-B)
- **Severity:** 🟡 Sharp edge
- **Filed by:** the Plasma project on 2026-06-11 (P-B)
- **What hurts:** The directory tree said OBSERVABILITY "OB-01..OB-08" (ships OB-01..**11**, incl. OB-10 the cross-language wire rule); the reading-order table said RELEASING "REL-01..REL-08" (ships REL-01..**13**). A DOC-18 propagation miss inside the doc that defines DOC-18.
- **Suggested shape:** correct the ranges now; permanently subsumed by PAPER-100's generation.
- **Resolution:** SHIPPED — `docs/standards/README.md` ranges corrected to `OB-01..OB-11` and `REL-01..REL-13`.
- **Status:** SHIPPED

### PAPER-102 — Cookiecutter overlay invites a non-existent conformance level (P-C)
- **Severity:** 🟡 Sharp edge
- **Filed by:** the Plasma project on 2026-06-11 (P-C)
- **What hurts:** `PROJECT_OVERLAY.md` said "Replace `<n>` with `0`, `1`, or `2`" but the ladder is L1/L2/L3 (CFM-02) — the first conformance declaration a scaffolded project makes was off-by-one (invites L0).
- **Suggested shape:** fix to `1`/`2`/`3`; (follow-up) a `doctor --standards` lint that declared level ∈ {L1,L2,L3}.
- **Resolution:** SHIPPED — template line corrected to `1`/`2`/`3`. The validating-lint is noted as a follow-up enhancement.
- **Status:** SHIPPED

### PAPER-103 — Paper-closure status vocabulary drifts between REL-09 and the FEEDBACK template (P-D)
- **Severity:** 🟢 Nice-to-have
- **Filed by:** the Plasma project on 2026-06-11 (P-D)
- **What hurts:** REL-09 said `SHIPPED / DEFERRED / ❌ REJECTED`; the canonical FEEDBACK template's set is `OPEN/SHIPPED/DEFERRED/WONTFIX/MOVED` — two sanctioned vocabularies for one lifecycle field.
- **Suggested shape:** the template's set is canonical (FB-01..04 own the lifecycle); reword REL-09 `REJECTED → WONTFIX`.
- **Resolution:** SHIPPED — REL-09 reworded to `SHIPPED / DEFERRED / WONTFIX`.
- **Status:** SHIPPED

### PAPER-104 — `evidence_level` term drifts between the principle and the recipe (P-E)
- **Severity:** 🟢 Nice-to-have
- **Filed by:** the Plasma project on 2026-06-11 (P-E)
- **What hurts:** `audit-outcomes` defines `VERIFIED_BY_EXECUTION`; `architecture-review` instructed `CONFIRMED_BY_EXECUTION` — synonym drift makes "show me everything execution-verified" a two-pattern query forever.
- **Suggested shape:** the principles doc owns the vocabulary; align the recipe to `VERIFIED_*`.
- **Resolution:** SHIPPED — `docs/recipes/architecture-review.md` aligned to `VERIFIED_BY_EXECUTION` (all occurrences).
- **Status:** SHIPPED

### PAPER-105 — Bundle agent briefing self-identifies as a different version than the bundle provenance (P-F)
- **Severity:** 🟢 Nice-to-have
- **Filed by:** the Plasma project on 2026-06-11 (P-F)
- **What hurts:** the shared `magogi-standard-bundle` said "captured from v0.1.48" while its embedded `AGENT_BRIEFING.md` said "you are here: mgf-standard 0.1.46" — OP-04 (headline-facts) applied to the export artifact.
- **Suggested shape:** the export regenerates + stamps both files from one source.
- **Resolution:** SHIPPED — the bundle briefing stamped to `0.1.48` to match the capture. **Durable fix recorded:** any future bundle export MUST stamp the briefing version from the same source as the capture provenance (one source of truth).
- **Status:** SHIPPED

### PAPER-106 — Raw NUL byte in TESTING.md flips the largest rules doc to "binary" (P-G)
- **Severity:** 🟡 Sharp edge (VERIFIED_BY_EXECUTION)
- **Filed by:** the Plasma project on 2026-06-11 (P-G)
- **What hurts:** `TESTING.md` held one literal NUL (offset 26561, line 355) inside a Hypothesis example meant to read `@example(value="\x00")` — the raw byte was embedded instead of the escape text. The file decoded as valid UTF-8 (hid from encoding checks) but `file(1)` reported `data` and GNU grep's binary heuristic suppressed matches — a daily DOC-12 (AI-navigability) cost on the doc holding TS-01..28.
- **Suggested shape:** replace the byte with the literal `\x00`; add a CI gate rejecting control bytes outside `\t\n\r` over `docs/standards/`.
- **Resolution:** SHIPPED — NUL replaced with the literal text `\x00` (example now renders as intended; `file(1)` → UTF-8 text). Prevention gate added: `tests/unit/test_no_control_bytes.py` scans the corpus for control bytes (catches the class in CI).
- **Status:** SHIPPED

---

### PAPER-107 — No shared-code / duplication discipline; a mature adopter independently built one
- **Severity:** 🟡 Sharp edge
- **Filed by:** Claude Code session (Magogi intake review of the Plasma "Commons" standard) on 2026-06-11
- **What hurts:** The corpus has SP (scope) + DP-08 (replaceability swap-recipes) but **no design-time discipline against code duplication / for shared-code admission**. There is no rule-of-three, no DUP-defect class, no junk-drawer-module-name ban, no blame-free-eviction stance, and no "duplication is cheaper than the wrong abstraction" counterweight. Verified: grep of `docs/standards/` finds **0** hits for duplication-as-defect, commons/shared-code, junk-drawer naming, rule-of-three, or eviction; NAMING.md has no `utils/misc/helpers` ban.
- **Why it matters:** "Silent divergence — two implementations of one rule drifting until they disagree" is a real consistency risk in a federation of ~22 libraries that **share** concepts (canonical encoders, ID schemes, time, hashing) through mgf-common. Without a design-time check, duplication accretes; with over-eager extraction, a god-library forms — both defects the corpus currently names neither. The Plasma project — a sophisticated adopter that took our principles trio nearly verbatim — independently authored a full "Shared Code Standard (the Commons)" to fill exactly this gap. An adopter reinventing a discipline is strong signal the gap is real.
- **Evidence:** reference design — `soothfast/ops/Plasma_Shared_Code_Standard_v0_2.md` (Commons Check §1, R1 rule-of-three §2, DUP defects §5, blame-free eviction §4, blast-radius tiers §3, failure modes §8). Our gap — `docs/standards/` grep = 0; DP-08 covers only swap-recipes (`DESIGN_PRINCIPLES.md:407`).
- **Suggested shape:** a short new discipline (a DP SHOULD-cluster or `docs/recipes/shared-code.md`) folding back the field-proven elements: (1) a design-time **Commons/DUP check** before adding a module ("does an existing module own this behavior?"); (2) a **rule-of-three** extraction trigger (two confirmed consumers OR a third occurrence — speculation doesn't count); (3) **duplication-as-defect** with cheap waivers (incidental dup needs none — judgment over bureaucracy); (4) a **junk-drawer-name ban** (no `utils/misc/helpers/common` — domain names only), likely a NAMING (NM) rule; (5) **blame-free eviction** as first-class (reversing a wrong abstraction is a success, not a failure); (6) the **"duplication is cheaper than the wrong abstraction"** counterweight stated up front so the discipline can't be weaponised into premature abstraction; (7) a **blast-radius tier** on shared code (output bytes that reach the wire/contract = a contract tier — ties to OB-10 + AP stability). Credit the Plasma Commons standard as the reference.
- **Resolution:** SHIPPED — authored as `docs/recipes/shared-code.md` (the full discipline, federation-adapted) + **NM-05** (junk-drawer-name SHOULD); indexed in `docs/recipes/README.md`; cross-referenced from NAMING. Kept recipe/SHOULD-level (not a new MUST) so it binds the fleet without reopening every §Z ledger (the PAPER-100 blast radius) — promotable to a MUST if/when the Index re-baseline lands. Fleet scan: no junk-drawer modules present (already compliant). Added to the cookiecutter for new projects.
- **Status:** SHIPPED

### PAPER-108 — Federation Zig CI template: pin not bound to the lock, no retry-wrap, no validator lane, no `verify_ci` checker
- **Severity:** 🟡 Sharp edge (two of the four are silent reliability/determinism hazards)
- **Filed by:** Claude Code session (sooth-family CI hardening sweep, relayed via sooth-standard) on 2026-06-30
- **What hurts:** Four gaps in the root Zig CI template + the CI tooling, each inherited by everything derived from it:
  1. **Pin not bound to the lock.** `templates/woodpecker/base-zig.yml` pins `ziglang==0.16.0` as a bare literal, not tied to a committed `toolchain.lock`. CI can build on a different compiler than the lock pins and nothing notices — a determinism break (the PRV-10 "pins bound to ground truth" idea, unenforced for CI).
  2. **No retry-wrap.** The `pip install ziglang` is not retry-wrapped, so a transient PyPI/network blip reds the pipeline. sooth hit this exact flake — a doc-only push reded while the *identical* step passed on the PR check.
  3. **No bundle-validator lane.** The gate runs build/test/fmt but never the repo's bundle validator (the "definition of done").
  4. **No `verify_ci` checker.** mgf-standard ships no `tools/verify_ci.py`; there is no machine check that a federation repo's `.woodpecker.yml` conforms (full-clone, secret-scan, triggers, the strict-YAML quoted-colon footgun, pin↔lock, validator-in-CI). Conformance is by eye.
- **Why it matters:** `base-zig.yml` is the root template the whole federation (~22 libs) and the sooth family derive from — every gap propagates fleet-wide. (1)+(2) are silent reliability/determinism hazards; (4) leaves CI conformance unenforced. Related federation hazard: `base-zig.yml` **and** soothai pin Zig **0.16.0**, but the sooth kernel (`soothfast`) and every path-dep sibling pin **0.15.1** — sharing Zig across that boundary is a determinism break, and soothai's own `toolchain.lock` already flags the split as needing reconciliation.
- **Evidence:** `mgf-standard/templates/woodpecker/base-zig.yml:30,37` (bare `ziglang==0.16.0`; no `--retries`/`--timeout`/`||`-retry); absent `mgf-standard/tools/verify_ci.py`. Field-proven reference (sooth, offered for promotion as-is): `sooth-standard/tools/verify_ci.py` (the checker incl. the new required pin↔lock check + the validator-in-CI advisory), `sooth-standard/templates/woodpecker/zig.yml` (retry-wrap + pin-from-lock + a `validate-bundle` lane), `sooth-standard/docs/recipes/ci-onboarding.md`, commit `8565641`.
- **Suggested shape:** fold the sooth hardening back into `base-zig.yml` + mgf CI tooling: (a) retry-wrap the toolchain fetch (`pip install --retries 8 --timeout 60 … || (sleep 10; retry)`); (b) require `ziglang==X.Y.Z` to equal a committed `toolchain.lock`, enforced by a `verify_ci`-style required check; (c) add an opt-in bundle-validator lane; (d) adopt `verify_ci.py` federation-wide (stdlib, no network → usable as a CI step itself); (e) declare a coherent federation Zig line (or a documented policy for the 0.16/0.15 split). Credit the sooth-standard CI work as the reference; `verify_ci.py` is offered for direct promotion.
- **Resolution:** SHIPPED — branch `feedback/ship-paper-108-113-114` (EXTEND per LOCK §2/§4-1: the status becomes true at the founder's enacting merge; the WF-13 fleet re-render wave follows it). Per gap: (a) retry-wrap had already landed pre-lock (`base-zig.yml` toolchain fetches). (b) pin↔lock: sooth `verify_ci` check-#10 **semantics folded into the template itself** — an inline coherence gate in `base-zig.yml`'s `zig-build-and-test` (reads the pin from the rendered pipeline, no duplicated literal; committed `toolchain.lock` + mismatch = red, no lock = noted-not-fatal — no mgf Zig repo ships a lock yet, so the gate arms per-repo as locks land). (c) validator lane ships as a commented opt-in block in `base-zig.yml` (no mgf Zig repo has a bundle validator today; enabling is a WF-13 template/generator event, never a hand-edit of a rendered pipeline). (d) `tools/verify_ci.py` adoption **deliberately deferred**: the Court-blessed disposition (LOCK §4-1) is an *EXTEND-class template change*, and both REQUIRED semantics the checker would add (#9 branch-filter — via PAPER-114 — and #10 pin↔lock) now execute in the pipeline itself; promoting the stdlib checker as an mgf tool + gate is a clean follow-up if wanted. (e) the 0.16/0.15 federation-Zig-line split stays a founder policy call — the inline gate makes any per-repo split explicit rather than silent. The push branch-filter (gap-1's sibling hazard) shipped under PAPER-114 in the same branch.
- **Status:** SHIPPED

### PAPER-109 — Base `clone` step flakes on auth ("could not read Username"); fleet pays a manual-re-trigger tax
- **Severity:** 🟡 Sharp edge
- **Filed by:** Claude Code session (sooth CI + federation sweep) on 2026-07-01
- **What hurts:** The base `clone` step intermittently fails with `fatal: could not read Username for 'https://codeberg.org': No such device or address` (exit 128) — the clone gets **no credentials** for the private repo, so every downstream step is skipped and the pipeline reds through no fault of the change. This is distinct from WF-09 (the treeless-partial-clone 504 that `partial: false` already fixes) — it is a clone-**auth/credential-injection** flake. The fleet's current mitigation is a **manual re-trigger**.
- **Why it matters:** it reds PRs spuriously, costs a human a manual re-trigger each time, and — worse — erodes trust in "red" (people learn to shrug off reds, so a real failure eventually slips through). It hits Python and Zig repos alike (it's the base clone, not the toolchain).
- **Evidence:** in one sweep, **5 sooth PRs** reded on the `clone` step (soothfast/soothweave/first-light/sooth-brand + a re-run of mgf-standard); e.g. soothfast pipeline #6 clone log: `git fetch … +be80406…: → fatal: could not read Username for 'https://codeberg.org': No such device or address; exit status 128`. **All cleared on a plain restart** (soothfast #7, soothweave #4, first-light #5, sooth-brand #4, mgf-standard #193 — all success), confirming it's transient. Correlated with a Woodpecker agent wedge/restart window (see PAPER-111). The fleet already re-triggers for this by hand — `mgf-fed` pipeline **#154** message: *"ci: re-trigger pipeline (clone step flaked)."*
- **Suggested shape:** (a) wrap the base clone in a **bounded retry** (the git-plugin supports retries, or a retry step) — the same discipline already blessed for the toolchain fetch; (b) OR auto-retrigger on a *clone-only* failure; (c) root-cause the credential gap (does the repo netrc drop on `pull_request` events or during an agent reconnect?); (d) at minimum, document in `run-ci.md` that a clone-only red is a known-transient, so it isn't re-investigated from scratch each time.
- **Investigation (2026-07-10 sweep):** (d) was already shipped (run-ci.md §"Known transient: a clone-only red", citing this paper). (a) is now **ruled out with evidence**: `woodpeckerci/plugin-git` retries by default (`attempts: 5` / `backoff: 5s`, per its docs.md) and our clone config inherits those defaults — so every observed flake already survived five in-step retries. That fits the failure shape: the netrc/credential injection is absent for the step's *whole lifetime*, so in-step retry re-fails identically; only a fresh pipeline start (fresh injection) clears it — exactly why plain restarts fix it. Recorded as comments on both templates' clone blocks so (a) isn't re-proposed. (b) auto-retrigger-on-clone-only-red relayed to mgf-fed (`pending-feedback/mgf-fed.md` — it already drives pipeline restarts). (c) root-cause correlates with the PAPER-111 agent-wedge window; tracked with that investigation.
- **Update 2026-07-11 — (b) ENACTED.** The auto-retrigger shipped in mgf-fed as the new **`mgf-fed ci-heal`** verb (merged): it restarts a pipeline whose **only** failed step is `clone`, **bounded to once** (skipped when any later pipeline exists for the same commit), polling Woodpecker only — never Codeberg (the PAPER-110 budget). Exercised live during the 2026-07 wave, where it would correctly have declined the *other* reds (docker-teardown / config-fetch flakes fail more than the clone step). (a) in-step retry stays **ruled out with evidence** (plugin-git already retries `attempts: 5`). (c) the credential root-cause is the only piece left — the netrc is absent for the step's whole lifetime, and it correlates with agent restart windows; the PAPER-111 net (now deployed + self-observing) is the instrumentation that should finally catch it in the act.
- **Update 2026-07-11 — the exit-126 SIBLING is ROOT-CAUSED (and it was self-inflicted).** The `exit 126` / `failed to set up container networking: network wp_… not found` / "Canceled with every step failed at once" family — long treated here and in PAPER-114 as forge/agent "contention" — was **our own self-heal cron killing healthy pipelines**. Its wedge test was `created >= 1 && running == 0` with **no age check**, which is exactly what a pipeline looks like *during startup*; when the `*/5` cron landed in that window it `docker rm -f`'d the containers that were about to run and restarted the agent. Caught red-handed on mgf-fed pipeline #255 (`WEDGE: 2 stuck Created, 0 running -> restarting agent` → all 14 steps failed, "Canceled"). Fixed in `mgf-cloud-provision` **PAPER-09** (only *stale* Created containers count; fire-tested both ways) — after which the same commit that had failed three times passed cleanly (#257 success). **This paper's own `could not read Username` credential-injection flake is a DIFFERENT failure and remains open** — but a large share of what the fleet has been calling "CI flakiness" now has a name.
- **ROOT CAUSE FOUND + FIXED 2026-07-11 (VERIFIED_BY_EXECUTION, both directions).** **The clone credential is a one-hour OAuth token.** Woodpecker derives the clone's netrc from the repo owner's **Forgejo OAuth access token** — read straight from the Woodpecker DB: `login=magogi-admin · token_present=true · refresh_present=true · expiry=2026-07-11 22:45 · expires_in_h=0`. It is short-lived and continuously refreshed. **A pipeline that starts inside the expiry/refresh window is handed a DEAD credential for the step's entire lifetime** → `fatal: could not read Username`, **exit 128**. Every symptom this paper recorded now follows exactly: *why no in-step retry helped* (the netrc is bad for the whole step — plugin-git's own `attempts: 5` cannot fix a rotten credential), *why a plain restart "cured" it* (the token had refreshed by then), and *why it hit every repo equally* (they share one user token).
  **And the chain closes on us.** Woodpecker refreshes that token **by calling Codeberg** — and **Codeberg rate-limits us (PAPER-110)**. Fleet automation at speed plausibly starved the refresh, which is precisely why the flake **clustered during sweeps** (this paper's own evidence: *5 sooth PRs reded in one sweep*). **PAPER-109 and PAPER-110 are one causal chain, not two neighbours** — our own API hammering was breaking our own clones.
  **PROVEN, both directions, on `mgf-brand` (a real repo, real pipelines):** ① `CI_NETRC_PASSWORD` set to a **deliberately wrong** value → clone **fails, exit 128** — *the flake's exact signature, reproduced on demand* (pipeline **#10**, 0/6 steps ran); ② the same clone with the credential **pinned to the long-lived `codeberg_clone_token`** org secret → clone **succeeds, whole pipeline green** (pipeline **#11**, 6/6). ① also proves an explicit `CI_NETRC_*` env **overrides** Woodpecker's injected credential — which is what makes the fix possible at all.
  **FIX (this branch):** both canonical templates (`base.yml`, `base-zig.yml`) pin the clone credential to `codeberg_clone_token` (a long-lived org secret, already present and scoped to `push`/`pull_request`/`tag`). The clone no longer depends on an expiring OAuth token. Rolls out to the fleet on the next WF-13 re-render wave; the stale *"restart it, it's a known transient"* comment is deleted from both templates — **it is no longer a transient, it is fixed.**
- **CORRECTION then RESOLUTION (2026-07-12).** The first fix — an `environment: CI_NETRC_*` pin — was **wrong**, and "proven both ways on mgf-brand #10/#11" was a lucky sample of two. At fleet scale it flaked (mgf-alembic clone red #97, green on restart #98, identical config) and it is **schema-invalid for the clone section** (Woodpecker: "should not configure both environment and settings"), so `partial: false` could be dropped and re-expose the WF-09 504 — i.e. it may only have TRADED the OAuth flake for a partial-clone flake. The DIAGNOSIS (expiring ~1 h Forgejo OAuth token, starved by our own PAPER-110 rate pressure) was correct; the fix was not.
  **RESOLVED — clone over SSH with a READ-ONLY deploy key.** `use-ssh: true` + `ssh-key-private`/`ssh-host-key` (Woodpecker org secrets), passed via `settings` — schema-clean, and it removes the expiring OAuth token from the loop **entirely** (a static key that never expires). Setup: a dedicated ed25519 CI key (separate from the operator key), its public half added as a **read-only deploy key on all 48 pipeline repos** (Codeberg allows one deploy key across repos — verified). **PROVEN DETERMINISTIC this time:** on mgf-alembic the clone succeeded across repeated runs (pipelines 100/101/102); the one pipeline red was an unrelated `sbom` docker-network flake, not the clone. Both templates carry the SSH block; fleet inherits it on the re-render wave. **Least-privilege bonus:** the clone credential is now clone-ONLY (cannot push), unlike the OAuth token it replaced — a small #6 win.
  **Lesson kept:** a fix proven on a sample of two is not proven; verify at the scale you will deploy, and isolate the flake (the SSH clone's determinism was only visible once I separated the clone failure from the unrelated docker-network failure).
- **Status:** SHIPPED (SSH clone, deterministic; supersedes the fragile env pin)

### PAPER-110 — Automated fleet orchestration exhausts Codeberg's API rate limit (429), then can't merge for ~an hour
- **Severity:** 🟡 Sharp edge
- **Filed by:** Claude Code session on 2026-07-01
- **What hurts:** Driving the fleet through the **Codeberg REST API** at automation speed — polling commit-status, opening PRs, restarting pipelines, merging — exhausts Codeberg's shared fair-use quota and returns **HTTP 429 Too Many Requests**. The 429 then **blocks merges** (`POST /pulls/{i}/merge` 429s) for what looks like an hourly window, so an agent can wedge itself out of the very merges it was driving. `activate-ci.md` warns rollout is "paced," but there's no concrete **API-budget** guidance, so an agent naturally polls aggressively and trips it. `mgf-fed` (which orchestrates exactly this) is the prime exposure.
- **Why it matters:** it turns a finished, all-green batch into a "can't land for an hour" stall, and retries compound the window. It silently caps how fast the federation can move PRs/releases, and it's invisible until you hit the wall.
- **Evidence:** after opening 9 PRs + polling 8 commit-statuses every ~20s + restarting 5 pipelines, **every** merge `POST` returned `429` even when spaced 25s apart; `GET /pulls/{i}` returned the 429 HTML page. Recovered only by **stopping all Codeberg calls**. (Contrast: Woodpecker — self-hosted — was never rate-limited, so status polling should go there.)
- **Suggested shape:** bake a **Codeberg API rate-budget** into the recipe + `mgf-fed`: (a) poll **Woodpecker** (self-hosted, unmetered) for pipeline status in loops, **never** Codeberg commit-status; (b) cap Codeberg API calls (e.g. ≤N/min) with **exponential backoff on 429**; (c) space PR opens/merges generously and batch them; (d) prefer **SSH git** (unmetered) over the HTTP API where possible (push, not `tea` where avoidable); (e) document the observed limit (hourly bucket) in `activate-ci.md` beside the existing "fair-use" note.
- **Resolution:** SHIPPED (recipe surface) — found already landed on the 2026-07-10 sweep: `e707df4` (2026-07-01, "CI-reliability notes from the sooth sweep") added the full **"Codeberg API rate-budget — avoiding the 429 wall"** section to `activate-ci.md` covering all five suggested items — (a) as §4's poll-via-Woodpecker-never-Codeberg instruction (citing this paper), (b) cap + exponential backoff on 429, (c) space + batch (plus the distinct-PR-title limiter dodge), (d) prefer SSH git, (e) the observed hourly-window evidence inline. The paper was never flipped. The remaining half of the ask — the budget baked into **mgf-fed's own Codeberg client** (code-level cap/backoff, not guidance) — is relayed via `pending-feedback/mgf-fed.md`.
- **Status:** SHIPPED (recipe; mgf-fed client-side budget relayed to its queue)

### PAPER-111 — The `*/5` agent self-heal cron did not clear a 15-min wedge (silent-failing safety net)
- **Severity:** 🟡 Sharp edge
- **Filed by:** Claude Code session on 2026-07-01
- **What hurts:** `MGF_INFRA.md §2` documents that a `*/5` self-heal cron restarts a wedged Woodpecker agent (`worker_count=0`). But an observed wedge **persisted 15+ minutes** — the whole fleet's CI stalled (queue `worker_count:0, pending:13, running:4`) — and cleared only after a **manual** `sudo docker compose restart woodpecker-agent`. So the documented auto-recovery either isn't running, doesn't detect this wedge shape (workers=0 with a backlog, vs container-down), or restarts-but-re-wedges.
- **Why it matters:** the self-heal cron is the safety net for the single most critical shared resource — the CI runner. If it silently doesn't fire, one wedge takes the **entire fleet's CI** down until a human notices and SSHes in. It also defeats the AG-20 promise (owned infra self-recovers) precisely where that promise is automated.
- **Evidence:** queue `{worker_count:0, pending_count:13, running_count:4}` sustained 15+ min (all 9 pipelines stuck `pending`); the manual `docker compose restart woodpecker-agent` (MGF_INFRA §2) immediately drained it (pending 13→6→0, worker_count→4, two agents cap 2 each). No sign the `*/5` cron acted in that window.
- **Suggested shape:** verify the self-heal cron exists and runs (inspect its crontab + logs); make its trigger the **wedge condition** (`worker_count==0 && pending>0`), not just container-down; and **emit a signal** (OpenObserve record / push) whenever it fires *or* when a wedge persists > N minutes — a silent-failing self-heal must itself be observable. Consider a compose `healthcheck` that restarts the agent on failed heartbeat.
- **Investigation (2026-07-10, on-host, VERIFIED_BY_EXECUTION) — root cause found; net restored:** there are **two** self-heal crons on woodpecker-prod covering different wedge shapes: `*/5 self-heal.sh` (docker-debris: `Created`-stuck && `running==0` — healthy, 13 historical recoveries, and **correctly** didn't fire on this paper's wedge, which had `running:4`) and `*/3 agent-reconciler.py` (agent DOWN, or **schedulable+idle while work pends** — exactly this paper's shape, with a 2-hit guard + force-recreate recovery, agent2 included). The reconciler had recovered such wedges on 2026-06-21/22 — then went **silently dead on 2026-06-23**: its static `/opt/woodpecker/reconciler.token` JWT began 401ing (Woodpecker JWTs are HS256-keyed on the user's DB `hash`; a hash rotation kills static mints), and every run since logged `api error` (~1,950 lines) with **nothing paging** — the paper's "silent-failing safety net," confirmed with a mechanism. **That is why the 2026-07-01 wedge outlived the net.** Repair applied 2026-07-10 (AG-20 self-owned path): fresh JWT minted on-host via the `woodpecker_api.sh` mint (old token kept as `.bak-2026-07-10`), validated `queue/info` 200, subsequent cron ticks clean. The estate watcher (agent2) is separately **live** (uptime probes + Codeberg-issue pager, heartbeating same-day) but does **not** yet probe the wedge condition. MGF_INFRA §2/§5 rewritten to the verified state.
- **CLOSED 2026-07-11 — both durable pieces SHIPPED + DEPLOYED (founder-authorized), VERIFIED_BY_EXECUTION.** (1) `agent-reconciler.py` now **mints its JWT per-run from the Woodpecker Postgres** — no static token left to rot; unattended cron runs log `ok token=db-mint pending=…` and there are **zero api-errors** since (vs 1,951 lifetime, all from the 06-23→07-10 outage). (2) The **signal exists at last**: the reconciler + both hosts' `self-heal.sh` POST success-only heartbeats to the OO `backup_heartbeats` stream, and the agent2 `*/10` watcher runs a freshness check that **pages via its deduped Codeberg issue** when one goes stale (>30 min) — proven both ways at deploy (never-heartbeating job → exit 1 → pages; healthy set → exit 0 → silent). The blocker turned out to be that **the heartbeat credential never existed** (`/etc/mgf/backup-heartbeat.{url,token}` absent on every host — §5's mechanism was documented but never wired); a **least-privilege OO service account** was minted for it. **The self-heal net is now self-observing:** if it dies again, it pages within ~30 min instead of rotting for 17 days. Code + deploy record: `mgf-cloud-provision` PAPER-01/02; infra truth: `MGF_INFRA.md` §2/§5. Residual (tracked, NOT part of this paper): the nightly **backups** still do not heartbeat → `mgf-cloud-provision` **PAPER-03** (🔴).
- **Status:** SHIPPED (deployed + verified 2026-07-11)

### PAPER-112 — Standards corpus still describes Codeberg-PyPI publishing after the devpi cutover
- **Severity:** 🟢 Nice-to-have (documentation-vs-running-system coherence; the cutover itself is intentional)
- **Filed by:** Claude Code session (federation CI/remote review) on 2026-07-01
- **What hurts:** The fleet is mid-cutover from the Codeberg PyPI registry to the self-hosted **devpi** index, and the two sources of truth disagree on the load-bearing "where do releases go?" question. The **running system** publishes to devpi: the generated `templates/woodpecker/base.yml` publish step targets `195.15.203.250/magogi/prod/` with `TWINE_USERNAME: magogi` / `TWINE_PASSWORD: {from_secret: devpi_password}`; `templates/policy.toml` lists `verify-devpi` as a required step; `frag-no-pypi-surface.yml` (PKG-12) guards against `pypi.org`; `MGF_INFRA.md` names devpi as "the private PyPI the fleet publishes to + resolves from." But large parts of the **standards corpus** still describe the Codeberg path: `docs/standards/WORKFLOWS.md` (WF-03/04/08 — `codeberg_package_token`), `PACKAGE_DISTRIBUTION.md` (PKG-*), `docs/standards/AGENTS.md` (AG-09), and `docs/recipes/cohort-release-wave.md`.
- **Why it matters:** an agent (or human) reasoning about the *current* publish flow from the corpus reaches the **wrong** (Codeberg) answer — exactly the silent running-system-vs-written-standard divergence the federation guards against (it's the sibling of PAPER-05's "stale-as-current"). It's low-severity because the cutover is deliberate and the generated CI is already correct — but the corpus is what agents read.
- **Evidence:** running truth — `templates/woodpecker/base.yml` (publish → devpi), `templates/policy.toml` (`verify-devpi` required), `frag-no-pypi-surface.yml` (PKG-12), `MGF_INFRA.md §1/§2` (devpi + `devpi_password`). Lagging corpus — `WORKFLOWS.md` WF-03/04/08, `PACKAGE_DISTRIBUTION.md` PKG-*, `AGENTS.md` AG-09, `docs/recipes/cohort-release-wave.md`. Cross-checked in `docs/memory/release-and-registry.md` (which already flags devpi as current).
- **Suggested shape:** a reconciliation sweep of those docs to the devpi truth (retarget WF-03/04/08 + PKG-* + AG-09 + `cohort-release-wave.md`, swap `codeberg_package_token` → `devpi_password`). Until that lands, a one-line banner at the top of each lagging doc — *"CUTOVER IN PROGRESS (Phase-2 B2): devpi is the current publish target; Codeberg-PyPI references below are pre-cutover"* — so a reader knows which source is authoritative.
- **Status:** SHIPPED — (1) the interim banner shipped in PR #179 (2026-07-01); (2) the full reconciliation sweep (`feedback/devpi-retarget`) **merged to main**, verified 2026-07-10: the whole publish corpus (`PACKAGE_DISTRIBUTION.md` PKG-01..12, `WORKFLOWS.md` WF-03/04/06/08, `RELEASING.md` REL-04/05/06, `WORKFLOWS_PATTERNS.md` §4, `AGENTS.md` AG-09/AG-16/AG-18, `NAMING.md`, `COMMON_COMPONENTS.md`, the README *Index of MUSTs*, the recipes + conformance ledger) is retargeted to the devpi model and every interim banner is gone (the sole remaining "CUTOVER IN PROGRESS" string in the repo is this paper's own quoted text; the only `codeberg_package_token` references left sit inside PACKAGE_DISTRIBUTION.md's collapsed *Historical record* block — intentional history). Open tails — **all closed 2026-07-10 (founder-delegated Court calls):** the three host-ops confirmations decided + recorded inline (PACKAGE_DISTRIBUTION.md §4/§6/§8 + MGF_INFRA §2: single identity stands, accepted risk, revisit at the public flip · no stage-pin mandate, single-trusted-index + private prefix is the posture · strictly append-only, version-bump recovery, remove = emergency-only behind a founder decision package), and `scripts/verify_codeberg.py` **removed** (script + template + both policy.toml entries + pyproject carve-out + SCOPE.md currency; superseded by the inline `verify-devpi` step; fleet copies deleted in the WF-13 wave).

### PAPER-113 — Generated Woodpecker templates inline the devpi index endpoint (3× in `base.yml` + 3 fragments) instead of one generated `DEVPI_URL`/anchor — an IP move is a fleet-wide committed-pipeline edit
- **Severity:** 🟡 Sharp edge
- **Filed by:** sooth family — cross-family reuse review on 2026-07-01
- **What hurts:** `templates/woodpecker/base.yml` is a **generated** artifact (header lines 1–3: "GENERATED — do not hand-edit … rendered by `mgf-fed` (mgf.fed._woodpecker) … never patch this file in place"; WF-13), yet it inlines the full devpi endpoint `https://195.15.203.250.sslip.io/magogi/prod/` as a bare literal in **3** separate steps — `--index-url` (`:120`), `--repository-url` (`:239`), and a `url=` string (`:254`). The same host is inlined again in three fragments (`frag-cornerstone-ping.yml`, `frag-fedres-check.yml`, `frag-mgf-common-matrix.yml`) and the cookiecutter, and **nothing** references a single `DEVPI_URL` env / YAML anchor (a `grep` for one finds none). Because the generator renders this text into **every** consumer repo's committed `.woodpecker.yml`, the endpoint is copied fleet-wide. `195.15.203.250.sslip.io` is *not* a stable indirection — sslip.io wildcard-DNS encodes the IP in the hostname (`<ip>.sslip.io` → that IP), so the "hostname" moves with the IP.
- **Why it matters:** A generated file is exactly where an endpoint should be emitted **once** and referenced. Today a devpi host-IP change — which `MGF_INFRA.md §4` explicitly names as a maintenance trigger ("Update when … a host IP changes") — is not a one-line generator edit; it is an N-repos × 3-sites rewrite of committed pipelines, plus the three fragments and the cookiecutter, with every repo then regenerating + re-committing. `MGF_INFRA.md:31` is the declared single source of truth for that endpoint (URL + raw IP), but the generated CI doesn't honor it — it copies the literal. This is the same source-of-truth-vs-N-copies drift shape as PAPER-112, one layer down.
- **Evidence:** `templates/woodpecker/base.yml:120` (`--index-url`), `:239` (`--repository-url`), `:254` (`url=`) — `grep -c '195\.15\.203\.250' base.yml` = **3**. Same host inlined at `frag-cornerstone-ping.yml:21`, `frag-fedres-check.yml:12` (×2, retry), `frag-mgf-common-matrix.yml:21` (×2, retry), + `templates/cookiecutter-mgf-project/.../{pyproject.toml,README.md}`; **0** uses of a `DEVPI_URL`/`INDEX_URL` env or YAML anchor. Generated-artifact provenance: `base.yml:1–3`; WF-13 at `MGF_INFRA.md:72` + `docs/recipes/run-ci.md:18,25`. Endpoint as single-source-of-truth + IP-can-move: `MGF_INFRA.md:31` (endpoint = URL + raw IP `195.15.203.250`), `MGF_INFRA.md:67` ("a host IP changes"). *(Note: mgf-standard has no verbatim "never hardcode an IP" rule; this paper rests on the MGF_INFRA single-source-of-truth + the maintenance-trigger, not an asserted rule.)*
- **Suggested shape:** Have `mgf.fed._woodpecker` emit the index endpoint **once** — a top-of-pipeline `DEVPI_URL` env (or a YAML anchor) sourced from a single generator constant that itself derives from `MGF_INFRA.md`/`policy.toml` — and reference `$DEVPI_URL` at the three call sites (and the fragments/cookiecutter). Then a host move is one generator-constant change + a regenerate wave, not a hand-search across every committed pipeline. Pairs naturally with PAPER-112's reconciliation sweep (one endpoint, one authority).
- **Resolution:** SHIPPED — branch `feedback/ship-paper-108-113-114` (EXTEND; true at the founder's enacting merge; fleet re-render wave follows, WF-13). Landed **stronger than the ask's env-emission**: the endpoint is not emitted per-pipeline at all — every template/fragment site references `$DEVPI_URL`, a Woodpecker **server-level** variable (`WOODPECKER_ENVIRONMENT` on the CI host, live since 2026-07-04; value = the `MGF_INFRA.md §1` endpoint `…/magogi/prod/+simple/`; name coordinated with sooth-standard, whose conversion is already live-green), each consuming step led by a fail-fast guard line. Converted sites: `base.yml` ×3 (`app-doctor --index-url "$DEVPI_URL"`; publish `--repository-url "${DEVPI_URL%%+simple*}"`; verify-devpi `url = '${DEVPI_URL%/}/…'`), `frag-cornerstone.yml` ×2, `frag-fedres-check.yml` ×2, `frag-mgf-common-matrix.yml` ×2, `frag-cornerstone-ping.yml` ×1 — `grep -c '195\.15\.203\.250' templates/woodpecker/` = **0**. `MGF_INFRA.md §2` documents the variable + the host-move procedure. **Consciously left for companions:** the *generator-side* installs (mgf-fed's `_DEVPI_INDEX` constant behind `{{EXTRAS_INSTALL_CMD}}`/`{{SMOKE_INSTALL}}` etc.) still inline the literal — that is `mgf.fed._woodpecker` code, a cross-repo companion change per the paper's own suggested shape; and the cookiecutter `pyproject.toml`/`README.md`, which are committed files a shell variable cannot reach (their endpoint follows PKG-*/PAPER-112 docs truth). A host move is now: server variable + `MGF_INFRA §1` row + mgf-fed constant + re-render wave.
- **Status:** SHIPPED

### PAPER-114 — `base-zig.yml` missing two sooth-proven fixes: `push` not branch-filtered (exit-126 PR/push contention) + no CI-pin↔`toolchain.lock` coherence check
- **Severity:** 🟡 Sharp edge
- **Filed by:** sooth family — cross-family reuse review on 2026-07-01
- **What hurts:** The root Zig CI template `templates/woodpecker/base-zig.yml` — which every mgf Zig repo derives from — is missing two fixes the sooth family already proved out and now ships:
  1. **`push` is not branch-filtered.** The `when:` block triggers on `push` *and* `pull_request` with no `branch:` filter on `push` (`base-zig.yml:10–13`), so on a feature-branch PR both pipelines run **concurrently on the same commit**. The redundant push run contends with the PR run over the shared workspace / container exec; sooth hit exactly this as an intermittent **exit 126**. (The Python `base.yml` shares the unfiltered shape, but the Zig template's `zig build` / container-exec steps are where the contention actually bit.)
  2. **No CI-pin↔lock coherence check.** `base-zig.yml:33,47` pin a bare `ziglang==0.16.0` with no coupling to a committed `toolchain.lock`, and mgf-standard ships no `tools/verify_ci.py` — so nothing verifies the pipeline's compiler equals the repo's pinned toolchain. CI can silently build on a different compiler than the lock pins (a determinism break).
- **Why it matters:** `base-zig.yml` is the shared root for mgf's own Zig libraries (e.g. mgf-hrb); both gaps propagate to each. (1) reds PRs spuriously and trains people to shrug off "red" (the sibling failure mode named in PAPER-109). (2) is a silent determinism hazard — the "pin bound to ground truth" idea, unenforced for CI. Both are field-proven fixes the sooth family is offering back.
- **Evidence:** Gap 1 — `base-zig.yml:11` (`- event: push`, no following `branch:`). Sooth fix: `sooth-standard/templates/woodpecker/zig.yml:14` (`branch: main` under `- event: push`), rationale `zig.yml:7–10` + `sooth-standard/docs/recipes/ci-onboarding.md:69–72` ("runs concurrently with the PR pipeline on the *same commit* … the contention can kill a step (a container exec / exit 126)"); enforced by `sooth-standard/tools/verify_ci.py:104–110` (check #9). Gap 2 — `base-zig.yml:33,47` (bare `ziglang==0.16.0`, no lock). Sooth fix: `verify_ci.py:112–125` (check #10), fail branch `:121–123` — `fail("CI ziglang==%s != toolchain.lock %s (%s) -- the CI pin must match the lock (VAL-08)" …)`; the lock is real + populated (`soothfast`/`soothtroth`/`soothweave` `toolchain.lock` pin `"version": "0.15.1"`). **Overlaps PAPER-108** (OPEN): gap 2 restates PAPER-108's gap-1 (pin not bound to lock) + gap-4 (no `verify_ci`) with the now-shipping sooth check; gap 1 (branch filter) is net-new. (PAPER-108's gap-2 retry-wrap has since landed at `base-zig.yml:33,47`.)
- **Suggested shape:** Fold both into `base-zig.yml` + mgf CI tooling: (a) add `branch: <default>` under the `push` event in the Zig template's `when:` block (and the Python `base.yml`); (b) bind the `ziglang==X.Y.Z` pin to a committed `toolchain.lock` and enforce equality via a `verify_ci`-style required check — adopt `sooth-standard/tools/verify_ci.py` (stdlib-only, no network, runnable as a CI step; it already ships both check #9 and check #10). Best merged with PAPER-108's disposition, since they cover the same Zig-template + CI-tooling surface. Credit the sooth-standard CI work as the reference.
- **Resolution:** SHIPPED — branch `feedback/ship-paper-108-113-114`, merged with PAPER-108's disposition as the paper suggested (EXTEND; true at the founder's enacting merge; fleet re-render wave follows, WF-13). Gap 1: `branch: main` now filters the `push` event in **both** `templates/woodpecker/base-zig.yml` and the Python `base.yml` `when:` blocks, with the sooth rationale comment (exit-126 same-commit contention; lineage `sooth-standard/templates/woodpecker/zig.yml:14` + `ci-onboarding.md:69-72`) — tag/cron/manual events untouched, and every fleet repo's default branch is `main` (verified; a different default becomes a generator param, not a hand-edit). Gap 2: the CI-pin↔`toolchain.lock` coherence check runs **inline in `base-zig.yml`** (check-#10 semantics: mismatch = red, no committed lock = noted; the pin is read from the rendered pipeline so no literal is duplicated). `verify_ci.py` itself deferred with reasons under PAPER-108's resolution. Credit: the sooth-standard CI hardening is the reference for both fixes.
- **Status:** SHIPPED

### PAPER-115 — Canonical CI lint step enforces `ruff check` but not `ruff format --check` — format drifts fleet-wide, unseen until a release
- **Severity:** 🟡 Sharp edge
- **Filed by:** mgf-fed supervisor (cockpit) on 2026-07-03
- **What hurts:** The canonical CI lint step runs `ruff check src tests` (the linter) but **never** `ruff format --check`. So formatting can drift into committed files with CI staying green. The only gate that catches it is the *local* release gate (`mgf-fed release-local`, whose `_drift` runs `ruff format --check`) — so drift surfaces only at release time, per-repo, on whatever ruff version the maintainer happens to have.
- **Why it matters:** On the mgf-fed 0.11.1 release, 3 test files carried accumulated ruff-format drift that CI had passed for weeks; the release **blocked**, needing a separate unblocker PR (mgf-fed #69). This is fleet-wide — every repo's format is ungated in CI — and it couples releasability to the maintainer's local ruff (pin is a wide `>=0.4,<0.16`).
- **Evidence:** `templates/woodpecker/base.yml:39` (`- ruff check src tests`; no `ruff format --check` in `base.yml` or any `frag-*.yml`). The gate that *does* catch it: mgf-fed `_drift` ("ruff format-stability pin"). Repro: mgf-fed PR #69 `chore(format): ruff-format 3 drifted test files` — `tests/test_closed_box.py`, `tests/fleet/refresh_lock.py`, `tests/fleet/test_fleet_coinstall.py` all drifted while CI was green.
- **Suggested shape:** Add `- ruff format --check src tests` to the lint step in `base.yml` (right after `ruff check`). Roll out as a cohort (like AP-16) — a fleet re-scaffold will surface existing format drift, each repo format-cleans or is already clean. Consider pinning ruff to an **exact** fleet version (not a range) so the format baseline is deterministic across machines + CI.
- **Resolution:** SHIPPED — branch `feedback/sweep-2026-07-10` (gate strengthening per LOCK §2: the status becomes true at the founder's enacting merge; the WF-13 fleet re-render wave follows and will surface any latent drift per-repo — the paper's own cohort rollout). `- ruff format --check src tests` now sits directly after `ruff check` in `base.yml`'s lint step, with the mgf-fed #69 rationale inline. The **exact-ruff-pin** question is consciously NOT taken here: `policy.toml`'s `ruff_spec = "ruff>=0.4,<0.16"` ceiling already freezes the format baseline at the fleet's 0.15.x line (its comment documents exactly this intent), so the residual exposure is a *within-0.15.x* format change — real but small; tightening to an exact pin is a fleet-wide pyproject wave and stays a founder policy call. **Pin decision taken 2026-07-10 (founder-delegated):** keep the window — with the CI format gate in place, the release-time-ambush class (the paper's actual harm) is closed at PR time; an exact pin would add a fleet-wide bump chore per ruff release for marginal residual gain. Revisit only if a within-0.15.x format change actually bites.
- **Status:** SHIPPED

### PAPER-116 — Canonical gitleaks template has no `.claude/` allowlist; repos with agent config carry a justified carve-out that reads as scaffolding drift
- **Severity:** 🟢 Nice-to-have
- **Filed by:** mgf-fed supervisor (cockpit) on 2026-07-03
- **What hurts:** `templates/gitleaks.toml` has no allowlist entry for `.claude/`. Repos that keep Claude Code agent config (`.claude/` — permission allowlists / settings embedding credential-**shaped** command patterns with placeholder tokens, e.g. `Authorization: token __TRACKED_VAR__`) must add a `'''\.claude/'''` allowlist path or gitleaks' curl-auth-header rule re-flags the placeholders. mgf-common **and** mgf-standard both carry this justified entry — and `mgf-fed drift-check` reports it as `[exact] .gitleaks.toml differs from template/gitleaks.toml`.
- **Why it matters:** Two of the fleet's most central repos show as "drift" for a correct, security-neutral carve-out — noise that trains maintainers to ignore drift-check, with no clean resolution (removing the entry re-introduces false-positive leak flags; the file can't match the template without losing the protection).
- **Evidence:** `mgf-common/.gitleaks.toml` + `mgf-standard/.gitleaks.toml` each add `'''\.claude/'''` under `[allowlist].paths` (absent from `templates/gitleaks.toml`, ~line 45). `mgf-fed drift-check` → `✗ mgf-common (2)` / `✗ mgf-standard (1)`, item `[exact] .gitleaks.toml differs from template/gitleaks.toml`.
- **Suggested shape:** Add `'''\.claude/'''` (with the placeholder-token rationale comment) to the canonical `templates/gitleaks.toml` allowlist — `.claude/` is now a fleet-standard directory, so every repo should allowlist it; roll out via the SH-05 gitleaks scaffold path. (Companion filed against mgf-fed: make drift-check's `.gitleaks.toml` `[exact]` rule tolerant of *additive* per-repo allowlist entries.)
- **Resolution:** SHIPPED — landed 2026-07-04 in `921f302` ("template gains .claude/ allowlist", the Wave-2 F-M11/F-M12 fleet sweep) as the paper's suggested shape, rationale comment included; the paper was simply never flipped (found on the 2026-07-10 feedback sweep). Verified 2026-07-10: `templates/gitleaks.toml` carries the entry, and both `mgf-standard/.gitleaks.toml` and `mgf-common/.gitleaks.toml` are **byte-identical** to the template — the `[exact]` drift noise is gone. The mgf-fed additive-tolerance companion is thereby **moot for this instance** (no additive entries remain to tolerate); whether drift-check should tolerate additive allowlist entries *in general* is mgf-fed PAPER-03's standing template-vs-subset question (also LOCK §4-2, via mgf-fastapi's extra entry).
- **Status:** SHIPPED

### PAPER-117 — AG-03 `core.hooksPath .githooks` is incompatible with the pre-commit framework (a repo can't run both)

- **Severity:** 🟡 High
- **Filed by:** figrecovery on 2026-07-09
- **What hurts:** `docs/recipes/standardized-git-config.md` §4 instructs `git config core.hooksPath .githooks` to activate the AG-03 `prepare-commit-msg` trailer hook. A repo that uses the **pre-commit framework** (figrecovery does — the four-gate + gitleaks + codename + test-mirror hooks) cannot also set `core.hooksPath`: `pre-commit install` hard-errors *"Cowardly refusing to install hooks with `core.hooksPath` set."* So a project cannot have BOTH the AG-03 hook (via `core.hooksPath`) AND its pre-commit gate — the recipe's activation step and the pre-commit framework are mutually exclusive.
- **Why it matters:** The conflict is **silent** — `mgf-fed app-doctor` passes without `core.hooksPath` set, so nothing flags that the AG-03 hook never fired. A repo can believe its trailer hook is active when it is not, and the recipe offers no guidance for the (very common) pre-commit-framework case.
- **Evidence:** `pre-commit install` refuses when `core.hooksPath` is set (upstream pre-commit behaviour). figrecovery hit this during the 2026-07-09 federation re-sync: it runs the pre-commit framework, so it could not follow §4's `core.hooksPath .githooks` step. Resolution taken: wire the trailer check (`scripts/check_commit_trailers.py`) as a `commit-trailers` pre-commit/pre-push hook-type in `.pre-commit-config.yaml` + author both AG-03 trailers manually; `app-doctor` accepts this.
- **Suggested shape:** Have `standardized-git-config.md` cover the pre-commit-framework path explicitly — wire `prepare-commit-msg` (and the trailer gate) as pre-commit `hook-types` (`pre-commit install --hook-type prepare-commit-msg`) instead of via `core.hooksPath`, OR document the `commit-trailers` pre-push-hook alternative figrecovery used. Consider having `app-doctor` warn when AG-03 is claimed but neither `core.hooksPath` nor a `prepare-commit-msg` pre-commit hook is active.
- **Resolution:** SHIPPED (this branch, 2026-07-10) — the conflict re-verified by execution (pre-commit 4.6.0 refuses install, both plain and `--hook-type`, with `core.hooksPath` set; exact "Cowardly refusing" error). Fix landed as the paper's first suggested shape: (1) `standardized-git-config.md` §4 split into **§4a** (`core.hooksPath`, no-framework repos) / **§4b** (pre-commit repos: the same committed `.githooks/prepare-commit-msg` script as a `repo: local` `stages: [prepare-commit-msg]` hook + `pre-commit install --hook-type prepare-commit-msg`) with the one-liner + Verify sections split to match — §4b **verified end-to-end** (install clean; `git commit -m` gains `Signed-off-by`; merge/squash still skipped). (2) The hook script now falls back to `PRE_COMMIT_COMMIT_MSG_SOURCE` (pre-commit exports it in place of `$2`; pre_commit/commands/run.py:378) so merge-skip parity holds under both wirings. (3) AG-18(c) + its enforcement-table row + the AGENTS.md §4 prose amended to name both wirings and their mutual exclusivity (CLARIFY-class — the MUST's substance, hook-present + authoritative CI gate, is unchanged). (4) CONTRIBUTING.md carries the caveat. (5) The recipe's stale "authoritative gate is tracked in mgf-common PAPER-102" note replaced — the gate ships today as `templates/woodpecker/frag-commit-trailers.yml` per AG-18(c). The `app-doctor` hook-*active* advisory (present-but-inert detection) is relayed to mgf-fed via `pending-feedback/mgf-fed.md`.
- **Status:** SHIPPED

### PAPER-120 — Bespoke-pipeline repos (`[exempt].woodpecker`) silently miss every template gate-strengthening

- **Severity:** 🟡 Sharp edge (VERIFIED_BY_EXECUTION — three repos found ungated *and* drifted, including this one)
- **Filed by:** mgf-standard (WF-13 re-render wave, PAPER-115 rollout) on 2026-07-10
- **What hurts:** four repos carry a hand-maintained `.woodpecker.yml` (`templates/policy.toml [exempt].woodpecker` = `mgf-hrb`, `mgf-test-supervisor`, `mgf-website-template`, **`mgf-standard`**). `mgf-fed scaffold` deliberately does not regenerate their pipelines — so a gate added to the canonical template reaches **every repo except them**, silently. Nothing warns; `drift-check` skips exempt repos by design, and `policy.toml`'s `required` list checks step *names*, not the commands inside them.
- **Why it matters:** the exempt set is not a backwater — it holds the standards repo itself and the test supervisor. Proven live this wave: after PAPER-115's `ruff format --check` shipped and the fleet re-rendered, **all three Python-linting exempt repos still had no format gate, and all three carried real format drift** (mgf-hrb `tests/_broker.py`; mgf-test-supervisor; mgf-standard) — i.e. the gate that was just declared fleet-wide was absent from the repo that authored it. Any future gate (a new lint, a new scan) inherits the same hole.
- **Evidence:** `templates/policy.toml` `[exempt].woodpecker`; post-wave `origin/main:.woodpecker.yml` for mgf-hrb (line ~100 `ruff check src tests`, no `ruff format --check`), mgf-test-supervisor, mgf-standard; `uv run ruff format --check src tests` → 1 drifted file in each of those three (CI-pinned ruff; a stale local ruff reports clean — that mismatch is what let the drift survive).
- **Suggested shape:** (a) make the exemption *narrow and checked*: keep hand-maintained pipelines, but have `drift-check`/`app-doctor` assert a small set of **required commands** (not just step names) in every pipeline — exempt or not — sourced from `policy.toml` (e.g. `required_commands = ["ruff check", "ruff format --check", "check_commit_trailers.py"]`), so an exempt repo REDs when it falls behind a gate; (b) add a "walk the exempt list" line to the WF-13 wave recipe (`run-ci.md`) so a template gate change is not reported complete until the bespoke pipelines are hand-updated; (c) short term (done in this branch): hand-add the format gate + format-clean the three repos.
- **Resolution:** **SHIPPED 2026-07-11** — the durable ask landed in `mgf-fed` as **`ci-command`** (merged): `required_commands` are now asserted against **every** member's committed `.woodpecker.yml` — **exempt or not**. Exempt means "we don't regenerate your file", never "you may silently drop a federation gate". Matching is per **command line** (not step name), so a step merely *named* `lint` is not a gate and a commented-out command is not a gate. Fire-tested by an independent verifier against a purpose-built synthetic federation: repos placed in `[exempt].woodpecker` were **still** flagged — the core claim of this paper, mechanically enforced. (The short-term hand-fix — gate + format-clean on all three drifted exempt repos, mgf-standard included — landed 2026-07-10.)
- **Status:** SHIPPED

### PAPER-121 — Supervisor-driven coverage step requires a pyproject key nothing enforces; repos red with ALL TESTS PASSING

- **Severity:** 🟡 Sharp edge (VERIFIED_BY_EXECUTION)
- **Filed by:** mgf-standard (WF-13 re-render wave) on 2026-07-10
- **What hurts:** the canonical coverage step drives the suite through the federation test supervisor (`coverage run --source=src/mgf -m mgf.test_supervisor --tier 0-2` → `coverage combine`), which runs pytest in **child processes**. That only produces coverage data if the consumer's `pyproject.toml` carries `[tool.coverage.run] patch = ["subprocess"]` (coverage ≥ 7.10). A repo missing that key reds with a *baffling* signature: **every test passes**, then `coverage` reports "No data was collected" and `coverage combine` exits 1 ("No data to combine"). The template comment *states* the requirement; nothing checks it, and the failure names neither the key nor the pyproject.
- **Why it matters:** hit **three repos in one wave** (`mgf-brand-web`, `mgf-cloud-web`, `mgf-fed-web`) the moment they were re-rendered onto the supervisor-driven step — a green suite reported as a red build, with a message that points at coverage internals rather than the missing config. Every future repo scaffolded or re-rendered onto that step walks into the same trap.
- **Evidence:** mgf-brand-web pipeline #31 `test-3.12`: `[mtest] OK: 39 passed (39 total)` → `CoverageWarning: No data was collected` → `coverage combine` → `No data to combine` → exit 1. Working reference: `mgf-http/pyproject.toml` `[tool.coverage.run] patch = ["subprocess"]` (green on the same step). Missing in brand-web / cloud-web / fed-web (fixed in the wave branches).
- **Suggested shape:** (a) `mgf-fed app-doctor` (or the scaffold/drift check) FAILS a repo whose pipeline uses the supervisor-driven coverage step while its `pyproject.toml` lacks `[tool.coverage.run] patch = ["subprocess"]` — the config and the step are a coupled pair (a DOC-18-style coupling); (b) the cookiecutter ships the key by default; (c) TESTING.md §19.8 gets a "if you see 'No data to combine', you are missing this key" line so the symptom maps to the cause. Companion relayed to mgf-fed (the doctor surface).
- **Resolution:** **SHIPPED 2026-07-11** — the durable ask landed in `mgf-fed` as **`ci-coverage`** (merged): it **FAILS** when a pipeline runs `coverage run … -m mgf.test_supervisor` while the repo's `pyproject.toml` lacks `[tool.coverage.run] patch = ["subprocess"]`. Surfaced in three places so the fix is *named* wherever the baffling failure is met (drift-check · app-doctor · app-doctor --standards TS-23) — because the build's own error message names neither the key nor the pyproject. Fire-tested: fires on the real coupling, stays silent when the key is present or there's no supervisor-under-coverage. (The per-repo fixes landed in the 2026-07-10 wave.)
- **Status:** SHIPPED

### PAPER-122 — `mgf-brand` is a registry member with NO pipeline at all: every CI run errors, and nothing notices

- **Severity:** 🔴 Blocker (a fleet library ships with **zero** CI enforcement — its gates have never run on a PR)
- **Filed by:** Court/CTO fleet sweep on 2026-07-11
- **What hurts:** `mgf-brand` ships **no `.woodpecker.yml`** (verified: `git ls-tree origin/main` → absent; it is the only registry member missing one). The repo IS enabled on Woodpecker, so every event still creates a pipeline — which immediately **errors**: `could not load config from forge`. Four consecutive pipelines (#2–#5, push + pull_request) died that way during this sweep. There is **no branch protection** either (`branch_protections` → `[]`), so a PR merges with no check of any kind.
- **Why it matters:** `mgf-brand` is the fleet's **brand source of truth** (tokens + generated assets that `mgf-brand-web` / `mgf-brand-qt` derive from), and it is the one library where **no gate has ever run in CI** — not ruff, not the tokens `--check`, not gitleaks, not the commit-trailers gate. The failure is *silent by shape*: an errored pipeline reports no failing step, so a casual glance at the repo's CI page looks like "nothing to see" rather than "this repo is ungated." The whole fleet-wide gate discipline (WF-02/WF-13, the PAPER-115 format gate, the PAPER-120 exempt-list audit) quietly does not apply to it.
- **Evidence:** `git ls-tree --name-only origin/main` on `mgf-brand` — no `.woodpecker.yml` (every other `mgf-*` member has one); Woodpecker pipelines #2/#3/#4/#5 all `error` with `could not load config from forge: %!w(<nil>)`; `GET /repos/magogi-admin/mgf-brand/branch_protections` → `[]`. It is **not** in `templates/policy.toml [exempt].woodpecker` (so nothing sanctions the absence — it is a gap, not a decision).
- **Suggested shape:** (a) scaffold `mgf-brand`'s pipeline (`mgf-fed scaffold mgf-brand`) — it is an assets/generator repo, so the shape may need a variant (tokens `--check` + gitleaks + trailers, no pytest matrix); (b) enable branch protection requiring the check, as every other member has; (c) **the durable half:** `mgf-fed drift-check` / the ownership audit should FAIL a registry member that has no `.woodpecker.yml` and is not in `[exempt].woodpecker` — today the absence is invisible to every gate we own (this is the same "unchecked exemption" class as PAPER-120, one step further: not exempt, just *missing*).
- **CORRECTION (2026-07-11) — my framing was WRONG, and the truth is worse.** This paper called `mgf-brand` "a registry member with no pipeline". **It is not a registry member at all** — `MGF_LIBRARIES.json` lists 37 members, and `mgf-brand` is not among them (it ships no publishable package, so the generator never listed it). Caught by the mgf-fed agent implementing the fix, who checked the premise instead of trusting it.
  **Why that matters far more than the typo:** *every tool we own iterates registry members.* So the real root cause of "no gate has ever run on mgf-brand" is not a missing pipeline — it is that **a repo outside the registry is invisible to our entire toolchain**: drift-check, the ownership audit, the conformance sweep, the release gate. A member-scoped check would have faithfully reproduced the blind spot instead of closing it. The registry is not just a list of packages; it is the *denominator of everything we verify*, and anything outside it is ungoverned by construction.
- **Resolution:** SHIPPED (2026-07-11) — closed on both halves:
  1. **The instance:** `mgf-brand` now has a **working, fire-tested pipeline** (5 gates: tokens-check · icons-check · naming-check · commit-trailers · secret-scan — each proven to RED on an injected violation), CI **runs green on main for the first time in the repo's existence** (pipeline #9), and **branch protection is enabled** (`ci/woodpecker/pr/woodpecker` required, direct push disabled) so the gate actually blocks a merge. Two defects were caught pre-merge by adversarial verification: an understated lint-debt figure, and — real security — gitleaks allowlist entries that wildcarded whole directories containing hand-authored text, making a plaintext credential in `brand/assets/print/` **invisible** to the scan (now extension-scoped; re-proven both ways).
  2. **The class:** `mgf-fed` ships **`ci-ungoverned`** — drift-check now scans the federation root for **cloned `mgf-*` repos the registry does not list that ship no pipeline**, and fails them. Deliberately narrow (a non-registry repo that HAS a pipeline is running gates and is not flagged). Verified against the real fleet: exactly **one** finding — `mgf-brand` — and zero noise across 48 repos. Alongside it: **`ci-command`** (required *commands*, asserted on every member **exempt or not** — exempt means "we don't regenerate your file", never "you may silently drop a gate") and **`ci-coverage`** (the supervisor-coverage ↔ `patch=["subprocess"]` coupling). All three fire-tested by the verifier against a purpose-built synthetic federation.
  **Honest residual (recorded, not hidden):** `ci-ungoverned` only sees repos **cloned on the machine running drift-check**. A repo that exists on the forge but was never cloned locally is still invisible — closing that needs a forge-side repo listing. The blind spot is narrowed, not eliminated.
- **Status:** SHIPPED (both halves; residual forge-listing gap recorded)

### PAPER-133 — Codify the Zig import/naming rule in NAMING.md (Zig analog of NM-02)

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | mgf-common-zig queue sweep (Court-delegated), routing its |
| Submitted | (see Origin) |
| Severity | 🟢 Low |
| Federation paper | relayed by the supervisor from `mgf-common-zig/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟢 Low
- **Filed by:** mgf-common-zig queue sweep (Court-delegated), routing its
  FEEDBACK PAPER-01, on 2026-07-10
- **What hurts:** `docs/standards/NAMING.md` NM-02 mandates the Python
  `import mgf.<sibling>` shape via PEP 420; there is no written Zig analog in
  the corpus. The de-facto convention is real and already codified *locally*
  as `mgf-common-zig/docs/standards/ZIG.md` ZG-02: **hyphens** for the
  Codeberg slug / local dir / registry entry (`mgf-common-zig`),
  **underscores** for `build.zig.zon` `.name` and the importable module id
  (`mgf_common_zig`), because Zig identifiers can't contain hyphens.
- **Why it matters:** every new `mgf-*` Zig sibling re-derives the split or
  copies it from mgf-common-zig; NAMING.md is where the fleet looks for
  naming law, and today it answers only for Python.
- **Evidence:** `mgf-standard/docs/standards/NAMING.md` rules table stops at
  NM-05 with no Zig/non-Python rule (verified 2026-07-10); the local codified
  form is `mgf-common-zig/docs/standards/ZIG.md` ZG-02 (lines 23, 85-89).
- **Suggested shape:** add a NAMING.md rule for non-Python siblings capturing
  the hyphen↔underscore split, citing ZIG.md ZG-02 as the source. **Note the
  original paper suggested the ID `NM-05`, but NM-05 has since been taken**
  (junk-drawer module rule, PAPER-107) — the new rule needs the next free ID
  (NM-06 at time of filing). Authoring lives with the mgf-standard
  supervisor; this paper is the request.
- **Status:** OPEN

### PAPER-134 — Promote `ZIG.md` into (or cross-link it from) the standards corpus

| Field | Value |
|---|---|
| Status | OPEN |
| Submitter | mgf-common-zig queue sweep (Court-delegated), routing its |
| Submitted | (see Origin) |
| Severity | 🟡 High |
| Federation paper | relayed by the supervisor from `mgf-common-zig/pending-feedback/mgf-standard.md` (FB-05) |

- **Severity:** 🟡 High
- **Filed by:** mgf-common-zig queue sweep (Court-delegated), routing its
  FEEDBACK PAPER-02, on 2026-07-10
- **What hurts:** `mgf-common-zig/docs/standards/ZIG.md` governs the whole
  `mgf-*` Zig cohort (ZG-01..ZG-5x MUSTs) but lives in one sibling. Per
  AG-13 / DOC-18 the canonical standards corpus is
  `mgf-standard/docs/standards/`; ZIG.md is neither there nor cross-linked
  from the corpus README / Index-of-MUSTs (verified 2026-07-10: no `ZIG.md`
  reference anywhere under `mgf-standard/docs/standards/`).
- **Why it matters:** an agent scaffolding a new Zig sibling from the corpus
  never learns ZIG.md exists; cohort-wide MUSTs that aren't discoverable from
  the corpus are MUSTs only for whoever already knows them.
- **Evidence:** `ls mgf-standard/docs/standards/` — no ZIG.md;
  `grep -ri zig mgf-standard/docs/standards/README.md` — no hits. Local
  canonical copy: `mgf-common-zig/docs/standards/ZIG.md`; promotion path
  sketched in `mgf-common-zig/docs/design/ROADMAP.md` ("Promotion path").
- **Suggested shape:** supervisor decision, two acceptable outcomes: (a)
  relocate ZIG.md into `mgf-standard/docs/standards/` and leave a pointer
  stub in mgf-common-zig, or (b) keep the canonical copy here and add a
  one-line pointer in the corpus README + the Index-of-MUSTs. Either way the
  corpus becomes the discovery point.
- **Status:** OPEN
