All checks were successful
check / check (push) Successful in 55s
goBack() only unhid its target. A reopened popup renders the wallet list and the one view restoreView() lands on, so every other view is still the blank static template from index.html: pressing Back from Settings onto an address showed an empty address line and no balances, and the same held for address-token, receive, confirm-tx and transaction. The per-view dispatch and its data guards move out of restoreView() into src/popup/viewRouter.js, and goBack() now routes a popped view through the same code by way of a renderer index.js registers with setBackRenderer(). A view whose backing state is gone falls back to Home the way the restore does, rather than showing an empty template. The Back path renders only a view this page load has not rendered yet. viewRouter.js keeps a page-load-scoped set of rendered views, written by showView() — the last thing every render path runs, forward navigation and the restore alike, so a view added later registers itself rather than needing to be remembered. Back onto a view already in that set unhides it and nothing more, exactly as it does for a view outside RESTORABLE_VIEWS: rendering a second time would re-fetch and overwrite what the view holds, such as an edit typed into Settings and not yet saved. Home stays the exception and is re-rendered on every Back, as it was when goBack() called the renderWalletList() registered through setRenderMain(), so the wallet list reflects what changed while the user was away from it. tests/backNavigation.test.js drives the real goBack() over the reproduction and over each of address-token, receive, confirm-tx, transaction, success-tx and error-tx, with and without their backing state, and pins that a view this page load already rendered — a live-session view, or Settings revisited — is only unhidden, while Home still re-renders. tests/e2e/run.js adds three cases against the real popup in a real browser, because make check cannot see a blank view: a real close and reopen then Back onto the address screen and onto Receive, and an in-session Back onto Settings that must keep unsaved input. All three were demonstrated failing first.
377 lines
24 KiB
Markdown
377 lines
24 KiB
Markdown
# 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](https://git.eeqj.de/sneak/AutistMask/pulls/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](https://git.eeqj.de/sneak/AutistMask/issues), which is
|
||
authoritative; this file does not duplicate it. Full policy file set present.
|
||
Real-browser end-to-end suites (`make test-e2e` for Chrome,
|
||
`make test-e2e-firefox` for Firefox) now sit alongside `make check`, which
|
||
cannot see a runtime `ReferenceError` in a popup view.
|
||
|
||
# Next Step
|
||
|
||
Land [#152](https://git.eeqj.de/sneak/AutistMask/issues/152): add ESLint to
|
||
`script/lint`. `make check` is `prettier --check` only today and cannot catch
|
||
undefined identifiers, which is how
|
||
[#150](https://git.eeqj.de/sneak/AutistMask/issues/150) and
|
||
[#151](https://git.eeqj.de/sneak/AutistMask/issues/151) shipped.
|
||
|
||
# Completed Steps
|
||
|
||
- 2026-08-12: EIP-1193 error codes now reach the page. `src/content/inpage.js`
|
||
rebuilt every failure as `new Error(error.message)`, so the code the
|
||
background produced and the content script relayed intact was dropped in the
|
||
last hop and a dApp checking `err.code === 4001` saw `undefined` — a wallet
|
||
the user deliberately declined was indistinguishable from one that broke. The
|
||
provider now rejects with a `ProviderRpcError` carrying `code` and, where the
|
||
boundary sent one, `data`, passed through verbatim rather than matched against
|
||
a list, so 4001, 4100 and 4902 all arrive and a future code needs no edit
|
||
here. An error the background sent with no code stays a plain `Error` with no
|
||
`code` property, and `message` is unchanged in every case. All four request
|
||
entry points (`request`, `enable`, `send`, `sendAsync`) are covered by
|
||
`tests/inpageErrors.test.js`, and the e2e probe that printed the missing code
|
||
now requires it on the page's Error as well as on the wire, for all four
|
||
rejected flows ([#274](https://git.eeqj.de/sneak/AutistMask/issues/274)).
|
||
- 2026-08-12: "Back" now renders the screen it lands on instead of only unhiding
|
||
it. A reopened popup renders the wallet list and the one screen it restores
|
||
onto, so every screen further down the stack was still the blank template from
|
||
`index.html`, and Back walked straight onto it — an empty address, no
|
||
balances, no QR code. The Back path now goes through the same per-view
|
||
dispatch and data guards as the restore (`src/popup/viewRouter.js`, shared
|
||
with `restoreView()`), falling back to Home when the state the target would
|
||
render is gone. It renders only a view this page load has not rendered yet:
|
||
`viewRouter.js` records every view that reaches `showView()`, which is where
|
||
forward navigation and the restore both end, so Back onto a view already on
|
||
the page unhides it and nothing more. That is what keeps a second render from
|
||
re-fetching and overwriting what the view holds — an unsaved edit in Settings,
|
||
a transaction list already loaded. Home is the exception and is always
|
||
re-rendered, as it was before. Covered by unit tests on the real `goBack()`
|
||
and by three end-to-end cases against the real popup, each demonstrated
|
||
failing on the unfixed build
|
||
([#268](https://git.eeqj.de/sneak/AutistMask/issues/268)).
|
||
- 2026-08-12: `KNOWN_SYMBOLS` now maps a symbol to the set of contract addresses
|
||
that bear it, not to one of them. A ticker is not unique: seven of the 512
|
||
bundled tokens — `FRAX`, `REUSD`, `TON`, `EURE`, `MSUSD`, `MUSD` and `JPYC` —
|
||
share a symbol with another bundled entry at a different real contract, and
|
||
the table, built from the list first-wins, kept only the earlier one. The
|
||
other seven were judged spoofs of their own symbol at their own address and
|
||
hidden from the balance list, the history and the send selector, so a holder
|
||
could not spend them. Both contracts of each pair come from the same CoinGecko
|
||
fetch of 2026-02-27, so neither was stale and neither was dropped.
|
||
`isSpoofedSymbol()` asks set membership instead of equality, which does not
|
||
loosen the rule — a contract outside the set is still a spoof — and a test now
|
||
walks `TOKENS` asserting no bundled token is filtered at its own address,
|
||
which is the walk the suite lacked
|
||
([#276](https://git.eeqj.de/sneak/AutistMask/issues/276)).
|
||
- 2026-08-12: The dApp approval round trips are driven end to end in the
|
||
browser. A test page served by the harness speaks EIP-1193 to the real inpage
|
||
provider through the real content script, background worker and approval popup
|
||
for `eth_requestAccounts`, `personal_sign`, `eth_signTypedData_v4` and
|
||
`eth_sendTransaction`. Every signature is recovered and compared against the
|
||
active address, the transaction is checked against the bytes handed to the
|
||
stubbed RPC, each rejection must reach the page as a rejection, and the
|
||
password must appear in no message the approval window sends — the assertion
|
||
that gives [#157](https://git.eeqj.de/sneak/AutistMask/issues/157) a permanent
|
||
floor. This does not discharge a real dApp with real funds against mainnet
|
||
([#183](https://git.eeqj.de/sneak/AutistMask/issues/183)).
|
||
- 2026-08-12: The known-symbol spoof rule now judges the symbol a user actually
|
||
sees. `isSpoofedSymbol()` normalizes before the lookup — NFKC, then every
|
||
character that paints nothing removed (the format and default-ignorable
|
||
characters, plus U+007F), then trimmed — so `" ETH "`, a no-break space, a
|
||
zero-width space, a Hangul filler, a variation selector, a DELETE and a
|
||
fullwidth `ETH` are all caught on the balance list, the history and the
|
||
send selector at once. Confusables that are distinct letters (Cyrillic `Е`),
|
||
bidi reordering and the visible C0/C1 controls — which measure 48.00px, a box,
|
||
in the pinned e2e Chromium where an invisible prefix measures 32.00px — stay
|
||
knowingly open and are asserted as open in the suite. No bundled symbol
|
||
contains whitespace or a non-ASCII character, so nothing legitimate is newly
|
||
filtered; the balance list's token-type gate also became case-insensitive,
|
||
which no longer drops a real holding if an explorer writes `erc-20`
|
||
([#260](https://git.eeqj.de/sneak/AutistMask/issues/260)).
|
||
- 2026-08-12: A containerized Firefox end-to-end harness
|
||
(`make test-e2e-firefox`) drives the real popup in a real Firefox with the MV2
|
||
build installed as a temporary add-on. Zero npm dependencies — a WebDriver
|
||
client over `fetch` against geckodriver — with `node`, Firefox 153.0.3 and
|
||
geckodriver 0.36.0 all pinned by digest. Uncaught errors are read from the
|
||
privileged console service in Marionette's chrome context, because BiDi
|
||
`log.entryAdded` reports nothing at all for extension pages; each drain reads
|
||
and clears the console in one chrome round trip, so no error is destroyed
|
||
unread by the drain itself, and errors logged during add-on install and
|
||
background startup are folded into step 1 instead of being cleared. The two
|
||
measured limits are documented rather than claimed away: the console ring
|
||
buffer holds 250 messages (a clean run peaks at 4), and the drained window
|
||
ends ≈1.5s after the last step returns. Demonstrated discriminating by exiting
|
||
1 on a `throw` at the top of `src/background/index.js`, on a build with one
|
||
import removed, on a `setTimeout` throw whose UI assertions all pass, on an
|
||
unhandled `Promise.reject` and on an undefined identifier in `home.js`, and 0
|
||
on the branch as it stands
|
||
([#184](https://git.eeqj.de/sneak/AutistMask/issues/184)).
|
||
- 2026-08-12: The transaction a dApp asks for is now populated in the background
|
||
before the approval window opens, so the object the user is shown is the
|
||
object the signed artifact is verified against — nonce, gas limit and every
|
||
fee field are compared exactly instead of being left to the ceilings, which
|
||
stay as a backstop against what a lying RPC node can talk the wallet into
|
||
displaying. The approval also pins the address it was raised for, so an
|
||
address switch between approval and signing refuses rather than signing from
|
||
an account the screen never named, and a request naming an address that is not
|
||
the active one is refused outright. The approval screen now shows the fee, gas
|
||
limit, network and nonce it vouches for
|
||
([#216](https://git.eeqj.de/sneak/AutistMask/issues/216)).
|
||
- 2026-08-12: The restored navigation stack is filtered against
|
||
`RESTORABLE_VIEWS` on load, truncated at the first entry the popup would not
|
||
render so that every surviving entry keeps the Back target it had. Back after
|
||
reopening can no longer land on a view the popup declined to restore, such as
|
||
`export-privkey` or `show-phrase`
|
||
([#224](https://git.eeqj.de/sneak/AutistMask/issues/224)). Restorable views in
|
||
the stack are still unhidden without being re-rendered; that is tracked
|
||
separately in ([#268](https://git.eeqj.de/sneak/AutistMask/issues/268)).
|
||
- 2026-08-12: One wording for a rejected password on every screen that asks for
|
||
one — the send confirmation and the delete-wallet confirmation no longer say
|
||
"Wrong password." (a fragment, which `RULES.md` Language & Labeling forbids)
|
||
and the two reveal screens no longer say "not correct", so all five
|
||
`decryptWithPassword` call sites now show the sentence the dApp approval paths
|
||
introduced. Strings only, no behaviour change, and each error container
|
||
measured at a 360px viewport in the pinned Playwright container
|
||
([#172](https://git.eeqj.de/sneak/AutistMask/issues/172)).
|
||
- 2026-08-12: Closed the empty-array hole in the end-to-end unstubbed-request
|
||
guard. `batch.every()` is vacuously true on `[]`, so a POST with body `[]` was
|
||
answered `200 []` instead of failing the suite; the guard now rejects an empty
|
||
batch, demonstrated green-before/red-after with a throwaway probe. The comment
|
||
claiming `postData()` returns `null` for undecodable bodies was corrected to
|
||
the two real paths — an absent or empty body decodes to `null`, a binary body
|
||
decodes lossily into invalid JSON
|
||
([#187](https://git.eeqj.de/sneak/AutistMask/issues/187)).
|
||
- 2026-08-12: The transaction confirmation screen has browser coverage. The
|
||
end-to-end suite reaches ConfirmTx for both the native ETH and the ERC-20 path
|
||
off a funded-balance fixture, and asserts the pending, funded, over-balance
|
||
and estimate-failed states, the fee block quoting the estimate and the reserve
|
||
separately, and a constant view height across every one of those transitions.
|
||
The load-bearing assertion is that the spend gate reads the reserve and not
|
||
the displayed estimate: swapping the two fails the suite
|
||
([#238](https://git.eeqj.de/sneak/AutistMask/issues/238)).
|
||
- 2026-08-12: The dust threshold field now explains a rejection instead of
|
||
snapping back in silence, with the parse in a pure, unit-tested module that
|
||
accepts plain decimal digits only — hex and exponent notation are refused
|
||
rather than read as 16 and 1000
|
||
([#233](https://git.eeqj.de/sneak/AutistMask/issues/233)).
|
||
- 2026-08-12: Approval verification became an allowlist — transaction type
|
||
restricted to 0/1/2 so an EIP-7702 delegation can no longer ride along on an
|
||
approved transfer, every consequential field compared, the artifact
|
||
re-serialized from the checked fields alone and its exact bytes required to be
|
||
the canonical encoding of what was broadcast. One approval now yields at most
|
||
one broadcast, and every path that retires a pending approval — popup close,
|
||
active-address change, a late reject — goes through a single chokepoint that
|
||
refuses to settle an attempt already claimed for signing and broadcast
|
||
([#174](https://git.eeqj.de/sneak/AutistMask/issues/174)).
|
||
- 2026-08-12: An address can be removed from an HD or xprv wallet behind a
|
||
confirmation screen that states nothing is destroyed, sharing the deletion
|
||
state transitions with wallet deletion so the selection, site permissions and
|
||
active-address broadcast follow the same rules
|
||
([#162](https://git.eeqj.de/sneak/AutistMask/issues/162)).
|
||
- 2026-08-12: The known-symbol spoof rule moved into `src/shared/symbolSpoof.js`
|
||
and is now the only copy. The balance list had exempted symbols the token list
|
||
maps to `null` — `"ETH"` alone — so a fake ETH ERC-20 was hidden from the
|
||
transaction history and the Send selector but listed as a holding named ETH. A
|
||
symbol with no legitimate contract may now be borne by no contract on any of
|
||
the three surfaces, and the native exemption is "has no contract address", so
|
||
a second null-mapped symbol needs no call-site change. The user's real ETH
|
||
balance is read over RPC and never passes through the rule
|
||
([#235](https://git.eeqj.de/sneak/AutistMask/issues/235)).
|
||
- 2026-08-12: `script/verify-build`'s failure modes are now a committed target,
|
||
`script/test-verify-build`, run by `make check`. It asserts the exit status
|
||
and the message of every case against a fixture tree in a temp dir, and drops
|
||
privileges (proving the runner against a mode-000 file first) for the cases
|
||
that only mean something when file permissions are in force
|
||
([#227](https://git.eeqj.de/sneak/AutistMask/issues/227)).
|
||
- 2026-08-12: WaitTx lifecycle: a receipt and the 60-second timeout can no
|
||
longer both render on one tick, no timer or in-flight lookup outlives its
|
||
wait, a failed receipt lookup no longer counts as a timeout (but six in a row
|
||
end the wait, reported as an unreachable network rather than as a timeout),
|
||
and the wait now resumes after a popup close
|
||
([#155](https://git.eeqj.de/sneak/AutistMask/issues/155)).
|
||
- 2026-08-12: The private key export screen now wipes the key from the page
|
||
whenever it is left by any route, and a decrypt still in flight when the
|
||
screen is left is discarded instead of written; the same `onViewLeave()`
|
||
cleanup was extended to every other screen holding secret material in the DOM
|
||
(AddWallet, ConfirmTx, DeleteWallet, ApproveTx, ApproveSign)
|
||
([#221](https://git.eeqj.de/sneak/AutistMask/issues/221)).
|
||
- 2026-08-12: An xprv wallet already in storage that was imported from a
|
||
non-master key is detected from the depth of its stored `xpub`, explained in
|
||
the wallet list, and blocked from signing, sending and private-key export
|
||
instead of throwing on the send screen
|
||
([#234](https://git.eeqj.de/sneak/AutistMask/issues/234)).
|
||
- 2026-08-12: An unreported `holders_count` is now parsed as `null` rather than
|
||
`0`, so the low-holder rule declines to judge an unknown count instead of
|
||
hiding a legitimate token as spam, in both the transaction history and the
|
||
Send token selector ([#230](https://git.eeqj.de/sneak/AutistMask/issues/230)).
|
||
- 2026-08-12: Bundled token list documentation no longer states a count. The
|
||
four "top 250" claims in `README.md` and the "roughly 500" claim in
|
||
`docs/README.md` are replaced with a description of how the list is actually
|
||
selected — a point-in-time CoinGecko snapshot of the highest-market-cap
|
||
Ethereum mainnet ERC-20s — with `TOKENS` in `src/shared/tokenList.js` named as
|
||
the authoritative set
|
||
([#239](https://git.eeqj.de/sneak/AutistMask/issues/239)).
|
||
- 2026-08-11: libsodium runs on WebAssembly in the shipped builds —
|
||
`'wasm-unsafe-eval'` added to both manifest CSPs after measuring the wasm2js
|
||
fallback at 20x the Argon2id cost, pinned in both directions by
|
||
`tests/manifest.test.js` and observed in the real popup by the e2e suite
|
||
([#182](https://git.eeqj.de/sneak/AutistMask/issues/182)).
|
||
- 2026-08-11: Known-symbol spoof verification became a Settings toggle
|
||
(`hideSpoofedSymbols`), on by default, governing the transaction-history
|
||
filter and the fraud-contract learning it feeds
|
||
([#176](https://git.eeqj.de/sneak/AutistMask/issues/176)).
|
||
- 2026-08-11: `script/verify-build` now walks `dist/` NUL-delimited and asserts
|
||
`dist/` is a real directory, so a path with a trailing space or a newline can
|
||
no longer carry a debug marker past the unlisted-bundle check
|
||
([#223](https://git.eeqj.de/sneak/AutistMask/issues/223)).
|
||
- 2026-08-11: UTC Timestamps checkbox moved from the Token Spam Protection well
|
||
into Display, next to the theme selector
|
||
([#212](https://git.eeqj.de/sneak/AutistMask/issues/212)).
|
||
- 2026-08-11: Network fee counted in the confirmation-screen balance check for
|
||
both ETH and ERC-20 sends, reserving what the node actually charges a type-2
|
||
transaction, with the arithmetic in a pure, unit-tested
|
||
`src/shared/txValidation.js`
|
||
([#154](https://git.eeqj.de/sneak/AutistMask/issues/154)).
|
||
- 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](https://git.eeqj.de/sneak/AutistMask/issues/179)).
|
||
- 2026-08-11: Password-gated recovery phrase display for HD wallets, reached
|
||
from the wallet row in Settings, wiped on leaving the screen and excluded from
|
||
the views the popup can reopen onto
|
||
([#161](https://git.eeqj.de/sneak/AutistMask/issues/161)).
|
||
- 2026-08-11: Extended-key import hardened — the base58 checksum is now enforced
|
||
on every xprv and xpub, and a non-master key is refused with an explanation
|
||
instead of being derived beneath
|
||
([#210](https://git.eeqj.de/sneak/AutistMask/issues/210)).
|
||
- 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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/159)).
|
||
- 2026-08-11: Three `README.md` claims corrected against the code — blocklist
|
||
attribution, token-display rule, navigation model
|
||
([#213](https://git.eeqj.de/sneak/AutistMask/issues/213)).
|
||
- 2026-08-11: README Screen Map rebuilt from the code — every screen, element
|
||
and transition re-verified against `src/popup/`
|
||
([#164](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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](https://git.eeqj.de/sneak/AutistMask/issues/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` and
|
||
`make test-e2e-firefox` runnable in the Gitea workflow. Extending the Chrome
|
||
suite itself is tracked as
|
||
[#183](https://git.eeqj.de/sneak/AutistMask/issues/183).
|
||
- Cut 1.0.0 once the milestone is empty, then continue tagging as milestones
|
||
land.
|