OECD Pillar Two · GloBE Model Rules · Consolidated Commentary (May 2025) Per-jurisdiction ETR · Safe-harbour-aware · Replayable lineage Self-hosted · Postgres + FastAPI + React
G GloBE Top-Up Calculator OrbaOS · Capital governance suite
OECD Pillar Two · GloBE Edition 2026

Top-up tax figures your audit, tax authority, and Big-4 reviewer can replay, jurisdiction by jurisdiction.

A self-hosted GloBE calculator where every top-up flows from raw constituent-entity inputs through Articles 3.2, 4.1, and 5 — with QDMTT / IIR / UTPR routing determined by per-jurisdiction qualified status — and a regulator-ready GIR XML at the end. Drift any input, any line item, any parameter, and the verifier identifies the exact node where the chain breaks.

Institutional infrastructure, not a self-serve product. Access granted after a brief conversation. Marketing pages, doctrine, and verifier explainer are public.

Articles 3 · 4 · 5 GloBE Income · ACT · Top-Up
QDMTT · IIR · UTPR Qualified-status routing
Article 8 GIR XML Regulator-ready export
Calibrated against
OECD Model RulesSide-by-Side Package · Jan 2026 Consolidated CommentaryMay 2025 · Articles 1–10 Safe Harbours PDFTransitional CbCR · §1 Central RecordQualified IIR / UTPR / QDMTT EU Directive 2022/252327 member states UK MTT / DTTHMRC manual
§ 01  Doctrine

Why institutional tax teams choose it

GloBE programmes don't fail on the headline math. They fail because the group's 30+ subsidiary trial balances, the local accountants' calls on Article 3.2 adjustments, and the Big-4 reviewer's independent recompute never agree on which input row produced which top-up — and the GIR you file has no replayable chain back to the source data. This calculator is built on the inverse premise: admissibility before calculation.

/ 01

Admissibility before calculation

A jurisdictional top-up is a node in a Merkle DAG anchored to its constituent-entity input leaves and to the function identity that produced it. Drift any of those — book numbers, schema contract, engine version, regime parameters, Central Record qualified status — and the root hash changes. The verifier identifies the exact node where the chain breaks.

SHA-256 over canonical JSONPure-function verifier
/ 02

Self-hosted on your network

One make up brings up Postgres, the FastAPI backend, an nginx-fronted React UI, and this marketing site on a single host. Constituent-entity financials never leave your infrastructure. Cloud deploy via Railway templates if you prefer.

Docker ComposeOIDC / API keysRetention controls
/ 03

Verified math, falsifiable lineage

Articles 3.2 / 4.1 / 5 / 9 pinned to hand-computed expected values and validated against 32 external scenarios on every PR. Per-jurisdiction qualified status calibrated from the OECD Administrative Guidance Central Record. A stateless verifier replays every figure offline from the saved lineage.

491 tests · CI on every push32 external validation scenarios
/ 04

Three-mode adoption · warn → gate → block

Roll the doctrine out without breaking your existing upload paths. warn observes refusals as data. gate requires a paired-actor override token, scoped and single-use. block fails closed. Every refusal is a first-class, queryable persisted entity — the audit answer to “show me every refused computational state in the last quarter.”

423 Locked · 409 Conflict5-minute scoped tokens
§ 02  Admissibility flow

From constituent-entity ingest to GIR XML, seven steps

A constituent-entity row enters the system only after the caller has been shown its canonical form and echoed the hash back. A jurisdictional top-up is produced only from inputs whose hashes are recorded under a registered function reference. A GIR export ships only when the chain verifies. A refusal is itself a first-class persisted entity.

  1. 01
    POST /uploads/parse

    Parse and canonicalise

    Validates the row against globe_constituent_entity.v2 — 26 fields, every monetary value declared in EUR. Returns the canonicalised payload, payload_sha256, per-row leaf hashes, and a pending_upload_id.

  2. 02
    POST /uploads/{id}/commit

    Echo the hash back

    Only succeeds if the caller echoes payload_sha256 verbatim. Mismatches and double-commits return 409 plus a structured InadmissibilityEvent. On success, rows become provenance_node[input_leaf] + a ConstituentEntity on the filing group.

  3. 03
    GET /filing-groups/{id}/topup

    Articles 3.2 + 4.1 walks

    Per entity, book PBT → GloBE Income via the eight Article 3.2 line items; book current tax → Adjusted Covered Taxes via the four Article 4.1 line items. Filer overrides flow through marked filer_supplied: true. Walks are returned alongside the calc.

  4. 04
    GET /filing-groups/{id}/topup

    Article 9 transitional safe harbour

    Three OR-tests per jurisdiction: de minimis (revenue < €10M and PBT < €1M), simplified ETR (year-indexed threshold — 17% in 2026), routine profits (PBT ≤ SBIE). Once-out-always-out tracked across years. Passing jurisdictions short-circuit to zero top-up.

  5. 05
    GET /filing-groups/{id}/topup

    Article 5 top-up

    ETR = ACT / GloBE Income; top_up_rate = max(0, 15% − ETR); SBIE = payroll×rp + tangibles×rt (year-indexed Article 9.2 schedule); excess = max(0, GloBE Income − SBIE); top_up = rate × excess − QDMTT. Calc emits a Merkle root binding engine + regime + parameter-set hash.

  6. 06
    GET /filing-groups/{id}/topup

    QDMTT → IIR → UTPR routing

    Per-jurisdiction qualified status from the OECD Administrative Guidance Central Record drives routing: QDMTT-qualified source jurisdiction collects locally; else IIR collects at the parent if parent qualifies; else UTPR splits across substance jurisdictions per Article 2.6.2.

  7. 07
    GET /filing-groups/{id}/export/gir.xml

    Article 8 GIR XML

    Returns a regulator-ready GloBE Information Return XML conforming to the OECD Jan-2025 schema. The XML body's SHA-256 + the function-reference SHA + the output-root SHA all surface in response headers — a Big-4 reviewer running the verifier against the saved lineage gets a single yes/no on reconciliation.

