Free learning / 45-minute adapter proof lab
Read every page before claiming the credit is missing
Build a scoped pagination adapter. Follow the credit onto a second page, reproduce false missing-credit and false-match results, and withhold incomplete evidence.
No account needed. Use your own copy for writing and keep the original as a reference.
Engineering lab library / Run locally
Collect every page before comparing.
Follow thirteen synthetic reads, reproduce two collection defects and inspect when the financial comparison must not run. Keep both Python files in one folder.
Synthetic records. No provider key or model inference. Runs locally with the standard library.
Start here / Python 3.11+ · Standard library
Paginated financial extract lab
Collect thirteen local response scenarios, compare two broken modes and prove when reconciliation must not run.
Python 3.11+ · standard library · keep both files together
A case handler asks, “Has the expected credit appeared?” Your first API response succeeds and contains no rows. That seems like an answer, until the next page contains the credit. The engineering problem is how you collected the evidence.
This original workshop connects an API adapter to the financial comparison from the reconciliation workbook. Start there if case, ledger entry or provisional credit is unfamiliar. Here you build the missing bridge: a complete, scoped read that can support a comparison.
Allow 45–60 minutes. Use Python 3.11 or newer. All records and provider responses are invented. The lab calls local functions, makes no HTTP or model calls and writes no financial records. The protected Academy lesson adds worked review, knowledge checks and a receiving-owner challenge.
1. Understand the job before writing the loop
An adapter translates a source system's contract into the input your application expects. In the previous lab, the comparison received a complete credit extract. An actual integration must establish that property rather than accept a model-generated complete: true.
Think of a statement spread across several pages. Reading the first sheet does not tell you everything on the statement. The application has to know how to continue, when the read has finished and whether every page belongs to the same question.
| Term | Plain-language meaning | Question to ask the source owner |
|---|---|---|
| Page | One portion of a collection | What marks the end? |
| Cursor | A source-supplied continuation value | How do we reuse it without changing the query? |
| Scope | The exact workspace, case, account and original transaction being read | Which references must remain fixed? |
| Snapshot | A defined version of the source collection | Can all pages represent the same version? |
| Complete extract | All rows returned under the agreed scope and termination rules | What evidence establishes coverage? |
| Page budget | A limit on how many source calls this attempt may make | Where does unfinished work go? |
This workshop's source promises a pinned snapshot. That promise is fictional and explicit. Pagination alone does not provide it, and a completed snapshot is not proof that the facts are still current when someone later acts.
2. Follow the credit onto the next page
The invented contract fixes four references on every request. The first response selects snapshot 7. Later requests send that same snapshot and scope with the supplied cursor. Each response must contain an explicit next_cursor string; "" means the collection ended.
| Read | Scope | Snapshot | Entries | Continuation |
|---|---|---|---|---|
| Page one | Same case and account | 7 | None | SYNTHETIC-CURSOR-A |
| Page two | Same case and account | 7 | SYNTHETIC-CREDIT-9 | Empty: end |
The guarded collector makes two calls and then invokes the existing comparison. It returns matched_snapshot. The broken first-page collector makes one call and reports missing_credit. The financial source did not change; the collector stopped too soon.
There is a second trap: page one can contain a matching credit while page two contains another distinct entry. Stopping early then produces a false match. Complete collection protects against both unsupported absence and unsupported agreement.
Use the visual below to follow the request, continuation, coverage check and receiving owner. Its example is a teaching trace; running the Python file produces the actual reports.
UNDERSTAND THE SYSTEM
An empty page can still have a next page
Follow an invented credit lookup from the staff question to the complete snapshot. The cursor is a continuation instruction; it does not say whether a credit exists.
See what moves and why.
Read the connections in plain English
- 01One case, one scope → Page one
The initial request has no cursor; the fictional provider pins a source snapshot.
- 02Page one → Page two
Keep the same query scope and snapshot; never invent a page number from the token.
- 03Page one → Same snapshot?
No entries, but the next cursor is present.
- 04Page two → Same snapshot?
The scope and snapshot agree and the continuation is empty.
- 05Same snapshot? → Reconciliation
Only a terminal, coherent read can feed the comparison.
- 06Same snapshot? → Receiving owner
A failed page, changed scope or changed snapshot withholds reconciliation.
- 07Reconciliation → Receiving owner
Keep the comparison, next action and separate investigation state.
Check your understanding: Page one contains one matching credit. Can you stop early?
No. The next page might contain another distinct credit. The lab's first-page defect hides that second entry and produces a false match. Finish the scoped snapshot or withhold the comparison.
3. Run the paginated extract lab
Download fde-financial-extract.py and its required companion fde-financial-reconciliation.py into the same folder. The collector calls the existing financial comparator only after it establishes the complete extract.
python3 fde-financial-extract.py
python3 fde-financial-extract.py --json > extract-guarded.json
python3 fde-financial-extract.py --stop-after-first --json > extract-first-page.json
python3 fde-financial-extract.py --allow-mixed-snapshots --json > extract-mixed.jsonThe last two commands deliberately remove different rules. Run them separately. Exit 0 means the program produced a report; it is not a grade or proof that an integration is ready.
| Scenario | Guarded collection | Downstream comparison |
|---|---|---|
credit-on-page-two | Two pages, one snapshot, end reached | matched_snapshot |
second-credit-on-page-two | Both distinct entries retained | multiple_credit_entries |
terminal-empty | End reached with no entries | missing_credit |
empty-middle-page | Continue through an empty middle page | matched_snapshot |
failed-later-page | page_unavailable | Not called |
changed-snapshot | snapshot_changed | Not called |
changed-scope | scope_changed | Not called |
repeated-cursor | cursor_cycle | Not called |
page-budget | page_budget_exhausted | Not called |
malformed-continuation | invalid_page | Not called |
expired-cursor | cursor_expired | Not called |
wrong-account-row | entry_scope_changed | Not called |
invalid-money-shape | invalid_entry | Not called |
For each result, inspect source_pages, collection.trace, collection.requests, collection.extract, reconciliation and handoff. A withheld run can have observed rows in its trace while extract and reconciliation remain null. That distinction is intentional: partial observations are diagnostic evidence, not an authorized financial conclusion.
The trace contains invented data for teaching. Do not copy a whole-response logging pattern into a real financial integration; production evidence needs the organization's access, redaction and retention controls.
4. Repair the right boundary
Compare credit-on-page-two and second-credit-on-page-two across the guarded and first-page reports. Keep source_pages identical. Explain why the same early-stop defect creates opposite errors: one missed credit and one hidden extra credit.
Then compare changed-snapshot across the guarded and mixed-snapshot reports. The second page is terminal, but it describes snapshot 8. The broken mode combines it with snapshot 7 and allows a match. Reaching the end does not repair the inconsistency.
In collect, find the three separate responsibilities:
- Check the response, scope, snapshot and row shape.
- Continue with the returned cursor while enforcing a request budget and detecting cycles.
- Publish an extract only at the explicit end; otherwise withhold it.
Do not repair these failures by changing the financial comparator, dropping rows or asking a model to “be more careful.” The comparator can only reason about the evidence it receives.
5. Change the code and test an unfamiliar case
In your own copy, add a fixture to scenarios() with an empty first page, an empty second page and a credit on page three. Predict three calls and a match, then run it. Lower its max_pages to 2. Predict no complete extract and no downstream comparison, then verify those two fields.
Next, leave a response envelope correct but change the account on its credit row. Explain why the envelope is not enough. The collector must withhold the row instead of joining it to the requested account by amount.
Finally, run a fresh timeout experiment with this companion script in the same folder:
import runpy
lab = runpy.run_path("fde-financial-extract.py")
calls = []
def fetch_page(scope, cursor, snapshot):
calls.append((cursor, snapshot))
if cursor:
raise TimeoutError("Synthetic final-page timeout")
return lab["page"]([lab["ENTRY"]], "SYNTHETIC-CURSOR-A")
result = lab["collect"](fetch_page, lab["SCOPE"])
assert result["reason"] == "transport_unavailable"
assert result["extract"] is None
assert result["observed_rows"] == 1
assert len(calls) == 2
print("The observed credit stayed out of a complete extract.")Keep your prediction beside the actual report and changed code. Add another case without copying one of the named scenarios. A passing result should explain a business consequence, not just satisfy a label.
6. Rehearse the receiving conversation
Use 20 minutes with a peer or facilitator. If working alone, record self-rehearsal and leave independent review outstanding.
| Time | Receiver's challenge | Evidence to show |
|---|---|---|
| 4 minutes | Explain an empty page without code | Scope, continuation and the unresolved customer question |
| 6 minutes | Move the credit to another page | Your prediction, changed fixture and actual calls |
| 5 minutes | Make the last page unavailable | No complete extract, no comparison, integration owner |
| 5 minutes | Remove the snapshot guarantee | The exact contract gap and the next owner decision |
Write two distinct handoffs. “The read stopped at page two with 503; integration operations must resolve coverage” is different from “The complete scoped snapshot contains no expected credit; ledger operations must investigate.” Neither statement closes the investigation or authorizes a credit.
For a real adapter, establish source permissions, consistency and freshness, bounded request duration and response size, cursor expiry, retry limits, cancellation and privacy-aware evidence retention. The local page-count proof does not test those external properties. If a source cannot pin a snapshot, agree its actual supported read strategy before calling the result a coherent snapshot.
7. Keep your proof and continue
Keep the changed collector, the unchanged comparator, three original reports, your unfamiliar fixture, the timeout proof and both owner handoffs. A receiver should reproduce the result without relying on your narration.
Continue to the receiving-review workbook with a precise claim: this synthetic collector distinguishes an unfinished read from a complete financial comparison. Real source integration remains a separate engineering task.
Primary reference checked 23 October 2026: Google AIP-158 pagination guidance describes opaque continuation tokens, empty pages and keeping query parameters consistent. It does not define this workshop's financial or snapshot contract. All scenarios, code and instruction here are original LockedIn Labs material.