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:
- License scan — every installed package's declared license field is
inspected (
scripts/license-scan.mjs); any AGPL/SSPL declaration fails. - 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.) - Name scan — denylisted names in
package.jsondependency blocks (postflop,texassolver,b-inary,piosolver).
If the gate ever fires
The fix is to remove the dependency — never to allowlist it.