DEV Community

Dakota Wu
Dakota Wu

Posted on

Limit a Messy Adjuster Cleanup to Calls You Have Already Recorded

Consider a checkout service that accumulated one function applying coupons, tax rounding, and partial refunds in a single pass. That function returned a payable total, yet it also inserted an audit row and mutated the cart in place. An assistant then proposed a broad cleanup that split the file into six new modules and renamed several helpers. The review would stall if the team could not name which outputs were already guaranteed by an executable check.

Start from a call set, not a target layout

The useful starting point is a small call set whose outputs a current caller already depends on today. Each recorded call should carry the inputs that change money and the fields a downstream job already reads. Side effects belong in that record when a missing write would become a production incident for the on-call reader. If a path has no current caller and no incident history, leave that path outside the first change budget.

This worked example uses a fictional apply_adjustment module so the method can be copied without borrowing a private repository. The numbers below are illustrative fixtures, not production metrics collected from a named company or incident. Treat every expected value as something you must regenerate on the current code before you trust it.

What the messy function is allowed to promise

The function currently mixes three decisions that tend to fail in different ways during a structural cleanup. Coupon application can drop the subtotal to zero before any tax amount is computed on the remainder. Tax rounding can change a single cent when the order of arithmetic operations shifts inside the function. A partial refund can subtract money that the coupon had already reduced from the same payable total.

Those three paths are enough to fund a first characterization budget without inviting a wider rewrite. A fourth path, such as a loyalty multiplier, stays unrecorded until some caller proves that it matters. Expanding the budget before the first edit usually recreates the broad rewrite you were trying to avoid.

Three calls that pin the current contract

  1. A standard cart applies a ten percent coupon, then rounds tax on the reduced subtotal, and writes one audit row.
  2. A zero subtotal after the coupon must return a zero total and must not insert a negative tax line.
  3. A partial refund must reduce the payable total without applying the same coupon a second time afterward.

Record outputs before anyone edits

The runner below is a proposed example, and it has not been executed against a production repository for this article. It loads a JSON call list, invokes the current function, and writes one golden file per call. A later check fails when the payable total, the audit payload, or the mutated cart fields differ from that file.

# proposal: not executed for this article
import json
from pathlib import Path

def record(calls_path: Path, golden_dir: Path, apply_adjustment) -> None:
    golden_dir.mkdir(parents=True, exist_ok=True)
    calls = json.loads(calls_path.read_text())
    for call in calls:
        result = apply_adjustment(call["cart"], call["coupon"], call["refund"])
        payload = {
            "total": result.total,
            "audit": result.audit,
            "cart": result.cart,
        }
        target = golden_dir / f"{call['id']}.json"
        target.write_text(json.dumps(payload, sort_keys=True, indent=2) + "\n")

def check(calls_path: Path, golden_dir: Path, apply_adjustment) -> list[str]:
    failures = []
    calls = json.loads(calls_path.read_text())
    for call in calls:
        result = apply_adjustment(call["cart"], call["coupon"], call["refund"])
        actual = {"total": result.total, "audit": result.audit, "cart": result.cart}
        expected = json.loads((golden_dir / f"{call['id']}.json").read_text())
        if actual != expected:
            failures.append(call["id"])
    return failures
Enter fullscreen mode Exit fullscreen mode

A companion call file keeps the budget visible in review, which matters more than a clever assertion library. Three records are easier to dispute than a generated suite that nobody can read in one sitting. Keep each call identifier stable so a reviewer can map one golden file to one row in the later decision table.

[
  {"id": "coupon-then-tax", "cart": {"subtotal": "20.00"}, "coupon": "0.10", "refund": "0.00"},
  {"id": "zero-after-coupon", "cart": {"subtotal": "0.00"}, "coupon": "0.10", "refund": "0.00"},
  {"id": "refund-once", "cart": {"subtotal": "20.00"}, "coupon": "0.10", "refund": "5.00"}
]
Enter fullscreen mode Exit fullscreen mode

Run the record step on the unchanged function, and commit the golden files before you open a cleanup branch. The check step then becomes the only executable gate that can approve a later structural edit safely. Store both commands in the module README only after a teammate can run them from a clean checkout. Parse money strings to Decimal inside the test adapter, or the golden files will pin binary float noise instead of cents.

python -m adjuster_characterize record --calls calls.json --out golden/
python -m adjuster_characterize check --calls calls.json --golden golden/
git diff --name-only main...HEAD
Enter fullscreen mode Exit fullscreen mode

