Repair ten functions, remove the recursion and residue, and compile src/ into the workbook - #64
Conversation
…rc/ into the workbook Correctness: Depreciateλ on an early disposal, Amortiseλ's default timeline, IsOccurrenceDateλ in short months, PeriodLabelλ's ISO year, FinancialYearλ on text dates, the two by-item schedulers on an item with no rows, IsInListλ and IsInListUλ on a grid, the Debt module's error path, CashRatioλ's help width and SumPeriodsλ on a date before the first period. Calculation: the Debt module solves its schedules with SCAN instead of one recursion level per period and InterestLRVλ in closed form; Depreciateλ, Amortiseλ and SumPeriodsλ aggregate months with one matrix product; Periodsλ, CorkScrewReversalλ, Movementλ, LabelAmortiseλ and the rolling functions are vectorised. Every rewrite was re-implemented in Python and reproduces the demonstration sheets' cached values; no cached value was changed. Tooling: tools/compile_sources.py renders src/ into the stored defined names and keeps the Name Manager comments and functions.csv in step; tools/postbuild/refresh_help_spills.py recomputes the cached help tables; tools/postbuild/remove_residue.py drops the hidden FMTs sheet, the custom properties, the stale custom-function declaration and unused styles, and freezes the wide sheets' label columns; the sanitiser pins session state; the AFE store holds all six modules; tools/generate_selftest_examples.py derives 292 native self-test assertions from the help. Documentation: the README's Amortiseλ walkthrough, the implicit-rate advice, the copied ratio help and the Debt help convention. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
PR Summary by QodoRepair workbook functions and add deterministic source compilation
AI Description
Diagram
High-Level Assessment
Files changed (28)
|
Code Review by Qodo
1.
|
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
…cible CI regenerates tools/selftest_examples.ps1 under Python 3.12, where sum() adds floats with compensated summation, and compared it with the fragment committed from Python 3.11: three totals differed (831.93 became 831.9300000000001, and two float artefacts became clean). The generator now sums the digits the help prints as exact decimals and writes each value as the shortest float literal, so every interpreter writes the same fragment. The three artefact lines (0.05999999999999999, 423.28999999999996, 0.12612199999999998) are regenerated clean, and a test pins the arithmetic. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
…d say what the help pass is Three of the review's findings hold. The compiler's tight() and the source gate's canonical() stripped whitespace inside string literals, so a source change inside a literal compared equal to the stored definition and was never written; both now keep every literal exactly, and the one definition that had drifted that way, oz.AboutEssentialsλ, whose stored About row had lost the padding its source and the other four About tables carry, is recompiled. The sanitiser pinned the modified stamp and the last editor only when the file named a creator; the stamp is now pinned regardless and the editor is dropped when there is no creator to replace it with. The postbuild README, the changelog and the help-spill pass itself now say that the pass is text, not recalculation evidence, and that tools/verify_cache.py still has to confirm every cell it writes. Tests cover each case. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
…only checker The postbuild pass that rewrote the cached help tables is withdrawn. The cached-value rule reserves those cells for Excel-backed evidence, the help-corrections precedent was a one-off for two cells, and tools/refresh_cache.py already refreshes them natively. The workbook is rebuilt from main through the unchanged pipeline with that pass omitted, so every cached value it carries is one Excel wrote; it differs from the previous head only in the ten help sheets, which now show the previous table until refresh_cache.py has run. tools/verify_help_spills.py keeps the model of TRIM and TEXTSPLIT as a read-only check: it reports which cached helps no longer match their definitions, without Excel, and never writes. On the tracked workbook it names exactly the ten helps this release changed and matches Excel's cache on the other 33. RELEASING.md runs it before the native gates, the postbuild run order drops the writer, and the tests cover the checker on constructed sheets plus one stable assertion on the tracked workbook. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
…Excel-written caches Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t
Summary
This actions every finding from the workbook review: the functions that returned wrong answers on ordinary inputs, the calculation hot spots, the verification gap, the residue and determinism items, and the documentation that contradicted the code. All eight CI gates pass under Python 3.11 and 3.12, and the 216 tool tests (39 of them new) pass.
Functions that returned wrong answers
oz.Depreciateλno longer errors on a disposal before the end of life (EXPAND cannot shrink); the remaining book value is written off in the disposal month.oz.Amortiseλbuilds its default timeline from every loan, and reads a text start date.oz.IsOccurrenceDateλfinds monthly, quarterly, semi-annual and annual items that start on the 29th to 31st in shorter months.oz.PeriodLabelλ's ISO week label carries the ISO year.oz.FinancialYearλreads a text date; a blank cell still returns a blank.#CALC!, and no longer recurse.oz.IsInListλandoz.IsInListUλsearch a row, column or grid, without wildcard semantics; their copied Name Manager comments now describe them.oz.CashRatioλspills two columns again;oz.SumPeriodsλdrops a date before the first period instead of erroring the row.Calculation that scales
SCANinstead of one recursion level per period, andoz.InterestLRVλis solved in closed form (reproduces 222.90 and every self-test value). With nothing recursing by name, Debt joins the AFE store andverify_afe.pyrequires all six modules.oz.Depreciateλ,oz.Amortiseλ(sub-monthly timelines) andoz.SumPeriodsλaggregate months into periods with one matrix product.oz.Periodsλ,oz.CorkScrewReversalλ,oz.Movementλ,oz.LabelAmortiseλand the four rolling functions are vectorised.Tooling
tools/compile_sources.py: renderssrc/into the stored defined names (_xlfn./_xlws./_xlop./_xlpm.markers,SINGLE()for@,oz.qualification, Excel's case normalisation), proves each rendering throughverify_sources.py's own comparison, refuses anything it cannot classify, rewrites only changed definitions, sets Name Manager comments from source headers and regeneratesfunctions.csv. It compares literal text exactly (layout whitespace and the[0]!marker aside), andverify_sources.pynow holds the same line; the one definition that had drifted inside a literal,oz.AboutEssentialsλ's About row, is recompiled.tools/verify_help_spills.py: a read-only check that models TRIM and TEXTSPLIT over each stored help literal and reports which cached help tables no longer match their definitions, without Excel. It never writes. On the tracked workbook it names exactly the ten helps this PR changed and matches Excel's cache on the other 33. RELEASING.md runs it before the native gates.tools/postbuild/remove_residue.py: drops the hidden FMTs sheet, the 38 custom properties, the stale custom-function declaration on the Excel Labs reference and the unused differential formats and named styles (references renumbered), and freezes the label columns on the six wide demonstration sheets. 211 parts become 169; 443,448 bytes become 430,473.sanitise_workbook.pypins the last editor (or removes it when the file names no creator), the modified stamp, window geometry, build stamp and revision pointer, so two saves of the same content agree.tools/generate_selftest_examples.pyandtools/selftest_examples.ps1: 134 help assertions and 158 worked-example assertions derived from the help, dot-sourced byexcel_selftest.ps1; the tool tests fail when the fragment is stale. Totals and tolerances are exact decimal sums of the printed digits, so the fragment regenerates identically under Python 3.11, 3.12 and 3.13.Documentation
README walkthrough for
oz.Amortiseλ, the implicit-rate conversion advice (README and lease help), the copied ratio help, the Debt help convention, the misspellings, and the run order intools/postbuild/README.md.Evidence and what remains
Periodsλ,ScheduleRatesByItemsλ,ScheduleValuesλ,ScheduleValuesByItemsλ,Depreciateλ,Movementλ,RollingSumλ,MinColsλ,IsOccurrenceDateλandOverLapDaysλshow the previous help table.python tools/verify_help_spills.py ozzit.xlsxlists them;tools/refresh_cache.pyin Excel, thentools/sanitise_workbook.py, refreshes them, and the manifest is realigned after that commit.tools/excel_selftest.ps1andtools/verify_cache.py, and the workbook should be opened in Excel once, per the sanitiser's own advice. RELEASING.md now records 730 assertions (438 hand-written plus 292 generated); the generated figure is a static count, so please record the number the script prints.main(the RELEASING.md colon change) is merged into the branch.🤖 Generated with Claude Code
https://claude.ai/code/session_01TntLJVhtvQFSQdoB2jBh9t