Skip to content

Commit 60ec068

Browse files
brabojclaude
andauthored
docs(decisions): what a release may change from 3.0.0 (#1921) (#1940)
ADR-051 freezes paths, IDs, the manifest schema, the declaration block, core-tier membership and check exit codes from 3.0.0 until 4.0.0. A 3.x minor only adds or deprecates, a security fix is the one exception, and 2.x receives nothing after v2.90.0. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent c236c8e commit 60ec068

3 files changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
![Releases on a line: 2.90.0 receives nothing more and is the pin until a project migrates; 3.0.0 freezes the contract; a 3.x minor adds and may deprecate; 4.0.0 removes what 3.x deprecated; a security fix may break early](../diagrams/compatibility.png)
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.

‎docs/diagrams/compatibility.drawio‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<mxfile host="drawio">
2+
<diagram id="compatibility" name="compatibility">
3+
<mxGraphModel grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="1440" pageHeight="560" background="#FFFFFF" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="t1" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=26;fontColor=#0F172A;fontStyle=1;" value="What a release may change" vertex="1"><mxGeometry x="30" y="18" width="1380" height="36" as="geometry" /></mxCell>
8+
<mxCell id="t2" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontFamily=Segoe UI;fontSize=13;fontColor=#64748B;" value="From 3.0.0 the contract a fork and a project build on is frozen; a 3.x minor only adds, and only 4.0.0 removes." vertex="1"><mxGeometry x="30" y="54" width="1380" height="24" as="geometry" /></mxCell>
9+
<mxCell id="g1" parent="1" style="rounded=1;arcSize=2;whiteSpace=wrap;html=1;fillColor=#F8FAFC;strokeColor=#CBD5E1;strokeWidth=1.5;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;fontFamily=Segoe UI;fontSize=14;fontColor=#334155;fontStyle=1;" value="Releases" vertex="1"><mxGeometry x="30" y="100" width="1380" height="200" as="geometry" /></mxCell>
10+
<mxCell id="r0" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#F1F5F9;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#475569;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;2.90.0&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#475569&#x27;&gt;the final 2.x, with no further fixes&lt;br&gt;a project&#x27;s pin until it migrates&lt;/span&gt;" vertex="1"><mxGeometry x="60" y="160" width="250" height="110" as="geometry" /></mxCell>
11+
<mxCell id="r1" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;3.0.0&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;freezes paths, IDs, the manifest schema,&lt;br&gt;the declaration block, core membership&lt;br&gt;and check exit codes&lt;/span&gt;" vertex="1"><mxGeometry x="420" y="160" width="250" height="110" as="geometry" /></mxCell>
12+
<mxCell id="r2" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;3.x minor&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;adds templates, sections, IDs and fields&lt;br&gt;may mark an element deprecated,&lt;br&gt;naming its replacement&lt;/span&gt;" vertex="1"><mxGeometry x="780" y="160" width="250" height="110" as="geometry" /></mxCell>
13+
<mxCell id="r3" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FEF3C7;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#B45309;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;4.0.0&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#92400E&#x27;&gt;removes what 3.x deprecated&lt;br&gt;the next major freezes again&lt;/span&gt;" vertex="1"><mxGeometry x="1140" y="160" width="250" height="110" as="geometry" /></mxCell>
14+
<mxCell id="e1" parent="1" source="r0" target="r1" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" value="migrate" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
15+
<mxCell id="e2" parent="1" source="r1" target="r2" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" value="additive" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
16+
<mxCell id="e3" parent="1" source="r2" target="r3" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" value="removal" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
17+
<mxCell id="g2" parent="1" style="rounded=1;arcSize=2;whiteSpace=wrap;html=1;fillColor=#F8FAFC;strokeColor=#CBD5E1;strokeWidth=1.5;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;fontFamily=Segoe UI;fontSize=14;fontColor=#334155;fontStyle=1;" value="The one exception" vertex="1"><mxGeometry x="30" y="320" width="1380" height="140" as="geometry" /></mxCell>
18+
<mxCell id="s" parent="1" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#FFE4E6;gradientColor=#FFFFFF;gradientDirection=north;strokeColor=#BE123C;strokeWidth=1.6;shadow=1;align=center;fontFamily=Segoe UI;fontColor=#0F172A;spacing=6;" value="&lt;b style=&#x27;font-size:14px;color:#0F172A&#x27;&gt;A security fix&lt;/b&gt;&lt;br&gt;&lt;span style=&#x27;font-size:11px;color:#9F1239&#x27;&gt;may change or remove a frozen element&lt;br&gt;in a minor, under Breaking changes&lt;/span&gt;" vertex="1"><mxGeometry x="780" y="370" width="250" height="70" as="geometry" /></mxCell>
19+
<mxCell id="e4" parent="1" source="s" target="r2" style="edgeStyle=orthogonalEdgeStyle;rounded=1;arcSize=16;html=1;jettySize=auto;strokeColor=#64748B;strokeWidth=2.0;endArrow=blockThin;endFill=1;endSize=5;fontFamily=Segoe UI;fontSize=11;fontColor=#475569;fontStyle=1;labelBackgroundColor=#F8FAFC;dashed=1;exitX=0.5;exitY=0;entryX=0.5;entryY=1;" value="breaks early" edge="1"><mxGeometry relative="1" as="geometry" /></mxCell>
20+
<mxCell id="t3" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=top;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="Prose inside a section changes freely in any release: the freeze covers what a fork or a project refers to, not the wording of a rule." vertex="1"><mxGeometry x="30" y="478" width="1380" height="24" as="geometry" /></mxCell>
21+
<mxCell id="lg-0s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#F1F5F9;strokeColor=#475569;" value="" vertex="1"><mxGeometry x="34" y="523" width="24" height="18" as="geometry" /></mxCell>
22+
<mxCell id="lg-0t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="A release that receives nothing more" vertex="1"><mxGeometry x="68" y="520" width="292" height="24" as="geometry" /></mxCell>
23+
<mxCell id="lg-1s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#FEF3C7;strokeColor=#B45309;" value="" vertex="1"><mxGeometry x="380" y="523" width="24" height="18" as="geometry" /></mxCell>
24+
<mxCell id="lg-1t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="A release of the 3.x line" vertex="1"><mxGeometry x="414" y="520" width="215" height="24" as="geometry" /></mxCell>
25+
<mxCell id="lg-2s" parent="1" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;gradientColor=#FFFFFF;gradientDirection=north;strokeWidth=1.6;fillColor=#FFE4E6;strokeColor=#BE123C;" value="" vertex="1"><mxGeometry x="649" y="523" width="24" height="18" as="geometry" /></mxCell>
26+
<mxCell id="lg-2t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="The security exception" vertex="1"><mxGeometry x="683" y="520" width="194" height="24" as="geometry" /></mxCell>
27+
<mxCell id="lg-3s" parent="1" style="endArrow=blockThin;endFill=1;endSize=5;html=1;strokeColor=#64748B;strokeWidth=2.0;dashed=1;" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="897" y="532" as="sourcePoint" /><mxPoint x="937" y="532" as="targetPoint" /></mxGeometry></mxCell>
28+
<mxCell id="lg-3t" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;fontFamily=Segoe UI;fontSize=12;fontColor=#475569;" value="A change outside the normal path" vertex="1"><mxGeometry x="947" y="520" width="260" height="24" as="geometry" /></mxCell>
29+
</root>
30+
</mxGraphModel>
31+
</diagram>
32+
</mxfile>

‎docs/diagrams/compatibility.png‎

346 KB
Loading

0 commit comments

Comments
 (0)