Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions docs/excise-tax-stamps-parity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Digital tax stamps / excise traceability: market comparison and design

## 1. What the leading platforms actually do

Reference set (public product documentation, plus the regulatory floor those products are built to):

| Platform | Vendor | Public source |
| --- | --- | --- |
| SICPATRACE® Evo | SICPA | https://www.sicpa.com/solutions/sicpatrace |
| TransAct™ | Authentix | https://authentix-us.com/governments/taxstamp/ |
| DirectTrace excise suite | DirectTrace | https://direct-trace.com/for-excise-tax/ |
| Regulatory floor | EU Commission Implementing Regulation (EU) 2018/574 (TPD Art. 15 traceability), implementing WHO FCTC Illicit Trade Protocol Art. 8 | https://eur-lex.europa.eu/eli/reg/2018/574/oj |

Distilling their published capability sets, a credible excise-traceability platform has to cover
eleven capability areas. `C*` labels are used throughout this document.

- **C1 Licensee / taxpayer administration.** Registration and licensing of manufacturers, importers,
distributors and retailers of excisable goods, with licence validity and suspension.
- **C2 Facility and production-line registry.** Each production or storage facility and each marking
machine identified. 2018/574 makes this explicit: economic operator identifier (EOID), facility
identifier (FID), machine identifier, all issued by an independent **ID issuer**.
- **C3 Product master data and taxation schemes.** Registered SKUs (brand, pack size, strength/volume)
mapped to an excise scheme — specific (per stick / per litre / per litre of pure alcohol),
ad valorem, or hybrid.
- **C4 Stamp / mark procurement.** Order → approval → fiscal liability → payment → fulfilment →
delivery, with stamp stock accounted for at every hop.
- **C5 Unique serialised identifiers.** A non-guessable unique identifier per unit packet, generated
independently of the manufacturer, resistant to duplication, and recorded with its issuance context.
- **C6 Activation and production reporting.** Marks are activated when applied; wastage, spoilage and
destruction are declared; issued stamps reconcile against activated stamps and reported production.
- **C7 Aggregation.** Unit → carton → master case → pallet, each aggregate carrying its own unique
aggregated identifier, so a pallet scan resolves every unit packet inside it (2018/574 Art. 10,
Annex II).
- **C8 Supply-chain movement events.** Dispatch, arrival, transfer of ownership, export, re-entry,
destruction — the event stream that turns marks into traceability.
- **C9 Field enforcement.** Inspector scans a mark and gets authenticity plus the mark's full history;
seizures recorded against the mark. Only authorised enforcement users see the data behind a stamp.
- **C10 Public / consumer authentication.** Anyone can verify a mark; the answer must not leak the
commercial data behind it.
- **C11 Analytics and revenue reconciliation.** Revenue realised vs. expected, illicit-trade
indicators, duplicate marks, diversion detection.

## 2. What this platform has today

Searching the repository for the excise domain returns exactly one thing:

```
server/businessRules.ts:275 exciseRate?: number; // For excisable goods
server/businessRules.ts:290 const excise = (cifValue * (input.exciseRate ?? 0)) / 100;
```

An ad valorem excise term inside `calculateDuty`, and nothing else. There is no stamp, mark, serial,
licensee, facility, SKU or activation concept anywhere in `drizzle/schema.ts` or in the 104 routers.

So the honest comparison is not "which features are missing" but **C1–C11 are all absent**: this is a
customs single-window with no excise-traceability capability at all. What it does bring, and what no
tax-stamp vendor has, is the other half of the problem: declarations, valuation, duty assessment, a
double-entry ledger, payments, risk lanes, manifests and bills of lading, an audit trail, and an
enforcement/officer model. That asymmetry is what section 4 exploits.

| Capability | Leading platforms | This platform (before) | Planned |
| --- | --- | --- | --- |
| C1 Licensee administration | yes | none | excise licences with validity + suspension |
| C2 Facility / machine registry | yes (EOID/FID/machine) | none | facility + machine identifiers, ID-issuer-owned |
| C3 Product master data + schemes | yes | none | SKU registry, specific/ad valorem/hybrid schemes |
| C4 Stamp procurement | yes | none | order → assess → pay → fulfil, ledger-posted |
| C5 Serialised UIDs | yes | none | signed, non-guessable UIDs minted server-side |
| C6 Activation + production reporting | yes | none | activation, wastage, destruction, reconciliation |
| C7 Aggregation | yes | none | unit → carton → case → pallet, resolvable both ways |
| C8 Movement events | yes | none | dispatch/receipt/export/seizure event stream |
| C9 Field enforcement | yes | none | authorised scan with full history + seizure capture |
| C10 Public authentication | yes | none | public rate-limited verify, no commercial data |
| C11 Analytics + reconciliation | yes | none | issued/activated/paid reconciliation + anomalies |

