What you will build.
A fictional card processor authorizes 5,000 minor units for DEMO-CARD-01, then clears 5,400. Review the difference alongside a reversal and a replayed event. This is reconciliation training, not card issuance or an authorization service.
Your working record
Create a private worksheet with columns for the source reference, observed state, responsible system, observation time, expected result and unresolved issue. Use the same fictional case throughout the steps; do not paste live personal or financial records into this exercise.
Run the example before changing it.
Inspect the baseline record below. Download and read the complete JavaScript file before running it. It uses only Node’s built-in test and assertion modules; there is no package installation, account connection or secret to configure.
{
"authorizedMinor": 5000,
"clearedMinor": 5000,
"reversed": false,
"eventSeen": false
}Save it as crypto-backed-debit-cards.mjs. Open a terminal in that folder and run:
node --version
node --test crypto-backed-debit-cards.mjsExpected result: four passing tests and zero failures. These tests verify the teaching classifier only. They do not verify a production integration, security boundary or financial outcome.
File or test runner will not start?
Check that Node.js 22 or later is installed, the filename ends in .mjs rather than .mjs.txt, and your terminal is in the download folder. If a managed browser blocks scripts, open “Read the full exercise” and save that text locally under the same filename. Do not disable organizational security controls.
Read the full exercise
// Hybrid-Chain offline teaching model: crypto-backed-debit-cards
// Fictional fields/states; NOT an API client, authorization system or production implementation.
// No network calls, credentials, payments or file writes. Review before running.
// Requires Node.js 22+. Run: node --test crypto-backed-debit-cards.mjs
import test from 'node:test';
import assert from 'node:assert/strict';
export function inspect(record) {
if (record.eventSeen) return 'ALREADY_PROCESSED';
if (record.reversed) return 'REVERSAL_REVIEW_REQUIRED';
if (record.authorizedMinor !== record.clearedMinor) return 'AMOUNT_REVIEW_REQUIRED';
return 'CLEARING_READY_FOR_RECONCILIATION';
}
const baseline = {
"authorizedMinor": 5000,
"clearedMinor": 5000,
"reversed": false,
"eventSeen": false
};
const cases = [
{
"name": "matching clearing",
"patch": {},
"expected": "CLEARING_READY_FOR_RECONCILIATION"
},
{
"name": "adjusted amount",
"patch": {
"clearedMinor": 5400
},
"expected": "AMOUNT_REVIEW_REQUIRED"
},
{
"name": "reversed authorization",
"patch": {
"reversed": true
},
"expected": "REVERSAL_REVIEW_REQUIRED"
},
{
"name": "replayed event",
"patch": {
"eventSeen": true
},
"expected": "ALREADY_PROCESSED"
}
];
for (const example of cases) {
test(example.name, () => {
assert.equal(inspect({...baseline, ...example.patch}), example.expected);
});
}
Know what the tests demonstrate
- matching clearing
CLEARING_READY_FOR_RECONCILIATION- adjusted amount
AMOUNT_REVIEW_REQUIRED- reversed authorization
REVERSAL_REVIEW_REQUIRED- replayed event
ALREADY_PROCESSED
Now change one fixture at a time. If you change a case’s input without changing its expected result, the test should fail. Read the actual-versus-expected difference and use the walkthrough to decide whether your rule or your expectation needs correcting. Keep an unchanged copy for comparison.
Work through the case, step by step.
- 01
Create the four-part record
Do this
- Write DEMO-CARD-01 and separate authorization amount, clearing amount, reversal state and funding reference.
- Use integer minor units in this exercise; record the currency separately.
- Identify which issuer/processor event is authoritative for each state.
Expected resultThe record distinguishes a temporary authorization from final clearing and from any separate asset conversion.
If your result is different
Do not invent a card-network integration from a wallet or funding endpoint. Establish the contracted issuer route first.
- 02
Inspect an amount mismatch
Do this
- Run the baseline with authorizedMinor and clearedMinor both 5000.
- Change clearedMinor to 5400 and expect AMOUNT_REVIEW_REQUIRED.
- Record the 400-unit difference and its provider reference instead of silently rewriting the authorization.
Expected resultThe reconciliation view preserves the discrepancy for fees, adjustments or other provider-specific investigation.
If your result is different
The model does not decide whether an adjustment is valid; use the actual processor rules and supporting evidence.
- 03
Handle reversal and replay separately
Do this
- Set reversed=true and confirm REVERSAL_REVIEW_REQUIRED.
- Restore the baseline and set eventSeen=true; expect ALREADY_PROCESSED.
- Document the durable event identity and atomic processing rule needed in the real adapter.
Expected resultA reversed authorization and a repeated event cannot be mistaken for a fresh instruction to move funds.
If your result is different
A local eventSeen flag is not concurrency protection. Test the real event store with duplicate and reordered deliveries.
- 04
Plan the funding reconciliation
Do this
- Keep funding evidence in a separate worksheet column rather than deducting assets inside the card-event handler.
- Identify the authorized conversion/funding owner and how failed or delayed funding is resolved.
- Save the fixture outcomes and compare the worksheet to the funding guide's lifecycle stages.
Expected resultThe team has a provider-aware reconciliation model without suggesting that a card event grants wallet authority.
If your result is different
Do not treat this exercise as chargeback processing, network certification or an enabled payout route.
Review what you produced.
Save the worksheet, unmodified test output, one deliberately failing case and the explanation of its fix. A useful result includes an unresolved item with an owner; it is not just a screenshot of four green tests.
Map the model to actual systems.
A contracted issuer/processor owns card issuance, authorization, clearing, reversals, chargebacks, customer disclosures, and network obligations. Confirm asset conversion and liquidity independently.
For each worksheet field, name the owning system, exact current operation, permission and error behavior. Put “not available” next to any missing operation and assign a dependency owner. Do not substitute the teaching classifier for that missing integration.
Open the current API reference and inspect each operation’s request, response, scope and implementation status. Code examples on this page are local models only; they do not call those operations.
Take the next technical step.
Use your worksheet and failing-case notes in the next walkthrough. Keep the same reference trail so you can see which assumptions become actual observations—and which remain dependencies.
Inspect the separate funding stages