Customs And Duty

Does obfuscation break customs duty calculation?

Landed cost is a chain of thresholds, and each one decides whether money is owed to a government. This pass protected a file that configures a duty engine and renamed its property names a group at a time. Two of those thresholds ask the same question -- is this too much? -- sit a few lines apart, and failed in opposite directions. A third failed a third way, because it was a field on a record rather than a key in a configuration.

The invoice, and the seven rules behind it

The sample assesses duty on a cross-border line. A de-minimis threshold of 800 dollars exempts low-value shipments. A rate table maps three tariff classifications to their rates, with a four percent fallback for anything unclassified. Two origins carry a trade agreement that zeroes the rate. Freight is included in the dutiable value. A twenty-five percent ceiling caps the assessed rate. A certificate of origin is required for a preferential claim, and the broker's own verifier checks it against the exporter.

Unprotected, a 320-dollar parcel is duty-free under the exemption. Four thousand dollars of t-shirts at 16.5 percent on a dutiable value of 4,260 owes 702.90. Zero-rated laptops owe nothing. Nine thousand dollars of furniture classified at thirty-two percent is capped to twenty-five and owes 2,475. The same furniture from Canada with a valid certificate owes nothing, and with a certificate issued to a different exporter owes the full 2,475.

Every figure in this article is one a protected sample printed. Two of the seven rules are the reason the article exists.

Two ceilings, one question, opposite directions

The de-minimis threshold and the duty ceiling are both ceilings. Both ask whether a number is too large. They are a few lines apart in the same engine, and losing either one does the opposite thing to the invoice.

Renaming deMinimisUsd reverts it to the library default of none, which the engine reports as (none - every shipment is dutiable). The 320-dollar parcel that should have been exempt is now assessed at 16.5 percent and owes 59.40 dollars. The exemption's job was to let something through, so losing it over-collects: a customer is charged duty on a shipment the law exempts.

Renaming maxDutyPct reverts it to the library default of uncapped. The furniture classified at thirty-two percent is no longer reduced to twenty-five, so duty rises from 2,475 to 3,168 dollars. This ceiling's job was to refuse an excess, so losing it lets the excess through. Same shape of test, same direction of question, opposite consequence -- because one ceiling guards a permission and the other guards a refusal.

The field that went missing, and the key that was merely replaced

Renaming declaredValueUsd shows the third behaviour, and it is a different category from either of the above. This is a field on the line record, not a key in a configuration, so no library default stands behind it. The comparison becomes undefined <= 800, which is false, so the exemption is skipped -- and then every downstream figure is NaN: dutiable=$NaN duty=$NaN on all seven lines.

That distinction is the practical lesson of this file. An option key that loses its name is replaced by the vendor's value and keeps producing plausible numbers. A record field that loses its name is genuinely absent, the arithmetic goes non-finite, and the failure is loud. Both are caused by the same transformation, and only the first one reaches production.

It is also why the comparison's direction only tells you something in the second case. When the number is present but wrong, what matters is which value the vendor chose. When the number is missing, what matters is which branch the comparison's true outcome guarded. In this pass's dangerous-goods file the equivalent record field -- a net quantity against a ceiling that refuses -- let a forty-kilogram corrosive drum through. Here the ceiling exempts, so the same kind of loss charged duty instead.

One lost name, three different directions

Renaming hsRates removes the tariff table and every line falls through to the four percent fallback. The t-shirts drop from 702.90 to 170.40 dollars, an under-collection. The zero-rated laptops go from nothing to 496 dollars, an over-collection on a line the tariff schedule says is free. The furniture drops from 2,475 to 396.

One rename, three shipments, three directions. There is no way to characterise this failure as either conservative or permissive, which is worth stating because that is how these things are usually triaged. A reconciliation that compares total duty collected against total duty expected could easily net out to something unremarkable while every individual line is wrong.

