Skip to content

docs: the composition how-to builds a component library from terms each file adds to a sum - #762

Merged
FBumann merged 2 commits into
mainfrom
docs/compose-one-coupling
Sep 28, 2026
Merged

FBumann merged 2 commits into
mainfrom
docs/compose-one-coupling

Conversation

@FBumann

@FBumann FBumann commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Prompt: Fix 4 too in a separate docs pr

Note

The following content was generated by AI.

What this changes

The how-to now composes its component library from an empty: true sum 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.md taught the port surface: Port_p, pinned by each component with at(...). It said that a component "pins the flow at its own port rather than adding a term to the balance". But docs/several-files.md and examples/pypsa/ teach the empty sum with term:. So a reader saw two patterns and a how-to that argued against the tutorial.

What changed.

  • The "A library of components" section. It now has network.yaml (an empty Bus_injection and its balance), generator.yaml and load.yaml (each adds a term), and a step 4 that adds store.yaml without touching the network.
  • "A column read one way and introduced another". This section now shows emissions.yaml, which reads Generator_p as binary, and quotes the real refusal.
  • The term-naming advice. It now uses the example's names.
  • The library page and the how-to link to each other. docs/examples/library/index.md gets one paragraph: it couples through Port_p so 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.

  • Every YAML fence in the new section is loaded with python -m mathspec check.
  • The merge results (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-build did not run to the end here. --strict aborts because the proxy blocks docs.python.org/3/objects.inv, and main fails the same way in this container. The only warning is the unresolved pathlib.Path from that inventory, so there is no dead anchor.
  • No file under examples/ changed, so compile-tex is not affected.

Interaction with #761. This PR branches from main and uses its dict form of merge. If #761 lands first, I merge main into this branch and change the two calls to lists. The how-to lines they touch overlap.

What this PR does not do.

  • It does not change the library example files or their generated pages.
  • It does not decide point 1, moving term: onto the named expression.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AApRDPxpZcALYLrFMXEF7z

…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
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 mathspec | 🛠️ Build #34807995 | 📁 Comparing bf404b1 against latest (22cdebd)

  🔍 Preview build  

3 files changed
± changelog/index.html
± examples/library/index.html
± howto/compose/index.html

@FBumann
FBumann merged commit 685bbb2 into main Sep 28, 2026
5 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants