docs: the composition how-to builds a component library from terms each file adds to a sum - #762
Merged
Merged
Conversation
…ch file adds to a sum The how-to taught a flow per port, pinned by each component, and said a component should not add a term to the balance. The tutorial and the PyPSA split teach the opposite: an empty sum that each component adds a term to. The how-to now teaches the empty sum and the term, and the library example says that it couples through a flow per port so the flow can be read back. Docs: howto/compose.md n 54, median 15, over25 2; library/index.md n 23, median 14, over25 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
FBumann
pushed a commit
that referenced
this pull request
Sep 28, 2026
#762 landed the empty-sum library on main with the mapping form of merge. The call becomes a list, a new component joins the list, and the quoted refusals name each file by its path, as a run of the page's files prints them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
FBumann
pushed a commit
that referenced
this pull request
Sep 28, 2026
The network reads Bus_injection under `given:`, and each component adds its term with `adds_to:`. A new component joins the list, and a merged spec takes no further term. Every quoted message is from a run of the page's files against this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
FBumann
pushed a commit
that referenced
this pull request
Sep 28, 2026
The network reads Bus_injection under `given:`, and each component adds its term with `adds_to:`. A new component joins the list, and a merged spec takes no further term. Every quoted message is from a run of the page's files against this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
FBumann
pushed a commit
that referenced
this pull request
Sep 28, 2026
The network reads Bus_injection under `given:`, and each component adds its term with `adds_to:`. A new component joins the list, and a merged spec takes no further term. Every quoted message is from a run of the page's files against this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z
FBumann
added a commit
that referenced
this pull request
Oct 1, 2026
…no file marks a sum as open (#763) * feat(language): a term names the sum it adds to with `adds_to:`, and no file marks a sum as open A term was named from the sum's side: `term:` on a `given: expressions:` entry, and the file that owned the sum declared it `empty: true`. Now the term names the sum: `adds_to:` on the named expression names a given expression of the same file. The given entry is the read, and `adds_to:` the write. The loader checks the target, the frame and self-reference in the one file. merge writes the sum as the body one fragment defines, if any, plus every term, so no file declares a sum open and a later merge adds more terms. Terms that only their own files read are refused with the near miss: some fragment has to define the name, read it and add nothing, or use it in its math. `empty: true`, `given: ... term:`, the empty-sum line and the ellipsis go. Docs: declarations.md n 197, several-files.md and named.md measured in the PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z * Add the changelog link for #763 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z * A term fills only a name every fragment reads A name one fragment defines takes no term, so a body means what its file says. merge defines a read name as its terms by name over the readers' frame, and refuses a term on a defined name, a merged sum included, with both fragments named. A file with a part of its own, such as a slack, adds it as a term of its own reading. The definer's body, its brackets, the cased-definition refusal and the definer clause of the misspelling check go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z * Write the library how-to from #762 with `adds_to:` The network reads Bus_injection under `given:`, and each component adds its term with `adds_to:`. A new component joins the list, and a merged spec takes no further term. Every quoted message is from a run of the page's files against this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z * A reported expression is no read of the sum, and the tools keep every term The misspelling check counted a reported expression as a use in the math, so a contributor that reported its misspelt sum passed it. `adds_to:` is now dropped from every composed expression, not only where a sum was written, and `merge` documents the two refusals. The PyPSA splitter keeps a folded term body, and the gallery index lists a hub once per fragment and names the sum that has no described reader instead of a bare KeyError. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhcGptSPeUeVFHwf7Nbpjc * A term on a name its own file defines says so, and names the body to write it into `adds_to:` naming an expression of the same file was refused as a name the file does not read under `given:`, ending in "Declared: nothing." It now says the file defines the name, and that a term is written into that body, or the name is read and its body added as a term. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z * The splitter keeps a term written as a flow mapping or a continued line `_term_block` nested a flow mapping under `expression:`, and kept only the head line of a plain body that runs on. It now rereads such a block as YAML and writes it as a mapping. The fragments it writes from examples/pypsa.yaml do not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AzXL2w5xdUm8FsYMNWf1KW * A term keeps its target under a one-line patch, and merge refuses what it read wrong - A one-line patch on a named expression replaces the body and keeps `adds_to:`, `dims:` and `description:`. - A name one fragment alone reads is refused as a misspelling, even where that fragment uses it in its math. - A term on a name a sibling declares as a variable, a parameter or a constraint names that kind. - Readers that write a sum's dims in different orders are refused, so the order of the list does not reach the canonical text. - `_uses` reads through `variables_of`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AzXL2w5xdUm8FsYMNWf1KW * feat(language): a term adds to a body another file defines A term's adds_to: may name an expression another fragment defines with one expression:. The merged body is that body followed by every term, joined with a plain +, so a merged spec takes more terms in a later merge and two merges print the same sum as one. A definition written as cases: takes no term. A term that reads its own sum through a name another fragment defines is refused at merge, both fragments named, rather than by the composed load, which named the loop only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JiNwuVCdEkSLKNxiCNaNAv * test(composition): a sum merged in steps equals one merged in one list Four splits: the last file later, the reader alone first, three steps, and a body a file defines. Each asserts the written body, since the canonical form reads a bracketed sum the same. A step that closes a sum no other file reads is refused, and the Terms section says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JiNwuVCdEkSLKNxiCNaNAv * docs(language): adds_to: adds an expression as a term to the sum it names The Terms section, the named-expression page, the merge table and the docstrings said an entry "is a term of" a given expression, which reads as a kind of declaration. A term is one part of a sum, so each now says what adds_to: does with the expression: it adds it as a term to the sum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JiNwuVCdEkSLKNxiCNaNAv * docs: the composition how-to shows a sum that one file defines and other files add terms to (#800) * feat(language): merge refuses a second objective, and a composed objective reads a sum that each file adds its part to (#804) merge summed the objectives of its fragments, by a rule that no other section has. Two fragments that set an objective now collide, and the message names the rewrite: read a sum under given: expressions: in the file that sets the objective, and add each part with adds_to:. The sense check across fragments and the first-description rule go with the join. examples/pypsa.yaml writes its objective as total_cost, the sum of one capital-cost term per component and the operating cost at risk; the split homes total_cost in settings, which sets the objective. In the library, the surface sets the objective and the generator adds Generator_cost. The tutorial, the composition how-to and the gallery pages follow. Closes #801. Claude-Session: https://claude.ai/code/session_01PBmqeqBrqpQC6MVoSrguHK Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <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.
Note
The following content was generated by AI.
What this changes
The how-to now composes its component library from an
empty: truesum that each file adds a term to, which matches the tutorial and the PyPSA split. The library example keeps its flow-per-port coupling and says why it uses it.Why
Method, gate output, alternatives
The problem on
main.docs/howto/compose.mdtaught the port surface:Port_p, pinned by each component withat(...). It said that a component "pins the flow at its own port rather than adding a term to the balance". Butdocs/several-files.mdandexamples/pypsa/teach the empty sum withterm:. So a reader saw two patterns and a how-to that argued against the tutorial.What changed.
network.yaml(an emptyBus_injectionand its balance),generator.yamlandload.yaml(each adds a term), and a step 4 that addsstore.yamlwithout touching the network.emissions.yaml, which readsGenerator_pas binary, and quotes the real refusal.docs/examples/library/index.mdgets one paragraph: it couples throughPort_pso that the solved flow at each port can be read back. Where no one reads that flow, the sum needs no variable. The how-to ends with one sentence that links back to it.Checks.
python -m mathspec check.Generator_injection + Load_injection, then+ Store_injection) and all three quoted refusals come from running the files. The files are not committed, because no test reads this page.Gates.
pixi run lint: clean.pixi run test: 2560 passed.docs-builddid not run to the end here.--strictaborts because the proxy blocksdocs.python.org/3/objects.inv, andmainfails the same way in this container. The only warning is the unresolvedpathlib.Pathfrom that inventory, so there is no dead anchor.examples/changed, socompile-texis not affected.Interaction with #761. This PR branches from
mainand uses its dict form ofmerge. If #761 lands first, I mergemaininto this branch and change the two calls to lists. The how-to lines they touch overlap.What this PR does not do.
term:onto the named expression.🤖 Generated with Claude Code
https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z