|
| 1 | +--- |
| 2 | +id: "051" |
| 3 | +status: Accepted |
| 4 | +date: 2026-10-16 |
| 5 | +category: release |
| 6 | +supersedes: [] |
| 7 | +superseded_by: [] |
| 8 | +--- |
| 9 | + |
| 10 | +# ADR-051: What a release may change from 3.0.0 |
| 11 | + |
| 12 | +## Context |
| 13 | + |
| 14 | +From v3.0, forks and projects build on upstream and update on their own |
| 15 | +schedule, so they need to know what a release can break. |
| 16 | + |
| 17 | +| Who depends on upstream | What they refer to | |
| 18 | +| ----------------------- | ------------------ | |
| 19 | +| A fork | Paths it merges, IDs it extends and overrides, the manifest schema it appends to | |
| 20 | +| A project | The declaration block its context file carries, the core tier its chain resolves, the exit codes its CI reads | |
| 21 | +| A project still on 2.x | The `v2.90.0` tag it pins | |
| 22 | + |
| 23 | +The forces: |
| 24 | + |
| 25 | +- Independent schedules: a fork merges upstream when it chooses, and a |
| 26 | + project bumps its pin when it chooses. A break they cannot see coming |
| 27 | + lands in their CI. |
| 28 | +- One maintainer: upstream has the capacity for one line of releases, not |
| 29 | + two. |
| 30 | +- Wording: rules are improved continually, and freezing their prose would |
| 31 | + stop the work the library exists for. |
| 32 | +- Security: a flaw in a frozen element cannot wait years for a major. |
| 33 | + |
| 34 | +## Decision |
| 35 | + |
| 36 | +From 3.0.0, what forks and projects refer to is frozen until 4.0.0: a 3.x |
| 37 | +release only adds or deprecates, a security fix is the one exception, and |
| 38 | +2.x receives nothing after `v2.90.0`. |
| 39 | + |
| 40 | +## Rationale |
| 41 | + |
| 42 | +- Forks and projects update on their own schedules, so a frozen contract |
| 43 | + lets them take any 3.x release without reading it first. |
| 44 | +- Freezing what is referred to, not the wording, keeps rules improving |
| 45 | + while nothing a fork or project names moves. |
| 46 | +- One maintainer can run one release line; a 2.x branch would halve the |
| 47 | + attention the 3.x line gets. |
| 48 | +- A security flaw cannot wait for a major, so the one exception is for |
| 49 | + security alone. |
| 50 | + |
| 51 | +## Design |
| 52 | + |
| 53 | + |
| 54 | + |
| 55 | +| # | Rule | In practice | |
| 56 | +| - | ---- | ----------- | |
| 57 | +| 1 | The frozen surface | Template paths, template and section IDs, the manifest schema, the declaration block (`Stack`, `Extras`, `Platform`), core-tier membership, and check exit codes: 0 passes, 1 fails, 3 does not apply | |
| 58 | +| 2 | Prose is free | The wording inside a section changes in any release, as long as the rule keeps its ID | |
| 59 | +| 3 | A minor only adds | A 3.x minor adds templates, sections, IDs and optional manifest fields. The core tier is frozen, so a new template is reached by declaring it, never by joining the core | |
| 60 | +| 4 | Deprecate, then remove at v4 | A minor may deprecate an element by naming its replacement. Nothing frozen is removed or renamed before 4.0.0 | |
| 61 | +| 5 | How a deprecation is marked | A deprecated template carries `deprecated: <replacement-id>` in its manifest entry; every deprecation is listed under `Deprecated` in the CHANGELOG with its replacement | |
| 62 | +| 6 | The security exception | A security fix may change or remove a frozen element in a minor. The CHANGELOG lists it under `Breaking changes`, naming the element and the reason | |
| 63 | +| 7 | 2.x is final | `v2.90.0` is the last 2.x release and receives no fixes; work merged after it ships in 3.0.0 | |
| 64 | +| 8 | The next major freezes again | 4.0.0 removes what 3.x deprecated and freezes its own surface under these rules | |
| 65 | + |
| 66 | +| Rule | Promise or mechanism | Enforced by | |
| 67 | +| ---- | -------------------- | ----------- | |
| 68 | +| 1, 3 | Promise to forks and projects | Smoke: every root resolves; the fork-sync CI job (#1924) | |
| 69 | +| 2 | Promise to maintainers | - | |
| 70 | +| 4, 5 | Promise to forks and projects | A smoke check that a `deprecated` field names an existing ID, and the release review | |
| 71 | +| 6 | Promise to forks and projects | The CHANGELOG `Breaking changes` section at the cut | |
| 72 | +| 7 | Promise to projects on 2.x | The migration guide (#1292) | |
| 73 | +| 8 | Promise to forks and projects | - | |
| 74 | + |
| 75 | +### Deprecating a template, worked through |
| 76 | + |
| 77 | +Suppose a hypothetical `backend-cache` replaces `backend-caching` in 3.4.0: |
| 78 | + |
| 79 | +| Release | Manifest | CHANGELOG | |
| 80 | +| ------- | -------- | --------- | |
| 81 | +| 3.4.0 | `backend-cache` added; `backend-caching` gains `deprecated: backend-cache` | `Deprecated`: `backend-caching`, use `backend-cache` | |
| 82 | +| 3.5.0 to 3.x | Both resolve | - | |
| 83 | +| 4.0.0 | `backend-caching` removed | `Removed`: `backend-caching`, deprecated in 3.4.0 | |
| 84 | + |
| 85 | +## Alternatives considered |
| 86 | + |
| 87 | +| Alternative | Why not | |
| 88 | +| ----------- | ------- | |
| 89 | +| Back-port security fixes to 2.x for six months | Two release lines for one maintainer, for a pin every project can leave by re-pinning. | |
| 90 | +| A minor adds only, with no deprecation | A replacement could not be announced until the major that removes the old element, so forks would meet the change all at once. | |
| 91 | +| Imbrain's rule: 24 months and until the second major | Two majors of overlap fits interfaces running on site for years; a context file is regenerated in minutes. | |
| 92 | +| No exception for security | A security flaw would wait for 4.0.0, or force a major for one fix. | |
| 93 | +| Freeze the prose as well | Rules could no longer be corrected, which is most of what a release does. | |
| 94 | + |
| 95 | +## Consequences |
| 96 | + |
| 97 | +| Consequence | Effect | |
| 98 | +| ----------- | ------ | |
| 99 | +| Manifest schema | Gains the optional `deprecated` field, with a smoke check that it names an existing ID | |
| 100 | +| CHANGELOG | Uses the `Deprecated` and `Breaking changes` sections from 3.0.0 | |
| 101 | +| Release review | Checks every diff to the frozen surface against rules 3 to 6 | |
| 102 | +| Migration guide | States that 2.x is final and how to re-pin (#1292) | |
| 103 | +| 2.x branch | None is kept; `v2.90.0` stays as a tag | |
| 104 | + |
| 105 | +## Compatibility |
| 106 | + |
| 107 | +- This record is the compatibility policy, so it changes nothing that |
| 108 | + exists today. It applies from 3.0.0. |
| 109 | +- A project on 2.x keeps working on `v2.90.0` for as long as it pins it, |
| 110 | + but receives nothing more; every later change, fixes included, arrives |
| 111 | + only by migrating to 3.0.0. |
| 112 | + |
| 113 | +## Security |
| 114 | + |
| 115 | +- A project that stays on `v2.90.0` receives no security fixes. A flaw |
| 116 | + found in a 2.x template stays in its pin until it migrates, and the |
| 117 | + migration guide says so. |
| 118 | +- The security exception lets a minor break a fork's chain without |
| 119 | + warning. The `Breaking changes` entry is the only warning, so a fork |
| 120 | + reads it before merging a release. |
| 121 | +- No credentials or secrets are involved. |
| 122 | + |
| 123 | +## Related |
| 124 | + |
| 125 | +- ADR-049 - the fork model this record protects. |
| 126 | +- ADR-050 - the boundary whose upstream side this record freezes. |
| 127 | +- solid-ai-dev/solid-ai-templates#1292 - the migration guide. |
0 commit comments