ENGINE 35
SFS-E35-EPU · EQUITY METHOD · REV 2026-07-24 · PRODUCTION
PRODUCTION = runnable end-to-end, CI-backed, full test suite passing. All data fictional and seeded.
Equity-Method Pickup & Eliminations
Does the pickup re-derive from ownership, and does the elimination extinguish the carrying value?
A reporting group consolidates its subsidiaries and joint ventures one holding at a time, and every period three things must hold at once: each parent's equity pickup equals its ownership share of the sub's net income, the investment carrying value rolls forward as begin + contributions + pickup - distributions = end, and on consolidation every Investment account is extinguished against the sub's Equity-Parent account so each entity block nets to zero. Around those sit the feeding schedules -- a preferred-return accrual built on a day count, and a member allocation that must sum back to the income it splits and tie to the trial balance. This engine reads the eight artifacts the consolidation file carries -- the entity register, the holding register, the sub results, the investment roll-forward, the elimination schedule, the preferred-return schedule, the member allocation and the trial balance -- and runs twenty-five deterministic controls over them, in six families. Is the file complete. Does every roll-forward row foot, name a registered holding, cover every holding exactly once, and carry the ownership share of the sub's declared distributions. Does each pickup recompute as ownership x sub net income, do cost-method holdings book none, is ownership in bounds and never over-allocated, and does every holding resolve to registered entities and a result row. Does every elimination block self-balance, is every equity holding paired investment-to-equity, is the full carrying value extinguished, does every block name a real equity holding, and do the GL accounts follow the company-code link key. Do the preferred-return day counts, accruals, capital chain and period continuity re-derive from the schedule's own dates and rates. Do the member allocations foot and sum to exactly the sub's net income, is every member a holder, and do the investment, pickup, should-be and adjustment columns of the trial balance tie out. It compares every figure with exact ==, rebuilds every pickup and share through the shared kernel that produced the data with the residual cent to the final holder, and never writes to a source artifact.
An equity-method workpaper looks like the most mechanical page in the close: a percentage times an income, a four-line roll-forward, a pair of eliminations that cancel. That is exactly why it drifts. Three failures hide inside it and none of them look wrong on their own page. The pickup drifts from the ownership math -- somebody keys it, or carries last quarter's percentage, and the parent books a share its ownership does not produce, or routes a pickup through a holding carried at cost that should book none. The elimination goes stale -- the carrying value moves all period but the entry does not, leaving a residual on consolidation that is neither an asset nor equity, or a holding is never paired to the sub's equity at all and the same net assets survive twice. And the rollup drifts from the evidence -- the trial balance carries a should-be column nobody re-derives, member allocations stop summing to the income they split, and a preferred-return accrual compounds a day-count error forward period after period. The engine rebuilds every pickup, share, accrual and tie from the base facts through the same kernel that produced the data and compares with exact ==, proves an elimination extinguishes rather than merely balances, ships a planted-defect file for every registered control, and states its benchmark as a command rather than a claim. A mis-keyed pickup, a stale elimination or a should-be nobody recomputed is invisible until consolidation stops netting to zero.
Architecture
functional block stack · static overviewSelect a layer
Six control families run in registry order over each consolidation file. The first proves the others had something to read, because a control that passes on an absent artifact reports assurance it never performed.
Key specifications
at a glanceWhat it does for you
plain termsA reporting group carries its subsidiaries and joint ventures under the equity method, booking each interest once as an investment and then holding three things true at the same time every period: the equity pickup it books must equal its ownership share of each sub's net income, the investment carrying value must roll forward as begin + contributions + pickup - distributions = end, and on consolidation every Investment account must be extinguished against the sub's Equity-Parent account so each entity block nets to zero. Three failures hide inside that, and none of them look wrong on a footed page. The pickup drifts from the ownership percentage -- a share of income the percentage does not produce, or a pickup routed through a holding carried at cost that should book none. The elimination goes stale -- the carrying value moved all period while the entry did not, leaving a residual that is neither an asset nor equity, or a holding never paired to the sub's equity at all so the same net assets survive twice. And the rollup drifts from the evidence beneath it -- a should-be column nobody re-derives, member allocations that stop summing to the income they split, a preferred-return accrual that compounds a day-count error forward. None of these are judgment calls. They are equalities, membership tests and date arithmetic -- a pickup against ownership x net income with exact ==, a carrying value against the roll-forward it ends at, an accrual against capital x rate x days/basis -- which a deterministic control settles better than a spreadsheet inherited by whoever maintains the consolidation this year.
The seeded demo runs every control over every consolidation file7. The CLI generates twenty-seven fictional consolidation files -- one clean baseline and one carrying each of the twenty-six planted defects -- then runs all twenty-five 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.
A balanced elimination can still be stale8. One defect file moves both sides of an elimination block down by the same amount, so the block still balances and elim_block_balances holds -- but it now credits last period's carrying value rather than the value the roll-forward ends at, and elim_extinguishes_investment fails. The two controls are independent by design: balancing is not extinguishing, and a residual survives on consolidation until the block ties to the ending carrying value.
The pickup is recomputed, not read back9. A defect file adds to the booked pickup and absorbs the same amount into contributions, so the roll-forward identity still foots and rf_identity holds. epu_pickup_rederives rebuilds the pickup from ownership x the sub's net income through the shared kernel and fails, proving the pickup is recomputed from the base facts beneath it rather than trusted as stated -- and alloc_tb_pickup_ties then ties the ledger to that re-derived share, not the stated one.
Functional block diagram
engineering · each block links to its sourcePlain terms
- Seeded Consolidation Files. fictional equity-method consolidation files enter the control registry
- Structural Precondition. is the consolidation file complete
- Investment Roll-Forward. does every roll-forward foot, cover its holdings and share distributions
- Equity Pickup. does the pickup re-derive from ownership x sub net income
- Consolidation Eliminations. does the elimination balance and extinguish the carrying value
- Preferred-Return Accrual. do the accrual, day count, capital chain and periods re-derive
- Allocation & TB Tie-Out. do the allocations tie to net income and the trial balance tie out
- Registers, Schedules & Trial Balance. the artifacts and dated rates every rule resolves against
- Verdict and Findings. every finding, with the reason it exists, ends at a person
Engineering
- Seeded Consolidation Files. generate_corpus writes one clean baseline plus twenty-six planted-defect files -- at least one for every registered control -- twenty-seven files in total. Only the entities, the holdings, the sub results, the roll-forward opening facts and the preferred-return period facts are stated; each holding's pickup and distribution share, every roll-forward ending value, the elimination blocks, the member allocation, the accrual chain and the trial-balance balances are re-derived through the same pickup kernel the engine later recomputes with, so the relationships the engine tests are the relationships that produced the data.
- Structural Precondition. One control: FAILs a file missing any of the eight artifact types in model.DOC_TYPES or carrying a duplicate, so no downstream rule holds vacuously on absent evidence.
- Investment Roll-Forward. Four controls: each row foots begin + contributions + pickup - distributions = end, names a registered holding, every holding carries exactly one row, and each equity holding's distributions are its ownership share of the sub's declared distributions.
- Equity Pickup. Four controls: each equity pickup recomputes through the shared kernel, cost-method holdings book none, ownership is positive and never over-allocated, and every holding resolves to registered entities, a result row and a known method.
- Consolidation Eliminations. Five controls: every block self-balances, every equity holding is paired investment-to-equity, the credit to the Investment account equals the roll-forward ending value, every block names a real equity holding, and the GL accounts follow the company-code link key.
- Preferred-Return Accrual. Four controls: the stated day count equals the dates counted inclusively, the accrual recomputes as capital x rate x days/basis from the dates, the capital balance chains without the return compounding into it, and the accrual periods abut without gap or overlap.
- Allocation & TB Tie-Out. Seven controls: each allocation foots and a fully-held sub's allocations sum to exactly its net income, every member holds the sub, the investment and pickup accounts tie the re-derived figures, every adjustment is should-be minus balance, and an unposted-but-consistent adjustment is flagged for review.
- Registers, Schedules & Trial Balance. The entity register carries each entity's role and company code; the holding register carries ownership, method and the linked GL accounts; the sub results carry net income and declared distributions; the roll-forward, elimination schedule, preferred-return schedule, allocation summary and trial balance carry the derived figures. Every roll-forward, pickup, elimination, accrual, allocation and tie control resolves against these through the shared pickup kernel, so a determination cannot disagree with the data that produced it.
- Verdict and Findings. Findings roll up per consolidation 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| Command | Operation | Output | Exit | Artifacts |
|---|---|---|---|---|
python run.py | regenerate the seeded fictional corpus, run all twenty-five controls, write both reports | per-file verdicts and every actionable finding, then the overall verdict | 2 for the bundled corpus, which carries a planted defect for every control by design | epu_report.json, epu_report.md, samples/ |
python -m pickup_engine samples | analyze an existing folder of consolidation files without regenerating it | per-file verdicts and findings | 0 PASS / 1 REVIEW / 2 FAIL / 3 usage | none unless --json or --md is passed |
python -m pickup_engine samples --generate --quiet | regenerate the corpus and print only the overall verdict | a single verdict line | 0 PASS / 1 REVIEW / 2 FAIL / 3 usage | samples/ |
python -m pytest pickup_engine/tests -q | run the full test suite for this engine | 10423 passed | 0 when every test passes | none |
Benchmarks
measured demo results| Measure | Result |
|---|---|
| Engine tests10 | 10,423 tests collected live collection from the engine directory |
| Registered controls11 | 25 controls counted from the registry, not from documentation |
| Planted defects12 | 26 defect files every registered control has at least one file that trips it |
| Control coverage13 | 100 percent of controls with a planted defect no control ships without a file demonstrating it firing |
Control characteristics
engineeringPlain terms
The engine has no write path and therefore no autonomy to gate. It produces findings; a person decides whether a figure is carried into consolidation and whether a derived adjustment is posted.
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
| Severity | Verdict | Action |
|---|---|---|
| No findings above PASS | PASS | carry the mechanically clean consolidation file into the documented sign-off and consolidation review |
| One or more FLAG, no FAIL | REVIEW | a human resolves each flag; a trial-balance adjustment that is internally consistent but has not been posted lands here |
| One or more FAIL | FAIL | the figure is not carried into consolidation until the failing control is cleared -- a pickup that does not recompute, an elimination that does not extinguish, an identity that does not foot, or a tie the trial balance does not hold |
- Read-only: consolidation files are parsed and never written back, so the engine cannot introduce the break it reports.
- Integer cents throughout, compared with exact ==; there is no tolerance band, and a figure a cent off its re-derivation is reported as a break.
- A figure that should be integer cents but is not produces an AMOUNT_INVALID finding contained to the one row it was read on, rather than being coerced into the number the engine is meant to audit.
- One pickup kernel: the controls and the generator share the arithmetic in pickup_engine.pickup, so a determination cannot disagree with the data that produced it -- floor division with the residual cent to the final holder, so a 50/50 split of an odd cent still sums back to the income it divides.
- The pickup is recomputed, not read back: alloc_tb_pickup_ties compares the ledger to the re-derived share, so a mis-keyed roll-forward cannot vouch for a mis-keyed ledger.
- The elimination must extinguish, not merely balance: a balanced block still crediting last period's carrying value fails elim_extinguishes_investment.
- Deterministic and byte-stable: same inputs produce the same findings in the same order, with no timestamps or absolute paths in any output.
- Absent evidence is never a passing control; a missing artifact fails completeness rather than letting the controls that read it pass unread.
Operating limits
what it refuses to do- The engine never posts a journal entry, books a pickup, moves an elimination, files a return or writes to a source artifact. It reads the consolidation file and stops.14
- It reads the eight artifacts the consolidation file carries. It does not connect to a general ledger, a consolidation system or the underlying valuation workpaper.15
- It re-derives and ties the equity-method arithmetic -- pickup, roll-forward, eliminations, accrual and allocation. It deliberately does not opine on impairment or fair value, which are judgment calls owned by a valuation workpaper, not a re-foot.16
- It takes the sub results, ownership percentages, method elections and dated rates the file carries at face value; it does not decide whether an ownership percentage, a cost-versus-equity election or a preferred-return rate is the correct one for the period and entity.17
- It confirms the schedules foot, re-derive and reconcile, not that a contribution or distribution actually occurred. All shipped data is fictional and the fiscal period is set in a fictional future.18
See it run
control architecture
Integration
how to run itDistribution: public repository, MIT license.
- 1python -m pytest --collect-only -q -o addopts= (equity-pickup-automation/)
- 2len(pickup_engine.engine.REGISTRY)
- 3distinct rule-id prefixes in pickup_engine.engine.REGISTRY
- 4samples/*.json after python run.py
- 5len(pickup_engine.model.DOC_TYPES)
- 6pickup_engine/tests boundary tests on the cent and the day count
- 7python run.py (equity-pickup-automation/); pickup_engine/tests planted-defect suite
- 8pickup_engine/generate.py DEFECTS elimination_understated -> elim_extinguishes_investment
- 9pickup_engine/generate.py DEFECTS pickup_not_rederived -> epu_pickup_rederives
- 10python -m pytest --collect-only -q -o addopts= (equity-pickup-automation/)
- 11len(pickup_engine.engine.REGISTRY)
- 12len(pickup_engine.generate.DEFECTS)
- 13pickup_engine/tests: every registered rule has a planted defect
- 14equity-pickup-automation/README.md and pickup_engine read-only / determinism tests
- 15pickup_engine/model.py DOC_TYPES
- 16pickup_engine/engine.py scope note and equity-pickup-automation/README.md
- 17pickup_engine/engine.py epu_ and pref_ families
- 18pickup_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