Skip to content

fix(ext): store-required icons + manifest description limit, with a CI gate - #12

Merged
astraedus merged 1 commit into
mainfrom
extension-listing-fixes
Jul 26, 2026
Merged

fix(ext): store-required icons + manifest description limit, with a CI gate#12
astraedus merged 1 commit into
mainfrom
extension-listing-fixes

Conversation

@astraedus

Copy link
Copy Markdown
Owner

Two Chrome Web Store submission blockers found by the listing-package prep, plus a gate so they can't silently come back.

1. No icons key at all

CWS requires 128×128; the built manifest had none. Generated 16/32/48/128 from store-listing/app-icon-512.png (the teal two-bar mark the NudgeMark SVG already renders) using Pillow with Lanczos, ImageMagick isn't installed on this box, and the resampling choice matters: a hard-edged glyph goes visibly ragged at 16px under a cheaper downscale.

Placed at extension/public/icon/{size}.png, which is WXT's documented auto-discovery convention, so the icons key is synthesized at build time rather than hand-maintained. action.default_icon is also set explicitly, Chrome would fall back to icons, but naming the small sizes keeps the toolbar button crisp instead of letting it downscale the 128 itself.

2. Description was 160 chars against a 132 limit

Replaced verbatim with the verified 130-char line from ops/routes/nudge/research/ext-09-listing-package/listing-copy.md:

Friction, not walls: delay and breathing pauses block distracting sites. Daily limits, local screen time. No account, no tracking.

3. The gate

Neither defect was visible to lint, tsc, 598 unit tests, the build, or 37 e2e specs, all green the entire time a submission would have been rejected. Store validity is invisible to every gate we had.

scripts/store-validity.mjs now holds the CWS rules once, and:

  • scripts/verify-manifest.mjs runs them against the BUILT .output manifest, wired into CI right after the build step. Deliberately not the source: WXT synthesizes the icons key, so it appears in no source file, a source-side check would have passed while the shipped artifact was still broken.
  • tests/build/storeValidity.test.ts unit-tests the rules themselves (10 cases, including the exactly-at-limit boundary and reporting both problems at once).

Plain ESM so both share one definition of the limits, a duplicated limit is a limit that drifts. Typed for the TS side via a .d.mts rather than a suppression comment.

Proven to bite: against a manifest with the icons key deleted and the old 160-char description restored, it reports both problems and exits 1.

Verification

Built manifest now contains:

"icons": {"16":"icon/16.png","32":"icon/32.png","48":"icon/48.png","128":"icon/128.png"}
"action": { "default_icon": { ... } }
description length: 130
Gate Result
npm run lint clean
npm run typecheck clean
npm test 608 passing, 22 files (+10)
npm run build loadable
npm run verify:manifest store-valid
npm run e2e 37/37 passing

Scope kept tight: no Lights Off files touched.

Draft on purpose, the orchestrator QA-gates the merge.

… guard both

Two Chrome Web Store submission blockers found by the listing-package prep, plus
a gate so they cannot silently come back.

ICONS. The built manifest had no `icons` key at all; CWS requires 128x128.
Generated 16/32/48/128 from store-listing/app-icon-512.png (the teal two-bar mark
the NudgeMark SVG already renders) with Pillow/Lanczos, ImageMagick is not
installed here, and Lanczos matters because a hard-edged glyph goes visibly
ragged at 16px under a cheaper downscale. Placed at extension/public/icon/{size}.png,
which is WXT's documented auto-discovery convention, so the `icons` key is
synthesized at build time rather than hand-maintained. action.default_icon is set
explicitly too: Chrome would fall back to `icons`, but naming the small sizes
keeps the toolbar button crisp instead of downscaling the 128 itself.

DESCRIPTION. Was 160 chars against a 132 hard limit. Replaced verbatim with the
verified 130-char line from
ops/routes/nudge/research/ext-09-listing-package/listing-copy.md.

THE GATE. Neither defect was visible to lint, tsc, 598 unit tests, the build or
37 e2e specs, all green the whole time a submission would have been rejected. So
scripts/store-validity.mjs holds the CWS rules once, and:
  - scripts/verify-manifest.mjs runs them against the BUILT .output manifest
    (deliberately not the source: WXT synthesizes the icons key, so it appears in
    no source file and a source-side check would have passed while the shipped
    artifact was still broken), wired into CI right after the build step
  - tests/build/storeValidity.test.ts unit-tests the rules themselves
Plain ESM so both share ONE definition of the limits; a duplicated limit drifts.
Proven to bite: against a manifest with the icons key deleted and the old 160-char
description restored it reports both problems and exits 1.

Verified in the BUILT manifest: icons {16,32,48,128}, action.default_icon, and a
130-character description.

Gate: eslint clean, tsc clean, 608 unit tests (22 files, +10), 37/37 e2e,
verify:manifest passing.
@astraedus
astraedus marked this pull request as ready for review July 26, 2026 23:55
@astraedus
astraedus merged commit 84601ce into main Jul 26, 2026
2 checks passed
@astraedus
astraedus deleted the extension-listing-fixes branch July 26, 2026 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant