ENGINE 41

SFS-E41-DTS · DEBT SIZING · REV 2026-07-24 · PRODUCTION

PRODUCTION = runnable end-to-end, CI-backed, full test suite passing. All data fictional and seeded.

Debt Term-Sheet Sizing & Loan Terms

Is the loan sized within the advance rate, and does every other term re-derive?

A borrower runs several projects through legal at once, and each period a new dated workbook lays the deals out side by side -- max loan amount, max loan-to-cost, the index-plus-spread rate build-up over a floor, the letter-of-credit and overdraft facilities, the origination / commitment / unused / admin fees, the term and its extension options, the recourse. A term sheet is a one-page summary re-keyed from a longer credit memo, and it drifts in ways nobody re-foots. This engine reads the seven artifacts that workbook emits -- the deal register, the rate build-up, the fee schedule, the rate summary, the fee summary, the expiry watchlist and the portfolio rollup -- and runs twenty-one deterministic controls over them. Is the sizing file complete and the pricing date readable, are the deal ids unique and the loan type, index and recourse each on their allowed list with a cost basis and advance rate declared, is the max loan within max loan-to-cost times the cost basis, is the drawn balance within the commitment, does the stated maturity reconcile to base term plus every extension option, does each deal carry exactly one rate build-up and does its all-in rate recompute as the greater of index-plus-spread and the floor, is every fee line well-typed and struck on a known base against a deal in the register with an amount that recomputes from that base and rate, is every term sheet still live at the pricing date and which are due to expire inside the lead-time window, and do the rollup's deal count, total commitment and total fees foot the deals while the expiry watchlist ties the term sheets actually due. It compares every figure with exact ==, caps the loan with exact <=, measures every expiry against the pricing date the file carries rather than the system clock, and never writes to a source artifact.

A term sheet is the tidiest page in the credit file: four deals side by side, a rate build-up under each, a fee schedule beneath that, and a rollup at the foot. That is exactly why it drifts. None of the ways it goes wrong look wrong in a tidy grid. The stated max loan creeps a cent or a million above max loan-to-cost times the cost basis, and the over-advance rides in the workbook while the cap sits in a cell nobody recomputed. A build-up figure is re-keyed rather than re-derived -- the all-in rate typed as index plus spread when the floor actually governs, or a fee struck on the commitment where it should have been struck on the undrawn balance -- so the number is arithmetically wrong against a rate that is entirely right. And the rollup is maintained beside the side-by-side rather than footed from it, so the total commitment, the total fees and the count of active deals drift the first time a deal moves and nobody re-adds the column. This engine rebuilds each of those figures from the base terms through the same kernel that produced them, compares with exact == and caps with exact <=, ships a planted-defect file for every registered control, and states its benchmark as a command rather than a claim. It is the sizing tie-out, run before anything closes: whether a draw is actually advanced against a budget line is a funding question a separate engine owns, and that engine explicitly declines to re-foot a term sheet.

Run it Book a consultation

Architecture

functional block stack · static overview
Structural Precondition Deal Register Sizing Constraints Rate Build-Up Fee Schedule Term-Sheet Currency Portfolio Rollup substrate: seeded fictional data

Select a layer

Seven control families run in registry order over each sizing file. The first proves the others had something to read and that the pricing date is legible, because a control that passes on absent evidence reports assurance it never performed.

Key specifications

at a glance
10,3381
Tests
the collected checks that pin this engine's behavior
212
Controls
independent rules run over every sizing file
73
Families
groups of controls, each answering one question
234
Sizing files
one clean baseline plus twenty-two planted-defect files
75
Artifacts read
deal register, rate build-up, fee schedule, rate summary, fee summary, expiry watchlist, term-sheet rollup
06
Tolerance
a figure a cent or a basis point off the re-derivation is a break, not a rounding band

What it does for you

plain terms

A borrower runs several projects through legal at once, and each period a new dated workbook is produced from one template as the deals move toward close. It lays the deals out side by side -- max loan amount, max loan-to-cost, the index-plus-spread rate build-up over a floor, the letter-of-credit and overdraft facilities, the origination / commitment / unused / admin fees, the term and its extension options, the recourse -- and the question is narrow and entirely arithmetic: do the numbers on the term sheet reconcile to the terms the term sheet states? A term sheet is a one-page summary re-keyed from a longer credit memo, and three failures hide inside it, none of which look wrong in a tidy grid. The loan is sized over the advance rate: the stated max loan creeps a cent or a million above max loan-to-cost times the cost basis, and the over-advance rides in the workbook while the cap sits in a cell nobody recomputed. A build-up figure is re-keyed rather than re-derived: the all-in rate typed as index plus spread when the floor actually governs, or a fee struck on the commitment where it should have been struck on the undrawn balance, so the amount is wrong against a rate that is right. And the rollup drifts from the deals: the total commitment, the total fees or the count of active deals is maintained beside the side-by-side rather than footed from it, and it drifts the first time a deal moves and nobody re-adds the column. None of these are judgment calls. They are equalities and comparisons -- a loan against a recomputed cap with exact <=, an all-in rate against max(index + spread, floor), a fee against the truncating basis-point product of its rate and its correct base, a stated total against its re-derivation -- which a deterministic control settles better than a template inherited by whoever maintains the workbook this period.