Keep the first edit inside the recorded lines

The smallest safe change, in this example, is extracting tax rounding into a pure helper while coupon and refund logic stay put. That extraction is safe only when the three golden files still match and the diff does not touch an unrecorded module. A rename of the audit writer, or a move of refund math, is a second change and waits for its own record.

# proposal: smallest safe extraction, not executed for this article
from decimal import Decimal, ROUND_HALF_UP

def round_tax(taxable: Decimal) -> Decimal:
    return taxable.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
Enter fullscreen mode Exit fullscreen mode

The helper accepts a decimal taxable amount and returns a half-up cent, with no cart mutation inside it. Coupon percentages and refund subtraction remain in the original function until a later budget records them alone. That split is the whole structural change the first patch is allowed to contain under this budget.

Reviewers can apply a simple blast-radius rule without opening a style argument about names or file layout. If git diff --name-only lists a file that no recorded call executes, the patch is too wide for this budget. If the check command prints a call id, the edit changed behavior and is no longer a cleanup. The shell fragment below is a proposal, and it treats any path besides the characterized file as a failed budget.

# proposal: fail review when a changed path sits outside the characterized file
git diff --name-only main...HEAD > changed.txt
grep -vx 'billing/adjuster.py' changed.txt && echo 'patch too wide' && exit 1
python -m adjuster_characterize check --calls calls.json --golden golden/
Enter fullscreen mode Exit fullscreen mode

The grep step prints every changed path that is not the characterized file, and a nonempty result means the patch is too wide. Run the characterization check only after that path list is empty, so a behavior failure is not confused with an oversized diff. Label this script as a review aid, because a rename of the characterized file would otherwise look like an oversized patch.

Review decision table

Observed signal Review action
Golden files match, and the diff stays inside the characterized function Accept the single extraction
Golden files match, but the diff edits an unrecorded helper Reject the patch and ask for a smaller diff
Any recorded call fails Stop and restore behavior before discussing structure
A draft adds calls that nobody has executed on current code Label them as proposals and exclude them from the gate

Where a free assistant fits, and where it does not

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode's free model access is useful here as a drafting aid for candidate call descriptions, not as a source of expected totals. You can paste the current function and ask for three input combinations that exercise coupon, zero, and refund branches. You still generate expected JSON by running the unchanged function, because a model can invent a cent that the production code does not return. A free server option fits the check command, since a clean environment avoids pinning a laptop path, a local time zone, or an editor-installed package.

Neither option replaces the golden-file gate, and this article does not claim a named model, a token quota, a hardware size, or a lasting availability window. Readers who lack a clean checkout can try that free server option while the golden-file check remains the only merge gate. Skip the assistant entirely when the function is short enough to record by hand in a single review sitting.

A failure you should expect on the first check

The first check often fails because the golden file captured a datetime string or a random audit identifier. Strip those fields in the recorder, or replace them with a fixed clock and a fixed identifier before you commit the files. A failure that mentions only the payable total is a behavior change, and it should block the extraction rather than refresh the golden file. Updating the golden file in the same commit as the extraction hides the drift this budget was built to catch.

Limitations and who should skip this

This approach pins observed behavior, and it does not prove that the observed behavior is legally or financially correct. A tax bug that already ships will be preserved on purpose until a separate, reviewed correction changes the golden file. Teams that need an audited tax opinion should not treat these three golden files as formal compliance evidence.

The runner also assumes you can call the function without sending a real payment or writing to a shared production table. If the audit insert cannot be intercepted, stop and wrap that write before you record any golden file. People who need a one-pull-request rewrite of the whole checkout flow should not use a three-call budget. The budget will reject that rewrite by design, which is the intended outcome rather than a tooling failure.

Model-drafted expected values are the wrong input for this gate, even when the draft looks precise. A hand-written expected total is also wrong unless it was produced by the unchanged function on the same inputs. If you cannot rerun the current function, you do not yet have a characterization record and should not edit.

What to merge first

Merge the golden files and the unchanged function in one commit, with no structural edit attached to that commit. Open a second commit that extracts only tax rounding, and require a clean check plus a name-only diff that stays inside the characterized file. Leave coupon stacking, refund ordering, and module splits for later budgets that carry their own recorded calls. That sequence is slower than accepting a six-file cleanup, and it still has an executable answer when the assistant layout is wrong.

Top comments (0)