Verify invitation signup after deploying the permanent platform adoption fix
Exercise new-recipient signup through an invitation and record the live domain, timeout handling, and Ireland platform rollout. The full WebKit flow passed against the already-staged app release.
Co-Authored-By: Codex <codex@openai.com>
2 files changed,
+75
−50
docs/infinity/status.md+18 −20test/infinity/live.mjs+57 −30
Intent
diff --git a/docs/infinity/status.md b/docs/infinity/status.md| index 995521c..95a39a0 100644 |
| --- a/docs/infinity/status.md |
| +++ b/docs/infinity/status.md |
| @@ -1,41 +1,39 @@ |
| # 🤖 ∞ status — 2026-09-06 |
| +## Try it |
| + |
| +https://ocho.chat is live with verified DNS and HTTPS. Public signup, signup through an invitation, consent and bidirectional encrypted messages passed a fresh WebKit drive after the platform fix. The two fictional accounts completed the full flow in 54 seconds; no browser errors occurred. |
| + |
| ## Implemented |
| Carlos personal-instance runtime; separate registration binary with an app-scoped instance credential, public-key-verified setup tickets, sealed proof of work and a persisted daily account budget; signed, encrypted, consent-gated DMs; group creation/acceptance/removal; flat mobile/desktop chat; ciphertext history in every participant's instance; durable outbox, retries and delivery status; encrypted account-state compare-and-swap; password-encrypted recovery and another-device restore; Myriad Pro infinity outline; isolated iOS/macOS WebKit apps. |
| -The latest registration change persists confirmed provisioning so readiness polls stop repeating allocation requests. Transient provisioning failures remain retryable on the same nonce. Tests cover failed allocation, delayed readiness, idempotent polling and recovery after a lost allocation reply. |
| +The browser keeps private keys. Invitation links survive front-door navigation, new-account setup, saved-account navigation and recovery. Requests abort after 30 seconds; signup has a two-minute deadline and distinguishes device checking, allocation and startup. Retry preserves the registration nonce and continues the same account. The broker persists confirmed allocation so readiness polls do not repeat provisioning. |
| ## Validation executed |
| -All inherited Go and Node tests passed. New Go protocol/storage tests, Chromium/WebKit registration-proof verification, Node crypto/projection tests and three-instance Chromium/WebKit drives passed, including recovery on an empty browser context. Both Apple targets compiled with signing disabled after fixing account persistence on asynchronous setup/restore. govulncheck found no reachable vulnerabilities with Go 1.25.13. |
| - |
| -A hosted WebKit drive on `https://ocho.chat` passed public registration of two fresh fictional accounts, actual invitation navigation through the front door into the recipient’s saved account, consent and bidirectional E2EE delivery without browser errors (43 seconds, 2026-09-06). Earlier signup attempts stalled on platform route materialization; the current full public-domain test passed. |
| - |
| -## Hosted state |
| +All inherited Go and Node tests passed during implementation. New Go tests/vet, Node crypto/projection tests and three-instance Chromium/WebKit drives passed, including DMs, groups, member removal, reload history, idempotent setup, encrypted recovery, mobile layout, raw SQLite/WAL plaintext absence and browser-error checks. Framework registration-worker verification passed under strict CSP. |
| -Account `ocho` / `bdy`; apps `infinity` and `infinity-home`; channel `canary/infinity`. Both apps now report build `f0b34405` from their own `/api/version` handlers; registration also reports it on `https://ocho.chat`. The registration watch initially timed out despite the edge header having advanced, because the existing process was still running the previous binary. An app-scoped `carlos restart` completed convergence; no fleet restart or database change was needed. |
| +The timeout change passed local Chromium/WebKit regressions for stalled requests, form recovery and nonce reuse, plus a deployed WebKit simulation on ocho.chat that submitted no registration. The latest public WebKit test creates its second account by following the first account's invitation, then verifies consent and encrypted messaging. Earlier tests also verified invitation navigation into an existing recipient account. |
| -Earlier restarts failed with `SQLITE_IOERR_SHMSIZE (4874)`. Read-only host metadata showed correct file ownership, 4 KB shared-memory files and roughly 95 MB of usable storage left on a 20 GiB root volume. Both canaries later woke successfully, with 32 KB shared-memory files, without database intervention. No database or WAL has been deleted/reset. A later capacity check reported roughly 114 MB available. Shared-volume expansion was prepared but not executed. A subsequent external cleanup freed roughly 9 GB; the baseline push then succeeded. Capacity was a suspected contributor to the earlier startup failure, not a proven errno diagnosis. |
| +Both Apple targets compiled with signing disabled after fixing account persistence on asynchronous setup/restore. They have not been distributed through TestFlight or a Mac installer. govulncheck found no reachable vulnerabilities with Go 1.25.13. |
| -The separate platform adoption fix is `90b0878`, branch `fix/relay-blocked-live-adoption` in `carlos/platform`. It relays permission errors replacing staged live symlinks through the existing privileged adoption pass. Its regression failed before the fix and passes afterward; independent review and full forge CI passed. The branch was pushed, but no platform change has been merged or deployed. |
| - |
| -`ocho.chat` is attached to the registration canary. DNSimple context `eleven` authenticates the Eleven Messenger team (account 176940). Its zone is active with apex A records at 99.81.104.219, 54.252.186.195, 16.60.78.128 and 44.210.206.26, TTL 300. All four endpoints passed certificate-validated HTTPS checks at 13:29 UTC. The initial certificate challenge failed before cross-edge alias propagation completed; it converged without a platform change. Registration `INFINITY_ORIGIN` and personal `INFINITY_HOME_ORIGIN` now point to `https://ocho.chat`. Public signup and encrypted messaging passed on the domain. |
| +## Hosted state |
| -## Explicit limits |
| +Account ocho / bdy; apps infinity and infinity-home; channel canary/infinity. Both apps report build f0b34405 from their own version handlers. The registration domain is ocho.chat; its backing route is infinity-home-test.bdy.oncarlos.com. Existing processes needed app-scoped restarts after promotion to load the new binaries. Initial concurrent uploads failed reading their second binary; sequential HTTP/1.1 retries shipped successfully. |
| -This is an early text-chat implementation, not an independently audited security product. Recipient-key encryption has no double-ratchet forward secrecy. Group removal takes effect at a sender when it receives the membership update; old epochs remain valid for authenticated history, with no global cutoff for delayed/backdated old-epoch messages. Web clients trust code served by their origin. Routing metadata, timing, sizes, public keys and outbound delivery capabilities are server-visible. Recovery clones the identity across devices; independent device revocation and passkey-based recovery remain future work. Apple apps share the tested web UI; universal links, background push and App Store signing are not configured. Attachments, voice and video are not implemented. |
| +DNSimple context eleven authenticates the Eleven Messenger team (account 176940). The ocho.chat zone is active with four apex A records: 99.81.104.219, 54.252.186.195, 16.60.78.128 and 44.210.206.26, TTL 300. All four endpoints passed certificate-validated HTTPS checks. The initial certificate challenge failed before cross-edge alias propagation completed; it subsequently converged. Registration INFINITY_ORIGIN and personal INFINITY_HOME_ORIGIN both point to https://ocho.chat. |
| -Source work is on `infinity-v1` in the isolated `.worktrees/infinity` checkout. The root checkout preserves the Eleven fork baseline; no main-branch merge has been performed. The user created `https://amadan.net/eleven/ocho` on 2026-09-06. The disclosed `codex` agent now has `eleven` and `carlos` grants, and local authentication has been verified. Codex CLI and Git authentication are configured. The initial baseline push was rejected with `No space left on device`. After external cleanup, the host had roughly 9 GB available and the original Eleven baseline was successfully pushed as `main`. The ∞ implementation is on the separate `infinity-v1` review branch; no implementation merge has been performed. All credentials remain outside the repository; no remote code writes should use another agent's identity. |
| +A real signup exposed a platform permission bug after the app release had already been staged: a new instance could not create its live symlink under the sandbox. A new app release initially unblocked the waiting user instance without claiming or resetting it. The permanent fix, originally 90b0878, was independently reviewed, integrated and merged through Amadan as b08445b994a63e79e62aade2823166cb88514fa5. Both branch and main passed the full platform gate, five cross-compilation targets and MinIO contract. |
| -## Invitation preview correction — 2026-09-06 (Codex) |
| +The Ireland host now runs platform b08445b. Its running executable hash was verified, services/relay paths were active, and new signup logs demonstrated the privileged adoption relay completing for already-staged releases. The rollout targeted Ireland only. The prior 66587fa binary was captured and verified for rollback; no tenant database or WAL was reset/deleted. No console deployment was needed. |
| -Invitation landing pages use the personal app’s `INFINITY_HOME_ORIGIN` setting (default `https://ocho.chat`). During DNS setup this pointed to the preview registration address; after HTTPS verification it was switched to `https://ocho.chat`. Invitation fragments survive the front-door redirect, saved-account navigation and same-origin recovery. Browser regression follows an actual invitation through the configured front door into the recipient’s existing account. |
| +Earlier disk pressure was resolved by external cleanup, freeing roughly 9 GB; this session did not expand the volume or delete shared data. The original Eleven baseline and the implementation branch are pushed to https://amadan.net/eleven/ocho under the authorized Codex agent identity. |
| -Personal release `47a9b014` is verified live, including the reserved user invitation instance’s configured home origin. Registration release `47a9b014` is also verified live after an app-scoped restart. Initial concurrent binary uploads failed reading the second part; sequential HTTP/1.1 retries shipped both releases successfully. The production WebKit invitation navigation check also passed against personal release `47a9b014`. |
| +## Explicit limits |
| -## Signup delay correction — 2026-09-06 (Codex) |
| +This is an early text-chat implementation, not an independently audited security product. Recipient-key encryption has no double-ratchet forward secrecy. Group removal takes effect at a sender when it receives the membership update; old epochs remain valid for authenticated history, with no global cutoff for delayed/backdated old-epoch messages. Web clients trust code served by their origin. Routing metadata, timing, sizes, public keys and outbound delivery capabilities are server-visible. Recovery clones the identity across devices; independent device revocation and passkey-based recovery remain future work. |
| -A real signup after the successful public smoke encountered the platform’s already-staged live-symlink permission failure: the release existed but a new personal hostname could not get its live link. No account/database reset is needed. The reviewed platform fix `90b0878` remains the durable remedy. Client requests now abort after 30 seconds, and the registration attempt has a two-minute overall deadline instead of up to 80 slow readiness requests. It distinguishes device checking from allocation and startup, re-enables retry on failure, and preserves the registration nonce so retry continues the same account. Chromium/WebKit regression simulates a stalled challenge request and checks timeout, form recovery and nonce reuse. |
| +Apple apps share the tested web UI; universal links, background push and App Store signing are not configured. Attachments, voice and video are not implemented. Amadan CI is not yet configured for the Ocho fork; local and hosted validation above ran explicitly. |
| -Release `f0b34405` is now live for both apps. Its new staging pass unblocked the waiting user instance; a read-only profile check returned HTTP 200 with setup still unclaimed. Existing processes needed app-scoped restarts to load the new live binaries. A deployed WebKit test on `ocho.chat` passed simulated request timeout, retry button recovery and registration-nonce reuse without submitting a registration. The permanent platform fix is still being prepared; later signups can encounter the already-staged permission bug until that platform rollout is complete. |
| +Source work is on infinity-v1 in the isolated .worktrees/infinity checkout. The root checkout preserves the Eleven fork baseline. No Ocho implementation merge to main has been performed. |
diff --git a/test/infinity/live.mjs b/test/infinity/live.mjs| index 0f3e384..21b24c1 100644 |
| --- a/test/infinity/live.mjs |
| +++ b/test/infinity/live.mjs |
| @@ -1,31 +1,58 @@ |
| // 🤖 Deployed-canary smoke. Only fictional accounts are provisioned. |
| -import {readFile} from 'node:fs/promises'; |
| -import {createRequire} from 'node:module';import assert from 'node:assert/strict'; |
| -const require=createRequire(process.env.INFINITY_PLAYWRIGHT_PATH||new URL('./package.json',import.meta.url));const{webkit}=require('playwright'); |
| -const home=process.env.INFINITY_TEST_HOME||'https://infinity-home-test.bdy.oncarlos.com'; |
| -const fixtures=process.env.INFINITY_TEST_ACCOUNTS_FILE?JSON.parse(await readFile(process.env.INFINITY_TEST_ACCOUNTS_FILE,'utf8')):null; |
| -const started=Date.now(); |
| -const browser=await webkit.launch({headless:true});const errors=[];const pages=[]; |
| -try{ |
| - await Promise.all(['Canary Alice','Canary Bob'].map(async (name,index)=>{ |
| - const ctx=await browser.newContext(),page=await ctx.newPage();page.setDefaultTimeout(90000);pages[index]=page; |
| - page.on('pageerror',e=>errors.push(e.message));page.on('console',m=>{if(m.type()==='error')errors.push(m.text())}); |
| - const fixture=fixtures?.[index]; |
| - await page.goto(fixture?fixture.origin+'/#claim='+fixture.claim:home);await page.getByLabel('Your name',{exact:true}).fill(name);await page.getByRole('button',{name:'Create your account',exact:true}).click(); |
| - await page.getByRole('button',{name:'Invite',exact:true}).waitFor(); |
| - })); |
| - const[a,b]=pages; |
| - await a.getByRole('button',{name:'Invite',exact:true}).click();await a.getByRole('button',{name:'Create invitation',exact:true}).click();const link=await a.getByLabel('Invitation link').inputValue();await a.getByRole('button',{name:'Close',exact:true}).click(); |
| - if (fixtures) { |
| - await b.locator('.account-menu summary').click();await b.getByRole('button',{name:'Connect with a link',exact:true}).click();await b.getByLabel('Invitation link').fill(link); |
| - } else { |
| - await b.goto(link);await b.getByRole('button',{name:'Continue',exact:true}).click(); |
| - await b.getByRole('button',{name:'Open your account',exact:true}).click(); |
| - assert.equal(await b.getByLabel('Invitation link').inputValue(),link); |
| - } |
| - await b.getByRole('button',{name:'Connect',exact:true}).click();await b.getByRole('dialog').waitFor({state:'detached'}); |
| - await a.getByRole('button',{name:'Accept',exact:true}).click();await a.getByRole('heading',{name:'Canary Bob',exact:true}).waitFor(); |
| - await b.locator('.thread-row').filter({hasText:'Canary Alice'}).click();await b.getByRole('textbox',{name:'Message',exact:true}).fill('The live encrypted delivery works.');await b.getByRole('button',{name:'Send message',exact:true}).click();await a.getByRole('log').getByText('The live encrypted delivery works.',{exact:true}).waitFor(); |
| - await a.getByRole('textbox',{name:'Message',exact:true}).fill('Confirmed from the other personal instance.');await a.getByRole('button',{name:'Send message',exact:true}).click();await b.getByRole('log').getByText('Confirmed from the other personal instance.',{exact:true}).waitFor(); |
| - assert.deepEqual(errors,[]);console.log(JSON.stringify({result:'passed',elapsedMs:Date.now()-started,home,accounts:pages.map(p=>new URL(p.url()).origin),browser:'webkit',scenarios:[fixtures?'pre-provisioned test-account setup':'public registration','distinct personal instances','invitation and consent','bidirectional E2EE delivery','no browser errors']})); |
| -}catch(e){for(let i=0;i<pages.length;i++)console.log('PAGE',i,new URL(pages[i].url()).origin,await pages[i].locator('body').innerText());throw new Error(e.message.split('Call log:')[0]);}finally{await browser.close();} |
| +import { readFile } from 'node:fs/promises'; |
| +import { createRequire } from 'node:module'; |
| +import assert from 'node:assert/strict'; |
| +const require = createRequire(process.env.INFINITY_PLAYWRIGHT_PATH || new URL('./package.json', import.meta.url)); |
| +const { webkit } = require('playwright'); |
| +const home = process.env.INFINITY_TEST_HOME || 'https://ocho.chat'; |
| +const fixtures = process.env.INFINITY_TEST_ACCOUNTS_FILE ? JSON.parse(await readFile(process.env.INFINITY_TEST_ACCOUNTS_FILE, 'utf8')) : null; |
| +const started = Date.now(), browser = await webkit.launch({ headless: true }); |
| +const errors = [], pages = []; |
| +async function create(index, invite) { |
| + const context = await browser.newContext(), page = await context.newPage(); |
| + page.setDefaultTimeout(90000); pages[index] = page; |
| + page.on('pageerror', error => errors.push(error.message)); |
| + page.on('console', message => { if (message.type() === 'error') errors.push(message.text()); }); |
| + const fixture = fixtures?.[index]; |
| + await page.goto(fixture ? fixture.origin + '/#claim=' + fixture.claim : invite || home); |
| + if (invite) await page.getByRole('button', { name: 'Continue', exact: true }).click(); |
| + await page.getByLabel('Your name', { exact: true }).fill(['Canary Alice', 'Canary Bob'][index]); |
| + await page.getByRole('button', { name: 'Create your account', exact: true }).click(); |
| + // An invitation opens the connection dialog as soon as setup completes. |
| + if (invite) await page.getByLabel('Invitation link').waitFor(); |
| + else await page.getByRole('button', { name: 'Invite', exact: true }).waitFor(); |
| + return page; |
| +} |
| +try { |
| + const a = await create(0); |
| + await a.getByRole('button', { name: 'Invite', exact: true }).click(); |
| + await a.getByRole('button', { name: 'Create invitation', exact: true }).click(); |
| + const link = await a.getByLabel('Invitation link').inputValue(); |
| + await a.getByRole('button', { name: 'Close', exact: true }).click(); |
| + // The recipient begins with only the invitation, exactly like a new member. |
| + const b = await create(1, fixtures ? null : link); |
| + if (fixtures) { |
| + await b.locator('.account-menu summary').click(); |
| + await b.getByRole('button', { name: 'Connect with a link', exact: true }).click(); |
| + await b.getByLabel('Invitation link').fill(link); |
| + } else assert.equal(await b.getByLabel('Invitation link').inputValue(), link); |
| + await b.getByRole('button', { name: 'Connect', exact: true }).click(); |
| + await b.getByRole('dialog').waitFor({ state: 'detached' }); |
| + await a.getByRole('button', { name: 'Accept', exact: true }).click(); |
| + await a.getByRole('heading', { name: 'Canary Bob', exact: true }).waitFor(); |
| + await b.locator('.thread-row').filter({ hasText: 'Canary Alice' }).click(); |
| + await b.getByRole('textbox', { name: 'Message', exact: true }).fill('The live encrypted delivery works.'); |
| + await b.getByRole('button', { name: 'Send message', exact: true }).click(); |
| + await a.getByRole('log').getByText('The live encrypted delivery works.', { exact: true }).waitFor(); |
| + await a.getByRole('textbox', { name: 'Message', exact: true }).fill('Confirmed from the other personal instance.'); |
| + await a.getByRole('button', { name: 'Send message', exact: true }).click(); |
| + await b.getByRole('log').getByText('Confirmed from the other personal instance.', { exact: true }).waitFor(); |
| + assert.deepEqual(errors, []); |
| + console.log(JSON.stringify({ result: 'passed', elapsedMs: Date.now() - started, home, |
| + accounts: pages.map(page => new URL(page.url()).origin), browser: 'webkit', |
| + scenarios: [fixtures ? 'pre-provisioned test-account setup' : 'public registration + new recipient signup through invitation', |
| + 'distinct personal instances', 'invitation and consent', 'bidirectional E2EE delivery', 'no browser errors'] })); |
| +} catch (error) { |
| + for (let i = 0; i < pages.length; i++) console.log('PAGE', i, new URL(pages[i].url()).origin, await pages[i].locator('body').innerText()); |
| + throw new Error(error.message.split('Call log:')[0]); |
| +} finally { await browser.close(); } |