# Registry Reconciliation Ledger — 2026-06-16

**Audience: the maintainer (sign-off) + AI agents.** Each item is a cross-source contradiction or a new census signal. **Do not silently resolve disposition by map-drawing** — the registry is a spec; changing it is a spec amendment (CLAUDE.md spec-first). Items are tagged:

- **[DECIDED — reconciled]** = already resolved by newer law (synthesis §6 / CLAUDE.md §2); this doc + `registry.json` just stop the drift. No sign-off needed; prose-`registry.md` edit pending.
- **[NEEDS YOUR CALL]** = a disposition/promotion verdict the census surfaced; the recommendation is mine, the decision is yours.

Source docs: `2026-06-12-module-registry.md` (prose index, R), `2026-06-13-monorepo-architecture-synthesis.md` (S), `CLAUDE.md` (C), `2026-06-16-donor-capability-inventory.md` (census).

> **ALL ITEMS RESOLVED 2026-06-16** — the user accepted every recommendation ("do per your recommendation") and ran the gate for #4. Each [NEEDS YOUR CALL] below now reads **[DECIDED — user-confirmed 2026-06-16]**; dispositions applied to `registry.md` + `registry.json` in the same commit. This doc is retained as the decision record, not an open queue.

---

## A. Authority + drift (the root cause)

### #8 — Two docs both claim registry authority **[DECIDED — reconciled]**
- **Evidence:** R line 1 self-labels *"Module Registry — Platform Source of Truth."* C §2 says *"Full registry + per-module status live in the synthesis doc §6 — that is the source of truth, not this index."* Two anointings.
- **Worse than it looks — staleness is bidirectional:** R is *newer* on built rows (helpdesk/tax/ledger = "built 2026-06-15"; util datetime/timezone built); S §6 is *newer* on `events` (DISSOLVED). Neither is uniformly canonical. That is the drift disease — any agent reading the wrong one re-derives wrong (this is why exploration agents respawn).
- **Resolution (your Q1 answer, 2026-06-16):** **`registry.md` is canonical** (it is the rich, most-edited index). Bring it fully current; **`registry.json` is its machine-readable mirror** (agents grep that); **synthesis §6's status table becomes a pointer** to `registry.md`, not a second table. One prose source + one JSON source. C §2's sentence must be edited to point at `registry.md`, not claim §6.
- **Action:** edit C §2 pointer; add a "supersedes §6 status table" line atop S §6; add canonical-pointer header to R. (Pending — not yet applied to C/S.)

---

## B. `events` dissolution cascade **[DECIDED — reconciled]**

`@platform-modules/events` is DISSOLVED (S §6, C §2; census x0). R still wires it live. Reconciled in `registry.json`; prose edits pending:

| # | Evidence (R) | Fix |
|---|---|---|
| 2a | line 39 — `@platform-modules/events` row = "candidate (build certain)" | → mark **dissolved**; signals = `jobs/outbox` + direct calls |
| 2b | line 56 — billing `Deps: db, events` | → drop `events` |
| 2c | line 67 — invoicing `Deps: db, events` + "listens payment.succeeded" | → drop `events`; signal via direct call/outbox |
| 2d | line 78 — affiliate `Deps: db, events, ledger` | → drop `events` |
| 2e | line 54 — auth `emits user.registered, session.revoked` | → keep signal, annotate "direct call / outbox, not a bus" |
| 2f | line 68 — marketing "listens domain events" | → annotate mechanism |
| 2g | line 138 — `presets.core` includes `@platform-modules/events` | → drop from preset |

---

## C. Status mismatches **[DECIDED — user-confirmed 2026-06-16: ran the gate]**

