The label budget is currently a property of escape islands: #38 caps the rows and columns an island may emit, declared and enforced before any Python runs. That is the right mechanism attached to the wrong noun. The property it prices — this construct emits more than its inputs suggest — is not specific to islands, and at least one in-language construct has it.
Raised by #378, which prices cumsum over a variable rather than refusing it and leaves the mechanism open.
The motivating case
cumsum(x, over=t) where x carries a variable. Row t carries t terms, so over an 8760-snapshot horizon it emits 38,384,280 nonzeros where the state-variable recurrence emits 26,280 — a factor of ~1460 for the same information.
The refusal in ROADMAP used to be locality, and that was wrong: a window function over unbounded rows is perfectly expressible in polars, and our own build throughput is ours to fix and must never gate what the language can say. What is not ours to fix is the size of the model the solver receives. That cost is paid on every solve, forever, and no engineering on this side reduces it later.
So the argument for refusing it is weak and the argument for making the cost visible is strong. That is exactly what a budget does.
What is being asked
Whether the budget generalises from "what an island may emit" to "what any construct may emit", and if so, what shape it takes.
Option A — declared per-construct, like #38. The user writes a cap; exceeding it fails. Honest and explicit; verbose if it has to be repeated wherever the construct appears.
Option B — a global emission ceiling on the build. One number for the model, checked as rows accumulate. Cheap, catches everything including compositions nobody predicted, but names no culprit — the failure says "too big", not "line 40 is why".
Option C — a warning, not a ceiling. Emit at load or bind time when a construct's projected emission is superlinear in a dim it spans, naming the rewrite. No refusal at all. Weakest guarantee, zero false positives.
They are not exclusive: C plus A is probably the real answer, with C carrying the common case.
The hard part
When can it be checked? #38 says "before any Python runs", which for an island is load time because the island's extent is fixed by the preceding where mask. For a construct like cumsum the emission depends on cardinality, which is data's to supply — SPEC §2 is explicit that foreach: [snapshot] does not know how many snapshots there are either.
So the check is bind time, not load time: after coordinates are resolved and before the matrix is built. That is a real point in the pipeline and it is cheap there — dim sizes are known, and projected nonzeros for a construct is arithmetic over them, not a pass over data. But it means the budget is not the load-time guarantee #38's phrasing implies, and the two cases would need to say so differently.
Why it matters beyond cumsum
Deciding this also decides how much job an escape island has left. If windows land as primitives and superlinear emission is priced generally rather than per-island, the island's remaining exclusive territory is narrow: arbitrary Python computing coefficients (already data prep) and non-relational manipulation. That is worth knowing before #38 is designed in detail, not after.
Out of scope
The budget does not touch degree — islands return affine COO rows, and so does cumsum. This is a size question only.
The label budget is currently a property of escape islands: #38 caps the rows and columns an island may emit, declared and enforced before any Python runs. That is the right mechanism attached to the wrong noun. The property it prices — this construct emits more than its inputs suggest — is not specific to islands, and at least one in-language construct has it.
Raised by #378, which prices
cumsumover a variable rather than refusing it and leaves the mechanism open.The motivating case
cumsum(x, over=t)wherexcarries a variable. Row t carries t terms, so over an 8760-snapshot horizon it emits 38,384,280 nonzeros where the state-variable recurrence emits 26,280 — a factor of ~1460 for the same information.The refusal in ROADMAP used to be locality, and that was wrong: a window function over unbounded rows is perfectly expressible in polars, and our own build throughput is ours to fix and must never gate what the language can say. What is not ours to fix is the size of the model the solver receives. That cost is paid on every solve, forever, and no engineering on this side reduces it later.
So the argument for refusing it is weak and the argument for making the cost visible is strong. That is exactly what a budget does.
What is being asked
Whether the budget generalises from "what an island may emit" to "what any construct may emit", and if so, what shape it takes.
Option A — declared per-construct, like #38. The user writes a cap; exceeding it fails. Honest and explicit; verbose if it has to be repeated wherever the construct appears.
Option B — a global emission ceiling on the build. One number for the model, checked as rows accumulate. Cheap, catches everything including compositions nobody predicted, but names no culprit — the failure says "too big", not "line 40 is why".
Option C — a warning, not a ceiling. Emit at load or bind time when a construct's projected emission is superlinear in a dim it spans, naming the rewrite. No refusal at all. Weakest guarantee, zero false positives.
They are not exclusive: C plus A is probably the real answer, with C carrying the common case.
The hard part
When can it be checked? #38 says "before any Python runs", which for an island is load time because the island's extent is fixed by the preceding
wheremask. For a construct likecumsumthe emission depends on cardinality, which is data's to supply — SPEC §2 is explicit thatforeach: [snapshot]does not know how many snapshots there are either.So the check is bind time, not load time: after coordinates are resolved and before the matrix is built. That is a real point in the pipeline and it is cheap there — dim sizes are known, and projected nonzeros for a construct is arithmetic over them, not a pass over data. But it means the budget is not the load-time guarantee #38's phrasing implies, and the two cases would need to say so differently.
Why it matters beyond
cumsumDeciding this also decides how much job an escape island has left. If windows land as primitives and superlinear emission is priced generally rather than per-island, the island's remaining exclusive territory is narrow: arbitrary Python computing coefficients (already data prep) and non-relational manipulation. That is worth knowing before #38 is designed in detail, not after.
Out of scope
The budget does not touch degree — islands return affine COO rows, and so does
cumsum. This is a size question only.