Commit Graph

240 Commits

Author SHA1 Message Date
martbost 1d52597c1c Fix missing QR on every member page — blocked by our own CSP
The QR on /p/<id> and /p/<id>/<slug> was drawn by an inline <script>, but the
site sends `script-src 'self'` with no 'unsafe-inline'. The browser silently
refused to run it, so the QR box rendered as an empty white square on every
member page, not just Funnel Factory ones.

Moved the bootstrap to /page-qr.js and pass the link via a data attribute, so
no page data is interpolated into executable script and the CSP stays as
strict as it is. Loosening script-src to fix this would have traded a
site-wide security property for one widget.

This matters more than it looks: these pages go on printed flyers and ad
destinations, where an unscannable QR is discovered by the person holding the
paper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 11:28:48 -05:00
martbost 7ca89f25ee Fix tool wall ordering, and make suite-me use the one entitlement helper
Two bugs Marty spotted from a screenshot of his own wall.

1. The Traffic Desk rendered between L5 and L6 under a stray second
   "L1 SCINTILLA" header. The wall emits a section header whenever the level
   changes while walking the TOOLS array, and the Traffic Desk was still in
   its original L5 array slot from before it moved to L1. Now the wall sorts
   by level before rendering, so the array can be edited in any order and
   this class of bug cannot come back.

2. Tiles above L4 still showed "UNLOCKS AT ..." despite suiteLevelOverride.
   /api/public/suite-me carried its OWN copy of the org/allowlist logic
   rather than calling suiteEntitlement, so the override reached every tool
   page but not the wall linking to them. That duplication is the actual
   defect — the route now calls the shared helper, and the override also
   carries levelName so the header cannot disagree with the tiles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 11:18:08 -05:00
martbost f05d5a2746 Founder Desk (L8): weekly campaign pack + Suite API
Completes the ladder — no tier is a placeholder now.

Every tier below builds one thing at a time, which is right for someone
still finding their words. At the top the constraint is different: these are
people running organisations who don't have an afternoon to spend clicking.
So one pass produces five social posts across five different angles, three
outreach messages (first approach, follow-up, pyramid-scheme answer), an
email, and three text ads — all carrying their link, all in the member's own
voice profile if they have one.

Partial failures are reported rather than hidden: if the engine can't finish
a section the pack says which, instead of quietly handing over a short week.

API access is real, not a label: a personal key over
GET /me, GET /team, POST /generate. Keys are stored hashed and shown exactly
once, compared in constant time, and every call goes through the same meters
and compliance rules as the web tools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 11:09:48 -05:00
martbost 3f8d23d66c Circle Suite: complete the ladder — every paid level now unlocks live software
Four new tools, so no tier is a placeholder any more:

L4 Voice Profile (/suite/voice) — five short answers that ride along with
every Copy Engine and Email Engine generation. It sits BEFORE the compliance
block in the prompt on purpose: a personal voice must never be able to talk
the model out of the honesty rules. suite-email builds its own prompt, so the
profile is threaded in there separately or email would keep sounding generic
while the Copy Engine sounded like the member.

L5 Split Tester (/suite/split) — 2-3 variants launched as one test with the
impressions split evenly, then click counters compared. Deliberately
conservative: it will not declare a winner until both arms have real volume
AND the leader is clearly ahead, because a 3-click gap on 400 impressions is
noise. A genuine tie is reported as a tie, which is useful information too.
A failed arm rolls back the whole test rather than leaving half of it running.
Apex is the right home for it — that is where impressions jump to 50,000.

L6 Funnel Factory (/suite/funnel) — extra named pages at /p/<id>/<slug>, so a
leader can run one page per audience and point different ads at each. Missing
slugs fall back to the member's main page, same no-dead-ends rule as /p/<id>.

L7 Leader Ops (/suite/leader) — the coaching radar already existed in chain.js
and only admin could see it, which was backwards: the leaders running those
legs need it more than anyone. Now scoped to the member's own organisation,
with a written plan built on contract-read facts only. Follows the
teach-forward rule — the digest gives the leader words to hand down, not just
numbers to act on.

