Taking a talk deck public

A talk deck goes public the moment a link leaves the building — a LinkedIn post, a slide photographed in the room, a line in a conference programme. Everything the deck POINTS AT is public at the same instant, and that is where it breaks. This page is the checklist, written from the 2026-09-10 dry run of the SAV Generalversammlung talk, one day before it went out.

The rule the whole page reduces to: walk the visitor's path yourself, signed out, then signed in as somebody who owns nothing. Neither state is the one you develop in, and each hides a different half of the funnel.

1. What a signed-out visitor actually reaches

Grants are per node and they inherit downward, so a deck can be public while its parent is not. Check each hop the deck names, not the deck alone:

mcp search "path:{Partition} scope:subtree nodeType:AccessAssignment"   # every grant
mcp get "@{Partition}/_Policy"                                          # publicRead: true? absent = no

Both Anonymous (not logged in) and Public (any signed-in account) are needed — they are different subjects, and a deck carrying only Public looks fine to you and bounces the world.

Measured on the SAV deck: Event/SavGeneralversammlung2026/Talk carried both and rendered anonymously; its PARENT Event/SavGeneralversammlung2026 carried neither, so the breadcrumb one click above the deck dead-ends at /login. Nothing warns you — the deck works.

2. Where the visitor is asked to register

On memex there is no local account: /login offers Microsoft, Google, LinkedIn and GitHub, and nothing else. So "register" always means an external identity, and the ask lands at the first gated hop — typically /{package}/Subscribe, which for a signed-out visitor renders the plan pitch and "Please sign in to subscribe — your enrollment is stored with your account."

A gated child does not 404: it REDIRECTS to that paywall. /ReinsuranceDemo/Walkthrough becoming /ReinsuranceDemo/Subscribe is the funnel working, not a broken link.

3. 🚨 The account you test with decides what you can see

Two traps, both of which make a broken funnel look healthy:

The usable test identity is one that holds nothing the funnel gates: no package entitlement for the target, and no row at Admin/Subscriptions/{viewer}.

mcp search "name:{viewer} nodeType:Markdown"      # every {package}/_Entitlements/{viewer} marker
mcp get "@Admin/Subscriptions/{viewer}"           # not found = no plan = good for testing

4. The coupon: two independent ways it dies, both silent

A coupon on a slide has to survive both. Neither shows up as an error anywhere until somebody types the code in front of an audience.

It grants no plan. CouponRedemption.Validate checks the tier FIRST — before the window, before the budget — and refuses a coupon that names none with "This coupon does not grant a plan." A coupon authored before that rule shipped is dead the day the rule deploys, and the coupon node looks perfectly healthy. Check content.tier and content.tierDays on every code you are about to hand out, and remember TierExpiry is CLAMPED to the coupon's own validUntil — a code windowed to 31 December gives eleven days to somebody redeeming on the 20th, not ninety.

There is nowhere to type it. The redeem row is built near the END of PluginLayoutAreas.BuildSubscribe, after several early returns. A package that declares contactEmail returns a contact-sales form and never reaches it, so a valid coupon for that package cannot be redeemed at all (MeshWeaver.Plugins#1617; worked around for the demo package in MeshWeaver.Reinsurance#192). The paywall renders beautifully either way.

Trust the ROW, not the page. A rendered paywall says nothing about whether the code has a home on it. Look for "Have a coupon?" with your own eyes, as the visitor's account.

An expired window is the third, ordinary way — and worth stating because a code is often parked INERT on purpose (validUntil in the past) while a build lands, and arming it again is a manual step somebody has to remember. Both SAV codes were parked that way; one had been forgotten.

5. The dry run, in order

  1. Signed out: the deck renders, and every hop it names either renders or asks to sign in — never an error, never a blank.
  2. Signed in as an account that owns nothing: each gated package's /Subscribe shows the redeem row, in the language the PACKAGE ROOT declares (StoreTexts.ResolveLocale), not the reader's.
  3. Type each code. A free coupon grants, installs the dependency closure, and lands in the content.
  4. Walk the demo to its last step as that account — the entitlement cascade covers dependencies only if they are unpriced, so a tour that crosses into a priced package stops there.
  5. Only then hand the link out.

Steps 1, 2 and 4 are the ones that get skipped, and each of them hid a launch blocker in this run.

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.