asc-community / asc-community/AngouriMath
BudgetOutcome has no consumer: the object that names which limit fired is never read outside Core/Budgets
- Dominant language
- C#
- Stars
- 831
- Forks
- 79
- Avg merge
- 3h 23m
- Merged PRs (30d)
- 309
Description
Measured on `2dbeedf7`.
`BudgetOutcome` (#1035) exists to name **where** a budget was exhausted and **why**. Grepping the kernel for it finds four files:
```
Core/Budgets/WorkBudget.cs
Core/Budgets/BudgetLedger.cs
Core/Budgets/BudgetOutcome.cs
Core/Budgets/BudgetRecording.cs
```
All four are the budget layer itself. **It has no consumer.** The object that says which limit fired is built, tested and read by nothing.
`WorkBudget` itself does slightly better, reaching four call sites outside its folder:
```
Core/Transformations/Saturation.cs
Core/Transformations/Transformation.Catalogue.cs
Functions/Simplification/Patterns/Patterns.ExpandFactorize.cs
Functions/Algebra/Groebner/Buchberger.cs
Functions/Continuous/Solvers/EquationSolver.cs
Convenience/MathS.cs
```
so a budget can be *spent* in saturation, expansion, Gröbner and the solver — and when it runs out, the outcome that would say so is not the thing that reaches the caller.
### Why re-open this rather than read it off #1036
#1036 ("giving up on a resource is spelled the same as a mathematical negative") was closed as completed on 2026-08-24, and #896 with it. Its step 1 landed in #1046 and is real: `Solve`'s two resource-driven exits answer with the equation as a set builder instead of `{ }`, so an empty set means an established emptiness again.
But #1036 was about one chokepoint, and the survey behind it found roughly seventy sites that give up on a resource, of which one threw and one recorded which limit fired. Closing the issue closed the `Solve` boundary, not the class. This is filed as its own thing because the remaining work is not "finish #1036" — it is that **the mechanism to do it exists and is unused**, which is a different and much cheaper starting position than the survey described.
### What it costs a caller today
A caller who hits a budget gets the shape of a mathematical answer with none of the provenance: which subsystem stopped, which limit it was, how much had been spent. `WorkBudget` carries an inherited ledger precisely so that a nested search can attribute its spend to the caller that granted it, and none of that reaches an API.
This is also #746 tier 4's prerequisite. A strategy engine picks between alternatives on the evidence of what the last one did; "it did not work" and "it ran out of room after 40,000 steps in Buchberger" select different next moves, and only the second is actionable.
### Smallest first step, for discussion
Pick one consumer and take it end to end rather than sweeping seventy sites:
* `Solve` is the obvious one — it already distinguishes the two exits since #1046, so it has the branch and only lacks the payload.
* Surface the outcome somewhere a caller can read it without changing the return type of anything (a property on the result, or an out-parameter overload) — the return types are the reason this stalls, and it should not be a breaking change to find out why a search stopped.
* Then a test asserting a deliberately under-budgeted call reports the subsystem by name, which is what stops the field going stale again.
The four sites where exhaustion is currently rendered as a mathematical claim, named in #1036's table, are the ones worth checking first — those are wrong answers rather than missing metadata.
Part of #746, tier 4.
Contributor guide
Research direction
Start with Core/Budgets/BudgetOutcome.cs and the existing budget flow through WorkBudget.cs, BudgetLedger.cs, and BudgetRecording.cs, then trace the resource-driven exits in Solve. Choose the Solve consumer path described in the issue and run a deliberately under-budgeted call. Done means the caller can read which subsystem or limit stopped the search, with a test preserving that report.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100