From 5fe7d9a28e19f8fdc563327bfba7a13dc33c1d11 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 15 Nov 2026 14:37:36 -0700 Subject: Ask for a way back in once, and only when there's money to lose. "Let's only prompt to add a way back in after there's some balance and only if we haven't prompted before" (Adam, 2026-11-15). A sign-up's wallet no longer carries the reminder line from its first minute. The first time it holds anything (Spending, Savings or an incoming payment) and has no way back in yet, it shows one notice: 'You have bitcoin in here now. Add a way back into your account, in case you lose this device.' with Add one (→ Settings → Wallet) and Not now. That's recorded on the account as soon as it shows (directory and synced snapshot too), so it stays for that visit and never comes back, here or on another device. Seed wallets opened by sign-in keep their old phrase reminder. signup-quick-test: nothing on an empty account; given a Spending balance it asks; Not now; not again after a reload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VMan6SwkivduFDDkMmnXjZ --- tools/signup-quick-test.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/signup-quick-test.js b/tools/signup-quick-test.js index d184457..a269faf 100644 --- a/tools/signup-quick-test.js +++ b/tools/signup-quick-test.js @@ -82,7 +82,32 @@ try { })); let s = await shape(); check('in, on Spending alone (no Savings face, no name on it)', s.faces === 1 && !s.carousel && !s.label, JSON.stringify({ faces: s.faces, carousel: s.carousel, label: s.label })); - check('a quiet line asks for a way back in', /add a way back into your account/i.test(s.body)); + // asked once, and only with money in the account (2026-11-15): not on an empty one + check('no way-back-in prompt on an empty account', !/add a way back into your account/i.test(s.body) && !(await page.$('.ways-back-prompt'))); + // money arrives in Spending (the ark feature, found on the heap, made to + // report a balance; then a repaint) + const giveBalance = async () => { + const protoH = await page.evaluateHandle(() => Object.prototype); + const all = await page.queryObjects(protoH); + const found = await page.evaluate((objs) => { + const f = objs.find((o) => { try { return o && o.id === 'ark' && typeof o.spendingSat === 'function'; } catch { return false; } }); + if (!f) return false; + f.spendingSat = () => 5000; + window.dispatchEvent(new Event('resize')); + document.querySelector('.tabs button')?.click(); document.querySelector('.tabs button')?.click(); + return true; + }, all); + await all.dispose(); await protoH.dispose(); + await sleep(800); + return found; + }; + check('(test: found the ark feature)', await giveBalance()); + check('with a balance, it asks once for a way back in', !!(await page.$('.ways-back-prompt')), (await text()).slice(0, 300).replace(/\n/g, ' | ')); + await page.evaluate(() => [...document.querySelectorAll('.ways-back-prompt button')].find((b) => /not now/i.test(b.textContent)).click()); await sleep(400); + check('Not now puts it away', !(await page.$('.ways-back-prompt'))); + await page.reload({ waitUntil: 'domcontentloaded' }); await page.waitForSelector('.balance-face', { timeout: 20000 }); await sleep(1500); + await giveBalance(); + check('...and never again, not after a reload', !(await page.$('.ways-back-prompt'))); for (let i = 0; i < 60 && !(await page.$('#recv-amount')); i++) await sleep(250); check('Receive has an Amount button', !!(await page.$('#recv-amount'))); check('no History heading on an empty wallet', !/\bHISTORY\b/.test(await page.evaluate(() => document.body.innerText))); @@ -110,7 +135,6 @@ try { const pk = await page.evaluate(() => ({ rows: [...document.querySelectorAll('.ways-back-row')].map((e) => e.dataset.way), err: document.querySelector('.ways-back .notice.err')?.textContent || '' })); check('adding a passkey lists it', pk.rows.includes('passkey') && !pk.err, JSON.stringify(pk)); const backups = await page.evaluate(() => (window.__relayGuard.events || []).filter((e) => e.kind === 30078 && e.tags.some((t) => t[0] === 'd' && t[1] === 'coinos:wallet:v1'))); - check('the reminder line is gone once there is a way back in', await (async () => { await page.goBack(); await page.goBack(); await sleep(600); const gone = !/add a way back into your account/i.test(await text()); await openWalletPage(); return gone; })()); // the list and the reminder, as the app sees them (record a method directly) check('the phrase card waits behind Pen and paper', !(await page.$('.recovery-card'))); await page.evaluate(() => document.querySelector('.ways-back-add[data-way="phrase"]')?.click()); -- cgit v1.2.3