Skip to content

chore: release 0.4.0 - #884

Open
FBumann wants to merge 46 commits into
mainfrom
chore/release-0.4.0
Open

FBumann wants to merge 46 commits into
mainfrom
chore/release-0.4.0

Conversation

@FBumann

@FBumann FBumann commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Prompt: Then prepare a release PR for 0.4.0

Note

The following content was generated by AI.

Renames ## Upcoming version to ## 0.4.0 (2026-10-15) and edits it into the release notes. The diff against main is CHANGELOG.md alone. Merging this PR tags v0.4.0 and publishes.

What the section holds, checks

Contents: one paragraph, six bullets that name each break and its rewrite, then the seven pull requests in five groups:

These seven are every pull request on main since v0.3.0.

From the specsolve port to 0.4.0 (f4b89a9), two additions to the bullets:

  • Code that uses the old meaning of Variable, Parameter, NamedExpression or NamedMask raises no error. On main, program.Parameter('p') builds Parameter(dims='p', …), and a reference node is not an instance of program.Variable. The bullet says to rename the four references before dropping the suffixes.
  • The language reference page declarations/ is now parameters-variables-constraints/, so outside links to it break. specsolve had five.

Why a minor version: #855 and #878 break imports, and #874 removes two flags of canonical. The language does not change, so a spec file that 0.3.0 loads still loads. #886 changes the math of the PyPSA example spec, not what the language accepts.

Merges from main: each one copied lines from main's ## Upcoming version into a group of this section. I moved them, so each pull request has one line in the group it belongs to.

Checks, on f4b89a9:

🤖 Generated with Claude Code

https://claude.ai/code/session_01XEunezSgDyec631PDMez53

claude and others added 30 commits October 6, 2026 22:22
The YAML layer suffix Block becomes Spec. The program layer entry
classes drop the Declaration suffix. The reference nodes Variable,
Parameter, NamedExpression and NamedMask become VariableReference,
ParameterReference, ExpressionReference and MaskReference, which frees
NamedExpression and NamedMask for the expressions: and masks: entries.
typeset_declaration becomes typeset_line, and DeclarationKind becomes
NameKind. The schema is regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEpVtSN4GJ5mT4Yhwd7Jz7
The noun "declaration" becomes "entry" in messages, docstrings, docs
and test names. The verb "declare" stays. The page
reference/language/declarations.md becomes entries.md, and
tests/typesetting/test_declaration.py becomes test_line.py. The layer
table in docs/contributing.md names Spec, Node and no suffix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EEpVtSN4GJ5mT4Yhwd7Jz7
`spec.ExpressionCase` becomes `ExpressionCaseSpec`, and
`spec.PiecewiseLink` becomes `PiecewiseLinkSpec`. Every class in
`mathspec.spec` now ends in `Spec`. The schema `$defs` keys follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LitpPsNupkUC7PmogJ9RWQ
"Block" named an entry, a section and a nested mapping. It now names
only a nested mapping inside one entry (`bounds:`, `cases:`), or a block
of a page or of a matrix.

- Prose in src, tools, tests, docs and examples: "a `piecewise:` block"
  becomes "a `piecewise:` entry", "the `given:` block" becomes "the
  `given:` section", and the same for every other entry and section.
- Messages: `ExpressionSpec` is now "an expression entry", and
  `GivenSpec` is "the 'given:' section", in "unknown key 'x' in …". The
  `--expand` help says "entries".
- Identifiers: `block` variables and parameters that hold an entry or a
  section become `entry`, `section` or a specific name. Private helpers
  follow: `canonical._canonical_entry`, `_sorted_entries`,
  `tools.pypsa_split._term_entry`, `tools.notation.SECTIONS`, and
  `piecewise._Block` becomes `_Expansion`. 11 test names follow.
- The legend row class `typesetting.format.Entry` becomes `LegendItem`,
  so that "entry" means one thing in the typesetter too.
- `docs/reference/language/entries.md` becomes
  `parameters-variables-constraints.md`, after its nav title. Dimensions,
  relations and expressions are entries too, and have their own pages.

