Conversation
Documentation build overview
30 files changed ·
|
FBumann
force-pushed
the
claude/fix-a-decision
branch
3 times, most recently
from
August 29, 2026 20:57
438b317 to
0e49394
Compare
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 07:13
aac6faf to
d48505b
Compare
FBumann
force-pushed
the
claude/fix-a-decision
branch
from
August 30, 2026 07:13
0e49394 to
ac04893
Compare
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 07:17
d48505b to
c5065c2
Compare
FBumann
force-pushed
the
claude/fix-a-decision
branch
from
August 30, 2026 07:17
ac04893 to
9f69c57
Compare
FBumann
force-pushed
the
claude/separable-along
branch
from
August 30, 2026 18:19
c5065c2 to
5f083ef
Compare
FBumann
force-pushed
the
claude/fix-a-decision
branch
from
August 30, 2026 18:19
9f69c57 to
cf0fe7c
Compare
FBumann
force-pushed
the
claude/separable-along
branch
from
August 31, 2026 18:08
5f083ef to
5918b28
Compare
FBumann
force-pushed
the
claude/fix-a-decision
branch
from
August 31, 2026 18:08
cf0fe7c to
163000f
Compare
…o whichever engine reads the data Three facts decide which model a file and a table make together — where a dimension's members come from, the order they stand in, and that a coordinate appears at most once. Each was real and each was written down in a consumer, so a second consumer would have inherited none of them. Co-Authored-By: Claude <noreply@anthropic.com> (cherry picked from commit 1e2b8a9)
…oordinate, so a row lost in preparation is not read as a mask A table short of a coordinate and a table that never had one are identical in the data and mean opposite things. `coverage:` says which was meant, and a parameter declaring itself a mask is refused as a bound or a divisor — the two positions where absence has no reading — before any data arrives. Co-Authored-By: Claude <noreply@anthropic.com> (cherry picked from commit 9a8045c)
…bproblem is a call rather than a second file A myopic pathway, a rolling horizon and a Benders subproblem share one move: a variable stops being a decision and becomes a number somebody else chose. fix takes every name in one call and validates once at the end. Two translations are decisions, not copies: a where-masked variable becomes coverage: masked, and a binary or integer variable becomes an int parameter — never a float, never a bool that would read as a mask. Rebased onto the parameter-coverage branch (#243) it needs for Coverage, off the closed #247/#248 stack it was authored on; only the fix additions are kept. Co-Authored-By: Claude <noreply@anthropic.com>
FBumann
force-pushed
the
claude/separable-along
branch
from
August 31, 2026 18:29
5918b28 to
b207667
Compare
FBumann
force-pushed
the
claude/fix-a-decision
branch
from
August 31, 2026 18:29
163000f to
3348d70
Compare
FBumann
changed the base branch from
claude/separable-along
to
claude/parameter-coverage
August 31, 2026 18:29
FBumann
force-pushed
the
claude/parameter-coverage
branch
2 times, most recently
from
September 2, 2026 08:44
200b831 to
4ada6e5
Compare
This was referenced Sep 2, 2026
Contributor
Author
|
Note The following content was generated by AI. Closed at the author's request, in a sweep of the open PRs. Closed rather than retargeted, for the same reason as #244: the base branch never landed.
#303 stays open. The finding this PR is built on is the durable part, and it is not in the diff: the four-line version in a driver is wrong twice, silently — a masked variable becomes a Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
The following content was generated by AI.
What this changes
A myopic pathway, a rolling horizon and a Benders subproblem share one move: a variable stops being a decision and becomes a supplied number.
docs/about/decomposition.mdsays it outright — "that single change is the whole of the decomposition" — and written by hand it is a second file to keep in step with the first.The name does not move, so every expression naming it goes on reading. Every name is given in one call and the model is revalidated once at the end of it, which is the shape the motivating workflows actually have: a myopic step fixes what earlier periods built, which is many.
Why it is not four lines in a driver
I originally proposed this as a
Spec → Spectoolkit above, and demonstrated a four-line version. Testing it changed the answer: the four-line version is wrong twice, and once silently.where:has rows that do not exist. As a parameter those coordinates have no value, so it iscoverage: masked. The obvious rewrite leaves ittotal, which claims a number everywhere and binds cleanly against data that has none — the exact class feat(language): a parameter says whether its table must cover every coordinate, so a row lost in preparation is not read as a mask #243 exists to prevent.binaryorintegervariable becomes anintparameter, never afloat. Aboolwould be a mask, anddeclarations.mdis explicit that a mask is not something a constraint multiplies by.Two drivers writing their own would each decide these, and differently. By "would two consumers answering separately be a bug?" that is one home, and the home is here.
Where the line falls
fixfollows; it does not decide. That is why it is in the language and elastic relaxation is not: where slacks go and what they cost is a modelling choice, closer to a formulation than to a rename.It is also not every half of a decomposition, which my first docstring overclaimed and the tests corrected. A Benders master has the dispatch gone, not fixed. Fixing every variable a constraint names leaves a row that decides nothing — and because
fixrevalidates, the language says so at the call:Bounds are dropped, the one thing lost: they constrained a decision the model no longer makes, and whether the supplied numbers respect them is a question about data.
What lpspec removes or changes
Nothing. No verb changes and nothing binds differently.
What it gains is that
examples/benders/,examples/myopic/andexamples/rolling/currently ship a hand-written variant file each —sub.yamlbesidemonolith.yaml— and the subproblem ones becomefix(monolith, 'cap'). That is a real reduction in files kept in step by hand, and it is the driftdocs/about/decomposition.mdwarns about.The masters stay files, because a master is the other move.
Verified
Toolchain at the versions
pixi.tomlpins:ruff format --check/ruff check(0.16.1) clean,pyrefly(1.2.0) 0 errors,pytest -q915 passed (905 on the base — 10 new).reuse,typos,prettierandmkdocs build --strictwere run on the top of the stack (#250), which contains this commit.Not run:
zizmor,taplo, and thetectonichalf ofcompile-tex.mkdocs build --strictneededdocs.python.org/objects.invdropped frommkdocs.yml, which this environment's proxy refuses; that affects cross-links into CPython's docs and nothing in this diff.Mutation table
model_construct)The third needed care: my first attempt at it was a no-op that passed the whole suite, which would have recorded a catch that did not happen.
tools/mutate.pycannot express "skip validation", so it was taken by hand throughSpec.model_construct.Deliberately not done
No
relax. It belongs above, per the line drawn earlier — and shipping it here would blur the distinction this PR's argument rests on.The description is carried, the bounds are not. A description describes the quantity, which the fix does not change; bounds describe a decision that is gone.
A name given twice raises rather than deduplicating.
fix(m, 'cap', 'cap')refuses on the second, because after the first it genuinely is not a variable any more.Changed in review. An earlier version of this description defended taking one name per call, on the grounds that a variadic form was an option nobody had asked for. Reading it back against the workflows the module docstring names, that was wrong the other way round — a myopic step fixes many, and composing calls costs a full revalidation each.
fix(model, *names)is what the PR now ships;fix(fix(m, 'a'), 'b')still composes and is asserted to agree withfix(m, 'a', 'b').Stack: eighth, on #248 → #247 → #246 → #245 → #244 → #243 → #242 → #168.
Generated by Claude Code
Closes #303