test: encode the extension's AMO rendering exception (milestone 318 step 8)
Build images / sign-extension (push) Successful in 4s
Build images / build-agent (push) Successful in 4s
Build images / build-ml (push) Successful in 5s
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
CI / frontend-build (push) Successful in 22s
Build images / build-web (push) Successful in 3s
CI / backend-lint-and-test (push) Successful in 31s
CI / integration (push) Successful in 3m40s
extension / lint (pull_request) Successful in 21s

Missed in 2e01242. This module pinned zero-padded `YYYY.MM.DD.HHMM` for all
four artifacts, which is the family shape and was right until the extension
acquired a documented reason not to use it. Both assertions failed exactly as
written, on the value they were written to catch.

Rather than exempt the extension, the exception is pinned to the constraint
that justifies it:

* `test_version_is_zero_padded_calver` now covers the three padded artifacts.
* A new sibling covers the unpadded one against **AMO's own grammar** —
  `2026.08.29.0201` fails it, so a regression to padding fires immediately.
  Matching only `YYYY.M.D.HHMM` would not: on a date with no leading zeros the
  two renderings are the same string, so a padding regression would sit unseen
  until the first single-digit month, and surface as a burned AMO version
  rather than a red lane.
* `test_version_and_revision_describe_the_same_commit` compares NUMBERS, per
  rule 148's own definition of comparison — so one assertion covers both
  renderings and says the real thing: whatever the padding, the extension must
  denote exactly the value its own commit stamps. Exact-string equality is
  still asserted for everything not in AMO_UNPADDED, so the exception cannot
  quietly spread.

