Commit Graph

4 Commits

Author SHA1 Message Date
martbost 2f4b70c886 Members can take it back off, and OPTIONAL is now impossible to miss
Three things, one of which we were quietly getting wrong.

REAL OPT-OUT. We told members "removable any time" in three separate places and there
was no way to remove anything. Same class of failure as the dead "Add mine" button:
copy written, mechanism never built. The profile card now offers Remove username,
Remove email and Remove everything, and profiles.remove() clears the value while never
touching the position. Adding it again later works exactly as before, so opting out is
not a one-way door.

It is a two-step inline confirm, not a native confirm() dialog. Browsers with "suppress
dialogs" switched on return false, which would have made Remove look broken in precisely
the way Add mine was broken. First tap arms and explains the consequence, second tap
does it, and it disarms itself after six seconds.

THE PROMISE WE WERE BREAKING. The payout mailer and the upgrade alerts read
member-alerts.json, NOT profiles.json. So a member who completed the new profile got
NOTHING, while the invitation card promised "a note the moment POL lands in your
wallet". Verifying a profile email now mirrors into member-alerts.json so every existing
alert path works, including the unsubscribe link, and removing the email clears both
stores so opting out actually stops the email.

MANSON'S HUGE ASTERISK. He asked for it to be bigger and bolder so nobody can say they
did not see it, and on a decentralized build that burden is ours, not the member's. One
gold badge now appears on the dashboard invitation, inside the dialog on every step, in
the inbox banner and on the profile card itself: "100% OPTIONAL - never required", with
the plain statement that the position, the payouts, the team and everything on the page
work exactly the same without it, nothing on chain depends on it, and it can be removed
again any time.

gate-e2e is 52 assertions, up from 38. The new ones prove one tap does NOT remove
anything, the second tap does, the server agrees the value is gone, an email-only
removal leaves the username alone, and the invitation reappears afterwards so the whole
thing is reversible. profiles-unit 28, signin-fallback 7, captions-e2e 158 all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:52:43 -05:00
martbost 88a3ad1149 Captions: add German and Portuguese, make them findable, and fix the dead "Add mine" button
Three things.

GERMAN AND PORTUGUESE. Marty's call, and the right one: the translation cache only
shows who is already here, not who Manson is bringing. Manson knows his audience, so
Portuguese goes in even though site data ranks German above it. All five videos now
carry English, Italian, French, Spanish, German and Portuguese. Disclaimers checked by
hand in the two new languages: "Es wird kein Einkommen garantiert" and "Nenhuma renda
e garantida".

FINDABILITY. Marty went looking for the multilingual feature on his own training page
and could not find it, because the first build leaned on the native CC control and
nothing switches on for an English reader. A feature nobody can find is not shipped.
Every captioned player now carries a visible row of subtitle chips underneath, named
in their own language, with an Off option. Captions still stay off by default for an
English reader and still turn themselves on for anyone who already picked a language
with the globe button; the chips just make the choice visible instead of buried.

THE DEAD BUTTON. The inbox banner's "Add mine" shipped with NO click handler, so it
rendered and did absolutely nothing. That is why Marty could not add his address while
connected to the right wallet: nothing was listening. It now opens the same optional
profile dialog and re-renders when it completes.

Tests: gate-e2e 38 (up from 33, and rendering that button is explicitly not the test
any more, it has to actually open the dialog), captions-e2e 158 across six languages
including the new chip behaviour, clicking one and turning them back off.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 06:39:08 -05:00
martbost 91a6893df9 Member profiles are optional: an invitation on the dashboard, never a gate
Manson's objection was that requiring a username and a verified email pulls the
build back toward a centralized database of members. He is right, and the
communication gap is real too, so the answer is to ask well rather than to force.

Nothing about holding a position, getting paid, reading the org, the training or
the tools depends on contact details any more. There is no onboarding gate: a
brand-new member registers, lands on their page and is never stopped by a modal.
The dashboard offers a dismissable card ("Not now" snoozes it for a week) that
leads with the thing members actually want, a note the moment a payout lands in
their wallet, and says outright that everything works the same without it. The
inbox is the one place that asks, because a message cannot be delivered to
someone who left no way to reach them, and even there it is an invitation.

The card sits above the tab strip rather than inside the dashboard pane: the page
opens on the pitch tab, so an invitation parked in the dashboard would never be
seen by the new members it is aimed at.

For leaders, /api/public/reach answers "how many of my org can I reach off the
site", scoped by chain.isInTeam so it leaks nothing upward or sideways. That
makes coverage a leader's own problem to solve by asking, not a rule imposed on
members.

Fixes a real bug found by the rewritten suite: the dismissable flag double-booked
as "single-field edit", so saving a username in the opt-in flow closed the dialog
instead of advancing to the email step. Split into oneShot; the suite now asserts
the advance as a regression.

QA, all green: profiles-unit 28, signin-fallback 7, gate-e2e 33 (rewritten to
assert the opposite of what it used to: no forced modal, dismissable everywhere,
visitors unaffected), join-flow 12 cold / 11 refuse / 12 warm.

qa/reseed.sh carries two hard-won guards: never name a shell variable TMP on
Windows (it inherits the system temp dir and rm -rf wipes it), and never pkill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 04:44:09 -05:00
martbost 2f90e1a97f QA pass on the member profile gate: stable button ids, completion opens the dashboard tab, local devCode, 47-test E2E suite
Findings fixed: the gate's buttons had no stable ids (fragile to test and maintain), and finishing the
gate left the member on the pitch tab where the profile card and Messages are not visible, so
completion now opens the Position Dashboard tab. /api/public/profile/email-start returns devCode
outside production so the flow is testable locally, matching the InstantAdPay pattern.

qa/profiles-unit.mjs (28 assertions) and qa/gate-e2e.mjs (47 assertions, real sessions, real UI) with
a README. All pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 17:40:03 -05:00