<mxfile host="app.diagrams.net" agent="FairWins architecture workbook" version="24.7.17">
  <diagram id="fw-arch" name="Architectural view">
    <mxGraphModel dx="1600" dy="1100" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1600" pageHeight="1150" math="0" shadow="0">
      <root>
        <mxCell id="0" />
        <mxCell id="1" parent="0" />

        <mxCell id="t" value="FairWins — Architectural View (components and seams)" style="text;html=1;fontSize=20;fontStyle=1;align=left;" vertex="1" parent="1">
          <mxGeometry x="40" y="20" width="800" height="30" as="geometry" />
        </mxCell>
        <mxCell id="t2" value="Five deployable units + one on-chain estate. EVERY off-chain unit is optional; each value flow keeps a self-submit path." style="text;html=1;fontSize=12;fontColor=#5A6B72;align=left;" vertex="1" parent="1">
          <mxGeometry x="40" y="48" width="900" height="20" as="geometry" />
        </mxCell>

        <mxCell id="client" value="CLIENT — the only place member keys exist" style="swimlane;html=1;startSize=32;fillColor=#E6F2F4;strokeColor=#2E7D8C;strokeWidth=2;fontStyle=1;fontSize=12;" vertex="1" parent="1">
          <mxGeometry x="40" y="100" width="480" height="420" as="geometry" />
        </mxCell>
        <mxCell id="spa" value="React SPA (frontend/)&#10;every member surface · all signing · all direct chain reads" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#2E7D8C;strokeWidth=2;fontSize=11;" vertex="1" parent="client">
          <mxGeometry x="20" y="45" width="440" height="60" as="geometry" />
        </mxCell>
        <mxCell id="seams" value="KEY SEAMS — each the only sanctioned path&#10;&#10;writeRail.js#resolveWriteRail — signer, NOT loginMethod&#10;accountLookup.js — 4-shape Resolution; only 'resolved' has an address&#10;verifyMessage — OFFLINE + SYNCHRONOUS by type&#10;rpcEndpoints#resolveRpcEndpoints → makeReadProvider&#10;screening: sources / verdict / screenEstate (+ 2 hooks, 2 jobs)&#10;syncedObjects.js — 9 in, 6 DELIBERATELY out (test-asserted)&#10;getContractAddressForChain · cohortChainIds · membershipChainId&#10;config/tenant.js ← virtual:tenant (build-time, fails loudly)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F7F8;strokeColor=#5A6B72;fontSize=9;align=left;spacingLeft=8;verticalAlign=top;spacingTop=6;" vertex="1" parent="client">
          <mxGeometry x="20" y="120" width="290" height="180" as="geometry" />
        </mxCell>
        <mxCell id="miniapp" value="Mini-app&#10;packages&#10;&#10;UNTRUSTED&#10;third-party&#10;&#10;immutable CID&#10;keccak(manifest)&#10;sha256 per byte&#10;executed" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FBEAE6;strokeColor=#8A3324;strokeWidth=2;fontSize=9;" vertex="1" parent="client">
          <mxGeometry x="325" y="120" width="135" height="180" as="geometry" />
        </mxCell>
        <mxCell id="hostobj" value="host object = THE ENTIRE privileged surface (hostApi 2)&#10;wrappers never handles · no signer · no context · no storage handle&#10;wallet.submit chooses the rail AND screens INSIDE itself" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFF6E6;strokeColor=#A46A21;strokeWidth=2;fontSize=9;" vertex="1" parent="client">
          <mxGeometry x="20" y="312" width="440" height="45" as="geometry" />
        </mxCell>
        <mxCell id="nat" value="Capacitor shells (iOS / Android) — native passkey ceremony, Ledger BLE, app lock, deep links; CSP DERIVED from nginx, never widened" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#2E7D8C;dashed=1;fontSize=9;" vertex="1" parent="client">
          <mxGeometry x="20" y="365" width="440" height="42" as="geometry" />
        </mxCell>
        <mxCell id="e-spa-mini" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#8A3324;strokeWidth=2;endArrow=block;" edge="1" parent="client" source="hostobj" target="miniapp">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>

        <mxCell id="pkgs" value="packages/ — SINGLE SOURCES OF TRUTH (extracted so they cannot drift)" style="swimlane;html=1;startSize=30;fillColor=#F0EDF5;strokeColor=#41236D;strokeWidth=2;fontStyle=1;fontSize=11;" vertex="1" parent="1">
          <mxGeometry x="40" y="560" width="480" height="190" as="geometry" />
        </mxCell>
        <mxCell id="pk1" value="@fairwins/intent-types — 34 contract-verified structs, 7 domains.&#10;Gated BOTH directions against Solidity *_TYPEHASH. Off-chain-only&#10;structs quarantined in offchain.js. DOMAINS are still hand-synced (#1038)." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="pkgs">
          <mxGeometry x="15" y="38" width="450" height="55" as="geometry" />
        </mxCell>
        <mxCell id="pk2" value="@fairwins/assistant-contract — prompt + tool defs + honest result wording;&#10;vendored into the MCP server as a snapshot, parity-gated both ways" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="pkgs">
          <mxGeometry x="15" y="100" width="450" height="40" as="geometry" />
        </mxCell>
        <mxCell id="pk3" value="finops-catalogue — every revenue and cost source declared ONCE.&#10;A money path with no entry FAILS CI." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="pkgs">
          <mxGeometry x="15" y="146" width="450" height="35" as="geometry" />
        </mxCell>

        <mxCell id="gw" value="relay-gateway — POLICY GATEWAY · HOLDS NO MEMBER KEY · OPTIONAL" style="swimlane;html=1;startSize=32;fillColor=#FFF6E6;strokeColor=#A46A21;strokeWidth=2;fontStyle=1;fontSize=11;" vertex="1" parent="1">
          <mxGeometry x="580" y="100" width="440" height="420" as="geometry" />
        </mxCell>
        <mxCell id="mw" value="middleware chain (order is the control)&#10;helmet → CORS → body-parse → ORIGIN LOCK (X-Origin-Auth)&#10;→ IDENTITY TIERING (spec 106 ROUTE_TABLE) → access router → modules" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#A46A21;strokeWidth=2;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="gw">
          <mxGeometry x="15" y="42" width="410" height="60" as="geometry" />
        </mxCell>
        <mxCell id="mods" value="modules — each independently optional, each 503 &lt;name&gt;_unconfigured when off&#10;&#10;intent · paymaster (KMS-signed ERC-7677) · polymarket&#10;perps (3 venues, per-venue failure isolation) · bitcoin&#10;news (Alphaday; TTL clamped ≥300s) · memberApi (fw1 bearer)&#10;x402 (pay-per-request; NEVER applies to a member) · fees (READS FeeRouter)&#10;&#10;Exists largely because vendors have NO CORS — it is a read proxy,&#10;not a backend. Stateless: no fee store, no member record." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#A46A21;fontSize=9;align=left;spacingLeft=6;verticalAlign=top;spacingTop=6;" vertex="1" parent="gw">
          <mxGeometry x="15" y="115" width="410" height="165" as="geometry" />
        </mxCell>
        <mxCell id="scope" value="NO write: scope exists on the member API.&#10;The only rail offered is: &quot;here is the typed data, YOU sign it.&quot;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6F2F4;strokeColor=#2E7D8C;strokeWidth=2;fontSize=9;" vertex="1" parent="gw">
          <mxGeometry x="15" y="295" width="410" height="45" as="geometry" />
        </mxCell>
        <mxCell id="e-mw-mods" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#A46A21;endArrow=block;" edge="1" parent="gw" source="mw" target="mods">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>

        <mxCell id="eng" value="SUBMISSION ENGINES — pay gas, hold no member funds" style="swimlane;html=1;startSize=30;fillColor=#EDF1F2;strokeColor=#5A6B72;strokeWidth=2;fontStyle=1;fontSize=11;" vertex="1" parent="1">
          <mxGeometry x="580" y="560" width="440" height="130" as="geometry" />
        </mxCell>
        <mxCell id="oz" value="OZ Relayer + redis&#10;relayed intents&#10;gas key in KMS" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#5A6B72;fontSize=10;" vertex="1" parent="eng">
          <mxGeometry x="20" y="40" width="190" height="70" as="geometry" />
        </mxCell>
        <mxCell id="al" value="alto bundler&#10;ERC-4337 · EntryPoint v0.6&#10;CHAIN 137 ONLY" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#5A6B72;fontSize=10;" vertex="1" parent="eng">
          <mxGeometry x="230" y="40" width="190" height="70" as="geometry" />
        </mxCell>

        <mxCell id="aux" value="AUXILIARY" style="swimlane;html=1;startSize=28;fillColor=#EDF1F2;strokeColor=#5A6B72;fontStyle=1;fontSize=11;" vertex="1" parent="1">
          <mxGeometry x="580" y="710" width="440" height="115" as="geometry" />
        </mxCell>
        <mxCell id="mcps" value="MCP server&#10;DEPENDENCY-FREE by policy&#10;(a lockfile hazard otherwise)&#10;cannot sign, cannot pay" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#5A6B72;fontSize=9;" vertex="1" parent="aux">
          <mxGeometry x="20" y="35" width="190" height="70" as="geometry" />
        </mxCell>
        <mxCell id="fx" value="FinOps exporter&#10;READ-ONLY BY CONSTRUCTION&#10;no signer, no write route,&#10;refuses boot if a key reaches it" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#5A6B72;fontSize=9;" vertex="1" parent="aux">
          <mxGeometry x="230" y="35" width="190" height="70" as="geometry" />
        </mxCell>

        <mxCell id="chain" value="ON-CHAIN ESTATE — the only custody of value" style="swimlane;html=1;startSize=32;fillColor=#E8E3F0;strokeColor=#41236D;strokeWidth=3;fontStyle=1;fontSize=12;" vertex="1" parent="1">
          <mxGeometry x="1080" y="100" width="470" height="725" as="geometry" />
        </mxCell>
        <mxCell id="c1" value="WagerRegistry (UUPS) + WagerRegistryIntents facet&#10;TWO facets, ONE proxy, ONE storage definition (WagerRegistryCore)&#10;— because the main impl sits against the 24 KB code limit" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;strokeWidth=2;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="45" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c2" value="MembershipManager (UUPS) — ONE chain per cohort&#10;+ MembershipVoucher (ERC-721 bearer claim, immutable)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="110" width="440" height="42" as="geometry" />
        </mxCell>
        <mxCell id="c3" value="WagerPoolFactory → immutable WagerPool clones (ERC-1167)&#10;FundingPoolFactory → FundingPool clones — DEPLOYED NOWHERE YET&#10;Sibling factories, never an extension of the wager registry" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="162" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c4" value="FeeRouter — THE ONLY fee-config store&#10;bytes32 serviceId → {capBps, feeBps, kind}; cap is immutable" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="227" width="440" height="42" as="geometry" />
        </mxCell>
        <mxCell id="c5" value="BridgeRouter · LiquidityRouter (UUPS) — NEVER take custody&#10;depositV3(msg.sender): an unfilled bridge refunds to the MEMBER,&#10;which is why there is NO rescue function. Admin = 1 hot key (#966)." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FBEAE6;strokeColor=#8A3324;strokeWidth=2;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="279" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c6" value="Passkey account + factory + FairWinsVerifyingPaymaster&#10;P-256 verified via RIP-7212 precompile, FCL software fallback,&#10;high-s rejected" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="344" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c7" value="SanctionsGuard — non-bypassable screening + operator deny list&#10;SafePolicyGuard v1 AND v2 side by side, DELIBERATELY NOT UPGRADEABLE&#10;(an upgrade key over a policy guard is a backdoor across every vault)&#10;v2: ordered rule array, first-match-governs, no match ⇒ DENIAL" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFF6E6;strokeColor=#A46A21;strokeWidth=2;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="409" width="440" height="70" as="geometry" />
        </mxCell>
        <mxCell id="c8" value="MiniAppRegistry — 'launchable' IS the serving decision, never 'status';&#10;approveApp(id, expectedManifestHash) reverts StaleProposal&#10;CallsignRegistry — optional, Gold+, commit→reveal, gates nothing" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="489" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c9" value="Oracle adapters (Polymarket · Chainlink feed + Functions · UMA)&#10;one IOracleAdapter interface → one uniform auto-resolve path" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#41236D;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="554" width="440" height="42" as="geometry" />
        </mxCell>
        <mxCell id="c10" value="EXTERNAL, CALLED NOT OWNED: EntryPoint v0.6 · Safe v1.4.1 singletons&#10;Across SpokePool/HubPool · Uniswap V3 · ERC-4626 vaults&#10;USDC / USDT · Chainalysis oracle · Polymarket CTF" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#EDF1F2;strokeColor=#5A6B72;dashed=1;fontSize=9;align=left;spacingLeft=6;" vertex="1" parent="chain">
          <mxGeometry x="15" y="606" width="440" height="55" as="geometry" />
        </mxCell>
        <mxCell id="c11" value="contracts-archive/ — REFERENCE ONLY. Never import, never deploy." style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F7F8;strokeColor=#8A3324;dashed=1;fontSize=9;" vertex="1" parent="chain">
          <mxGeometry x="15" y="671" width="440" height="32" as="geometry" />
        </mxCell>

        <mxCell id="ea" value="direct reads + SELF-SUBMIT&#10;(always available)" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#41236D;strokeWidth=3;endArrow=block;fontSize=9;" edge="1" parent="1" source="client" target="chain">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="eb" value="optional rails&#10;+ vendor reads" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#A46A21;strokeWidth=2;dashed=1;endArrow=block;fontSize=9;" edge="1" parent="1" source="client" target="gw">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="ec" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#5A6B72;endArrow=block;" edge="1" parent="1" source="gw" target="eng">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="ed" value="member's own token" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#5A6B72;dashed=1;endArrow=block;fontSize=9;" edge="1" parent="1" source="mcps" target="gw">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="ee" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#41236D;endArrow=block;" edge="1" parent="1" source="eng" target="chain">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="ef" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#41236D;dashed=1;endArrow=none;" edge="1" parent="1" source="pkgs" target="client">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="eg" style="edgeStyle=orthogonalEdgeStyle;html=1;strokeColor=#41236D;dashed=1;endArrow=none;" edge="1" parent="1" source="pkgs" target="gw">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>