§ 03  Three routes, one source-of-truth

QDMTT · IIR · UTPR — routed by qualified status, not by hope

Every per-jurisdiction top-up is routed through one of three mechanisms. Which one applies is a function of OECD-published facts (the Administrative Guidance Central Record), not a filer judgement call. The engine encodes the routing as a deterministic pipeline; the output enumerates exactly which mechanism collected which source.

First in line
QDMTT

Source collects, before anyone else.

If the source jurisdiction has qualified QDMTT in the regime params (IE, GB, NL, DE, JE, BM, KY-no, etc.), it collects the full top-up locally. IIR and UTPR see a residual of zero. This is the dominant outcome for 2026 filers — most low-tax jurisdictions have qualified QDMTT precisely so they collect their own top-up rather than ceding it.

qdmtt_collections[] source-resident
Second in line
IIR

Parent collects, if parent qualifies.

When QDMTT doesn't apply, the ultimate parent's jurisdiction collects the top-up via the Income Inclusion Rule — provided that jurisdiction has qualified IIR. Most EU + UK + CA + AU + JP qualify; US GILTI is not (yet) recognised as qualified IIR by OECD. Single-tier in the MVP; multi-tier ownership chains land in a later phase.

iir_allocations[] parent-collected
Backstop
UTPR

Substance jurisdictions split the rest.

When IIR can't apply (parent not qualified), the Undertaxed Profits Rule splits the unallocated top-up across UTPR-qualified jurisdictions where the group has substance, using ½ payroll-ratio + ½ tangible-assets-ratio per Article 2.6.2. Even-split fallback per Article 2.6.3 when neither denominator is positive.

utpr_allocations[] employee + asset split
§ 04  Adoption path

Three modes, one variable

Set ADMISSIBILITY_MODE on the backend container. The intended adoption path is warn → gate → block. Migration from warn to gate makes every override a paired audit event; migration to block removes the override entirely. Same doctrine as the FRTB calculator — the admissibility layer is regime-agnostic by design.

Default · onboarding
warn

Observe; preserve adoption.

A provenance gap on calc or export proceeds, but persists an InadmissibilityEvent so the gap is observable. Useful for rolling out the doctrine without breaking the legacy upload path.

HTTP 200 OK + event recorded
Operating posture
gate

Acknowledge; pair the actors.

Refuses with 423 Locked unless a single-use override token is presented. Tokens are scoped to (operation, filing_group_id, reason_code), expire in 5 minutes, and require different actors on issuance vs consumption.

HTTP 423 Locked 4-eyes override
Destination state
block

Fail closed. No override path.

Refuses with 409 Conflict. A bearer with a token in block mode still gets 409. Every figure that ships is anchored to a verified root. The doctrine, fully enforced.

HTTP 409 Conflict terminal posture
§ 05  Falsifiable lineage

Five things the verifier catches at the exact broken node

The verifier is a stateless, single-file program. Hand it a saved lineage payload — for an FRTB capital figure or a GloBE jurisdictional top-up, they verify identically — and it recomputes every claimed hash from its claimed payload. Each failure mode below is provable in a unit test against a deliberately tampered fixture. Download verify_lineage.py · Read the verifier explainer →

HASH_MISMATCH

Byte mutation in any leaf or interior payload — flagged at the tampered node, not at the root.

EDGE_LEAF_MISMATCH

A function_node whose payload claims a different set of leaves than its edges actually carry.

EDGE_FUNCTION_MISMATCH

An output_root pointing at a function_node not present in its edges. No silent re-parenting.

FUNCTION_REFERENCE_DRIFT

The function_node's claimed engine + regime + parameter-set hash differs from what the caller expects — silent parameter changes (e.g. a Central Record qualified-status flip) are caught.

ROOT_NOT_IN_NODE_SET

The lineage payload's claimed root has no matching node — orphan root, refused.

All five plus their happy-path counterparts are pinned in test_admissibility_falsification.py on every push. The 32 external GloBE validation scenarios (hand-derived from OECD source documents) re-verify every shipped calc surface on every PR.  ·  Field note: Pillar Two programmes don't burn capital on math →

§ 06  Deployment

Built to run in your environment

The same engine + admissibility layer that hosts the FRTB calculator hosts this one. Postgres + FastAPI + React, plus this static marketing site. Constituent-entity financials never leave your network. Same Docker Compose, same Railway deploy, same shared Postgres instance — the doctrine layer is regime-agnostic by design.

One command

make up brings up everything: db, backend, FRTB SPA, GloBE SPA, marketing. CORS_ORIGINS pre-configured for the four local ports.

$ make up

One Postgres

FRTB and GloBE share the same doctrine layer (provenance_nodes, provenance_edges, inadmissibility_events, csv_schema_contracts, function_references). Filing groups and portfolios live in different tables but the same DB — one backup, one migration path.

Health-gated

/health returns build, regime, and auth_required. Railway probes it; your monitoring can too.

GET /health → 200

OIDC or API keys

Set REQUIRE_AUTH=true + either BOOTSTRAP_API_KEY or OIDC_ISSUER + OIDC_AUDIENCE. Federated identity flows resolve to oidc:<sub> for audit attribution.

§ 07  Request access

Tell me about your group.

Filing group size, jurisdictions in scope, fiscal-year start, and where you are in the Pillar Two readiness arc. I'll come back within two business days.

Marketing pages, doctrine, and the verifier are public — no form needed. The form is for credentialed access to the running demo + a working call to scope deployment to your infrastructure.