The seeded demo runs every control over every sizing file7. The CLI generates twenty-three fictional sizing files -- one clean baseline and one carrying each of the twenty-two planted defects -- then runs all twenty-one controls over each. The clean file returns PASS with no flags; every defect file returns REVIEW or FAIL and names the control it tripped along with the reason that control exists.

The advance-rate cap is met at the cent8. Deal DL-203 is seeded sized exactly at its advance-rate cap, so the cap is proved to be met rather than merely cleared. One defect file re-sizes DL-204 to one cent above max loan-to-cost times its cost basis and re-derives the rollup, so the only control that sees it is size_ltc_not_exceeded -- the over-advance is one cent, the finding is unambiguous, and nothing else in the file moves.

The floor is exercised, not assumed9. Deal DL-202's build-up lands below its floor -- index plus spread is 600 basis points against a 700 basis-point floor -- so the max in the all-in rate genuinely governs on the clean baseline. A defect file then contradicts DL-201's stated all-in rate without touching its build-up, and rate_all_in_recomputes rebuilds the rate from index, spread and floor and fails, proving the rate is recomputed rather than read back.

Functional block diagram

engineering · each block links to its source
Functional block diagram of the Debt Term-Sheet Sizing & Loan Terms engine sizing files sizing files sizing files sizing files sizing files sizing files sizing files artifact set resolves resolves resolves resolves resolves resolves findings findings findings findings findings findings findings findings Seeded Sizing Files StructuralPrecondition Deal Register Sizing Constraints Rate Build-Up Fee Schedule Term-Sheet Currency Portfolio Rollup Register,Schedule & Rollup Verdict and Findings SFS-E41-DTS · FUNCTIONAL BLOCK DIAGRAM · REV 2026-07-24

Plain terms

  • Seeded Sizing Files. fictional term-sheet workbooks enter the control registry
  • Structural Precondition. is the sizing file complete and the pricing date legible
  • Deal Register. is the register sound and every governing term on its list
  • Sizing Constraints. is the loan within the advance rate and the maturity reconciled
  • Rate Build-Up. does the all-in rate recompute from index, spread and floor
  • Fee Schedule. is every fee struck on its correct base and does it recompute
  • Term-Sheet Currency. is the term sheet still live and what is due to expire
  • Portfolio Rollup. does the rollup foot the deals and tie the watchlist
  • Register, Schedule & Rollup. the artifacts and the pricing date every rule resolves against
  • Verdict and Findings. every finding, with the reason it exists, ends at a person

Engineering

  • Seeded Sizing Files. generate_corpus writes one clean baseline plus twenty-two planted-defect files, twenty-three in total -- at least one file for every registered control, with a malformed-amount file added on the over-advance rule to exercise the integer-cents guard. Only the deals, the rate build-ups and the fee lines are stated as base facts; each deal's all-in rate, each fee line's amount, the expiry watchlist and the portfolio count and totals are re-derived through the same term-sheet kernel the engine later recomputes with, so the relationships the engine tests are the same relationships that produced the data.
  • Structural Precondition. One control. FAILs a file missing any of the seven artifact types or carrying a duplicate, and FAILs an unreadable as_of pricing date, so no downstream rule holds vacuously on absent evidence.
  • Deal Register. Five controls: unique deal ids, a known loan type, a known reference index, a known recourse structure, and a positive cost basis and max loan-to-cost for the advance-rate control to size against.
  • Sizing Constraints. Three controls: max loan <= max loan-to-cost times cost basis recomputed with truncating basis-point math, drawn balance within the commitment, and stated maturity equal to base term plus every extension option.
  • Rate Build-Up. Two controls: exactly one build-up row per deal, and the stated all-in rate equal to max(index + spread, floor) rebuilt through the shared kernel and compared at the basis point.
  • Fee Schedule. Four controls: a known fee type, a known base of commitment / drawn / undrawn / facility, a deal in the register to attribute the line to, and an amount equal to the truncating basis-point product of the rate and that base.
  • Term-Sheet Currency. Two controls: a FAIL for a term sheet lapsed on or before the pricing date, and a FLAG for one expiring inside the file's own lead-time window, which is still live but has to close before it lapses.
  • Portfolio Rollup. Four controls: the active-deal count ties the register, the total commitment foots the deals' max loan amounts, the total fees foots the priceable fee lines, and the expiry watchlist is rebuilt from the deals and tied entry by entry.
  • Register, Schedule & Rollup. The deal register carries each deal's id, project, loan type, index name, recourse, cost basis, max loan-to-cost, max loan amount, drawn balance, facility limit, base term, extension options, stated maturity and term-sheet expiration; the rate build-up carries the index, spread and floor behind each all-in rate; the fee schedule carries each line's type, base and rate; the rate summary, fee summary, expiry watchlist and term-sheet rollup carry the derived figures the controls re-derive; and the file itself carries the as_of pricing date and the commitment lead-time window. Every sizing, rate, fee, expiry and rollup control resolves against these through the shared term-sheet kernel.
  • Verdict and Findings. Findings roll up per sizing file: any FAIL is FAIL, FLAGs without FAILs are REVIEW, clean is PASS. The CLI exit code is the verdict, so a pipeline can gate on it. Reports carry no timestamps or absolute paths, which is what makes the committed report diffable.