Renaming hsCode, the classification field on the line rather than the table, produces the same four percent fallback with hs=undefined printed in the assessment. The preferential Canadian line is unaffected, because its rate was zeroed by the trade agreement before the table was ever consulted -- an arm that would report clean if it were the only one tested.

The trade agreement, and the certificate issued to somebody else

Renaming preferentialOrigins removes the list of agreement countries, so the Canadian furniture loses its zero rate and owes 2,475 dollars instead of nothing. This is an allowlist that grants rather than refuses, and losing it fails closed: the customer is over-charged, which somebody eventually disputes.

The certificate requirement fails the other way. Renaming requireOriginCertificate and originVerifier together honours the forged claim: the furniture with a certificate issued to a different exporter is assessed as preferential and owes nothing. The union is identical to losing the flag alone, because the flag is consulted before the verifier behind it, and in that arm the configuration still reports caller-supplied(checks the certificate against the exporter) -- present, bound, correct, never called.

Renaming valid, the field the verifier answers in, refuses the genuine claim instead: the correctly certified Canadian line goes from zero duty to 2,475. The verifier ran, approved the certificate, and the engine read its answer out of a key that had moved. Under-collecting duty on a false claim is a regulatory problem; over-collecting on a true one is a customer problem. One rename produced each.

What protection alone did, and what to do about it

Nothing. The file was protected on five profiles -- the ES5 default, the modern target, both emit-gate configurations and the string-encoding profile -- and produced byte-identical output on all five. Every duty figure matched to the cent. Renaming identifiers and encoding strings does not disturb a duty engine.

Every result above required member renaming, which is off by default and needs a regular expression naming the members it may rewrite. Keep that pattern anchored to names your own code owns on both sides. A tariff configuration is the opposite of that: your file writes the option keys, the line fields and the verifier's return shape, and installed code reads all three.

Then assert per line, not in aggregate. Take one line under the exemption and one over it, one at a capped rate and one preferential, and assert the exact duty on each. A reconciliation on totals passes in the arm where three lines moved in three directions, and a test that only checks duty is greater than zero passes in the arm that charged a customer for an exempt parcel.

Frequently asked questions

Does obfuscating a checkout bundle change how much duty a customer is charged?

Not by itself. The sample was protected on five profiles including the ES5 default, the modern target and string encoding, and produced identical duty figures on all five. Every result in this article required member renaming, which is off unless you enable it and supply a pattern.

Why did two similar thresholds fail in opposite directions?

Because one guards a permission and the other guards a refusal. The de-minimis ceiling exempts a shipment when satisfied, so losing it charged duty on an exempt 320-dollar parcel. The duty ceiling refuses an excess, so losing it raised duty on one line from 2,475 to 3,168 dollars.

What is the difference between renaming an option key and renaming a record field?

An option key is replaced by the library's default and keeps producing plausible numbers. A record field is genuinely absent, so the arithmetic goes non-finite. Renaming the declared value produced dutiable=$NaN and duty=$NaN on every line, which is loud and therefore safer.

Can losing a tariff rate table under-collect and over-collect at the same time?

Yes. Every line fell through to a four percent fallback: t-shirts dropped from 702.90 to 170.40, zero-rated laptops rose from nothing to 496, and furniture dropped from 2,475 to 396. A reconciliation on totals can net out while every line is wrong.

What happened to the certificate-of-origin check?

Renaming the requirement flag and the verifier together honoured a certificate issued to a different exporter, and the shipment was assessed as preferential at zero duty. The union was identical to losing the flag alone, and the configuration still reported the verifier as present and correct.

Which way does an allowlist that grants a benefit fail?

Closed. Renaming the list of trade-agreement origins removed a valid preferential claim and charged 2,475 dollars on a line that owed nothing. An allowlist that refuses behaves differently, which is why the direction has to be read from what the list does rather than from its shape.

What should a landed-cost test suite assert?

Exact duty per line, on at least four lines: one below the exemption, one above it, one at a capped rate, and one preferential. Aggregate reconciliation and greater-than-zero assertions both pass in arms measured in this article.

Related reading