markdown fix
All checks were successful
Deploy / build-deploy (push) Successful in 2m23s

This commit is contained in:
Jorijn van der Graaf 2026-08-18 11:12:24 +02:00
commit 4666c1995f
14 changed files with 876 additions and 346 deletions

View file

@ -117,21 +117,66 @@ int main() {
// Zones still classify US and CA (the arithmetic is destination-blind, and
// keeping it that way means one policy switch, not two); the sale is what
// stops, in SellsTo.
// Two hard gates, and the shipping one is an ALLOW-list. The assertion that
// matters most is therefore the DEFAULT: a country nobody has cleared
// refuses. This is the test that fails if the gate is ever "simplified" back
// into a deny-list, which would silently reopen most of the world.
Check(SellsTo("NL") && SellsTo("CH") && SellsTo("AU")
&& SellsTo("HK") && SellsTo("SG")
&& SellsTo("RS") && SellsTo("ME") && SellsTo("AL") && SellsTo("XK")
&& SellsTo("GE"),
"policy: every cleared destination sells");
// Both were cleared once and refuted on verification. JP because using a
// non-giteki handset is a Radio Act offence for the BUYER; NZ because its
// radio regulator's supplier duties expressly reach a website seller and an
// overseas company cannot register to comply. Asserted by name so a future
// "these look fine, add them back" cannot pass silently.
Check(!SellsTo("JP") && !SellsTo("NZ"),
"policy: refuted destinations stay refuted");
Check(!SellsTo("DE") && !SellsTo("FR") && !SellsTo("BE"),
"policy: uncleared member states refuse by default");
Check(!SellsTo("KR") && !SellsTo("MX") && !SellsTo("ZA") && !SellsTo("XX"),
"policy: uncleared and unknown codes refuse by default");
Check(!SellsTo("NO") && !SellsTo("IS"),
"policy: the EEA inherits the EU's distance-seller duties, so it waits");
Check(!SellsTo("GB"), "policy: GB waits on its EA small-producer entries");
Check(!SellsTo("TR") && !SellsTo("IN") && !SellsTo("BR"),
"policy: IMEI and type-approval destinations refuse");
// North America is refused for regulatory reasons now, not insurance ones —
// it simply is not on the list, and there is no separate category for it.
Check(!SellsTo("US") && !SellsTo("CA"), "policy: north america refused");
Check(SellsTo("NL") && SellsTo("DE"), "policy: EU sells");
Check(SellsTo("GB") && SellsTo("CH") && SellsTo("AU"),
"policy: the rest of the world still sells");
Check(SellsTo("us"), "policy: matched on the normalised code, like membership");
// Matching is on the normalised code, as everywhere else here — but note the
// direction the allow-list fails in. Under the old deny-list, "us" missed the
// blocked entry and SOLD; now an unnormalised code is simply absent from the
// list and refuses. Callers still uppercase first (ValidateCheckout does),
// but the consequence of forgetting is a lost sale rather than a shipment to
// a country the shop cannot serve.
Check(!SellsTo("us") && !SellsTo("nl"),
"policy: an unnormalised code fails closed, not open");
Check(ZoneFor("US") == Zone::World, "zone: refused countries still classify");
// Sanctioned destinations refuse through the same gate, but the two lists
// stay distinguishable — the checkout error names the law for one and the
// shop's own choice for the other.
Check(ShipsTo("NL") && !ShipsTo("US") && !ShipsTo("DE"),
"policy: ShipsTo is the allow-list on its own");
// Form::kShipsToMessage names these countries in prose for the buy page, and
// prose cannot be generated from ISO codes. If this fails because a country
// was opened, update that sentence too — the two must not drift.
Check(ShippableCountries().size() == 10,
"policy: opening a country means updating Form::kShipsToMessage as well");
// Sanctioned destinations refuse through the same gate, but stay
// distinguishable — the checkout error names the law for one and pending
// paperwork for the other, and conflating them would tell a Russian buyer
// to email and ask.
Check(!SellsTo("RU") && !SellsTo("BY") && !SellsTo("KP"),
"sanctions: RU, BY and KP refused");
Check(IsSanctioned("RU") && IsSanctioned("BY") && IsSanctioned("KP"),
"sanctions: the list knows its members");
Check(!IsSanctioned("US") && !IsSanctioned("NL"),
"sanctions: the insurance refusal is not a sanctions refusal");
Check(!IsSanctioned("US") && !IsSanctioned("DE") && !IsSanctioned("NL"),
"sanctions: an uncleared country is not a sanctioned one");
// Belt and braces: a sanctioned code must never reach the allow-list, or the
// wrong sentence would be shown for a criminal-law refusal.
for (const std::string_view cc : SanctionedCountries()) {
Check(!ShipsTo(cc), "sanctions: never on the shipping list", cc);
}
// ── carrier weight brackets ───────────────────────────────────────
// The only shipping prices that exist. A ladder covering 2 kg / 10 kg /
@ -264,14 +309,20 @@ int main() {
// A country the shop refuses gets no localised price either — the two
// tables are kept consistent on purpose, so this is a real invariant and
// not a coincidence of the current list.
for (const std::string_view cc : NoSaleCountries()) {
Check(!CurrencyFor(cc).has_value(),
"fx: refused destinations have no display currency", cc);
}
for (const std::string_view cc : SanctionedCountries()) {
Check(!CurrencyFor(cc).has_value(),
"fx: sanctioned destinations have no display currency", cc);
}
Check(!CurrencyFor("US").has_value() && !CurrencyFor("CA").has_value(),
"fx: north america has no display currency either");
// The invariant covers only refusals nothing will lift. The table otherwise
// runs AHEAD of the shipping list on purpose — GB keeps its GBP row while its
// e-waste registrations are pending, because "what would this cost me" stays
// a fair question for a country one small registration from opening, and
// deleting the row to restore it weeks later would be churn. The refusal that
// must not be quoted around is enforced in SellsTo, not here.
Check(CurrencyFor("GB").has_value(),
"fx: a temporarily-closed destination keeps its display currency");
// ── rates loader ──────────────────────────────────────────────────
const Rates r = LoadRates(