# 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-common 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

> 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-common catch-up`/`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:** OPEN (mechanism shipped; relay recipe + binding decision pending)

### 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:** OPEN — prompt guard shipped (0.1.18); CLI side RELAYED + SHIPPED as mgf-common PAPER-98 (no-network snapshot-provenance advisory; catch-up stays offline, live check stays agent-side; PR #9, commit `100b52e`)

### 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:** OPEN (shipped in prompt; AGENTS.md encoding decision pending)

### 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:** OPEN (shipped in prompt; naming-convention decision pending)

## 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

---

## 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