## 3. Design rules carried over from the audit

This module is built under the same rules the fail-closed remediation established, because an excise
system is a money system:

1. **No fabricated authenticity.** A verification result is `authentic`, `unknown`, `suspect` or
`unavailable`. A dependency outage never renders as "authentic", and never as "counterfeit" either —
accusing a legitimate trader on the strength of a Redis timeout is the same defect in the other
direction.
2. **No fabricated reconciliation.** Unreconciled variance is reported as variance. It is never
rounded to zero and never suppressed.
3. **Fail closed on money.** Stamps are not released, and marks are not activated, when the ledger,
database or payment path is unavailable.
4. **UIDs are minted server-side and are unguessable.** A licensee cannot choose its own serials, and
a serial cannot be derived from another serial.
5. **Public endpoints disclose status only.** No brand, licensee, volume, consignee, value or route on
a public scan.
6. **Unknown is nullable.** No zero-valued or empty-string placeholders standing in for absent data.

## 4. The six innovations

These are deliberately *not* reimplementations of vendor features. Each one exists only because this
platform holds both halves of the data — the customs/fiscal side and the mark side — which the
standalone tax-stamp platforms do not.

**I1 — Declaration-linked stamp issuance, gated on settled duty.**
For imported excisable goods, a stamp order is bound to the customs declaration (and through the
linkage added for shipment tracking, to its bill of lading and manifest). Stamps are released only
when the declaration's duty is *settled in the ledger* — not merely marked paid. This closes the
leak every standalone stamp platform lives with: the stamp programme and the customs programme are
different systems, so goods can clear customs and never be stamped, or be stamped and never declared.
Here the two are the same transaction.

**I2 — Offline-verifiable marks.**
Each UID carries a truncated HMAC over the serial payload, keyed by a server-held secret with a key
identifier in the mark. An inspector's device holds a verification key and can distinguish a
well-formed mark from an invented one *with no connectivity*, then reconcile the scan on reconnect.
The offline answer is explicitly labelled `signature_valid_pending_reconciliation` — it proves the
mark was minted by the authority, and does not claim the pack is legitimate, because a genuine mark
can still be cloned onto illicit product. That distinction is the entire point, and it is the one
thing offline verification usually gets dishonestly wrong.

**I3 — Impossible-travel detection on scans.**
The same UID scanned in two places implies a speed between them. Above a physical threshold, one of
the two marks is a clone. This is the mobile-money fraud-detection pattern applied to fiscal marks,
using the platform's existing geospatial data. It flags the *mark*, not the trader, and it records
both scans as evidence rather than deleting the "wrong" one.

**I4 — Stamp liability on the double-entry ledger.**
Stamp orders post to the existing ledger, so at any moment `stamps issued × unit liability` is
reconcilable against `paid`, `activated` and `reported production`. Vendors report stamp counts;
posting the liability into the same ledger that carries duty and VAT means excise revenue is
auditable by the same reconciliation that covers everything else, and a variance cannot hide in a
spreadsheet between two systems.

**I5 — Consumer scan as an enforcement sensor.**
Public verification is anonymous and discloses nothing commercial, but the scan itself is retained as
a signal feeding I3 and the risk model. Consumers become a national sensor network for illicit trade
without surrendering any personal data and without being told anything about the supply chain.

**I6 — Seizure-to-source graph traversal.**
From a seized unit packet, resolve upward through aggregation (carton → case → pallet) to the
production or import event, the declaration, the manifest, the importer and the mandate-holding agent
who filed it — and back down to every sibling mark from the same batch that is still in the market.
Enforcement's real question is not "is this pack fake" but "where did it come from and what else came
with it", and answering that needs both the aggregation tree and the customs record.

## 5. Also closing: two residual findings from the audit

Both were left open in the audit's residual register as policy decisions. They are closed here as
*mechanism* — configuration replaces hardcoded constants, and absence fails closed — without inventing
Nigerian or Ghanaian rates, which remains the authority's data to load:

- **Flat 10% duty / 15% VAT.** Replaced by a persisted tariff schedule keyed by HS code and effective
date. A declaration whose HS code has no effective rate is **rejected**, not assessed at a default.
A wrong-but-plausible assessment is worse than a refusal.
- **GHS/NGN/USD incoherence.** Replaced by an explicit jurisdiction configuration (customs accounting
currency plus permitted settlement currencies) and a persisted FX rate with a source and timestamp.
No rate on the valuation date means the assessment fails closed rather than silently mixing
currencies.
117 changes: 117 additions & 0 deletions docs/single-window-market-parity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Single-window market comparison: gaps and innovations

