OllinDocs
Architecture

The AGPL boundary

Why the solver never runs in the serving path, and how CI enforces it.

The strongest open-source poker solvers — postflop-solver / wasm-postflop by b-inary, and TexasSolver — are AGPL-3.0. AGPL §13 extends copyleft to network use: if the serving API contained AGPL code in any form (a crate, a wasm blob, a vendored file), the business would be obligated to release the source of the entire service. That obligation is not acceptable, so the boundary is structural, not aspirational.

The rule

The serving path must never link, vendor, or depend on solver code.

  • Solvers run in a separate, offline data plane — separate repos, separate processes — that writes plain JSON/binary artifacts to cloud storage.
  • The serving API and the app only ever read those artifacts. Reading data produced by an AGPL program does not propagate the license; linking its code does.

The teacher itself (a fork of b-inary/postflop-solver, pinned near 9d1509f) is used exclusively as offline data-generation tooling. The clean-room product engine is a separate effort with no dependency on it. TexasSolver and PIOSolver exist in the workspace only as validation references — never bulk teachers, never dependencies.

The preflop side never touches AGPL at all: those trees are the CEO's own HRC solve output (proprietary tool, company-owned results).

CI enforcement — the deny-gate

ollin-study-api runs scripts/agpl-check.sh before every pnpm test, so the gate rides along with CI and every local test run. Three checks:

  1. License scan — every installed package's declared license field is inspected (scripts/license-scan.mjs); any AGPL/SSPL declaration fails.
  2. Symbol scan — denylisted identifiers anywhere in the repo: postflop-solver, postflop_solver, wasm-postflop, desktop-postflop, b-inary, PostFlopGame, TexasSolver, holdem-hand-evaluator. (The bare word "postflop" is deliberately allowed — it is a poker term.)
  3. Name scan — denylisted names in package.json dependency blocks (postflop, texassolver, b-inary, piosolver).

If the gate ever fires

The fix is to remove the dependency — never to allowlist it.

On this page