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

## Verdict
Rework before freeze. The direction is plausible, but the note freezes several unproven architecture decisions as if already validated: a single contract across ASYCUDA and Rwanda’s portal proxy, a computed legal/tax engine, shadow-mode validation while OBR test is down, and adoption of a full authenticated multi-tenant vertical platform for an anonymous public iframe. Step 2 would be blocked by missing security, data ownership, legal accuracy, and contract details.

## Findings

| # | Severity | Section | Finding | Evidence (file:line or source) | Suggested fix |
|---|---|---|---|---|---|
| C1 | blocker | §3 | “One contract” is under-specified and partly contradicted by the prototype: Burundi uses `/api/v1/*`; Rwanda uses `/api/Tariffs/*` through the trade portal and PascalCase response mapping. | `server.js:28-42`; `burundi/app.js:26-57`; `rwanda/app.js:37-51`; `rwanda/app.js:68-80`; `README.md:20-31` | Define the canonical contract separately from ASYCUDA and portal shapes; list adapters and mapping per method. |
| C2 | blocker | §7/§8 | Pilot 1 depends on shadow mode against OBR, but the note also says OBR test has not answered since 04-09-2026. Stored golden cases cannot prove current ASYCUDA parity. | `docs/step1/concept-note.md:130-141`; `docs/handover/README.md:34-35` | Make shadow mode conditional on restored access; define offline validation as “fixture replay”, not pilot acceptance. |
| C3 | blocker | §4/§7 | The computed engine’s legal accuracy risk is understated. Burundi has complex bases, flat USD charges, VAT exclusions, excise/specific duties, weekly rates, and national levies; “TARIC simplified” is not enough. | `docs/BURUNDI.md:145-189`; `docs/BURUNDI.md:263-281`; `docs/handover/2026-09-24-reunion-OBR-CNUCED.md:16-19` | Add an explicit legal/tax model appendix: per-tax base, currency, rounding, order, source, update owner, and dispute wording. |
| C4 | major | §4 | “Every country change is data, never code” is too absolute. Rwanda already needs `additionalVariables` for vehicles, and required fields differ by country. | `rwanda/config/rw.json:15-20`; `docs/NUEVO-PAIS.md:40-48`; `TariffsFeature.cs:24-31` | Replace with “country behavior is data plus parameterized rules”; specify extension points. |
| C5 | major | §5/§8 | Embedding security is thin. Existing prototype sends `Access-Control-Allow-Origin: *`, has no `frame-ancestors`, no host allowlist, no iframe height script, and no abuse control. | `server.js:66-67`; `server.js:92-94`; `README.md:129-144`; `burundi/app.js:689-693` | Add concrete headers: CSP `frame-ancestors`, CORS policy, embed-token/host model, clickjacking posture, and resizing protocol. |
| C6 | major | §3/§8 | Public estimate endpoint abuse is not handled for the new platform. v7 has a courtesy per-IP limiter and admits XFF is forgeable; prototype has none. API key custody is mentioned but not operationalized. | `TariffsRateLimiting.cs:6-14`; `TariffsRateLimiting.cs:20-37`; `server.js:125-154`; `docs/handover/README.md:26-27` | Specify rate limits, quotas by country/provider, key rotation, upstream lockout handling, logging, and anomaly alerts. |
| C7 | major | §6 | Vertical-base fit is asserted, not argued. The template is for authenticated vertical services with accounts, tenants, admin, installer and MCP; the calculator is anonymous and embeddable. | `vb/README.md:3-8`; `vb/README.md:29`; `vb/README.md:46-55`; `vb/docs/method/M3-safety-invariants.md:24-38` | Add an architecture decision: which template parts are kept, disabled, or isolated for public anonymous traffic. |
| C8 | major | §6/§8 | The note relies on `npm run check`, but vertical-base itself says green does not prove real integrations, security, accessibility, load, or real users. | `vb/docs/method/M1-how-a-vertical-is-built.md:62-82` | Promote these to explicit acceptance gates in Step 2, with owners and closing conditions. |
| C9 | major | §5/§9 | D2 says v7 untouched until pilot 1 passes; D14 says OBR meeting tasks are done in today’s calculator within a week and become requirements here. That is a live-v7/prototype change before pilot acceptance. | `docs/DECISIONS.md:14`; `docs/DECISIONS.md:26`; `docs/handover/2026-09-24-reunion-OBR-CNUCED.md:28-44` | Split “current calculator remediation” from “new platform”; name repository/system for each task. |
| C10 | major | §9 | OBR meeting requirements are not fully carried into scope: currencies per cost element, export tabs, language decisions, hosting by OBR, and preference explanations are only partially reflected. | `docs/handover/2026-09-24-reunion-OBR-CNUCED.md:11-24`; `concept-note.md:151-155` | Add a traceability table from each meeting task to Step 2 modules or explicit out-of-scope. |
| C11 | major | §4/§7 | Data-source realism is weak. EAC CET and Burundi national levies are named, but no source, machine-readable path, update cadence, owner, or manual QA budget is frozen. | `concept-note.md:76-85`; `concept-note.md:130`; `docs/handover/README.md:11-15` | Require a country data register: source URL/file, authority, format, update frequency, ingestion method, reviewer. |
| C12 | minor | §1 | “Allows only four routes” is true for Burundi but not for the relay overall: Rwanda has five allowed routes. | `concept-note.md:29`; `server.js:28-42` | Say “Burundi allowlist has four routes; Rwanda proxy allowlist has five.” |
| C13 | minor | §1/Sources | PR numbers and dates are asserted but not verifiable from the cited local files; the note admits later PRs were not seen. | `concept-note.md:31`; `concept-note.md:170` | Either cite commit/merge evidence or remove PR numbers from the frozen note. |

## Questions for the analyst

1. Provider contract: pick **A** canonical ASYCUDA-shaped contract, **B** new neutral calculator contract, or **C** separate contracts per provider with a UI facade.
2. Burundi outage policy: pick **A** no pilot until OBR access returns, **B** fixture-only acceptance, or **C** temporary production endpoint access by agreement.
3. Computed estimates: pick **A** legally reviewed official calculator, **B** clearly unofficial indicative estimate, or **C** internal comparison only until authority approval.
4. Vertical-base: pick **A** full template, **B** public-only thin app plus admin later, or **C** keep current prototype architecture and harden it.
5. Data ownership: pick **A** OBR owns and publishes tariff data, **B** UNCTAD maintains data after handover, or **C** shared maintenance with written SLA.
6. Embedding: pick **A** allowlisted iframe only, **B** public iframe anywhere, or **C** script embed with origin registration.

## What holds

- The prototype evidence is valuable and unusually concrete: required fields, defects, rate/base behavior, and “do not correct customs” are well supported.
- The v7 line counts and core technical description mostly check out: `TariffsBO` 447 lines, `tariffs.js` 644 lines, cache default 7 days.
- The decision to avoid mock data in live mode is strongly supported by the Burundi/Rwanda placeholder failure.
- The seven-step document process and adversarial review gate are appropriate for this risk level.