Repository navigation
Releases: antrixy/headerwright
Release list
v0.1.7 — a delete path no longer requests permissions
Closes FINDING-028 and FINDING-024. They were one line, not two.
diffDomainGrants() computed its two sides from different questions: toRevoke
read profile MEMBERSHIP, toRequest read GRANT STATE alone. So toRequest was
every ungranted domain in the resulting set, with no reference to what the
user had just done. A delete cannot add a domain, so it had nothing new to
want, and requested anyway — one approval on a delete confirmation granted
four domains the user never approved. The same filter re-requested the whole
legacy set on any edit, silently, because a previously-approved origin
re-grants without a dialog.
const toRequest = [...after].filter((d) => !before.has(d) && !granted.has(d));
Delete never requests. Save requests only newly-typed domains. Import
requests only domains the previous set did not reference. Recovery for a
denied or legacy domain is the chip, which is what the migration notice
already told users to use.
Also FINDING-032: the selftest's source-text scans could not tell a use from
a mention. Deleting FINDING-022's fix while a comment named it kept the suite
green — a false pass on the tripwire built to stop exactly that regression.
No new capability. No new permission. The extension still has no webRequest.
Selftest 273 -> 281, three mutation passes, browser sitting G with
predictions pre-registered before Chrome opened.
v0.1.6
Fix
-
The master toggle and status line no longer scroll out of view. The popup was three elements in normal flow, so once the profile list overflowed, both the on/off control and the
X/Y domains grantedreadout left the viewport (FINDING-022). The list now scrolls between a fixed header and a fixed footer. This was reached sooner than expected: v0.1.5's collision marker costs roughly 110px per card, so two colliding profiles could push Add profile below the fold at three profiles, not six. Verified against that exact configuration. -
Two refusal messages no longer describe a state that isn't happening. Saving a colliding profile, and importing a file containing a collision, both reused the wording written for the per-profile card marker — which reports that a stored profile is not applying (FINDING-026). Neither case is that: nothing had been saved, nothing had been imported, and on import the message could appear directly beneath cards that legitimately did say "Not applying". Both now describe the refused action and name what to change. The import message also stated the problem twice and ended in a double period; both are corrected. The card marker's wording is unchanged.
Change
- The subdomain migration notice now names its visual marker. It closes with "Click any underlined domain below to re-approve it", and domains carrying a pre-0.1.4 grant are the only ones underlined. No behaviour change; the notice was already correct, and this makes the domains it counts identifiable.
Notes
- No new permissions. The manifest is unchanged:
declarativeNetRequestWithHostAccessandstorage, with host access requested per-domain at grant time. NowebRequest; the extension cannot read your traffic. - v0.1.5's notes said the four-surface gap was "being addressed in the next release". This release does not close it. A colliding profile still shows a green domain dot, is counted in the "domains granted" total, and the status line still reads "applying" — the per-profile marker remains the only surface reporting the collision. Closing it means the status line and badge reporting how many profiles were skipped, which is new signal rather than corrected signal, so it is queued rather than patched.
- Known limit: with many profiles, a delete confirmation can render below the visible area, with nothing indicating that the popup continues below (FINDING-030). Not a regression — it was also off-screen before this release — but the pinned footer now reads as the end of the popup.
- Browser evidence for this release is in
test/EVIDENCE.md(v0.1.6 — sitting E). Predictions were frozen before the browser opened (test/RUNBOOK-2026-09-04-v016.md); 12 of 13 were right, and the wrong one is recorded with its original wording. - FINDING-023, a claim that domain chip tooltips never render, was withdrawn during this cycle as not reproducible. The tooltips render. The migration notice change above stands on its own merits.
- Selftest is 273 checks, 32 of them for this change. The new logic also passes a 31-mutation pass, re-runnable via
test/mutate-collisions.py. - Known open items are tracked in
FINDINGS.md(024, 025, 027–031); none block this fix.
v0.1.5
Fix
- Two profiles that write the same header on overlapping domains no longer
pick a silent winner. Every generated rule carries the same DNR priority,
and Chrome does not standardise ordering between rules with the same action
and priority — so one profile's header applied, the other silently did
nothing, and the popup showed both as applying (FINDING-021). v0.1.5 refuses
the configuration instead of letting Chrome choose: a colliding pair applies
neither header, both profiles are marked in the popup with the header
name and the other profile's name, and a save or import that would create a
collision is refused with the same explanation. Domains overlap the way rules
do —example.comoverlapsapi.example.com,notexample.comdoes not.
Verified on the wire.
Migration
- This can affect you without your having changed anything. v0.1.4's
subdomain fix made profiles overlap that did not overlap before —
example.comandapi.example.comis the common case — so a pair that
worked under v0.1.3 may be marked after updating, with neither header
applying until the header or the domains are changed in one of them. The
refusal is reversible, and editing an unrelated profile is not blocked while
a collision exists.
Notes
- No new permissions. The manifest remains
declarativeNetRequestWithHostAccess
andstorage, with host access requested per-domain at grant time. No
webRequest; the extension cannot read your traffic. - A colliding profile still shows a green domain dot, is counted in the
"domains granted" total, and the status line still reads "applying" — the
per-profile marker is the only surface reporting the collision. Being
addressed in the next release (FINDING-022, FINDING-026). - Full wire evidence for this release is in
test/EVIDENCE.md(v0.1.5 —
sitting D). Predictions were frozen before the browser opened
(test/RUNBOOK-2026-09-01-v015.md); 13 of 15 were right, and the 2 wrong
ones are recorded with their original wording. - Selftest is 241 checks, 36 of them for this change, including a control that
notexample.comis not treated as overlappingexample.com. The new logic
also passes an eleven-mutation pass, re-runnable via
test/mutate-collisions.py. - Known open items are tracked in
FINDINGS.md(022–027); none block this fix.
v0.1.4
v0.1.4
Fix
- Headers now apply on subdomains of a granted domain. Under v0.1.3, a
profile scoped toexample.comapplied on the apex but silently failed on
api.example.com— the host permission did not cover the hosts the rule
matched (FINDING-018). v0.1.4 requests*://*.<domain>/*alongside the
apex, so a granted domain covers its subdomains. Verified on the wire.
Migration
- Domains granted under v0.1.3 are shown as gray ("not covered yet") after
updating, with a notice, and apply again once re-approved with one click.
Existing grants are preserved across the update; nothing is silently lost.
Notes
- No new permissions. The manifest remains
declarativeNetRequestWithHostAccess
andstorage, with host access requested per-domain at grant time. No
webRequest; the extension cannot read your traffic. - Full wire evidence for this release, including the upgrade path and the
reconciliation behavior, is intest/EVIDENCE.md(v0.1.4 — sitting C). - Known open items are tracked in
FINDINGS.md(021–025); none block this fix.
v0.1.3
v0.1.2
Fixes
- Generated profile ids could exceed Chrome's rule-id range after importing a
profile at the maximum id, which caused every subsequent rule update to fail
silently. Ids are now allocated from the lowest free value. - Duplicate domains within a profile were stored, displayed and exported as
duplicates, so the chip list and the domain count disagreed on screen.
Domains are now deduplicated, which brings the exported file into line with
the set semantics the format already specified. No conforming file's bytes
change. - Imports larger than Chrome's 5,000-rule limit were accepted and silently
truncated, applying fewer rules than configured while reporting success.
Over-cap imports are now refused with an exact reason, and profiles can no
longer be added past the limit. - The popup showed stale status while open: a sync failure arriving after the
popup rendered left it reporting that rules were applying. It now updates in
place. - Deleting a profile now asks for confirmation. Delete is unrecoverable and
was the only destructive action without one. - Exporting now states that header values are saved in plain text.
v0.1.1
Invariant-repair patch. Fixes only, no new capability.
- Edit path now reconciles host permissions; a domain removed during an edit
no longer keeps its grant, and a domain another profile still references is
retained - Header name and value validation tightened to the HTTP token set and to
reject control characters; rule-id range enforced on import - Rule sync failures are caught and surfaced; the badge no longer shows ON
when Chrome rejected the rule registration - Ungranted domain chips are now clickable to request access, replacing an
undiscoverable Edit-then-Save recovery path - Rule sync calls serialized
Selftest suite: 113 checks, count tripwire.
Verified against live traffic (postman-echo.com) and a written smoke script
(test/SMOKE.md) before tagging.
v0.1.0
Initial release.
- Header profiles: set / append / remove request headers, scoped per domain
- Optional per-site host permissions — nothing granted at install
- Master toggle with state badge
- Canonical JSON import/export (key-sorted, byte-stable)
- declarativeNetRequest only; no webRequest permission
- Selftest suite: 47 checks, count tripwire
Verified against live traffic (httpbin.org) before tagging.