Instruction set

every public command
CommandOperationOutputExitArtifacts
python run.py
regenerate the seeded fictional corpus, run all twenty-one controls, write both reportsper-file verdicts and every actionable finding, then the overall verdict2 for the bundled corpus, which carries a planted defect for every control by designsizing_report.json, sizing_report.md, samples/
python -m sizing_engine samples
analyze an existing folder of sizing files without regenerating itper-file verdicts and findings0 PASS / 1 REVIEW / 2 FAIL / 3 usagenone unless --json or --md is passed
python -m sizing_engine samples --generate --quiet
regenerate the corpus and print only the overall verdicta single verdict line0 PASS / 1 REVIEW / 2 FAIL / 3 usagesamples/
python -m pytest sizing_engine/tests -q
run the full test suite for this engine10338 passed0 when every test passesnone

Benchmarks

measured demo results
MeasureResult
Engine tests1010,338 tests collected
live collection from the engine directory
Registered controls1121 controls
counted from the registry, not from documentation
Planted defects1222 defect files
every registered control has at least one file that trips it
Control coverage13100 percent of controls with a planted defect
no control ships without a file demonstrating it firing

Control characteristics

engineering

Plain terms

The engine has no write path and therefore no autonomy to gate. It produces findings; a person decides whether a deal is re-sized, whether a rate or fee is corrected, and whether a term sheet is chased before it lapses.

Engineering

Deterministic envelope. seeded fictional inputs, read-only operation, offline default mode.

Demo gate. FAIL on the bundled corpus, by design -- it carries a planted defect for every registered control

SeverityVerdictAction
No findings above PASSPASScarry the mechanically clean sizing file into the documented credit and legal review
One or more FLAG, no FAILREVIEWa human resolves each flag; a term sheet expiring inside the lead-time window and an expiry watchlist that does not tie the deals both land here
One or more FAILFAILthe deal or figure is not carried forward until the failing control is cleared -- an over-advance, a draw past its commitment, a maturity that does not reconcile, a rate or fee that does not recompute, a term off its allowed list, a lapsed term sheet, or a rollup total that does not foot

Operating limits

what it refuses to do

See it run

control architecture
Corporate comparison architecture for Debt Term-Sheet Sizing & Loan Terms: declared inputs feed a deterministic calculation, computed and stated results are compared, and the final output is verified.
The Debt Term-Sheet Sizing engine tile states the question that has to hold deal by deal: the loan sized within max loan-to-cost times its cost basis, the draw within the commitment, the maturity reconciled to term plus extensions, and the all-in rate, every fee amount and the portfolio rollup all recomputed from the base terms rather than read back.

Integration

how to run it

Distribution: public repository, MIT license.

python run.py
python -m pytest sizing_engine/tests -q
Source on GitHub Engine README All tests, by engine Run in Codespaces
Substantiation
  • 1python -m pytest --collect-only -q -o addopts= (debt-sizing-automation/)
  • 2len(sizing_engine.engine.REGISTRY)
  • 3distinct rule-id prefixes in sizing_engine.engine.REGISTRY
  • 4samples/*.json after python run.py
  • 5len(sizing_engine.model.DOC_TYPES)
  • 6sizing_engine/tests boundary tests on the cent, the basis point, the month and the expiry date
  • 7python run.py (debt-sizing-automation/); sizing_engine/tests planted-defect suite
  • 8sizing_engine/generate.py DEALS DL-203 and DEFECTS loan_over_advance -> size_ltc_not_exceeded
  • 9sizing_engine/generate.py BUILDUPS DL-202 and DEFECTS all_in_wrong -> rate_all_in_recomputes
  • 10python -m pytest --collect-only -q -o addopts= (debt-sizing-automation/)
  • 11len(sizing_engine.engine.REGISTRY)
  • 12len(sizing_engine.generate.DEFECTS)
  • 13sizing_engine/tests: every registered rule has a planted defect
  • 14debt-sizing-automation/README.md and sizing_engine read-only / determinism tests
  • 15sizing_engine/model.py DOC_TYPES and the scope note in sizing_engine/engine.py
  • 16sizing_engine/engine.py REGISTRY
  • 17sizing_engine/terms.py and sizing_engine/model.py INDEX_NAMES
  • 18sizing_engine/generate.py

Show us where the hours go.

One conversation: you describe the work that consumes your team's month; we tell you plainly what this engine can take over, what it can't, and what a scoped first phase would cost. Your people keep approval authority.

Book a free consultation