Skip to content

docs: add the module and versioning design - #147

Open
thiremani wants to merge 6 commits into
masterfrom
docs-module-design
Open

thiremani wants to merge 6 commits into
masterfrom
docs-module-design

Conversation

@thiremani

@thiremani thiremani commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Adds docs/Pluto Module Design.md, a design record for modules, imports and versioning. Nothing in it is implemented yet: today a directory is the unit of compilation, pt.mod names the module path, and there are no imports.

What it records

  • No visibility, as decided earlier: everything a module defines is part of its contract, since functions share no mutable state.
  • The major version in the module path (github.com/you/math/v2), which the C ABI already accepts and mangles. Majors coexist in one program; their struct types stay distinct, though a generic template accepts either.
  • SemVer versions picked when publishing, from a table of minimum categories: publishing numbers each release itself, and the publisher may only ask for a higher category. A function is identified by its name and input count; constants promise their exact values; a struct may gain a field in a Minor release, since literals name their fields and omitted ones take their zero value, and a struct constant keeps its value while its existing fields keep their types and values. Reordering fields is Major.
  • The contract is what declarations state, not the argument types tests happen to use, so tests stay representative examples. Rerun tests catch what their assertions or type-sensitive operations expose, and the publisher declares the rest; a narrowing that escapes is a breaking change the release should have declared.
  • Publishing steps: build the API manifest, compare it with the release being updated, work out the category from the detected changes and the publisher's declared additions and breaks, run the module's tests, which must pass, and the previous release's tests, whose failures must each be explained by a detected change, a declared break or bug fix, or something outside the contract, require every function body to run at least once, and number the release, refusing a lower category than the changes require.
  • No deprecation marks: a Major release may remove or change anything, majors coexist so each dependent moves when ready, and release notes list the detected removals and changes plus the publisher's declared breaks and migration steps.
  • Development stays permissive: an optional reachability report, execution coverage from tests, and CI decides how strict to be.
  • Open questions: import syntax, where a release's version is recorded and how dependents choose a release, how a publisher declares an addition, break or bug fix and asks for a higher category, backports, how the major is spelled, stable C wrappers, and an inferred check of what each input must support.

Commits

  1. docs: the design record.
  2. docs: from review: a failing test from the previous release must be explained rather than always stopping publishing; struct constants and Minor field additions; field order; generic calls across majors; what rerun tests catch; the visibility rationale.
  3. docs: drops deprecation marks, so compiling never warns about future removals.
  4. docs: from review: release notes include declared breaks and migration steps, and the manifest keeps struct field order.
  5. docs: publishing picks the version number, so a publisher never chooses one and can only ask for a higher category.
  6. docs: from review: publishers declare compatible additions the comparison cannot see (Minor) as well as breaks (Major); release notes are generated; running every function shows it runs, not that it is needed; backports join the open questions.

Verification

  • Docs only; the compiler code is master's. gofmt, go vet and go test -race ./lexer ./parser ./compiler pass, and python3 test.py --leak-check passes 84/84 with every leak check clean, at the pushed head.
  • The facts the doc relies on were checked: struct literals may omit fields (tests/struct prints Ada 28 0), a template is keyed by name and input count, versioned module paths are valid and mangled (C ABI spec §1.1), and [Double(0:0)] never runs Double's body.
  • No conflict with feat(compiler)!: require definite function outputs and build ranges only from literals #145: this branch only adds a new file, and git merge-tree of the two branches is clean.

🤖 Generated with Claude Code

thiremani and others added 6 commits October 10, 2026 13:58
Records the decisions taken so far for modules, imports and versioning,
none of them implemented yet: no visibility, so everything a module
defines is part of its contract; the major version in the module path,
so majors coexist; SemVer categories enforced when publishing, from what
declarations state rather than from tested argument types; the publishing
steps, including rerunning the previous release's tests and requiring
every function body to run in the module's tests; deprecation; and
development reports that keep compilation permissive. Lists the
questions still open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A failing test from the previous release stops publishing only when
  nothing explains it: a change the comparison found, a declared break or
  bug fix, or something outside the contract such as a struct's printed
  form. Before, any failure stopped publishing, which ruled out every
  Major release that removes a function.
- A struct constant keeps its value while every field it had keeps its
  type and value, so a Minor field addition no longer counts as changing
  the constants of that struct type. Reordering fields is Major.
- Distinct struct types across majors don't stop a template from
  accepting either one.
- Rerun tests catch only what their assertions or type-sensitive
  operations expose, and a narrowing that escapes is a breaking change the
  release should have declared.
- The visibility rationale is that functions share no mutable state;
  functions can print and read constants, so the stronger claims are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Minor release no longer marks things as going away, so compiling never
warns about what a later Major release will remove. A Major release may
remove or change anything; each dependent moves to it when it chooses,
since majors coexist, and the release notes list every removal and
change, taken from the comparison with the release before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… order

The comparison only sees declarations, so a behavior change such as
`Double(x)` going from `x * 2` to `x * 3` never shows up in it. Release
notes now list the removals and changes the comparison detects together
with the breaking changes the publisher declares and their migration
steps, and a module's own documentation can give advance notice of
removals.

The API manifest records each struct's ordered field names and types,
since reordering fields is Major and the checker has to see it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The publisher no longer proposes a version for the checker to accept or
reject. Publishing works out the category from the detected changes and
any declared break, and numbers the release itself; the publisher may
ask for a higher category, never a lower one. Publishing reports the
version it picked and why, and a request for a lower category is refused
with the change that rules it out.

Adds an open question: how a publisher declares a break or a bug fix
and asks for a higher category.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Publishing worked out a release's category from detected changes and
declared breaks only, so a template that newly accepts more argument
types, which the comparison cannot see, would have been numbered as a
Patch although the table requires a Minor. The publisher now declares
compatible additions the comparison cannot see as well as breaks, and
the category is the highest any detected or declared change requires.

Also states that release notes are generated, so publishers never write
out changed functions, constants or fields; that requiring every
function body to run shows each function runs, not that it is needed;
and adds backports to the open questions.

Co-Authored-By: Claude Opus 5.5 <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.

1 participant