A decision table, not a reference table

Returned ACH debits: what each reason maps to.

17 return codes sort into 5 decisions, because there are 5 answers to the one question that decides what happens next: what has to change before this debit can exist again. Nothing, the account details, their instruction, our own entry, or nothing ever will.

RowGoes againChange firstPerson firstCodes
1yesnothingnoR01 R09
2not on this entryaccount detailsnoR02 R03 R04 R13 R20 R28
3not until they asktheir instructionnoR08
4corrected onlyour own entrynoR11
5nonothing willyesR05 R07 R10 R14 R15 R16 R29
5nonothing willyesevery other code, which never lands on row 1

One row per code would be a reference document, and the registrar publishes that for free. One row per decision is a rule set, and that is the part a team cannot download.

The row worth the table

R11 arrives in the unauthorized family and is still correctable. It is the one code where the family and the decision disagree, and the one thing here that is hard to know.

The default is visible as a default

Every code the table does not list lands on row 5, where nothing automatic happens, and the answer says it fell through rather than matched. It is never null and it is never row 1. A caller that cannot tell a match from a fallback has been handed a guess dressed as an answer.

Callable by an agent

The table ships as an MCP server with three read-only tools: lookup_return_code, list_decisions and explain. The agent asks, the table decides, and the answer carries which rule fired. No model is consulted, so the decision cannot be argued with by anything the agent read on the way in.

pip install "mcp>=2,<3"
python -m app.mcp_server

Nothing writes, nothing calls a model, and nothing reaches the network. Each tool declares that as read_only_hint and open_world_hint: false, so a client reads it off the tool list rather than taking this page's word for it, and the test suite runs every tool again with the socket layer replaced by a function that raises.

A green unit suite is not evidence that a client can load a server, so CI spawns it over stdio, completes the handshake, and carries a positive control (R11 must come back on row 4 in the unauthorized family) and a negative one (an unlisted code must come back on the conservative row, marked as a fallback) in every run.

What this page does not claim

Read the source