Allocation is a policy, not a second invoice
Three tasks share a resource. The source record contains thirty-seven subunits. The proposed weights are three, two and two. A report divides the amount proportionally, rounds each result independently and produces sixteen, eleven and eleven.
Reading tools Listen or translate
Read aloud
Uses an installed voice on your device.
Translate article
Machine translation. Code and evidence notes stay in English.
Original English text.
Retrospective edition, scoped to 30 December 2025. All amounts are synthetic accounting units named SYN. The arithmetic model does not inspect Azure expenditure, an account balance or a provider invoice.
Three tasks share a resource. The source record contains thirty-seven subunits. The proposed weights are three, two and two. A report divides the amount proportionally, rounds each result independently and produces sixteen, eleven and eleven. The spreadsheet looks tidy. It has also created a subunit that the source never contained.
Fixing the arithmetic is necessary, but it does not settle the larger question: why should those tasks receive those shares? A weight can represent observed work, reserved capacity or an ownership convention. Each can be defensible for a particular purpose. None becomes a physical measurement merely because the calculation is precise.
This is the distinction I would preserve in a task-cost discussion. A source amount describes a recorded quantity within a scope. An allocation policy distributes it. A report should retain both identities so a reader can challenge the arithmetic and the interpretation separately.
We will follow a hand-sized allocation through deduplication, proportional shares, residual assignment and an explicit unallocated remainder. The reader should be able to prove that no units were created or lost while still asking whether the chosen policy answers the intended question.
Conservation is an acceptance condition, not a fairness claim
Let the deduplicated source total be T, the sum assigned to tasks be A and the amount left unallocated be U. The basic invariant is T = A + U. A report that violates it cannot explain where the source amount went.
In the worked example, thirty-seven subunits are assigned under weights 3:2:2. Another eight subunits belong to an unmapped source category and remain unallocated. The source total is forty-five. Correct task shares are sixteen, eleven and ten under the declared largest-remainder rule, leaving the separate eight unallocated.
Many policies could conserve forty-five. We could assign everything to one task, divide equally, or use another set of weights. Conservation rejects arithmetic loss and duplication; it does not choose the policy. Keeping that distinction visible prevents a green invariant check from becoming an unjustified claim that the allocation is economically fair.
The visual lets you change source subunits, weights, the unmapped amount and a negative-adjustment sign. It calculates every share. A deliberately naive independent-rounding mode exposes when tidy rounded values fail conservation. The displayed units are a synthetic discrete domain, not real money or a forecast of cloud charges.
A duplicate record is not another source amount
Before allocating, identify the source record. Reimporting the same record should not create another charge merely because it arrived in a second file or retry. The stable identity should be defined by the selected source contract, not invented from the order in which the importer happened to see rows.
A content fingerprint can distinguish an exact duplicate from the same identity carrying different content. The first can be ignored under an idempotent import policy. The second needs a correction or conflict rule. Silently accepting both makes the total depend on delivery history rather than the intended source history.
For a synthetic model, the key can be a small record ID. A real billing or usage adapter needs to understand the dataset's identity, revision and period semantics. A trace ID is not automatically the unique identity of a provider charge, and a provider record is not automatically the identity of one application task.
public sealed record SourceAmount(
string RecordId, string ResourceCategory, long Subunits, string Unit);
public sealed record Weight(string TaskId, long Value);
These are illustrative application types using the .NET 9 baseline, released before this edition. They do not claim that a particular Azure export has this schema. The adapter owns the translation from its chosen source representation into a validated accounting domain.
Whole subunits make the residual unavoidable
Thirty-seven times three sevenths is fifteen and six sevenths. Thirty-seven times two sevenths is ten and four sevenths, for both remaining tasks. Taking the whole portions gives fifteen, ten and ten: thirty-five assigned subunits, with two left to distribute.
The largest remainder belongs to A, so A receives one residual subunit. B and C have equal remainders. The example breaks ties by ordinal task identity, giving the next unit to B. The final allocation is sixteen, eleven and ten.
This rule is not the only possible rounding policy. Its advantages here are determinism and conservation. The report can explain why B received one more subunit than C even though their weights match. If that tie-break is unsuitable for the business purpose, choose another explicit policy and preserve its version.
The browser's animation shows the residual units moving out of an unassigned pool into specific task shares. The counters change at the same step as the visual allocation. It is not a decorative progress indicator and not a runtime measurement; it depicts the exact integer calculation selected by the reader.
Integer arithmetic can keep the proof inspectable
The proportional numerator can overflow a fixed-width integer even when the final share fits. A bounded implementation can reject excessive inputs, use checked arithmetic or use a wider integer representation for the intermediate calculation.
For a general discrete example, BigInteger keeps the division and remainder exact:
BigInteger numerator = (BigInteger)magnitude * weight;
BigInteger floorShare = BigInteger.DivRem(numerator, totalWeight, out var remainder);
After computing every floor share, subtract their sum from the source magnitude. Assign the remaining subunits by descending remainder and the declared stable tie-break. Finally restore the sign for a negative source adjustment. The magnitude path should not accidentally overflow when taking the absolute value of the most negative fixed-width integer. For a long source, widen before taking the absolute value: BigInteger.Abs((BigInteger)sourceAmount). Likewise, the cast in the multiplication must occur before the product is evaluated, not only when it is assigned.
Validate the weights before division. A zero total weight cannot define proportional shares. Negative weights need a separate meaning and should not be accepted casually in a policy intended to distribute a nonnegative magnitude. Repeated task identities within one policy should also be refused or normalized explicitly; otherwise one task can receive multiple shares under different rows.
The visual restricts the input domain and uses exact integer operations for its synthetic subunits. It does not rely on the formatted decimal value as the authoritative quantity. Formatting is an output concern; the allocation operates on the discrete units the contract declared.
Negative adjustments should not invent a new rounding rule
Suppose the source amount is a negative thirty-seven subunits. If the adjustment is meant to reverse the same proportional policy, allocate the magnitude under the same rule and restore the negative sign. The shares become minus sixteen, minus eleven and minus ten.
Rounding signed fractions independently can produce surprising asymmetry depending on the language's midpoint and floor rules. Separating magnitude from sign makes the chosen behavior easier to explain and test. It does not imply that every real provider adjustment should be distributed this way; a correction may refer to a specific earlier task or source record and require another policy.
This is another reason to preserve the source-to-policy relationship. A generic negative row is not necessarily a refund for the same cohort that produced a positive row. The source period, identity and correction semantics determine whether the two belong in one reconciliation.
Unallocated is different from unknown
The eight unmapped subunits in the example are known source data with no accepted assignment policy. They are unallocated, not missing. The total can still be complete while task attribution remains incomplete.
Unknown source data is a different problem. If the source dataset itself has not finalized, the report may need a provisional total and an explicit completeness state. Distributing the observed rows across known tasks does not make absent rows equal to zero.
Do not distribute unresolved amounts merely to make the task column add up neatly. An explicit unallocated bucket lets the report conserve the source while exposing the missing interpretation. A later policy can create a new allocation version without silently rewriting the meaning of an earlier report.
The strongest objection is that management often needs one number now. A provisional number can be useful if its boundary is visible. The problem is not timeliness; it is presenting a complete-looking answer whose unresolved terms have been hidden by arithmetic.
A trace does not contain a unique share of every shared cost
A trace can show which services participated in a task and how long selected operations took. A resource-level source amount can cover many tasks and idle capacity over a different interval. Connecting the two requires a policy about time, ownership and shared work.
CPU duration, request count, reserved capacity and data volume can each be useful weights for a particular question. They are not interchangeable measures. A task that uses little CPU may still require expensive reserved capacity or a large storage footprint. A task that finishes quickly may trigger work whose costs appear later.
This edition does not fetch Azure Cost Management data or quote live prices. It isolates the allocator that would consume an already defined source domain. A real integration should establish source semantics, provider adjustments and overlap with application-level usage before adding totals from different views.
For example, a model-call ledger and a shared-resource allocator may both account for part of the same work. Adding them without an overlap rule can double-count even when each component conserves its own input perfectly. Component correctness does not establish correctness of the combined accounting boundary.
The denominator belongs in the report too
Allocated cost per attempted task differs from allocated cost per accepted outcome. Rejected work and unresolved tasks do not disappear because the final report counts only successful results. A useful integration preserves the work performed and the rule defining acceptance separately.
The allocator here does not decide that denominator. It returns source total, unallocated amount and shares by task. A consumer can then apply its own explicitly versioned outcome rule. Keeping the layers separate makes it easier to identify whether a change came from resource attribution or from a revised definition of useful work.
It also makes testing more meaningful. Conservation tests can use literal expected integer shares. Outcome tests can use an independent task-status fixture. An end-to-end accounting report should verify the combination without copying the implementation's own intermediate numbers into its expected result.
Preserve the policy that made the number possible
An allocation receipt should identify source records, source period, unit, deduplication decisions, policy version, weights, rounding rule and unallocated amount. That is enough to make the arithmetic challengeable without pretending the report can answer every economic question about the service.
Before accepting the next per-task cost chart, test a one-subunit split, equal remainders, a negative adjustment, a duplicate source record and a missing allocation policy. Then ask why the weights are appropriate for the decision the chart supports.
The most useful result is not simply an exact total. It is an exact total whose interpretation remains open to inspection. Precision should make the assumptions easier to see, not make them look like facts the source never supplied.
GO FURTHER
Inspect the contemporary laboratory.
This is a newly reconstructed historical edition, not a claim of earlier authorship. Later executed experiments, their exact environments and original results are preserved in a separate notebook.