Tile copy across the wall and the payout alerts now describes what actually
exists rather than what was sketched. suite-tools.js was stale in both
directions (it still had the Traffic Desk at L5 and L3 not live).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 10:49:36 -05:00
martbost d5c9e33e0e Traffic Desk: AI-written text ads alongside banners
Text placements out-perform banners on this network — 357 text ads average
~171 clicks each against ~150 for banners, on far less inventory — so
members can now run them too.

The format is measured, not guessed. Across 60 live text ads: Subject caps
at 20 characters and Body is ALWAYS exactly three <br>-joined lines of at
most 24 characters. Every ad in the sample obeyed it.

Emoji: the NAS columns are latin1, but so is the connection, so UTF-8 bytes
pass through and render — which is how the existing emoji ads got there. The
bridge's clean() would have deleted every emoji via iconv //TRANSLIT//IGNORE,
so text copy now uses clean_ad_text(), which preserves them and strips angle
brackets instead. The bridge builds the <br> separators itself from a lines[]
array, so a member can never inject markup.

The engine writes plain text to a tight budget and we apply emoji ourselves:
models cannot count characters, least of all with emoji, so decoration is
arithmetic we control. It also lets the emoji rotate independently of the
copy. The palette carries no money emoji — the network is full of them, but
implying earnings outranks matching the neighbours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 10:19:36 -05:00
martbost 931eb4336b Traffic Desk: stop-and-refund, plus never let a banner dead-end
Three fixes from live testing of the Traffic Desk:

- /p/<id> with no page built now 302s to /join/<id> instead of returning
  raw JSON 404. Any /p/ link already on a banner, flyer, or in a DM must
  always land somewhere useful.
- The personal-page ad destination is only offered (client) and only
  accepted (server) once a page actually exists; otherwise the member is
  pointed at the Page Builder.
- Members can stop a running banner and get the unserved impressions back
  in their monthly balance. Counters are read before deactivation, since
  deactivating zeroes `remaining` and would look fully served.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 10:03:38 -05:00
