The paper engine receives a narrow read-only snapshot interface. It cannot access HTTP sessions, provider SDKs, environment secrets, or arbitrary URLs. This is capability security: components receive only what they need, so a programming mistake cannot become an external transaction.
Define MarketSnapshotReader.get(source_id, observed_at) and list_for_run(run_id). The returned object contains validated quote data, status, freshness, raw hash, and schema version. It has no methods. Network capture happens earlier in a separate process; paper simulation reads sealed run bundles.
Use a repository guard that rejects imports or strings associated with authenticated clients and write operations. More importantly, dependency injection should make such objects impossible to pass. The command that runs paper fills opens the event database and sealed fixture directory only. Run it with network access disabled in tests and deployment where feasible.
The interface returns typed errors: not found, stale, invalid schema, quarantined, unresolved provenance, and incomplete run. The paper engine converts every one to ABSTAIN and appends an audit event. It never substitutes the most recent record or assumes a missing field.
Separate quote observation from synthetic fill assumption. A snapshot says bid/ask observed at time T. The fill policy says how fictional points would be priced under latency and slippage assumptions. Both versions appear in the fill event. Neither claims an obtainable real transaction.
Test the boundary at packaging and runtime. Build the paper worker in an environment without requests, DNS access, or venue packages; its dependency lock should still resolve. Feed it sealed bundles through a read-only mount and a writable event directory. An integration test attempts HTTP, socket creation, and an undeclared file read, expecting denial and a safety incident rather than silent fallback.
Version the interface contract and reject newer snapshot schemas until reviewed. Backward compatibility must never mean ignoring an unknown field that changes quote meaning. Contract tests cover every typed error and prove the engine appends no paper event when provenance validation fails.
🇵🇰 Pakistan Angle
This boundary makes the lab safe to run on a personal laptop without accounts, wallets, deposits, or KYC. It also makes the project suitable for an engineering portfolio: reviewers can inspect data contracts and tests without exposure to financial credentials.
Hands-On Exercise
Implement the reader over sealed fixtures and SQLite. Add tests that deny network, inject stale and quarantined records, and attempt to pass an object with a submit method. The constructor or type check must reject it. Produce an interface contract document.
Completion Rubric
- The paper process reads sealed snapshots and cannot fetch directly.
- Returned objects contain data only, with provenance.
- Every data failure becomes an audited abstention.
- Quote and synthetic-fill assumptions stay separate.
- Forbidden-capability tests and network-denied tests pass.
Sources
- Python protocols and typing
- OWASP Secure Product Design Cheat Sheet
- Polymarket public market-data skill
Key takeaway: A read-only interface is strongest when the paper engine never receives a network or transaction capability.