> **RESOLVED:** ran `turbo run typecheck test build` for all 5 — **18/18 green (FULL TURBO)**. All 5 carry `verified: true` (2026-06-16) in `registry.json`. **`status` = build intent, `verified` = gate-truth** (recommendation #4 adopted): synthesis §6's "designed" was stale on tenancy/mail/notifications/uploads; auth keeps `status:"designed"` (core seam verified; method subpaths opt-in/unbuilt) with `verified:true` on the built surface.

### #4 — `shipped` vs `designed` disagreements
- **Evidence:** R table vs S §6 disagree on: **auth** (R-table=designed, R-json-block=shipped, S=designed — R contradicts *itself*), **tenancy** (R=shipped, S=designed), **mail** (R=shipped, S=designed), **notifications** (R=shipped, S=designed), **uploads** (R=built, S=designed). All have scaffolded `packages/<name>/` dirs.
- **Why it matters:** `shipped` means *importable now*; `designed` means *boundary-only*. A consumer (multideal migration) that trusts a false `shipped` imports vapor.
- **Recommendation:** status is not verifiable from docs — it needs the build-run-sheet (`docs/plans/2026-06-14-build-run-sheet.md`) + `turbo run build` truth, not a doc vote. **Define status = boundary/build intent in `registry.md`; add a separate `verified` boolean fed by the gate** (typecheck+test+build green). Until then I left `registry.json` status at the R-table value and flagged each `status_conflict`. **Your call:** treat R-table or S §6 as the status authority for these 5 rows, or have me run the gate to derive ground truth.

---

## D. New census signals (2026-06-16) **[DECIDED — user-confirmed 2026-06-16, all per recommendation]**

### #1 — `auth/api-keys`: stays ×2, promote candidate→designed on convergence?
- **Evidence:** R §auth lists `api-keys` `candidate ×2 (zync+vibeflare)`. Census **count unchanged**: an earlier draft of this ledger claimed a 3rd donor (Press.zone) — **that was wrong** and is corrected here. Press.zone's only `api_key` strings are `BUNNY_API_KEY` *consumption* (CDN-key config, `src/config/index.ts` + `routes/media.ts`), with **zero issuance markers** (no generate/mint/hash) — a different capability that does not count. zync impl is `H` (KV-cached, scope-checked, tenant+tier-resolved); vibeflare `W` (`vf_<prefix>.<secret>` + sha256 hash-lookup + last-used touch).
- **Disposition test:** convergence>count — do the **2** share a seam? Both = `Bearer <prefix>.<secret>` → hash-lookup → scope/tenant resolve → last-used touch. Convergent. Per R's own 2-donor rule, **×2 same-seam → `designed`** is in-policy without a 3rd donor. Cross-class forward-need: every public-API surface needs it.
- **Recommendation:** **promote `auth/api-keys` candidate→designed** (subpath, not module) **on ×2-convergence, not count**. Low risk, high forward-need. ← *your confirm*

### #5 — `webhooks` OUTBOUND delivery: dissolved on "1-donor", but census finds ×2+ (zync hardened)
- **Evidence:** R dissolved webhooks; "outbound = 1-donor (zync) → WATCH." Census: outbound HMAC-signed delivery present in zync (`H`, generic `packages/db/schema/webhooks.ts` + `queues/webhook-deliver.ts`), plus multideal/ForumZone/trance/PZ have outbound dispatch.
- **Disposition test:** are the others *generic delivery* or *per-provider inbound*? Most are inbound-receive (stays dissolved, correct). zync's is the only *generic outbound* (endpoint registry + HMAC-sign + retry log). So genuine outbound-delivery donors may still be ×1 (zync) — the others are inbound. **Likely still WATCH**, but verify before deciding.
- **Recommendation:** **hold WATCH**; re-census the 4 "outbound" hits to confirm inbound-vs-outbound before promoting. ← *your confirm / I can re-census*

### #3 — `invoicing`: ×1 → ×2 standalone, but divergent shape
- **Evidence:** R = "1 standalone donor (multideal) → WATCH." Census: zync has standalone invoicing too (`H`: recurring-invoices, AR-aging, credit-notes, PDF queue, dunning).
- **Disposition test:** convergence? multideal = IL *provider-adapter dispatch* (iCount/Morning). zync = *accounting AR sub-ledger* (recurring/aging/matching). **Different shapes** — a shared module would be an empty interface (the inventory/promotions trap).
- **Recommendation:** **hold WATCH** (×2 count, ×0 convergence). Revisit when a 3rd donor matches *either* shape. ← *your confirm*

### #6 — `integrations`: new capability class, absent from taxonomy
- **Evidence:** zync `packages/{integrations,zapier,make}` — slack/trello/asana/jira/monday/clickup task-sync + Zapier OAuth + Make.com. ×1 donor.
- **Recommendation:** **register as WATCH** (forward-need for any SaaS, but ×1 and no 2nd-donor convergence). Not a module now. ← *your confirm*

### #7 — `ticketing` + `commerce`: new domains (trance, hardened)
- **Evidence:** trance `ticketing` (CF Worker+DO HMAC tickets, scan-log, offline PWA validator) `H`; `commerce` (cart+checkout+coupons+Printful POD, tested) `H`. Both ×1.
- **Recommendation (superseded 2026-06-16):** ~~`ticketing` → WATCH module~~ → **`ticketing` EXCLUDED — NOT a platform candidate.** Event ticketing is the **proprietary core product of trance-shop-israel**, not generic substrate; harvesting a donor's own flagship product as a module is out of scope regardless of census count. The reusable substrate (auth/realtime/jobs/ledger) already ships — an adopter composes those. **`commerce` → a BLUEPRINT, not a module** (it spans billing/ledger/invoicing/uploads/search — it's a composition, feeds the marketplace blueprint). ← *your confirm; ticketing exclusion per owner 2026-06-16*