Scribe #3138.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 13:46:18 -04:00
co-authored by Claude Opus 5
parent 2e01242381
commit 1a941e900b
+72 -2
View File
@@ -34,6 +34,15 @@ is genuinely the commit those paths last changed in.
emit. Two nearly-identical formats are more dangerous than two obviously emit. Two nearly-identical formats are more dangerous than two obviously
different ones, and the only thing keeping them identical is a test. different ones, and the only thing keeping them identical is a test.
**The extension is the one exception, and it is a rendering exception only.**
AMO's version grammar forbids a leading zero, so the extension emits the same
numbers unpadded — `2026.8.29.201` where the family says `2026.08.29.0201`
(#3138, milestone 318 step 8). Rule 148 defines comparison as numeric per
dot-segment, under which the two are equal, so this is pinned in both
directions below: the extension must satisfy AMO's grammar, and every artifact
must derive the same NUMBERS its own commit stamps. An exception left as "the
extension is different" would drift into being differently different.
The identity-TAG tests this file used to hold are gone with the tag. There is The identity-TAG tests this file used to hold are gone with the tag. There is
no longer a `CHANNELLED` list to drift (the channel is which tag you inspect), no longer a `CHANNELLED` list to drift (the channel is which tag you inspect),
and no `identity` subcommand to refuse an unqualified call. and no `identity` subcommand to refuse an unqualified call.
@@ -57,6 +66,26 @@ _REVISION = re.compile(r"^[0-9a-f]{12}$")
# YYYY.MM.DD.HHMM, every segment zero-padded to its full width. # YYYY.MM.DD.HHMM, every segment zero-padded to its full width.
_VERSION = re.compile(r"^\d{4}\.\d{2}\.\d{2}\.\d{4}$") _VERSION = re.compile(r"^\d{4}\.\d{2}\.\d{2}\.\d{4}$")
# The artifacts that cannot use the padded rendering. Exactly one, and the
# reason is external: `packaging.sh` derives the extension's version and AMO
# refuses to sign a padded one.
AMO_UNPADDED = frozenset({"extension"})
# Mozilla's published grammar for addons.mozilla.org, transcribed from MDN's
# manifest.json/version page. A segment is the single digit `0` or starts 1-9,
# and there are at most four. This is the constraint the exception exists for,
# so it is what the exception is tested against — `2026.08.29.0201` fails it.
_AMO = re.compile(r"^(0|[1-9][0-9]{0,8})(\.(0|[1-9][0-9]{0,8})){0,3}$")
# YYYY.M.D.HHMM — four segments, none of them zero-padded.
_UNPADDED = re.compile(r"^\d{4}(\.(0|[1-9]\d*)){3}$")
def segments(value: str) -> tuple[int, ...]:
"""A version as the numbers it denotes, which is how rule 148 says to
compare one. `2026.08.29.0201` and `2026.8.29.201` are one value here."""
return tuple(int(part) for part in value.split("."))
# Everything here goes through artifacts.sh rather than importing a sibling # Everything here goes through artifacts.sh rather than importing a sibling
# test module. That is the interface build.yml actually calls, so the tests # test module. That is the interface build.yml actually calls, so the tests
@@ -126,7 +155,7 @@ def test_revision_is_a_legal_label_value_and_is_stable(artifact):
assert first == revision(artifact), "revision is not stable across calls" assert first == revision(artifact), "revision is not stable across calls"
@pytest.mark.parametrize("artifact", ARTIFACTS) @pytest.mark.parametrize("artifact", sorted(set(ARTIFACTS) - AMO_UNPADDED))
def test_version_is_zero_padded_calver(artifact): def test_version_is_zero_padded_calver(artifact):
"""The family shape, pinned. """The family shape, pinned.
@@ -148,6 +177,31 @@ def test_version_is_zero_padded_calver(artifact):
) )
@pytest.mark.parametrize("artifact", sorted(AMO_UNPADDED))
def test_the_unpadded_artifacts_derive_something_amo_will_sign(artifact):
"""The other half of the family shape: the documented exception, tested
against the constraint that justifies it rather than against itself.
A padded value passes `_UNPADDED` on any date with no leading zeros, so
that pattern alone would let a regression sit unnoticed until the first
single-digit month — at which point the failure is a burned AMO version,
not a red lane. AMO's grammar is the assertion that fires immediately.
"""
value = artifacts("version", artifact).strip()
assert _AMO.match(value), (
f"{artifact} derives {value!r}, which AMO refuses: a segment must be "
f"the single digit `0` or start 1-9, and there are at most four. "
f"Almost certainly a zero-padded segment — the family pads and this "
f"artifact must not (#3138). AMO 409s on re-signing, so a version it "
f"rejects is burned."
)
assert _UNPADDED.match(value), (
f"{artifact} derives {value!r}, which is not YYYY.M.D.HHMM. AMO would "
f"also accept the pre-318 `1.0.<minutes>`, and that orders below every "
f"ext-2026.* release already signed."
)
@pytest.mark.parametrize("artifact", ARTIFACTS) @pytest.mark.parametrize("artifact", ARTIFACTS)
def test_version_and_revision_describe_the_same_commit(artifact): def test_version_and_revision_describe_the_same_commit(artifact):
"""They are derived independently and must not be able to disagree. """They are derived independently and must not be able to disagree.
@@ -162,5 +216,21 @@ def test_version_and_revision_describe_the_same_commit(artifact):
capture_output=True, text=True, check=True, cwd=ROOT, capture_output=True, text=True, check=True, cwd=ROOT,
env={"TZ": "UTC", "PATH": os.environ.get("PATH", "")}, env={"TZ": "UTC", "PATH": os.environ.get("PATH", "")},
).stdout.strip() ).stdout.strip()
assert artifacts("version", artifact).strip() == stamped derived = artifacts("version", artifact).strip()
# Compared as NUMBERS, which is how rule 148 defines comparison and the
# only way one assertion can cover both renderings. This is what makes the
# extension's exception cosmetic rather than semantic: it must denote
# exactly the value its own commit stamps, whatever the padding.
assert segments(derived) == segments(stamped), (
f"{artifact} derives {derived!r}, but its newest shipped commit "
f"{sha[:12]} is {stamped!r}. The instance would name one commit while "
f"carrying another's bytes."
)
if artifact not in AMO_UNPADDED:
assert derived == stamped, (
f"{artifact} derives {derived!r} where the family shape is "
f"{stamped!r} — same numbers, wrong rendering. Only the artifacts "
f"in AMO_UNPADDED may differ here."
)
assert sha.startswith(revision(artifact)) assert sha.startswith(revision(artifact))