martbost f7276589e9 Traffic Desk ships: signed NAS bridge client, monthly impression allowance by level (2.5k Scintilla -> 150k Corona), team-kit creative only (no member uploads = no moderation risk), local grant ledger, live serve stats; tile moved to L1 since credits are included at every paid level
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 09:50:03 -05:00
martbost 6c73b5d9c5 Page Builder fixes from Marty's test: our own CSP frame-src blocked framing our member pages (preview showed broken) — add 'self'; /p/<id> now sends explicit permissive framing headers so member pages always render embedded; button label tracks whether a page exists; live progress line with step narration + elapsed seconds; stale preview hidden during rebuild and cache-busted after
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 08:56:32 -05:00
martbost 44816571b6 Video Maker ships (L3): ffmpeg end-card composite over the team master videos (member name + link + server-generated QR as PPM), audio preserved, metered; ffmpeg+ttf-dejavu added to the image; tile live
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 08:37:59 -05:00
martbost 7c3e98eaa9 Email Engine ships (L3): sequence generation (welcome/follow-up/re-engagement/broadcast) on the Suite engine with tolerant EMAIL/SUBJECT/BODY parsing, per-email copy buttons, metered; tile live
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 08:17:24 -05:00
martbost f7d5c3f358 Syndicated network display advertising language: homepage toolkit card, how-pay-works toolkit section, Suite Traffic Desk tile, AI prompt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:36:30 -05:00
martbost 7f289bb495 Policies + tools angle: /privacy and /refunds pages (crypto payments are final, we never hold funds), footer links sitewide, toolkit section on How You Get Paid, toolkit line on Getting Started
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:32:51 -05:00
martbost 6a7867588d Page Builder ships: labelled-section AI output parsed deterministically, escaped renderer, one page per position at public /p/<id> with angle video + QR, rebuild keeps the same URL; L2 tile live
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 07:15:11 -05:00
martbost 2a8b311a83 Copy Engine ships: Suite AI layer (own engine, RM facts + compliance in our system prompt, deterministic link injection), metered generate/meters APIs, /suite/copy tool page; L2 tile now live
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 06:51:16 -05:00
martbost 323c86b750 L6 tile: 'webinar rooms' -> Replay Funnels (evergreen registration page around a recorded team webinar, timed CTA); AI prompt clarifies it is NOT live conferencing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 06:44:16 -05:00
martbost 35b3c07e74 Fix Suite org check: teamRootId is a comma-separated list, Number() made it NaN so every member read as outside the org (Marty hit this as #21); parse all roots + orgRootId fallback. Nav dedupe on /suite. Adds suite-meter module (per-position monthly quotas by level)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 06:33:08 -05:00
martbost 6f28e94abd Suite team-beta gate: config.suiteAllowlist restricts entitlements to listed IDs (others get an honest 'you're early' notice); homepage CTA + chatbot answer held until launch; AI prompt marked private-beta
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 05:22:50 -05:00
martbost 0258b82a16 Circle Suite P0: /suite tool wall — wallet sign-in (existing challenge/verify flow), live level entitlements via /api/public/suite-me (org-gated to teamRootId), all tiles always visible (yours / unlocks-at / in-development), L1 = today's real tools; homepage CTA + chatbot + AI prompt synced
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 05:19:09 -05:00
martbost 1259e5284a Confident product framing: 'every paid member gets a license to the toolkit' (drop the defensive what's-the-product line); hero weaves teach-forward-with-tools
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 04:51:41 -05:00
martbost feb9dec0ac Product-centric homepage: hero leads with the marketing toolkit (config override updated to match); toolkit section reframed as the product; printables card covers handouts + Generation Pay chart
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 04:33:06 -05:00
martbost ad5c5721aa Wallet-connect resilience: contract costs are immutable constants, so bake verified wei fallbacks for when the wallet's internal RPC fails (MetaMask iOS 'Load failed'); friendlier retry message on network hiccups
join-now.js entry price + my.js upgrade table. Reported by Neville's team overnight 8/28.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 04:03:18 -05:00
martbost 21e105b953 /generation-pay: printable generation-pay chart personalized from the live chain (level/tier/qualification -> catching vs needs-Level-N per generation); dashboard + how-pay-works links, chatbot + AI prompt synced; exact-costs card now states the exact one-catch identity
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:34:20 -05:00
martbost 30a5c7237e Training Video 7 'Your level is your reach' (97s, script Marty-approved): catch eligibility + reach rule + pass-over + one-catch funding identity; how-pay-works first-catch line tightened to exact; chatbot + AI prompt synced
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 13:23:08 -05:00
martbost 1029bdb3e2 Two hard-question objection cards from live member Q&A (catch-eligibility: level = reach; fixed counts vs quadrupling value) + chatbot + AI prompt synced
Both verified against contract source today (payout loop: level > levelIndex && 2 directs; one structural skip per depth).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 12:59:09 -05:00
martbost 79282af325 Level-scale full-generation totals aligned to exact contract math (were computed from pre-rounded per-person values, drifting up to 31 POL at Vertex)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 11:50:53 -05:00
martbost b76a590714 Correct #exact-costs: entry exists ONLY at Scintilla (register() has no level param; upgrade() one rung per call) — levels cannot be skipped; table now shows upgrade path + cumulative totals; AI prompt synced
Verified against the exact-match ABI on Sourcify: per-level entry rows on company charts are vestigial contract data with no callable path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 11:32:43 -05:00
martbost bdfb40667e Contract-exact price table (#exact-costs on how-pay-works) + entry-vs-upgrade objection card; chatbot + AI prompt synced
Live getAllCosts() numbers: entry 360.58 incl 5% (sponsor 326.24), upgrades double exactly per level, 100% member-to-member. Answers the 'why is entry different from upgrade / is the chart inflated' question with verifiable numbers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 11:08:07 -05:00
martbost 8858470244 stopwaiting angle: squeeze page on the lander (combined overview video) + handout QR now carries ?v=stopwaiting
The stop-waiting handout QR previously hit the plain join page with no angle continuation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 10:11:41 -05:00
martbost 7fb7a6c0d1 Remove tear-off full-page flyers; /flyers is now the five artwork handouts only
Marty: the tear-off designs did not look good next to the artwork handouts. Page renamed Printable Handouts; dashboard link, tools card/nav, chatbot answer, and AI prompt synced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 09:25:17 -05:00
martbost a8f3a1290e No trailing blank print page: cancel page-break-after on the last/only printed design
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 08:48:26 -05:00
martbost e83f2543fd Print sizing in physical inches: 100vh broke print-to-PDF from mobile (design overflowed to 2 pages, split second copy)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 08:42:21 -05:00
martbost 792fa1d97b Phone handout art v2: no baked-in button (QR panel overlapped it), calm lower-right
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 08:31:16 -05:00
martbost e03ccb479d Handout art as optimized JPEGs (~330KB each vs 3MB PNGs); new filenames bust stale caches
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 08:19:56 -05:00
martbost c4cabb0a8f Handouts v2: kie.ai detailed artwork backgrounds + fixed DOM overlay (mobile layout repaired)
Five full-bleed AI-generated designs (nano-banana-pro) with baked-in stylized headlines matching the banner-kit energy; QR + link + disclaimer now a percentage-scaled DOM overlay (canvas approach removed - it collapsed on mobile and clipped the QR). Lower-right of each artwork kept calm for the QR panel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 08:15:59 -05:00
martbost b019becebe Image-based half-sheet handouts: vibrant gradient backgrounds with dynamic QR overlay
Replaces text-heavy card design with eye-catching image backgrounds (pocket/two/phone/graveyard/stop-waiting angles, 1700x1100px, half-sheet 2-per-page format). QR code + link overlaid dynamically via Canvas in bottom-right with semi-dark fade for readability. Print layout: two copies per letter page with cut line between. Visual impact first, clean overlay on top.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 07:47:52 -05:00
martbost 3761fab3c6 Half-sheet handouts on /flyers: 5 vibrant angle designs (pocket, two, phone, graveyard, stop-waiting), 2 per letter page with cut line, personalized QR + angle-matched links; chatbot + AI prompt + tools card synced
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 07:31:40 -05:00
martbost 3a877add05 Host full banner set at /banners: colorful teambuild variants, graveyard, circle-method, stop-waiting, all ad sizes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 05:38:18 -05:00
martbost df5f94573e Printable flyers feature: 4 colorful personalized flyer designs with member QR + tear-off tabs for offline promotion; /flyers route, tools + dashboard links, chatbot + AI prompt synced 2026-08-26 16:55:50 -05:00
martbost 4b53dd5326 Direct link option: opt out of moving-link rotation to build personal spillover (Team link default, Direct link alternate) 2026-08-26 14:24:32 -05:00
martbost 6282e8c768 Triple Play: add the upgrade strategy (concentrate on the top position; pass-ups bubble up to it) 2026-08-26 08:13:33 -05:00
martbost 04a0ae1c6a Triple Play: correct the wallet guidance (separate addresses; MetaMask add-account switch gotcha -> already-registered) 2026-08-26 08:02:21 -05:00
martbost c3d28f17a8 The Triple Play: optional 3-position fast-start (how-pay-works section + objection card + chatbot + AI prompt) 2026-08-26 07:50:58 -05:00
martbost 76785288e4 Corona promo: add ElevenLabs-generated music bed under the VO 2026-08-26 07:21:57 -05:00
martbost 1ba525a643 Add Corona pass-up-flow motion promo (32s) to tools video clips 2026-08-26 07:04:20 -05:00
martbost ced4bec462 wallet-notice: show only once per page (was repeating under every gated training video) 2026-08-26 06:21:37 -05:00
martbost cffaf4ffc0 how-pay-works: Does it cap at 8 levels explainer (pass-ups bubble up; Corona catches all) + chatbot + AI prompt 2026-08-26 06:17:07 -05:00
martbost 1f5bcd688f how-pay-works: What each level opens up scaling table (illustration, not a promise) + dashboard link 2026-08-26 06:00:31 -05:00
martbost be129a46a4 Fix SIWE chain-mismatch: switch wallet to Polygon 137 before sign-in and members-area unlock 2026-08-26 05:36:26 -05:00
martbost b923bc18bc Dashboard level ladder: show POL upgrade cost under each level (live from contract, USD in tooltip) 2026-08-26 05:22:30 -05:00
martbost 6cf78a37b7 Wallet discovery: detect Phantom (window.phantom.ethereum) + legacy providers[]
Phantom exposes its EVM provider at window.phantom.ethereum and does not always
fire EIP-6963, so the picker never saw it. probeInjected() now folds in Phantom
and any window.ethereum.providers[] entries (deduped by identity + name) for
both pick() and list(). Phantom added to the mobile in-app-browser hint and the
dashboard no-wallet message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 05:14:57 -05:00