Calculation catalog › Cash flow and summary

Bucket lens allocation

Investable assets assigned to near-, middle-, and long-horizon spending buckets.

Field: buckets Unit: US dollars Basis: nominal dollars Computed by: UI-native Status: Complete chain

Appears in: results-table (bucket lens allocation)

Calculation records

  • Bucket view of the investable total Formula record, justified by derivation

    Purpose: Each year's investable total read as buckets: the next years of net spending, then the rest, as the Results bucket card draws it.

    Statement: projection/bucketLens.ts#bucketLens reads each projection year i with investable total T_i and published net portfolio needs n_j (YearResult.netPortfolioNeed) as spans.length + 1 buckets: bucket k claims the needs of the next spans[k] years, starting with year i and continuing after the earlier buckets' years, capped by what is left, and the last bucket is the remainder. Needs past the horizon count 0. BUCKET_LENS_SPANS holds the two presets the planner offers, [2, 8] and [3]. It refuses a span that is not a positive whole number and a year whose netPortfolioNeed is not a finite number, naming the year, rather than reading it as 0. For needs 10,000, 20,000, 30,000, 40,000 and 50,000 against totals 200,000, 150,000, 100,000, 60,000 and 20,000, spans [2, 8] give year 0 buckets of 30,000, 120,000 and 50,000 and year 2 buckets of 70,000, 30,000 and 0. Units: nominal dollars of each row's year; needs summed undiscounted across future years. Rounding: none; the buckets add to the investable total to within 2 × spans.length units in the last place of the total, since the spans.length subtractions and the spans.length additions of their sum each round once (the worksheet derives the bound).

    Formula: need_k = sum of n_j for j from c_k to min(c_k + s_k, N) − 1; b_k = min(R_k, need_k); R_0 = T_i; R_(k+1) = R_k − b_k; c_0 = i; c_(k+1) = c_k + s_k; growth bucket = R_K

    • T_i: Investable total of year i (YearResult.investableTotal) (unit: USD, nominal of year i) (domain: >= 0)
    • n_j: Net portfolio need of year j (YearResult.netPortfolioNeed) (unit: USD, nominal of year j) (domain: >= 0, finite)
    • s_k: Span of bucket k (unit: years) (domain: positive whole number)
    • N: Number of projection years (unit: years) (domain: >= 0)

    Timing: annual; each row reads the needs of later rows

    Rounding: none

    Limits:

    • A reporting view: nothing feeds back into the projection, and the bucket literature (Estrada; Kitces) finds no systematic benefit from managing money as buckets over a rebalanced total-return portfolio.
    • Needs past the horizon count 0, so the leading buckets drain near the end of the plan.
    • Future needs are nominal and undiscounted, so bucket 2 read in today's dollars overstates its real size by the inflation between the row's year and each need's year.
    • The buckets add to the investable total to within 2 × spans.length units in the last place, not exactly: at most 4 units for the [2, 8] preset and 2 for [3]; 127 of 2,420 example rows differ by one unit, and spans [1, 1, 1] can differ by two (the worksheet's three-span case).

    Provenance: derived by claude, implemented by claude-subagent.

    Independent review: codex

    Gates (6 of 6 pass): fixture registers a test: pass; pins resolve: pass; families exist: pass; worksheet exists: pass; mutation receipt exists: pass; provenance independent: pass

    Worksheet: bucket-lens-allocation.md Mutation receipt: bucket-lens-allocation.mutation.md

    Evidence tests: bucketLens.evidence.test.ts

    Implemented in: bucketLens.ts

    Is the number of: bucket-lens-allocation

Transformations

  • For each year, walk the selected spans (BUCKET_LENS_SPANS: 2/8 or 3 years) summing netPortfolioNeed over the covered future years, claim min(remaining investable, bucket need) per bucket, and put the remainder in the growth bucket, in projection/bucketLens.ts#bucketLens; the buckets add to investableTotal to within one unit in the last place.

The evidence links on this page (each record's worksheet, mutation receipt, evidence tests and implementation, and the source links) are pinned to engine commit 2624dbdba9fd, committed 2026-10-11. The live calculation index and output-family census links point at the repository's main branch, so you can check this snapshot against them.