Conversation
`sum_back` reaches back along an axis; nothing reached forward. With a literal width that is a composition and belongs in `macros:` --- but the composition is not the same operator turned around: - `shift` past the end drops the rows it vacates, or fills them with a number. A window running off the axis is short, not empty, and the row being written is always inside its own window, so none is ever lost. - A width that is a parameter has no forward spelling at all. It would need `offset=-(p-1)`, a negative named offset, which the language refuses so a translation's direction is never something the data decides. Per-entity forward windows --- a minimum down time, a notice period --- were unsayable. So it is one operator pointed two ways, and it lands as one branch: the width, the edge policy, the summation and the pullback are all shared, and only which side of the difference carries the prime tells them apart. `0 <= t - t' < n` becomes `0 <= t' - t < n`, and nothing else in the equation moves --- which the golden diff says out loud, being pure addition with no rendered line disturbed. No new node type: an operator is a `FunctionCallNode` and its name, so the public surface that grows is `BUILTIN_NAMES`, by one string. Refs #49 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sumed `dimensions.py` partition-checked the windows and `operators.py` said `by=` worked on them, but neither `Builtin` carried `lookup_kwargs`, so `call_shape_error` refused the call before either could speak. Half a feature, checked but unreachable. The half that was missing is the render. Resolution is generic --- it reads `lookup_kwargs` --- so the signature alone makes `by=` arrive as a `LookupNode`; what had to be built is the group on the operator inside the domain, where `shift` carries it on a leaf subscript instead. It is the bare index there, not the subscript in force: the group is a property of the row being written, and a window over a translated operand still asks which group *that row* is in. What asks for it is representative periods. A dozen typical days stand in for a year and their hours are numbered consecutively, but that numbering is storage order, not a timeline --- so an unpartitioned window sums straight across the seam between two samples and returns a schedule coupling days that never touch. Nothing could warn about it, the axis being ordered and the language having no other way to learn the order is not time. Not sayable another way either: the partition is a condition inside the summation's domain, and a `where` masks which rows are built rather than how far one reaches. Closes #57 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 24, 2026
FBumann
marked this pull request as ready for review
August 25, 2026 05:02
FBumann
added a commit
that referenced
this pull request
Aug 25, 2026
…ordinate Two of the three rules #62 collected, and the first is why it was filed. `shift(offset=-lead)` loaded clean and then raised a bare `AssertionError` out of the typesetter, because `_amount` matches a unary minus and asserts the operand is a number. That assert was reading a rule the language stated and never enforced --- and it is the rule the whole treatment of a named offset rests on: `walk.py` renders one as always-backward *because* a negated one is refused. It is refused now, at load, in a sentence, so the assert is a precondition rather than a hope. Its docstring said `by=` throughout, which was the kwarg's name two renames ago and is now a different kwarg on the same operator. The second rule is the dim half of the same idea: an amount is read at the coordinate its operator walks, so a parameter varying over a dim that coordinate does not carry has nowhere to be read from. It rendered as a bare symbol, which on the page says "one number" about a column --- the same way an unchecked width did before #58, and wrong in the same direction. `by=` is what makes such a parameter readable again, one amount per group, so the rule admits the dims a partition maps into. That half was `shift`'s alone until #59 gave the windows a partition too; both get it here, and a width per representative day now says what it means. Refs #62 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
FBumann
added a commit
that referenced
this pull request
Aug 25, 2026
`sum_forward(<expr>, over=<dim>, within=<n|parameter>[, edge='wrap'][, by=<lookup>])` sums the next n positions along an axis, where `sum_back` sums the last n. The two are one operator with a direction, so the typesetter renders them from one branch — `_WINDOWS` decides only which side of the lag operator the written index falls on. Also carries the `sum_forward` half of #59: `by=` partitions a leading window exactly as it does a trailing one, so a window stops at its group's edge rather than reaching across it. The `sum_back` half of that change landed separately, since it fixed a rule main already documented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SeNnVvhYnokz8C37o7ejW
FBumann
force-pushed
the
feat/sum-forward
branch
from
August 25, 2026 05:44
5d43331 to
ba0f980
Compare
Contributor
Author
|
Split in two and closing as superseded — the change turned out to be two independent ones wearing a single commit.
Nothing from this branch is dropped. Generated by Claude Code |
FBumann
added a commit
that referenced
this pull request
Aug 25, 2026
…ordinate (#63) Two of the three rules #62 collected, and the first is why it was filed. `shift(offset=-lead)` loaded clean and then raised a bare `AssertionError` out of the typesetter, because `_amount` matches a unary minus and asserts the operand is a number. That assert was reading a rule the language stated and never enforced --- and it is the rule the whole treatment of a named offset rests on: `walk.py` renders one as always-backward *because* a negated one is refused. It is refused now, at load, in a sentence, so the assert is a precondition rather than a hope. Its docstring said `by=` throughout, which was the kwarg's name two renames ago and is now a different kwarg on the same operator. The second rule is the dim half of the same idea: an amount is read at the coordinate its operator walks, so a parameter varying over a dim that coordinate does not carry has nowhere to be read from. It rendered as a bare symbol, which on the page says "one number" about a column --- the same way an unchecked width did before #58, and wrong in the same direction. `by=` is what makes such a parameter readable again, one amount per group, so the rule admits the dims a partition maps into. That half was `shift`'s alone until #59 gave the windows a partition too; both get it here, and a width per representative day now says what it means. Refs #62 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Closes #57. Stacked on #56 — base is
feat/sum-forward, so review that first.What was wrong
by=was half-landed.dimensions.pypartition-checkedsum_back, andoperators.py's docstring saidby=worked on it — but theBuiltinhad nolookup_kwargs, socall_shape_errorrefused the call before either could run. Checked, documented, unreachable.What was missing
Only the render. Resolution is generic (it reads
lookup_kwargs), so the signature change alone makesby=arrive as aLookupNodeand the existing dimension checks light up. What had to be built is the group on the operator inside the domain, whereshiftcarries it on a leaf subscript instead:The superscript takes the bare index, not the subscript in force — the group is a property of the row being written, and a window over a translated operand still asks which group that row is in. That matches
_Context.subscript, which does the same forshift.Why it's needed
Representative periods. A dozen typical days stand in for a year, each weighted, their hours numbered consecutively — but that numbering is storage order, not a timeline. The last hour of one representative day does not precede the first of the next in any physical sense.
An unpartitioned window sums straight across that seam. It builds, it solves, and the commitment it returns couples two independent samples through a boundary that doesn't exist. Nothing warns, because the axis is ordered and the language has no other way to learn the order isn't time.
Not sayable another way, so this is Capability rather than ergonomics under #30: the partition is a condition inside the summation's domain, relating the bound index to the row's. A
wheremasks which rows get built, not how far one reaches — excluding rows near a boundary would drop the constraints entirely rather than shorten the windows.Notes for review
-^{group}typography is pre-existing. A bare partitioned window renders0 \le h -^{\mathrm{day\_of}(h)} h' < 3, a plain minus carrying a superscript.shiftalready does exactly this —x_{h -^{\mathrm{day\_of}(h)} 1}— so the windows now follow the established convention rather than inventing one. If that convention is worth revisiting, it should be revisited for both.test_the_golden_model_reaches_every_line_of_the_walkcaught the missing golden coverage before I did;seasonal_windowis there for it.sum_back_partitioned,sum_forward_partitioned), two doc-table rows, and a prose section leading with the representative-periods case.🤖 Generated with Claude Code