# Review of the concept note · Claude · 29-09-2026

## Verdict

**Freeze after fixes.** The direction is sound, but three things would block a step-2 author: D14 contradicts D2 and §5.1; the premise that the contract keeps ASYCUDA's shapes is wrong on the evidence; and the template's integration switch does not do per-country providers or shadow mode. Several factual slips also need correcting.

## Findings

| # | Severity | Section | Finding | Evidence | Suggested fix |
|---|---|---|---|---|---|
| C1 | blocker | §5.1, §9, D2, D14 | D14 puts the OBR meeting's tasks in "the calculator OBR uses today". That is v7 on the portal. D2 and §5.1 say v7 is not touched. Every field then lands twice, which undoes the "one implementation" argument. | reunion-OBR-CNUCED.md "Devises", Tâches; DECISIONS.md:14,26 | Reword D2: "v7's architecture untouched; the D14 fixes are the only v7 changes". List them. |
| C2 | blocker | §3 | "Both speak ASYCUDA's shapes" is false. v7's public API is eRegulations' own: `api/tariffs/search`, `GetCommodityDetails`, a PascalCase `TariffsTax`. Only `TariffsBO` speaks `/api/v1`. Inputs are `int`, outputs `float` (which cannot hold 53 184 493,74), and there is one `CurrencyCode` per request, where D14 needs one per cost element. The template requires translating supplier codes into the platform's own. | Public Api/…/TariffsController.cs:32-130; TariffsModel.cs:77-163; burundi/app.js:65; vb M5 §2 | Define the platform's own contract: decimal money, a currency per amount, provider-neutral codes. The ASYCUDA adapter translates. |
| C3 | blocker | §3, §6 | M5 picks an adapter with one environment `switch` per installation. The note needs a provider per country plus two providers at once (shadow mode). That is new core code. | vb docs/method/M5 §2 "Choose it in the switch" | Name it as new core code, or run one installation per country. |
| C4 | major | §7, D13 | Rwanda is not an ASYCUDA `/api/v1` provider. It is the legacy eRegulations portal (`rwandatrade.rw/api/Tariffs/*`), reached with a spoofed `Referer` and `User-Agent`, with no key and no agreement. "Measured the way Burundi is" needs a third adapter or access to RRA directly. | server.js:19,38-42,62-63; handover/README.md:14 (RRA OpenAPI) | Choose between RRA's API under agreement and a named portal adapter used with the owner's consent (Q4). |
| C5 | major | §3, §7, risks | Shadow mode is not feasible as written. The test host has been down since 04-09. The production host (`api-gue`, `etariff-prod-obr`) works for v7, but a new server needs OBR to allow-list its IP. While v7 serves Burundi, no importer reaches the new page, so the shadow is only a fixture replay. | BURUNDI.md:21-29; instance.yml:24; NUEVO-PAIS.md:171 | Name the host, key and traffic. Ask OBR for the IP authorisation now. |
| C6 | major | §4, D12 | The golden cases "stored" are one real declaration (wine, 07-08). No OBR estimate responses are kept as fixtures. D12's exact equality also forces the engine to reproduce OBR's defects (invented codes quoted; origin not applying the agreement). | handover/data/ (commodities.json and the OpenAPI only); BURUNDI.md:263-283; defectos CSV #1, #2 | Set a number of cases for 7.2. Keep a register of known OBR defects that exempts named taxes. |
| C7 | major | §4, §7 | "Rwanda shares the CET, so only national taxes are new" ignores stays of application and remission schemes, which the EAC gazettes per member state, and COMESA preferences (the meeting's Ethiopia 10 %). The duty itself differs by country. | reunion "Traitements préférentiels"; base-legal.md:19 | Model stays and preferences as measures. Test them in pilot 2. |
| C8 | major | §5 | Embedding and abuse are not specified. The prototype sends `Access-Control-Allow-Origin: *`. v7 rate-limits on the first `X-Forwarded-For` hop, which any client can spoof. A public estimate endpoint spends OBR quota under UNCTAD's key. Iframe resizing needs a checked `postMessage`. The template sets no security headers. | server.js:67,94,132; TariffsRateLimiting.cs:44-49; vb next.config.ts | Add to modules 8 and 10: `frame-ancestors`, a CORS allow-list, trusted-proxy rate limiting, estimate caching, key custody. |
| C9 | major | §2, D7 | Hosting and ownership are missing. The meeting moves the portal to OBR's servers from 28-09. The note fixes `calculator.eregistrations.dev`. Nothing says who holds the OBR key, who runs the host, or who maintains the tariff each July after handover. | reunion "Hébergement"; handover/README.md:25 | Add a "who runs it" section. |
| C10 | major | §6 | Two methods collide. The project's process has 7 steps. vertical-base has 12 spec documents, 45 questions and "no schema before `spec/`". The template is also built for signed-in applicants, not an anonymous public page. | vb README "Then what", proxy.ts:26-31 | State which process governs, and which `spec/` files and template pages are dropped. |
| C11 | minor | §1 | Factual slips. The relay allows 9 routes (4 OBR and 5 Rwanda), not 4. The prototype starts 04-08, not 06-08. The template's "one commit" is an artefact of a shallow clone (its head merges PR #4). Admin PR #26 is omitted. | server.js:27-42; git log; vb `git rev-parse --is-shallow-repository`=true | Correct them. |
| C12 | minor | D1, §5.3, D5/D13 | D1 records the retirement as decided, but §5.3 says it is "its own decision, taken then". D13 narrows D5 without naming it, against the log's own rule. | DECISIONS.md:9,13,17,25 | Trim D1. Make D13 cite D5. |
| C13 | minor | §8 | Staleness is not only a July event: TSR changed in December 2025. v7 caches exchange rates for 7 days, so a weekly rate can be up to a week behind. | base-legal.md:34; instance.yml:26 | Allow versions at any date; give rates their own TTL. |
| C14 | minor | §4, §6 | Scope: four connectors, publishing with diffs, and an MCP server come before one pilot has passed. | §4, §6 lists | Keep only CSV and manual entry for 7.2. |
| C15 | minor | whole note | Missing items: languages (Kirundi switched off, Swahili, Kinyarwanda), the accessibility bar, printing the estimate, health checks (the prototype's probe), and data protection for shadow logs, which hold invoice values and origins. | reunion "Langues"; server.js:156-184 | One line each, with an owning module. |
| C16 | minor | §1, §4 | "The only one there is" (TARIC) and "no other system offers an estimate API" have no citations. | Sources list | Cite them or soften them. |

## Questions for the analyst

1. v7 during the build: (a) D14 fixes only, (b) frozen, D14 dropped?
2. The contract: (a) the platform's own, with an ASYCUDA adapter, (b) ASYCUDA's shapes as they are?
3. Choosing a provider: (a) per country in the database, (b) one installation per country?
4. Rwanda's source: (a) RRA's ASYCUDA API under agreement, (b) the rwandatrade.rw portal with consent, (c) computed only?
5. Shadow host for Burundi: (a) production with a new IP authorisation, (b) wait for the test host?
6. Golden cases before 7.2: (a) at least 20, (b) at least 50, (c) whatever OBR sends?
7. Known OBR defects in golden cases: (a) exempt by name, (b) replicate?
8. Hosting after the pilot: (a) UNCTAD, (b) OBR, (c) decided at 7.4?
9. The first country where a computed figure reaches the public: (a) Rwanda, (b) none planned yet?

## What holds

- The v7 figures check out, including Public's dependence on Admin's library (WebAppCore.csproj:13).
- The 184-line relay, the 21 defects and the down test host are all accurate.
- "Show customs' answer, correct nothing" and "no stand-in in a live installation" are the right rules.
- Dated versions with a legal act per line, and no `if` in country data.
- D11 (no computed figure when customs is down, for Burundi) sensibly limits the legal risk.