---

## E. Housekeeping **[DECIDED — reconciled]**

### #9 — `CommentPressZone` is a dead donor
- **Evidence:** repo = single 4-byte `test.txt`, no source.
- **Action:** ✓ **DONE 2026-06-16** — removed from the `2026-06-12-module-discovery-census.md` skip-list + the `platform-orchestrator` census-roster sweep path; `CLAUDE.md` header donor list already clean. `catalog/index.md` + donor-inventory already record it DEAD.

### #10 — mining-doc viewer has a duplicate-key bug
- **Evidence:** `tmp/mining-docs/index.html` `layers` array — one node carries both `id:"blueprints"` and `id:"targets"`; `id:"blueprints"` repeats (~lines 842–851). "No ignored signals" defect.
- **Action:** ✓ **DONE 2026-06-16** — viewer **kept** (the `tmp/mining-docs/*.md` are live, edited 2026-06-16). Fixed the duplicate `id` in the **Surface Targets** node of `index.html` (removed the stray `id:"blueprints"`, leaving `id:"targets"`; the Layer 5 node keeps the now-unique `id:"blueprints"`). `tmp/mining-docs/` is untracked — the fix is on disk, not committed.

---

## F. Status model — Model B adopted **[DECIDED — user-confirmed 2026-06-16, #14]**

