An unfurl discloses on paste, not on open

Parley is video meetings where guests join from a link, with no account and no download. The decision I would defend hardest is the one where I cut my own specification.


role
Defined, designed, specified
then directed an AI coding agent to build it
testing
Six people in one room
largest real session · wider testing next · no traction claimed
status
Live on Vercel
v1.4 and v1.5 shipped
budget
Inside a 250 kB budget
room route · 170 kB of 250 · check:bundle 11 of 11

Video meetings where guests join from a link. No account, no download, no plugin.

This is a portfolio project, not a product with users. The largest real session so far was six people in one room, and it worked, which is enough to show it holds at a size past a demo. Wider testing is next. None of the argument below rests on traction.

I defined it, designed it, set the architecture and specified it end to end, then directed an AI coding agent to implement it. Two of the places that arrangement broke are written up in the essay rather than here.

A Parley meeting room on a phone, with two participant video tiles and a compact control bar along the bottom of the screen.
fig 1 · parley.app/j/kqr-8mzt-vnp. That is the entire onboarding.

The guest I designed around

A guest on a phone, on mobile data, following a link out of WhatsApp, who has never heard of the product and will not create an account to talk to someone for ten minutes. Nearly every consequential decision falls out of that one person.

A four-step sequence on a phone for an instant meeting: a Parley link sitting in a WhatsApp conversation, the link tapped, a single name field with a join button, then the meeting room.
fig 2 · Four steps from a chat message to a meeting. Scheduled meetings add a fifth, because the waiting room now defaults on for those.
Bundle analysis for the room route, showing the shipped JavaScript for the route sitting under a 250 kB budget line.
fig 3 · A 250 kB budget on the room route, and the route comes in at 170 kB. A guest on mobile data pays for every kilobyte before they can say hello.
The Parley waiting room, asking the host to admit a named guest, with no equivalent prompt shown for signed-in participants.
fig 4 · The waiting room asks about guests rather than everyone, because the risk it exists for is the unknown person with the link.

The decision I reversed

Two link previews side by side in a messaging channel. On the left, the specified version showing a meeting title and host name. On the right, the shipped generic Parley card with no meeting details.
fig 5 · I specified the one on the left. It is what every competitor does and it looks better. I shipped the one on the right.
The same meeting link pasted into the wrong channel, shown twice. Above, with an unfurl rendering the meeting title beneath it. Below, with no unfurl, showing only the bare URL.
fig 6 · The counter is that anyone in the channel could click the link and read the title anyway, so nothing is really hidden. It does not survive this. With an unfurl, “1:1 re: performance concerns” is broadcast instantly and passively to everyone scrolling past. Without one, the link sits there inert until somebody cares enough to click it.

The gap between passive broadcast and deliberate click is the entire disclosure.

It costs something visible. Meeting links are the most-shared artefact in the product, and they now unfurl as a generic card in exactly the place most people will first encounter it.


Three theories that each fit until they did not

The magic-link verification pattern: a run after three weeks idle producing a single refusal, and a run forty minutes later producing twenty-six, shown beside the Supabase setting of thirty verifications per five minutes.
fig 7 · Three weeks idle produced one refusal. Forty minutes later, twenty-six. No per-day or per-run model explains both.

Magic-link sign-in started refusing during testing. I had three theories about why, and each one fitted every run I had until the next run arrived and broke it.

The answer was a rolling window of thirty verifications per five minutes, which explains a long idle period spending almost nothing and a short burst spending everything. It was on the Supabase dashboard.

An entry in Parley's decision record recording the rolling window, alongside the theories it replaced.
fig 8 · Written in alongside the theories it replaced, so the next person to reason their way to a per-run model finds the window first.

Live on Vercel. v1.4 and v1.5 have both shipped, the second bringing the waiting room, the ten-minute block, the layer scale and the reaction anchor.

For three weeks in between, it could not host a meeting. A dozen full test suites in one night exhausted LiveKit’s connection-minutes allowance, so sign-in worked, the waiting room worked, and every guest landed on the room’s connection-dropped screen: the right screen for the wrong reason. It recovered with no code change, because no code change could have fixed it.