fix(frontend): EVM Legal Accept dead-ends on portal (Binance Web3 / MetaMask iOS) #16

Closed
opened 2026-08-30 15:47:44 +00:00 by PlasticDigits · 6 comments
PlasticDigits commented 2026-08-30 15:47:44 +00:00 (Migrated from gitlab.com)

Summary

Community report (2026-08-30) on production Legal portal: after consent, Connect & sign showed Error: No EVM wallet found (install MetaMask or similar) for Binance Web3 and again for MetaMask on iOS.

That failure is implemented in Legal (web/src/pages/evm.ts) — tracked as cl8y-ecosystem-legal#15. Voting is the EVM integrator that sends users into it.

This dApp can connect MetaMask / WalletConnect on vote.cl8y.com (Bridge-style wagmi, #6). Unsigned EVM wallets then hit ConnectedTermsGate → Accept Terms → full navigation to sign_urls.evm (https://terms.cl8y.com/sign/evm?property=vote.cl8y.com). The Legal page does not inherit the voting WalletConnect session. Safari / Chrome still have no window.ethereum. The user is stranded after they already connected here.

Terra already has LegalKeplrInAppHint for the same class of problem (DEX #554 / WC-M12). EVM has no equivalent. skills/AGENTS_LEGAL_CLICKWRAP.md already says: “Same class of hint for EVM in-app browsers.”


Current codebase


Why this is needed

  • Voting’s BSC electorate (#4) is EVM. Retail users are on mobile (Binance Web3, MetaMask iOS).
  • Connecting on voting is not enough: terms evidence is created on the portal. A WC/injected session on vote.cl8y.com does not follow the user to terms.cl8y.com.
  • Without a voting-side next step, Accept looks like it will work and then repeats Legal #15. Terra users already get “Open this site in the Keplr browser…”.
  • Legal #15 is the portal fix. Voting still needs: (1) not to dead-end UX before that ships, (2) to pass account=0x… for continuity once Legal binds it, (3) to re-verify the round-trip after Legal ships.

Constraints / guardrails

  1. Do not reimplement Legal EIP-191 / POST /signatures/wallet in voting. Portal full navigation only — no iframe Accept, no in-dApp terms personal_sign (#5, AGENTS_LEGAL_CLICKWRAP.md).
  2. Do not skip TermsGate after WalletConnect or injected connect (#12). Unsigned / unknown status stays fail-closed.
  3. Network match: EVM address → network="EVM" / status EVM. Do not check TERRA_CLASSIC for a 0x account (or the reverse).
  4. redirect_uri: keep resolveLegalRedirectUri sanitize + https://vote.cl8y.com allowlist. Portal allowlist remains authoritative (#8 /vote 200). Do not mint redirect from Host. Deep-link / copy-link targets are the Legal sign URL, not an arbitrary query URL.
  5. account query: pass the connected checksum/0x address only as the integrator-claimed account. Never treat account as a redirect target. Do not put other users’ addresses on the Accept URL from untrusted input.
  6. No Legal ADMIN_TOKEN in this frontend. No new WalletConnect Cloud id for terms (Legal owns portal WC).
  7. CSP unchanged: no blanket connect-src https:.
  8. Copy: retail-short. Do not tell phones to install a desktop MetaMask extension. Do not call Legal sign a vote.
  9. Production E2E hatch unset. prodEnvGuards / Dockerfile still fail if VITE_PLAYWRIGHT_E2E is set on Coolify.
  10. Prefer extending LegalKeplrInAppHint (or a shared “Legal in-app browser” helper) over a second gate. Terra Keplr copy must keep working.

Relevant files

Area Path
Gate frontend/src/components/legal/ConnectedTermsGate.tsx
Terra-only hint frontend/src/components/legal/LegalKeplrInAppHint.tsx, frontend/src/utils/legalKeplrInAppHint.ts
Identity / network frontend/src/hooks/useConnectedIdentity.ts
Legal client / redirect frontend/src/utils/legalClickwrap.ts
Vendor SDK fallback frontend/src/vendor/cl8y-clickwrap.ts, frontend/src/vendor/cl8y-clickwrap-react.tsx
Tests frontend/src/components/legal/__tests__/ConnectedTermsGate.test.tsx
Skill skills/AGENTS_LEGAL_CLICKWRAP.md, skills/AGENTS_WALLET_CONNECTORS.md
Legal portal (dependency) cl8y-ecosystem-legal#15

Stage on voting; do not wait to document the dead-end:

  1. EVM in-app / copy hint (this repo, independent of Legal #15): when legalNetwork === 'EVM', signed_latest === false, and there is no injected EIP-1193 in this page (or user connected via WalletConnect), show the same class of CTA as Keplr: Open in MetaMask, Open in Binance Web3 (documented universal / dapp-browser links whose url is the Legal sign URL with property, redirect_uri, app_name, and account), plus Copy link. Idle copy: Chrome/Safari cannot finish terms; open the Legal page in the wallet app browser. If a documented Binance dapp URL cannot be confirmed, still ship Copy-link + MetaMask rather than inventing a scheme.
  2. Pass account: use published SDK buildSignUrl({ account }) (and align vendor fallback). Connected 0x… must appear on the portal query so Legal can bind continuity when #15 lands.
  3. After Legal #15: Accept from voting in system Safari/Chrome must complete signed_latest for (vote.cl8y.com, EVM, 0x…) via portal Open-in-app or portal WalletConnect — then return to allowlisted vote.cl8y.com path (#8).
  4. Do not implement portal personal_sign inside voting to “avoid” Legal.

Acceptance criteria

  • Unsigned EVM user on mobile Chrome/Safari never gets only an Accept button that lands on Legal No EVM wallet found (install MetaMask or similar) with no next step on voting (hint and/or copy Legal link) and Legal #15 remaining the portal fix.
  • Accept URL includes property=vote.cl8y.com (or VITE_LEGAL_PROPERTY), sanitized redirect_uri, app_name=CL8Y Voting, and connected account=0x….
  • Terra LegalKeplrInAppHint still shows for unsigned Terra without Keplr extension; still hidden for EVM.
  • TermsGate still fail-closes propose/vote when signed_latest is false or status errors. WC connect does not skip the gate.
  • After Legal #15: happy path MetaMask iOS or Binance Web3 → Accept → portal sign → signed_latest: true for EVM → return to voting page (200, not /vote 404).
  • Desktop injected MetaMask on voting → Accept → portal still works.
  • Vendor fallback buildSignUrl / TermsGate pass account if the published package is missing.
  • Skill updated: EVM hint is required, not a parenthetical.

Test plan (functional paths)

  1. Disconnected: browse OK; no Legal status fetch (existing test).
  2. EVM unsigned, no inject: Accept visible; EVM in-app/copy hint visible; Keplr hint absent. Propose/vote hidden.
  3. EVM unsigned, WalletConnect connector: same hint (Legal will not see this WC session).
  4. EVM signed_latest true: children render; hint hidden.
  5. Terra unsigned, no Keplr: existing Keplr hint still shows; EVM MetaMask/Binance CTAs absent.
  6. Accept href: sign/evm, property, redirect_uri origin allowlisted, account matches connected address (checksum vs lowercase both OK to send; portal lowercases).
  7. Evil redirect: resolveLegalRedirectUri still drops non-allowlisted origins (existing sanitize tests).
  8. Wrong network: EVM address never queried as TERRA_CLASSIC.
  9. Playwright hatch: VITE_PLAYWRIGHT_E2E=true still skips gate in e2e only.
  10. Manual after Legal #15: iOS Safari WC connect on voting → hint → Open in MetaMask or paste in Binance Web3 → terms signed → back on vote.cl8y.com.
  11. Manual: Binance Web3 in-app on voting (injected) → Accept stays in WebView → portal discovery (#15) or existing inject succeeds.

Test plan (attack / abuse / hack vectors)

Vector Expectation
Skip TermsGate after WC Still gated until Legal signed_latest (#12)
account= on Accept URL for a different 0x than connected Must be the connected store address only; do not read account from query to overwrite
redirect_uri open redirect via Accept Sanitize + portal allowlist; no javascript:
Hint / copy-link uses attacker URL Only Legal terms origin + current sign path/query from API sign_urls (or constructed from getLegalTermsBaseUrl + property). Do not open arbitrary https:// from wallet payloads
Treating Legal sign as a vote Voting evmSign.ts payloads stay separate; Legal URL not used for register/propose/vote
Status API error Fail closed (no propose/vote)
LocalStorage “accepted” flag Not Legal proof
VITE_PLAYWRIGHT_E2E in prod image Build/guard fail
XSS in hint / account display Text nodes only

Verification criteria

  • Manual: unsigned BSC wallet on mobile system browser at https://vote.cl8y.com — sees a working next step for terms (copy/open in MetaMask or Binance), not a silent trip to Legal #15 with no explanation.
  • Manual (blocked on Legal #15): complete EVM terms from that path; GET /api/v1/signatures/status?property=vote.cl8y.com&network=EVM&account=0x… is signed_latest: true; return URL is voting origin.
  • ConnectedTermsGate unit tests green for EVM hint presence/absence and account on Accept URL.
  • Terra Keplr hint tests still green.
  • Production Coolify still has Legal hatch unset.

Depends on: cl8y-ecosystem-legal#15 for the portal sign itself. This issue is the voting gate / hint / account continuity.

## Summary Community report (2026-08-30) on production Legal portal: after consent, **Connect & sign** showed `Error: No EVM wallet found (install MetaMask or similar)` for **Binance Web3** and again for **MetaMask on iOS**. That failure is implemented in Legal (`web/src/pages/evm.ts`) — tracked as [cl8y-ecosystem-legal#15](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/15). **Voting is the EVM integrator that sends users into it.** This dApp can connect MetaMask / WalletConnect on `vote.cl8y.com` (Bridge-style wagmi, [#6](https://gitlab.com/PlasticDigits/voting/-/issues/6)). Unsigned EVM wallets then hit `ConnectedTermsGate` → **Accept Terms** → full navigation to `sign_urls.evm` (`https://terms.cl8y.com/sign/evm?property=vote.cl8y.com`). The Legal page does **not** inherit the voting WalletConnect session. Safari / Chrome still have no `window.ethereum`. The user is stranded after they already connected here. Terra already has `LegalKeplrInAppHint` for the same class of problem (DEX #554 / WC-M12). EVM has **no** equivalent. [`skills/AGENTS_LEGAL_CLICKWRAP.md`](skills/AGENTS_LEGAL_CLICKWRAP.md) already says: “Same class of hint for EVM in-app browsers.” --- ## Current codebase - [`frontend/src/components/legal/ConnectedTermsGate.tsx`](frontend/src/components/legal/ConnectedTermsGate.tsx) — after connect, `TermsGate` with `network` from [`useConnectedIdentity`](frontend/src/hooks/useConnectedIdentity.ts): Terra → `TerraClassic`, `0x…` → `EVM`. - Accept navigates via vendor/SDK `buildSignUrl(sign_urls.evm, { redirectUri, appName })`. **Published** `@plasticdigits/cl8y-clickwrap` `TermsGate` also passes `account`. Voting’s **vendor fallback** [`frontend/src/vendor/cl8y-clickwrap-react.tsx`](frontend/src/vendor/cl8y-clickwrap-react.tsx) does **not** pass `account`. [`frontend/src/vendor/cl8y-clickwrap.ts`](frontend/src/vendor/cl8y-clickwrap.ts) `buildSignUrl` has no `account` option. - [`LegalKeplrInAppHint`](frontend/src/components/legal/LegalKeplrInAppHint.tsx) returns `null` unless `network === 'TerraClassic'`. - Legal signing is **not** in this repo (invariant: SDK-only, [#5](https://gitlab.com/PlasticDigits/voting/-/issues/5)). Voting EIP-191 in `evmSign.ts` is for **votes**, not terms. - Playwright hatch `VITE_PLAYWRIGHT_E2E=true` skips the gate; production must stay gated ([#12](https://gitlab.com/PlasticDigits/voting/-/issues/12): WC success must not skip TermsGate). --- ## Why this is needed - Voting’s BSC electorate ([#4](https://gitlab.com/PlasticDigits/voting/-/issues/4)) is EVM. Retail users are on **mobile** (Binance Web3, MetaMask iOS). - Connecting on voting is not enough: terms evidence is created on the **portal**. A WC/injected session on `vote.cl8y.com` does not follow the user to `terms.cl8y.com`. - Without a voting-side next step, Accept looks like it will work and then repeats Legal #15. Terra users already get “Open this site in the Keplr browser…”. - Legal #15 is the portal fix. Voting still needs: (1) not to dead-end UX **before** that ships, (2) to pass `account=0x…` for continuity once Legal binds it, (3) to re-verify the round-trip after Legal ships. --- ## Constraints / guardrails 1. **Do not reimplement Legal EIP-191 / `POST /signatures/wallet` in voting.** Portal full navigation only — no iframe Accept, no in-dApp terms `personal_sign` ([#5](https://gitlab.com/PlasticDigits/voting/-/issues/5), `AGENTS_LEGAL_CLICKWRAP.md`). 2. **Do not skip TermsGate** after WalletConnect or injected connect ([#12](https://gitlab.com/PlasticDigits/voting/-/issues/12)). Unsigned / unknown status stays fail-closed. 3. **Network match:** EVM address → `network="EVM"` / status `EVM`. Do not check `TERRA_CLASSIC` for a `0x` account (or the reverse). 4. **`redirect_uri`:** keep `resolveLegalRedirectUri` sanitize + `https://vote.cl8y.com` allowlist. Portal allowlist remains authoritative ([#8](https://gitlab.com/PlasticDigits/voting/-/issues/8) `/vote` 200). Do not mint redirect from `Host`. Deep-link / copy-link targets are the **Legal sign URL**, not an arbitrary query URL. 5. **`account` query:** pass the connected checksum/`0x` address only as the integrator-claimed account. Never treat `account` as a redirect target. Do not put other users’ addresses on the Accept URL from untrusted input. 6. **No Legal `ADMIN_TOKEN`** in this frontend. No new WalletConnect Cloud id for **terms** (Legal owns portal WC). 7. **CSP** unchanged: no blanket `connect-src https:`. 8. **Copy:** retail-short. Do not tell phones to install a **desktop** MetaMask extension. Do not call Legal sign a vote. 9. **Production E2E hatch unset.** `prodEnvGuards` / Dockerfile still fail if `VITE_PLAYWRIGHT_E2E` is set on Coolify. 10. Prefer extending `LegalKeplrInAppHint` (or a shared “Legal in-app browser” helper) over a second gate. Terra Keplr copy must keep working. --- ## Relevant files | Area | Path | |------|------| | Gate | `frontend/src/components/legal/ConnectedTermsGate.tsx` | | Terra-only hint | `frontend/src/components/legal/LegalKeplrInAppHint.tsx`, `frontend/src/utils/legalKeplrInAppHint.ts` | | Identity / network | `frontend/src/hooks/useConnectedIdentity.ts` | | Legal client / redirect | `frontend/src/utils/legalClickwrap.ts` | | Vendor SDK fallback | `frontend/src/vendor/cl8y-clickwrap.ts`, `frontend/src/vendor/cl8y-clickwrap-react.tsx` | | Tests | `frontend/src/components/legal/__tests__/ConnectedTermsGate.test.tsx` | | Skill | `skills/AGENTS_LEGAL_CLICKWRAP.md`, `skills/AGENTS_WALLET_CONNECTORS.md` | | Legal portal (dependency) | [cl8y-ecosystem-legal#15](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/15) | --- ## Recommended direction Stage on voting; do **not** wait to document the dead-end: 1. **EVM in-app / copy hint (this repo, independent of Legal #15):** when `legalNetwork === 'EVM'`, `signed_latest === false`, and there is no injected EIP-1193 in **this** page (or user connected via WalletConnect), show the same class of CTA as Keplr: **Open in MetaMask**, **Open in Binance Web3** (documented universal / dapp-browser links whose `url` is the Legal sign URL with `property`, `redirect_uri`, `app_name`, and `account`), plus **Copy link**. Idle copy: Chrome/Safari cannot finish terms; open the Legal page in the wallet app browser. If a documented Binance dapp URL cannot be confirmed, still ship Copy-link + MetaMask rather than inventing a scheme. 2. **Pass `account`:** use published SDK `buildSignUrl({ account })` (and align vendor fallback). Connected `0x…` must appear on the portal query so Legal can bind continuity when #15 lands. 3. **After Legal #15:** Accept from voting in system Safari/Chrome must complete `signed_latest` for `(vote.cl8y.com, EVM, 0x…)` via portal Open-in-app or portal WalletConnect — then return to allowlisted `vote.cl8y.com` path ([#8](https://gitlab.com/PlasticDigits/voting/-/issues/8)). 4. **Do not** implement portal `personal_sign` inside voting to “avoid” Legal. --- ## Acceptance criteria - [ ] Unsigned EVM user on mobile Chrome/Safari never gets **only** an Accept button that lands on Legal `No EVM wallet found (install MetaMask or similar)` with no next step on **voting** (hint and/or copy Legal link) **and** Legal #15 remaining the portal fix. - [ ] Accept URL includes `property=vote.cl8y.com` (or `VITE_LEGAL_PROPERTY`), sanitized `redirect_uri`, `app_name=CL8Y Voting`, and connected `account=0x…`. - [ ] Terra `LegalKeplrInAppHint` still shows for unsigned Terra without Keplr extension; still hidden for EVM. - [ ] TermsGate still fail-closes propose/vote when `signed_latest` is false or status errors. WC connect does not skip the gate. - [ ] After Legal #15: happy path MetaMask iOS **or** Binance Web3 → Accept → portal sign → `signed_latest: true` for EVM → return to voting page (200, not `/vote` 404). - [ ] Desktop injected MetaMask on voting → Accept → portal still works. - [ ] Vendor fallback `buildSignUrl` / `TermsGate` pass `account` if the published package is missing. - [ ] Skill updated: EVM hint is required, not a parenthetical. --- ## Test plan (functional paths) 1. **Disconnected:** browse OK; no Legal status fetch (existing test). 2. **EVM unsigned, no inject:** Accept visible; EVM in-app/copy hint visible; Keplr hint **absent**. Propose/vote hidden. 3. **EVM unsigned, WalletConnect connector:** same hint (Legal will not see this WC session). 4. **EVM signed_latest true:** children render; hint hidden. 5. **Terra unsigned, no Keplr:** existing Keplr hint still shows; EVM MetaMask/Binance CTAs absent. 6. **Accept href:** `sign/evm`, property, redirect_uri origin allowlisted, `account` matches connected address (checksum vs lowercase both OK to send; portal lowercases). 7. **Evil redirect:** `resolveLegalRedirectUri` still drops non-allowlisted origins (existing sanitize tests). 8. **Wrong network:** EVM address never queried as `TERRA_CLASSIC`. 9. **Playwright hatch:** `VITE_PLAYWRIGHT_E2E=true` still skips gate in e2e only. 10. **Manual after Legal #15:** iOS Safari WC connect on voting → hint → Open in MetaMask or paste in Binance Web3 → terms signed → back on `vote.cl8y.com`. 11. **Manual:** Binance Web3 **in-app** on voting (injected) → Accept stays in WebView → portal discovery (#15) or existing inject succeeds. --- ## Test plan (attack / abuse / hack vectors) | Vector | Expectation | |--------|-------------| | Skip TermsGate after WC | Still gated until Legal `signed_latest` ([#12](https://gitlab.com/PlasticDigits/voting/-/issues/12)) | | `account=` on Accept URL for a different 0x than connected | Must be the **connected** store address only; do not read `account` from query to overwrite | | `redirect_uri` open redirect via Accept | Sanitize + portal allowlist; no `javascript:` | | Hint / copy-link uses attacker URL | Only Legal terms origin + current sign path/query from API `sign_urls` (or constructed from `getLegalTermsBaseUrl` + property). Do not open arbitrary `https://` from wallet payloads | | Treating Legal sign as a vote | Voting `evmSign.ts` payloads stay separate; Legal URL not used for register/propose/vote | | Status API error | Fail closed (no propose/vote) | | LocalStorage “accepted” flag | Not Legal proof | | `VITE_PLAYWRIGHT_E2E` in prod image | Build/guard fail | | XSS in hint / account display | Text nodes only | --- ## Verification criteria - Manual: unsigned BSC wallet on mobile system browser at `https://vote.cl8y.com` — sees a working next step for terms (copy/open in MetaMask or Binance), not a silent trip to Legal #15 with no explanation. - Manual (blocked on Legal #15): complete EVM terms from that path; `GET /api/v1/signatures/status?property=vote.cl8y.com&network=EVM&account=0x…` is `signed_latest: true`; return URL is voting origin. - `ConnectedTermsGate` unit tests green for EVM hint presence/absence and `account` on Accept URL. - Terra Keplr hint tests still green. - Production Coolify still has Legal hatch unset. **Depends on:** [cl8y-ecosystem-legal#15](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/15) for the portal sign itself. This issue is the voting gate / hint / `account` continuity.
PlasticDigits commented 2026-08-30 17:56:40 +00:00 (Migrated from gitlab.com)

mentioned in merge request !27

mentioned in merge request !27
PlasticDigits commented 2026-08-31 05:16:27 +00:00 (Migrated from gitlab.com)

mentioned in merge request !28

mentioned in merge request !28
PlasticDigits commented 2026-08-31 09:09:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #17

mentioned in issue #17
PlasticDigits commented 2026-08-31 09:10:04 +00:00 (Migrated from gitlab.com)

!28 merge review (no automerge, did not wait for CI)

MR !28 is merged onto main (f000040). GitLab reported no conflicts (can_be_merged). Source branch fix/16-evm-legal-copy was removed on origin.

Sanity check

  • Copy change is consistent with live Legal: Accept opens the portal; hint is a phone shortcut (Open in MetaMask + Copy), not a claim that Chrome/Safari cannot finish terms.
  • That intentionally diverges from this issue’s original recommended idle copy (Chrome and Safari cannot finish terms…) because cl8y-ecosystem-legal#15 is closed. Product-correct; do not revert to the dead-end sentence.
  • @plasticdigits/cl8y-clickwrap on main is already ^0.1.1 (Accept account=). !28 did not bump the package again. A leftover local stash (evm copy) still had ^0.1.0 — not merged (would regress Accept).
  • Local unit tests on the MR tree: legalEvmInAppHint + ConnectedTermsGate 19 passed; full frontend 110 passed.

Acceptance criteria vs tree

AC In-tree Live
Unsigned EVM never gets only Accept (hint and/or copy link) Yes (!27 hint + !28 copy). Unit tests. Not verified on vote.cl8y.com after this merge
Accept URL: property, sanitized redirect_uri, app_name=CL8Y Voting, connected account=0x… Yes (gate test + clickwrap >= 0.1.1) Not verified after Coolify rebuild
Terra LegalKeplrInAppHint still Terra-only Yes (unit tests) Not re-run on device
TermsGate fail-closed; WC does not skip gate Yes (existing tests) Playwright hatch skips the gate — not #16 QA
After Legal #15: MetaMask iOS or Binance Web3 → signed_latest: true → return 200 Depends on live wallets Open
Desktop injected MetaMask Accept still works Unchanged path Open
Vendor fallback still passes account Yes n/a
Skill: EVM hint required, not a parenthetical Yes (!28 skill/docs) n/a

Do not close this issue until live unsigned EVM on https://vote.cl8y.com shows: Accept opens the Legal page. On a phone, open it in MetaMask or paste the link in Binance Web3. and Accept still has account=.

Problems

  1. Live / after-deploy QA still open (MR test plan checkbox). Coolify rebuild is tracked on #17.
  2. GitLab CI did not run on !28. Pipeline 2804368993 failed every job with ci_quota_exceeded (no runner, no traces). Merge settings do not require a green pipeline. Local tests are the only check that ran.
  3. Issue AC checkboxes above are still unchecked; several are in-tree-only until a human wallet pass.

No other open MRs. Leftover fix/16-evm-legal-inapp-hint / fix/16-evm-legal-copy worktrees were already contained in main; dangling stash would downgrade clickwrap and was not applied.

## !28 merge review (no automerge, did not wait for CI) [MR !28](https://gitlab.com/PlasticDigits/voting/-/merge_requests/11) is **merged** onto `main` (`f000040`). GitLab reported **no conflicts** (`can_be_merged`). Source branch `fix/16-evm-legal-copy` was removed on origin. ### Sanity check - Copy change is consistent with live Legal: Accept opens the portal; hint is a phone shortcut (Open in MetaMask + Copy), not a claim that Chrome/Safari cannot finish terms. - That **intentionally diverges** from this issue’s original recommended idle copy (`Chrome and Safari cannot finish terms…`) because [cl8y-ecosystem-legal#15](https://gitlab.com/PlasticDigits/cl8y-ecosystem-legal/-/issues/15) is **closed**. Product-correct; do not revert to the dead-end sentence. - `@plasticdigits/cl8y-clickwrap` on `main` is already **^0.1.1** (Accept `account=`). !28 did not bump the package again. A leftover local stash (`evm copy`) still had **^0.1.0** — **not** merged (would regress Accept). - Local unit tests on the MR tree: `legalEvmInAppHint` + `ConnectedTermsGate` **19 passed**; full frontend **110 passed**. ### Acceptance criteria vs tree | AC | In-tree | Live | |----|---------|------| | Unsigned EVM never gets **only** Accept (hint and/or copy link) | Yes (!27 hint + !28 copy). Unit tests. | **Not verified** on `vote.cl8y.com` after this merge | | Accept URL: `property`, sanitized `redirect_uri`, `app_name=CL8Y Voting`, connected `account=0x…` | Yes (gate test + clickwrap >= 0.1.1) | **Not verified** after Coolify rebuild | | Terra `LegalKeplrInAppHint` still Terra-only | Yes (unit tests) | Not re-run on device | | TermsGate fail-closed; WC does not skip gate | Yes (existing tests) | Playwright hatch skips the gate — not #16 QA | | After Legal #15: MetaMask iOS **or** Binance Web3 → `signed_latest: true` → return 200 | Depends on live wallets | **Open** | | Desktop injected MetaMask Accept still works | Unchanged path | **Open** | | Vendor fallback still passes `account` | Yes | n/a | | Skill: EVM hint required, not a parenthetical | Yes (!28 skill/docs) | n/a | **Do not close this issue** until live unsigned EVM on `https://vote.cl8y.com` shows: `Accept opens the Legal page. On a phone, open it in MetaMask or paste the link in Binance Web3.` and Accept still has `account=`. ### Problems 1. **Live / after-deploy QA still open** (MR test plan checkbox). Coolify rebuild is tracked on [#17](https://gitlab.com/PlasticDigits/voting/-/issues/17). 2. **GitLab CI did not run on !28.** Pipeline `2804368993` failed every job with `ci_quota_exceeded` (no runner, no traces). Merge settings do not require a green pipeline. Local tests are the only check that ran. 3. Issue AC checkboxes above are still unchecked; several are in-tree-only until a human wallet pass. No other open MRs. Leftover `fix/16-evm-legal-inapp-hint` / `fix/16-evm-legal-copy` worktrees were already contained in `main`; dangling stash would downgrade clickwrap and was not applied.
PlasticDigits commented 2026-09-01 08:09:10 +00:00 (Migrated from gitlab.com)

Verify pass (2026-09-01) — in-tree only; this issue stays open

Pushed d7f4d51 to main.

In-tree (pass)

  • EVM hint + copy: LEGAL_EVM_INAPP_HINT; Terra Keplr hint stays Terra-only.
  • Accept URL: property, sanitized redirect_uri, app_name=CL8Y Voting, connected account= (clickwrap ^0.1.1 + vendor fallback).
  • TermsGate still fail-closes; WalletConnect does not skip the gate. Playwright hatch is not this issue’s QA.
  • Frontend unit 110 passed (includes ConnectedTermsGate / legalEvmInAppHint).
  • Skill AGENTS_LEGAL_CLICKWRAP.md treats the EVM hint as required and points at the Coolify rebuild (issue 17).

Live (remaining AC)

  • vote.cl8y.com still serves Chrome and Safari cannot finish terms… (index-cN5sRfvA.js). Rebuild is issue 17.
  • Unsigned EVM on a phone at the live origin, and desktop injected MetaMask Accept, were not re-run (no device session here).
  • Legal portal issue 15 is closed; the voting hint is a shortcut, not a claim that Accept is a dead end.

Checklist

  • Unit tests: hint presence/absence and account on Accept
  • Terra Keplr tests still green
  • Live unsigned BSC on mobile Chrome/Safari shows the !28 sentence after the issue 17 rebuild
  • Accept URL on live has account=
  • Manual: MetaMask iOS or Binance Web3 → portal sign → signed_latest: true → return 200 on voting origin
  • Desktop injected MetaMask Accept still works
  • Production Coolify Legal hatch unset

Stays open: live copy and human wallet round-trip are still required.

## Verify pass (2026-09-01) — in-tree only; this issue stays **open** Pushed `d7f4d51` to `main`. ### In-tree (pass) - EVM hint + copy: `LEGAL_EVM_INAPP_HINT`; Terra Keplr hint stays Terra-only. - Accept URL: property, sanitized `redirect_uri`, `app_name=CL8Y Voting`, connected `account=` (clickwrap ^0.1.1 + vendor fallback). - TermsGate still fail-closes; WalletConnect does not skip the gate. Playwright hatch is not this issue’s QA. - Frontend unit **110** passed (includes `ConnectedTermsGate` / `legalEvmInAppHint`). - Skill `AGENTS_LEGAL_CLICKWRAP.md` treats the EVM hint as required and points at the Coolify rebuild (issue 17). ### Live (remaining AC) - `vote.cl8y.com` still serves `Chrome and Safari cannot finish terms…` (`index-cN5sRfvA.js`). Rebuild is issue 17. - Unsigned EVM on a phone at the live origin, and desktop injected MetaMask Accept, were not re-run (no device session here). - Legal portal issue 15 is closed; the voting hint is a shortcut, not a claim that Accept is a dead end. ### Checklist - [x] Unit tests: hint presence/absence and `account` on Accept - [x] Terra Keplr tests still green - [ ] Live unsigned BSC on mobile Chrome/Safari shows the !28 sentence after the issue 17 rebuild - [ ] Accept URL on live has `account=` - [ ] Manual: MetaMask iOS or Binance Web3 → portal sign → `signed_latest: true` → return 200 on voting origin - [ ] Desktop injected MetaMask Accept still works - [ ] Production Coolify Legal hatch unset **Stays open:** live copy and human wallet round-trip are still required.
PlasticDigits commented 2026-09-01 08:51:27 +00:00 (Migrated from gitlab.com)

Redeploy check — closing on in-tree + live copy

After the Coolify rebuild, live vote.cl8y.com serves the !28 hint (Accept opens the Legal page…) and still constructs /sign/evm with account=. Clickwrap on main is ^0.1.1. Legal portal next-steps (ecosystem-legal issue 15) are already closed.

In-tree: EVM hint unit tests, Terra Keplr still Terra-only, TermsGate fail-closed, vendor fallback account. Playwright hatch is not device QA.

Not re-run here: MetaMask iOS / Binance Web3 full sign round-trip, desktop injected Accept. Those stay manual on issue 7 live wallet QA. Product dead-end on voting is fixed.

## Redeploy check — closing on in-tree + live copy After the Coolify rebuild, live `vote.cl8y.com` serves the !28 hint (`Accept opens the Legal page…`) and still constructs `/sign/evm` with `account=`. Clickwrap on `main` is `^0.1.1`. Legal portal next-steps (ecosystem-legal issue 15) are already closed. In-tree: EVM hint unit tests, Terra Keplr still Terra-only, TermsGate fail-closed, vendor fallback `account`. Playwright hatch is not device QA. Not re-run here: MetaMask iOS / Binance Web3 full sign round-trip, desktop injected Accept. Those stay manual on issue 7 live wallet QA. Product dead-end on voting is fixed.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-09-01 08:51:48 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/voting#16
No description provided.