### #14 — `status` field semantics: intent vs build-lifecycle
- **Evidence:** #4 set `status`=intent / `verified`=truth, leaving built + gate-green modules at `designed`/`built`/`pilot` while `verified:true` carried the real state. By 2026-06-16 all 20 buildable modules are built + published 0.0.1 + full-gate-green (`pnpm gate` EXIT 0 this session), so the split left `status` reading **false-by-legend** (`designed`="not built") for shipped code — the exact drift #4's `verified` flag was a stopgap for.
- **Decision (Model B, user-confirmed via AskUserQuestion 2026-06-16):** `status` = **build-lifecycle** (`designed`→`pilot`→`built`→**`shipped`**); `shipped` = core built + `verified` + red-on-break consumer fixture. `verified` is **retained** as the gate-evidence sub-field (honors #4's truth-marker). Per-subpath completeness moves to each subpath's `build` flag + the row note, never the module status. **Supersedes #4's "status = intent / auth stays designed."**
- **Applied (same commit):** 11 modules advanced to `shipped` (util · auth · search · seo · ai · audit · billing · ledger · tax · uploads · helpdesk) + `verified:true` with this-session gate evidence; `marketing` → `built` (`verified:false` — root-smoke *import* only, no behavioral consumer fixture: **GAP**). `registry.json` + prose `registry.md` mirrored same commit; `_meta.status_caveat` + the `auth`/`ai` rationale rewritten off the old "intent" model. `cache` stays `designed` (no package dir); `invoicing`/`affiliate` stay WATCH.
- **Open gap — ✓ CLOSED 2026-06-16:** `marketing` now has a behavioral consumer-harness fixture — `apps/consumer/tests/marketing.test.ts` (7 assertions over the compliance seam: legal-gate fail-closed, suppression + EU/IL double-opt-in refusal, RFC 8058 headers, tracking-off-by-default, region branch, adapter-registry error), **red-on-break proven** (dropping the `executeCompliantSend` re-export fails 4 tests). Advanced `built` → **`shipped`** (`verified:true`); registry.json + prose mirrored same commit. Also reconciled the `loops` adapter subpath drift (listed but not built → annotated census-only). **Model B (#14) now fully applied — no open status gaps.**

---

## G. CMS gap dispositions **[NEEDS YOUR CALL — 2026-06-17]**

### #15 — `comments` module + separable `moderation` (reference CMS-parity gap)
- **Evidence:** reference CMS gap analysis (`docs/specs/2026-06-17-mod-cms-feature-gap-analysis.md`). Donor matrix: comment **thread store/display** = FZ `H` only (**×1**); **moderation/spam** = MD AI-moderation + FZ KB + TS tested (**×2–3**). Distinct seams under one noun.
- **Recommendation:** `@platform-modules/comments` (L2) core = thread store/display, ship on **×1-forward-need** (owner build-at-×1 + cross-class need: forum/deal/product/CMS), NOT ×2-convergence. Moderation stays a **separable** importable/composed capability — keep OUT of comments core contract (convergence>count). Supersedes runsheet "open disposition (re-census at P4)" for comments.
- **Status:** OPEN — confirm before build; Gate-1 delete-test + same-seam re-checked at build time.

---

## Decisions summary (DECIDED — user-confirmed 2026-06-16)

| # | Decision | Recommendation | Outcome 2026-06-16 |
|---|---|---|---|
| 1 | promote `auth/api-keys`? (stays ×2 — Press.zone miscount corrected) | **YES → designed** (on ×2-convergence) | ✅ **DONE** — `build:"designed"` in R+json; seam → auth spec before build |
| 3 | promote `invoicing`? | **NO → hold WATCH** (divergent) | ✅ **WATCH held** (×2, ×0 convergence) |
| 4 | status authority for auth/tenancy/mail/notifications/uploads | **run the gate to derive `verified`**; R-table is intent | ✅ **gate ran, 18/18 green** — `verified:true` ×5; `status`=intent, `verified`=truth. **⤷ SUPERSEDED by #14 (Model B, 2026-06-16): `status` now = build-lifecycle; `verified` retained as gate-truth.** |
| 14 | `status` field = intent or build-lifecycle? | **Model B — build-lifecycle**; `verified` retained | ✅ **applied 2026-06-16** — 11→`shipped`; marketing→`built` then →**`shipped`** once its red-on-break fixture landed (gap closed same day, `tests/marketing.test.ts`); registry.json+prose+ledger; supersedes #4 |
| 5 | promote outbound-webhook-delivery? | **NO → hold WATCH**; re-census to confirm | ✅ **WATCH held** — re-census still open as a *future* check, not a blocker |
| 6 | register `integrations`? | **WATCH** | ✅ **WATCH registered** |
| 7 | `ticketing` / `commerce` | ~~ticketing=WATCH module~~ → **ticketing=EXCLUDED (TSI proprietary core product); commerce=blueprint** | ✅ **applied 2026-06-16** — `ticketing` removed from watch (owner: proprietary to trance-shop-israel, not a platform candidate); `commerce`∈deliveryStages blueprint |
