Files
AutistMask/TODO.md
clawbot b114151116
Some checks failed
check / check (push) Has been cancelled
fix: drive background refresh and phishing update from alarms (closes #158)
The Chrome MV3 service worker is terminated after roughly 30 seconds idle,
which destroyed both recurring jobs: the 60-second balance refresh and the
24-hour phishing blocklist refresh were setInterval schedules, so in
practice each ran only while the worker happened to be alive. The phishing
delta was persisted to localStorage, which does not exist in a service
worker, so on Chrome it was never persisted at all.

Both jobs now run off the extension alarms API in the new
src/shared/alarms.js: the browser holds the schedule and wakes the worker to
deliver it. The balance refresh is one minute and the phishing refresh is
1440 minutes, both whole minutes at or above the one-minute minimum, so
neither is silently clamped. Alarms are created only when missing or when the
existing one carries a different period, because creating one restarts its
period and the startup path runs on every wake — while an alarm left at an
older release's period would otherwise never be reconciled.

Each job's freshness guard is decoupled from its alarm period, or the period
would not be the cadence. A guard is measured from when the last run
finished, which is one run-duration after the alarm that started it, so a
guard timed to the period vetoes the very next tick and the real rate halves.
The two are handled differently because the guards differ in purpose: the
phishing cache TTL exists to keep the worker off the network on the wakes
between refreshes, so the scheduled tick bypasses it and fetches
unconditionally; the balance guard exists to skip work an open popup has
already done, so it must keep applying on the tick and is instead shortened
to half the alarm period — above the popup's 10-second refresh, below the
60-second period.

The phishing delta and the timestamps of the fetch that produced it now live
in extension storage, and updatePhishingList() reloads that record before
deciding whether a fetch is due. A revived worker therefore neither
re-fetches on every wake nor sleeps through an overdue update. A timestamp
read back from storage is discarded if it lies in the future: clock skew or a
restored profile backup would otherwise suppress updates until that time
arrived, permanently, now that the value outlives the worker.

Two timestamps are kept, not one. The 256 KiB cap still drops an oversized
delta together with its freshness claim, but the record of having contacted
the network at all is written regardless — as it is after a failed fetch —
and floors unscheduled retries at one hour. Without it, a list that is
persistently oversized or a fetch that persistently fails means a full
blocklist download on every worker wake, indefinitely.

The startup path (ensureRecurringAlarms plus the phishing list init) is
registered on onInstalled and onStartup as well as running at the top level
of the worker, and is idempotent. The concurrent callers on a fresh install
share one in-flight run rather than racing to create the same alarm, and a
failure is logged instead of becoming an unhandled rejection.

Firefox MV2 has a persistent background page where timers would have
survived, but both browsers are built from one bundle and both take the
alarm path, so there is a single code path; "alarms" is declared in both
manifests.

src/shared/ens.js keeps its localStorage cache and gains a comment recording
that it is popup-only, so it does not get pulled into the worker later.
2026-08-11 13:23:58 +00:00

8.5 KiB

Workflow

  • git pull next and cut a branch from it — one branch per issue, named issue-<N>-<slug>. Never branch from main.
  • Do the work as one commit whose title ends with (closes #N), with the TODO.md update in that same commit.
  • Move Next Step to the top of Completed Steps; move the top item of Future Steps into Next Step.
  • Run make fmt, then make check. A feature branch may be red; next and main may not.
  • Rebase onto current next immediately before pushing — other branches land on next continuously — and re-run make check after resolving, because a clean textual merge can still break the build.
  • Push the branch and open one PR per issue with base next. Never base main.
  • An independent reviewer who did not write the change gates the merge. On a passed review the PR is squash-merged into next.
  • next is the branch for the next milestone. It is kept green and mergeable to main at any moment, without notice.
  • main receives exactly one PR per milestone, from next. Releases are tagged from main.

Status

pre-1.0, working towards the 1.0.0 milestone. Tagged v0.1.0 on 2026-02-27. The milestone is in flight on next; its next -> main PR is #190. make check verified green on next at e9fa8be on 2026-08-10, and make build produces dist/chrome/ and dist/firefox/ with every bundle verified to have DEBUG compiled off.

The backlog lives on the Gitea tracker, which is authoritative; this file does not duplicate it. Full policy file set present. A real-browser end-to-end suite (make test-e2e) now sits alongside make check, which cannot see a runtime ReferenceError in a popup view.

Next Step

Land #152: add ESLint to script/lint. make check is prettier --check only today and cannot catch undefined identifiers, which is how #150 and #151 shipped.

Completed Steps

  • 2026-08-11: A dust threshold of 0 now means "hide nothing" instead of falling back to the 100,000 gwei default, and every address comparison in src/shared/transactions.js goes through one case-normalising helper so a checksummed genuine contract is no longer read as a spoof (#179).
  • 2026-08-11: the balance refresh and the 24-hour phishing list refresh moved from setInterval to the extension alarms API, with the phishing delta and its fetch timestamps persisted to extension storage, so neither job dies with the MV3 service worker. Each job's freshness guard was decoupled from its alarm period at the same time — timed to the period, a guard vetoes its own scheduled tick and halves the real refresh rate (#158).
  • 2026-08-11: Policy compliance sweep — conditional verbose test rerun, local Tailwind binary instead of npx, --frozen-lockfile on make install, and the Makefile-only targets documented in the README (#166).
  • 2026-08-11: script/verify-build diagnostics corrected: the both-markers message now states what is and is not proven, an unreadable bundle is diagnosed as an I/O fault rather than as changed output, the *.js assumption lives only in build.js, and the unlisted-bundle scan hard-fails when it cannot enumerate dist/ (#180).
  • 2026-08-11: Known-answer test coverage for the crypto core — BIP-39/BIP-32 derivation in wallet.js and the Argon2id vault in vault.js (#159).
  • 2026-08-11: Three README.md claims corrected against the code — blocklist attribution, token-display rule, navigation model (#213).
  • 2026-08-11: README Screen Map rebuilt from the code — every screen, element and transition re-verified against src/popup/ (#164).
  • 2026-08-11: docs/README.md rewritten against the code: no competitor names, all five network destinations documented, password/Settings/Add Wallet sections corrected (#163).
  • 2026-08-11: loadState() now derives hasWallet from the wallet list instead of trusting the persisted flag, so a profile already saved inconsistent no longer stays broken on every load (#195).
  • 2026-08-11: Wallet deletion repairs its own state — hasWallet follows the remaining wallets, the selection only moves when it was deleted, and the active-address change is broadcast to connected sites (#156).
  • 2026-08-11: One row per on-chain value movement in transaction history: the merge moved into the pure mergeTransactions and the zero-ETH native side of a plain ERC-20 transfer absorbed into its token row (#177).
  • 2026-08-11: TODO.md Workflow rewritten to the branch-and-PR-per-issue model on next, with Status and Next Step refreshed (#191).
  • 2026-08-09: DEBUG became a build-time constant defaulting to off, injected as the __BUILD_DEBUG__ esbuild define and turned on with AUTISTMASK_DEBUG=1, so a plain make build no longer hands every newly created wallet the publicly committed test recovery phrase (#149).
  • 2026-08-09: dApp approval signing moved into the popup — the password no longer crosses the extension messaging boundary; the background broadcasts and resolves approvals only, and verifies the signed artifact against the approval it holds (#157).
  • 2026-08-09: Post-build assertion that every emitted bundle containing constants.js has DEBUG compiled off, via script/verify-build on the make build path (#170).
  • 2026-08-09: Containerized Chrome end-to-end harness (make test-e2e / script/test-e2e) driving the real popup with all network intercepted, plus the two used-but-not-imported crashes it caught: AddToken unreachable (#150) and TransactionDetail broken for every ERC-20 transfer (#151). Harness demonstrated failing before the fixes and passing after (#181). Interception covers the MV3 background service worker, not just the popup page, and a launch-time canary aborts the suite if worker traffic starts escaping.
  • 2026-08-09: Reviewed the repo end to end and filed the 1.0.0 backlog (#149-#168).
  • 2026-08-09: Test coverage for the address-poisoning defense in src/shared/transactions.js (#160)
  • 2026-07-26: About well in settings with build info, repo link and the version click easter egg (#145); proper view navigation stack (#146).
  • 2026-07-07 Adopted scripts-to-rule-them-all: script/ entrypoints, Makefile shims, README Entrypoints section (#148)
  • 2026-03-01: USD display suppressed on testnets (#142); estimated USD for ETH in approve-tx view (#141).
  • Sepolia testnet support (#137); etherscan links go to token-specific URLs (#136).
  • Transaction detail improvements: Type field and on-chain details (#130), txid-first reordering (#133), swap display corrections (#128), expanded confirm-tx warnings (#118).
  • Dark mode theme setting (Light/Dark/System) with contrast fixes (#126); timestamps include timezone offset (#120); layout shift audit, reserved space for error messages (#124).
  • Copy-flash visual feedback with timing tune (#113, #121); cross-wallet-type duplicate detection (#115).
  • 2026-02-27: v0.1.0 tagged.
  • 2026-02-24: Initial scaffolding: popup UI, BIP-39 wallet creation via ethers.js, wallet persistence, real ETH balances over RPC, ENS forward and reverse resolution.

Future Steps

Only work that has no issue of its own belongs here; everything else is on the tracker.

  • Pre-1.0 security review of the extension (key handling, DEBUG mode policy, RPC input validation) before any 1.0rc tag. Individual filed issues are parts of it, but the review is broader than any of them.
  • Decide whether docker-in-docker makes make test-e2e runnable in the Gitea workflow. Extending the suite itself is tracked as #183 and #184.
  • Cut 1.0.0 once the milestone is empty, then continue tagging as milestones land.