## 1. Reference set

| Platform | Operator | Public source |
| --- | --- | --- |
| TradeNet / Networked Trade Platform (NTP) | Singapore Customs | https://www.customs.gov.sg/doing-business/quick-links-for-traders/tradenet/what-you-need-to-know-about-tradenet/ |
| EU Single Window Environment for Customs / CSW-CERTEX | European Commission (DG TAXUD) | https://taxation-customs.ec.europa.eu/customs/customs-controls/eu-single-window-environment-customs_en |
| ASYCUDAWorld national/regional single window | UNCTAD | https://asycuda.org/ |
| Regulatory floor | Regulation (EU) 2022/2399 + Delegated Reg. (EU) 2024/2514; WTO TFA Arts. 3, 4, 7, 10.4; WCO Data Model | https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=CELEX:02022R2399-20241017 |

Capability areas distilled from those sources, labelled `SW*` below.

## 2. Comparison

Verified against the repository, not against its own marketing components.

| # | Capability | Reference platforms | This platform | Verdict |
| --- | --- | --- | --- | --- |
| SW1 | Single declaration serving all agencies | TradeNet: one submission, all controlling agencies | declarations + `ogaPermits` per declaration | **present** |
| SW2 | Declaring-agent model (submission on behalf of a principal) | TradeNet DA functions | `stakeholderMandates`, principal/acting-agent on declarations | **present** (added in the parity work) |
| SW3 | Amendment / cancellation / refund of a lodged declaration | TradeNet: amendment, cancellation **and** refund applications | `declarationAmendments` (request/review only); `drawback` covers duty drawback on re-export | **partial** — no cancellation, no overpayment refund |
| SW4 | Formalities catalogue: which non-customs permits a consignment actually needs | CSW-CERTEX's core purpose — automatic verification of non-customs formalities against declaration data at clearance | nothing; a grep for `requiredPermits`/`permitRequirement` across `server/` returns one unrelated type field in `server/_core/polyglotClients.ts:178` | **absent** |
| SW5 | Prohibitions & restrictions register keyed by HS code / origin / regime | standard in all three | no register; only incidental mentions in `vision.ts`, `auditEngine.ts` | **absent** |
| SW6 | Tariff quotas / quantitative restrictions with balance drawdown | ASYCUDA, EU | none | **absent** |
| SW7 | Right of appeal against a customs decision (TFA Art. 4) | all three; a treaty obligation | none — no appeals router or table | **absent** |
| SW8 | Advance rulings | TFA Art. 3 | `advanceRuling` (submit, issue decision) | **present**, but rulings are not binding on later assessment and are not published |
| SW9 | Machine-to-machine channel for approved trader front-ends | TradeNet front-end providers; NTP API/SFTP | `devPortal` (scoped API keys, rate limits, sandbox) | **present** |
| SW10 | Standards-based messaging (WCO Data Model, EDIFACT CUSDEC/CUSRES) | all three | `ncsNrs.ingestEDI` accepts EDIFACT, but the mapping lives behind an external gateway, not in this repo | **partial / unverifiable here** |
| SW11 | Cross-border exchange with partner administrations | NTP↔foreign customs; CSW-CERTEX; ASYCUDA regional | `aseanSw` adapter exists and now honestly reports unavailable (the fabricated data was removed in the audit remediation) | **surface only** |
| SW12 | AEO / trusted trader | all three | `aeo`, `aeoRenewals`, MRA partners | **present** |
| SW13 | Risk management, valuation, origin, post-clearance audit | all three | `riskModel`, `valuation`, `wtoValuation`, `rulesOfOrigin`, `postAudit` | **present, ahead** |
| SW14 | Payment, ledger, reconciliation | GIRO / banking APIs | Mojaloop + TigerBeetle double-entry, fail-closed after remediation | **present, ahead** |

So on the classic single-window core this platform is at or ahead of the reference set. The gaps are
concentrated in the **regulatory-obligation layer** — SW4, SW5, SW6, SW7 — plus SW3's missing halves.
That is a coherent pattern: the platform automates the *customs* decision well and has almost nothing
that tells it what the *law* requires for a given consignment, or that gives a trader recourse when
the decision goes against them.

### A confirmed defect found while comparing

`server/businessRules.ts:517-560` presents itself as a live exchange-rate service:

```
// ─── 11. Live Exchange Rate Fetcher (R2 FIX) ─────────────────────────────────
// Replaces the previously hardcoded USD conversion rates with a live fetch
// from the European Central Bank (ECB) XML feed — free, no API key required.
// Falls back to a conservative in-memory cache on network failure.

const FALLBACK_RATES_TO_EUR: Record<string, number> = {
USD: 1.08, GBP: 0.86, GHS: 16.5, RWF: 1430, KES: 140, NGN: 1680, ...
```

The ECB daily reference feed does not publish NGN, GHS, RWF, KES, XOF or XAF. Fetched just now, the
feed carries 29 currencies: USD JPY CZK DKK GBP HUF PLN RON SEK CHF ISK NOK TRY AUD BRL CAD CNY HKD
IDR ILS INR KRW MXN MYR NZD PHP SGD THB ZAR — `grep -c NGN` returns `0`.

So for **every** currency this platform actually operates in, the "live" fetch always misses and the
hardcoded constant is always used. A duty assessment in Nigeria is being computed at a rate hardcoded
in source in mid-2026, labelled as live, with no staleness surfaced to the officer or the trader — and
for NGN the legally correct source is the CBN rate, which the codebase already knows about
(`ncsNrs.updateCBNRate`) and does not consult here. Same family as the audit's fabricated-success
findings: the number is plausible, wrong, and presented as authoritative.

## 3. Gaps to close

- **SW4 formalities catalogue.** A register of non-customs formalities keyed by HS code, origin,
destination and regime, which derives the required permits at submission, routes to the right
agencies, and blocks release while a required formality is unsatisfied. Mirrors CSW-CERTEX: the
permit is *verified against the declaration data*, not merely attached to it — quantity decremented,
validity checked, consignee matched.
- **SW5 prohibitions & restrictions.** Prohibited and restricted goods keyed by classification and
origin, evaluated at submission, with the legal instrument cited on refusal.
- **SW6 tariff quotas.** Quota periods with balances, allocation on a first-come basis, and drawdown
that cannot go negative or double-spend under concurrency.
- **SW7 appeals.** A right-of-appeal workflow against a customs decision (assessment, seizure,
classification, refusal), with statutory deadlines, independent reviewer separation from the
original decision-maker, and an outcome that can actually reverse the decision it appeals.
- **SW3 completion.** Declaration cancellation, and refund of overpaid duty, distinct from drawback.
- **SW8 hardening.** Advance rulings become binding: a ruling on the same HS code/goods for the same
trader is applied to later assessment, and diverging from it requires a recorded justification.
- **FX fail-closed.** Stated in section 2. No authoritative rate for the valuation date means the
assessment refuses, using the CBN rate as the Nigerian source of truth.

## 4. The six innovations for this track

**J1 — Formality-aware clearance graph.** Compute, at submission, the exact set of formalities a
consignment needs (SW4/SW5/SW6 evaluated together) and expose it as a dependency graph the trader can
see: what is required, what is satisfied, what is blocking, and which legal instrument imposes it.
Reference platforms tell a trader their declaration was rejected; this tells them the specific
unsatisfied obligation before they submit.

**J2 — Quota drawdown on the double-entry ledger.** Tariff-quota balances are held as ledger accounts
rather than a counter column, so allocation is atomic, auditable and impossible to double-spend under
concurrent submissions — the same property the platform already relies on for money. Quota fraud in
practice *is* concurrency fraud, and a `UPDATE ... SET balance = balance - n` column loses that race.

**J3 — Binding advance rulings enforced at assessment time.** A ruling is not a document, it is a
constraint: when a declaration matches an issued ruling's scope, the assessment must follow it, and an
officer departing from it must record a justification that is itself appealable. Turns TFA Art. 3 from
a filing cabinet into a control.

**J4 — Appeal that reverses through the ledger.** An upheld appeal against an assessment issues the
corrective ledger entries (refund, quota restoration, seizure release) as part of the appeal outcome,
rather than leaving a human to remember. Independence is enforced structurally: the reviewer cannot be
the original decision-maker, and the platform's insider-threat surface already gives us the primitives.

**J5 — Staleness-aware valuation.** Every assessment records the exchange rate it used, its source,
and the age of that rate; an assessment computed on a rate older than its permitted window is refused
rather than silently produced. The FX defect above becomes structurally impossible instead of
individually patched.

**J6 — Regulatory-change replay.** Formalities, P&R entries, quotas and tariff rates are all
effective-dated. That makes it possible to ask what a past declaration *would* have been assessed at
under today's rules, and — more usefully for a revenue authority — to quantify the exposure of a rule
change before enacting it, over real historical declarations rather than a projection.
Loading