The schema, the gallery, notation and home pages are regenerated. The
golden typesetter output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LitpPsNupkUC7PmogJ9RWQ
A `Spec` instance was named `schema` in about 30 signatures and the
`Namespace.schema` attribute, while "schema" also names the JSON Schema
and pydantic's validation schema. It is now `spec`, as the docs call it.
`dimensions.check_schema` becomes `check_spec`, and the test helpers
follow (`fixtures.spec_of`, `dispatch_spec`, …). Every "schema" that
means the JSON Schema or pydantic's schema stays, and so does
`SchemaError`. No public signature changes, and no printed text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LitpPsNupkUC7PmogJ9RWQ
#840 rewrote the prose of the docs, docstrings and messages. Each
conflict takes main's wording with this branch's vocabulary: "entry"
for one named item, "section" for a top-level key, the `*Spec` and bare
program class names, `typeset_line`, and the
`parameters-variables-constraints.md` page. The prose-writing skill that
#840 adds now lists "entry" where it listed "declaration". The schema,
the gallery, notation and home pages are regenerated; the golden
typesetter output is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LitpPsNupkUC7PmogJ9RWQ
"Block" was left for a nested mapping inside one entry. The key now
names it: "a `cases:` block needs an `otherwise:`" becomes "`cases:`
needs an `otherwise:`", and "unknown key 'x' in a bounds block" becomes
"… in a variable's 'bounds:'". Where the typesetter prints one, it is a
cased expression. "Block" is left only for a block of a page, a YAML
block scalar and the block-diagonal form in `separability.py`.

The glossary gains **Section**, and **Entry** names its Python classes:
a `*Spec` in `mathspec.spec` and the bare name in `mathspec.program`.
"Section" joins the words with two senses, beside a heading of a
typeset document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LitpPsNupkUC7PmogJ9RWQ
…n in paragraphs

The convention note on upright and italic symbols is gone. Each translation
and position symbol the equations print gets a row under Notation, with the
spec spelling it stands for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NhSP67Jo21s6i7zgF7WFe9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NhSP67Jo21s6i7zgF7WFe9
… single words on one line

`to_yaml()` and `to_yaml(canonical=True)` now share one writer. It puts a
list of plain values, and a mapping of numbers and single words such as
`bounds`, on one line when that line holds 80 characters or fewer. A
declaration with a description or an expression of several words keeps
one key on each line. No line is wrapped, and a multi-line string is a
block scalar in both forms.

A file that `mathspec canonical --check` accepted before is refused until
it is written again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…ine out, and a mapping holds only names

Counting each value as Python prints it, rather than dumping the
candidate a second time, keeps the writer near the old one's speed and
counts an accented name as its characters instead of its escape. A
one-word expression such as `sum(p)` now keeps one key on each line,
like every other expression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…e-line mapping holds only names

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…t, and a mapping value is checked once

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…rote, never a stored one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…ical form, and `canonical` no longer rewrites or checks a file

`diff before.yaml after.yaml` writes both specs in the canonical form
with the mathspec that runs it, prints a unified diff of the two, and
exits 0, 1 or 2 as `diff` does. `canonical --write` and `--check` are
gone: they kept a file in the form, which dropped its comments and
failed on every release that changed the form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…e to a line

The writer puts prose in a folded block, one sentence on each line.
YAML reads a line break between two lines of a folded block as one
space, so the description loads back as the string it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…line holds 100 characters or fewer

The emitter knows the column a list starts at, after its key or its
dash, so the limit now counts the indent and the key as well as the
brackets. The representer passes the list's width to the emitter on
the event's flow style, which PyYAML reads only as true or false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…eading page states the 100-character line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…n verbs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAz2z9GVsHSQypiTUZyrY9
…that starts with an underscore

The sixteen modules behind the top level (advising, boundedness, canonical,
composition, degree, dimensions, exclusivity, expansion, lowering, operators,
piecewise, resolution, separability, sos, typesetting, validation) now start
with an underscore. A test refuses a new module named without one.

Closes #872.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
…ore is not public

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
…sentences, without history

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
claude added 11 commits October 15, 2026 11:34
Keeps this branch's refusal message in composition.py, its test cases and
docs/howto/compose.md. The case `declared-as-something-else`, which main
added, now expects the new message. The changelog line moves under a new
`## Upcoming version` heading above 0.3.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Takes main's section order (#848), its bare-relation `missing:` (#879),
the 0.3.0 release section and #857's dimension message, each in this
branch's vocabulary: entry, section, `*Spec`, `typeset_line`, `spec_of`.
Regenerated: the schema, the golden output and the generated pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Takes #855's names in the notation code (`LegendItem`, `typeset_line`,
`test_line.py`) and main's section order. Regenerated: the golden output
and the generated pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Names a declaration an entry in the writer's docstring and on the
reading page, as #855 does elsewhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Keeps this branch's `command` naming in the shell front, with the
`--no-legend` help text from #870.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Redoes the rename on #874's new head, which now carries #855, #857, #870
and #871: the same 16 modules, the guard test, the two docs paragraphs
and the changelog line. The tree equals the rename applied to that head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
@read-the-docs-community

read-the-docs-community Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

@FBumann
FBumann changed the base branch from claude/eloquent-davinci-nmllxp to main October 15, 2026 12:02
Keeps the 0.4.0 section. The merge had copied three of main's
changelog lines under Typesetting, which now holds #870 alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
Adds #886 to the notes under a PyPSA example group. The merge had
put its line under Python API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53
…, and name the moved reference page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEunezSgDyec631PDMez53

This branch has not been deployed

No deployments
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.

3 participants