The partner-brand chain is merged and live DARK. S5 is the only remaining slice: it turns publication ON.
Full spec: docs/plans/SOFRA-PARTNER-PLAN.md §11h (design in §11, owner's answer in §11e).
Why this is not a one-line change
buildTenantRegistryEntry is called from exactly one place — lib/provisioning.ts:99, inside openProvisioningPr — which runs only when a new tenant is provisioned. Nothing regenerates an existing tenant's registry entry.
So a partner who ticks the box changes nothing on their already-live sites (obresse, kebabdilhan) until the founder hand-edits tenants/registry.yml and re-provisions. A checkbox implying otherwise would be the same lie S1 avoided by shipping it disabled.
Build order — the OFF transition first
It is the only failure here with a real person on the other end: a partner asks to withdraw their name, the flag flips, and the name stays public on a restaurant's site indefinitely because nothing regenerates that entry. If any of S5 is cut, this is the last piece to go.
- Founder mail on the OFF transition (
true → false). Model on requestOnboardingAction / "Ask for a change": email inside a .catch(), audit(...) after the send, rate-limited per partner id. Must name the tenants still carrying the credit.
- Founder mail on the ON transition, same mechanism.
- Enable the checkbox with real copy + a live preview of the exact string (
Site by X).
- State the per-partner scope as fact — owner-endorsed, not an apology.
- Per-tenant LIVE / PENDING status on
/dashboard/brand, derived from the registry. Where it cannot be determined, say so for that tenant rather than implying either state.
- Small
/admin surface: which partners have publication ON with tenants still needing a re-provision.
- i18n ×6, unit + e2e. Negative control: publication ON with no live tenants produces no notification and no pending rows.
Do not change
renderableBrand's refusal behaviour (a brand echoing the partner's legal name is refused — owner-confirmed), the attribution-only projection (name + https website; no address, phone or legal name), or the partner_attribution: registry key, which stays as the founder-level override for abuse or a disputed tenant.
Already merged (all dark)
| Slice |
PR |
Commit |
| S1 brand model + partner form |
sofra #204 |
87bac9d |
| S3a publish choke point + registry emitter |
sofra #205 |
48091a5 |
| S3b provisioning + compose mapping |
deploy #158 |
13521bf |
S4a GET /api/tenant/partner |
backend #456 |
dd1667c |
| S4b footer render ×4 public sites |
frontend #645 |
c1fb98e |
Also outstanding
S3c — the chain has never run on a box. It is proven at unit/template level in four repos, across a seam whose two halves are tested separately. The post-release box checklist is in §11h's neighbouring text and was handed to the release coordinator; the withdrawal path (remove the keys, re-provision, confirm the footer is byte-identical) has never been executed at all.
The partner-brand chain is merged and live DARK. S5 is the only remaining slice: it turns publication ON.
Full spec:
docs/plans/SOFRA-PARTNER-PLAN.md§11h (design in §11, owner's answer in §11e).Why this is not a one-line change
buildTenantRegistryEntryis called from exactly one place —lib/provisioning.ts:99, insideopenProvisioningPr— which runs only when a new tenant is provisioned. Nothing regenerates an existing tenant's registry entry.So a partner who ticks the box changes nothing on their already-live sites (
obresse,kebabdilhan) until the founder hand-editstenants/registry.ymland re-provisions. A checkbox implying otherwise would be the same lie S1 avoided by shipping it disabled.Build order — the OFF transition first
It is the only failure here with a real person on the other end: a partner asks to withdraw their name, the flag flips, and the name stays public on a restaurant's site indefinitely because nothing regenerates that entry. If any of S5 is cut, this is the last piece to go.
true→false). Model onrequestOnboardingAction/ "Ask for a change": email inside a.catch(),audit(...)after the send, rate-limited per partner id. Must name the tenants still carrying the credit.Site by X)./dashboard/brand, derived from the registry. Where it cannot be determined, say so for that tenant rather than implying either state./adminsurface: which partners have publication ON with tenants still needing a re-provision.Do not change
renderableBrand's refusal behaviour (a brand echoing the partner's legal name is refused — owner-confirmed), the attribution-only projection (name + https website; no address, phone or legal name), or thepartner_attribution:registry key, which stays as the founder-level override for abuse or a disputed tenant.Already merged (all dark)
87bac9d48091a513521bfGET /api/tenant/partnerdd1667cc1fb98eAlso outstanding
S3c — the chain has never run on a box. It is proven at unit/template level in four repos, across a seam whose two halves are tested separately. The post-release box checklist is in §11h's neighbouring text and was handed to the release coordinator; the withdrawal path (remove the keys, re-provision, confirm the footer is byte-identical) has never been executed at all.