You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 99afa65
Browse filesBrowse the repository at this point in the historyBrowse files
docs(decisions): rewrite ADR-049 in the imbrain form (#1936)
* docs(decisions): rewrite ADR-049 in the imbrain form
ADR-049 now has a table-led Context, a one-sentence Decision, a
Rationale, a draw.io diagram, a rule table with what enforces each rule,
a worked example of merging the split, and assessed Compatibility and
Security sections.
base-docs adopts the two imbrain rules this needs: a record may be
rewritten in place until the first merge that implements it, and a
record may show a rendered diagram with its source beside it instead of
inline ASCII. No implementation of ADR-049 has merged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(decisions): merge everything before the split, not only the path move
-s ours marks the split and all its ancestors as merged, so a change between the path move and the split was skipped for good. Merge the split's parent normally first, and land the split as one commit. Reproduced: the old steps kept a pre-split policy fix out of the fork; the new ones keep it and the fork's stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
| One organisation's choices | 17 stacks, 3 platforms, release and session process, interview, examples, generated chains | Projects that work the way Imbra works |
22
+
23
+
The forces:
24
+
25
+
- Contradiction: a review of the core found half of it is an operating
26
+
manual. A team running a different process inherits rules that
27
+
contradict its practice, a failure the efficacy benchmark tests for.
28
+
- Release coupling: every stack ships in every release, so a change to
29
+
one organisation's process is a release for everyone.
30
+
- Size: the generated chains grew until the e2e canary hits the
31
+
generator's output ceiling.
32
+
- Precedent: the previous scope decision already sent other
33
+
organisations to their own repositories, but kept a curated stack set
34
+
here.
32
35
33
36
## Decision
34
37
35
-
Upstream holds the composition engine and the invariant policy, and forks
36
-
carry the stacks, platforms, process layer, interview, examples and
37
-
generated chains, syncing by merging upstream.
38
+
Upstream holds the composition engine and the policy every team shares;
39
+
forks carry the stacks, platforms, process layer, interview, examples and
40
+
generated chains, and stay current by merging upstream.
38
41
39
42
## Rationale
40
43
41
-
- One organisation's process in the shared core contradicts the practice of
42
-
a team running a different one; in a fork it binds only that organisation.
43
-
- With the stacks in forks, upstream no longer ships every stack in every
44
-
release, and one organisation's process change is no longer a release for
45
-
everyone.
46
-
- A fork that merges upstream receives upstream's fixes, which a copy that
47
-
drifts does not.
44
+
- One organisation's process binds only the projects that chose it, so no
45
+
team inherits rules that contradict its practice.
46
+
- A new stack or a process change is a release of one fork, not of every
47
+
consumer.
48
+
- A git fork receives upstream's fixes by merging; a copy drifts, and
49
+
nothing carries a fix into it.
50
+
- Generation stays an agent reading Markdown, so a project needs no new
51
+
tool.
48
52
49
53
## Design
50
54
51
-
1.**Upstream holds the engine and the invariant policy** — this
52
-
repository keeps the manifest schema, IDs, EXTEND and OVERRIDE, the
53
-
resolver, the checks and the engineering policy that holds for any
54
-
team. Which files fall on which side is a separate boundary decision.
55
-
2.**Forks hold the rest** — stacks, platforms, the process layer, the
56
-
interview, examples and generated chains live in forks. Imbra's fork,
57
-
`imbra-ai-templates`, is the first; any organisation MAY fork the same
58
-
way.
59
-
3.**A fork is a git fork that merges upstream** — a fork syncs with
60
-
`git merge upstream/main`, never by copying files.
61
-
4.**A fork appends and never edits upstream keys** — a fork MUST NOT edit
62
-
the manifest keys upstream owns (`core:`, `base:`, `backend:`,
63
-
`frontend:`). It appends under `stacks:`, `platform:` and keys of its
64
-
own.
65
-
5.**Forks own their ID namespaces** — the prefixes `stack-*`,
66
-
`platform-*` and `<org>-*` are reserved for forks, and upstream adds no
67
-
ID under them.
68
-
6.**Upstream commits no derived content** — no `generated/`, no
69
-
`examples/` and no stack table. A fork regenerates its own.
70
-
7.**Some files are expected to conflict** — `README.md`, `CLAUDE.md` and
71
-
`CHANGELOG.md` are fork-owned, and a fork resolves them in its own
72
-
favour on every merge.
73
-
8.**The split is merged with the `ours` strategy** — a fork that exists
74
-
before the split merges the split commit with `git merge -s ours`. An
75
-
ordinary merge deletes every file the fork left unchanged and upstream
76
-
removed.
77
-
9.**Generation stays agent-driven** — the split adds no compiler. A
78
-
project still hands its agent the interview and a resolved chain.
79
-
10.**The split takes effect in the v3.0 release** — until then this
80
-
repository carries both kinds of content as it does today.
55
+

56
+
57
+
| # | Rule | In practice |
58
+
| - | ---- | ----------- |
59
+
| 1 | Upstream holds the engine and shared policy | The manifest schema, IDs, EXTEND and OVERRIDE, the resolver, the checks, and the policy that holds for any team. Which file falls on which side is the boundary record's call (#1919) |
60
+
| 2 | Forks hold the rest | Stacks, platforms, the process layer, the interview, examples and generated chains. `imbra-ai-templates` is the first fork; any organisation MAY fork the same way |
61
+
| 3 | A fork merges upstream | A fork syncs with `git merge upstream/main`, never by copying files |
62
+
| 4 | A fork appends, never edits upstream keys | A fork MUST NOT edit `core:`, `base:`, `backend:` or `frontend:` in the manifest; it appends under `stacks:`, `platform:` and keys of its own |
63
+
| 5 | Forks own their ID prefixes |`stack-*`, `platform-*` and `<org>-*` are reserved for forks; upstream adds no ID under them |
64
+
| 6 | Upstream commits no derived content | No `generated/`, no `examples/`, no stack table; a fork regenerates its own |
65
+
| 7 | Fork-owned files conflict by design |`README.md`, `CLAUDE.md` and `CHANGELOG.md` belong to the fork, which resolves them in its own favour on every merge |
66
+
| 8 | The split merges with `ours`| Upstream lands the split as one commit. A fork that predates it merges the commit's parent normally, then the split commit with `git merge -s ours`; an ordinary merge deletes every file the fork left unchanged and upstream removed |
67
+
| 9 | Generation stays agent-driven | No compiler: a project hands its agent the interview and a resolved chain |
68
+
| 10 | Takes effect in v3.0 | Until then this repository carries both kinds of content, as it does today |
69
+
70
+
| Rule | Promise or mechanism | Enforced by |
71
+
| ---- | -------------------- | ----------- |
72
+
| 1, 2 | Promise to projects and forks | The boundary record (#1919) |
73
+
| 3, 9 | Mechanism | - |
74
+
| 4 | Promise to forks | The manifest ownership check (#1923) |
75
+
| 5 | Promise to forks | The duplicate-ID smoke check, which fires on the merge |
76
+
| 6, 7, 8 | Mechanism | The fork-sync CI job (#1924) and the migration guide (#1292) |
77
+
| 10 | Promise to projects | The compatibility record (#1921) |
78
+
79
+
### Merging the split
80
+
81
+
A fork made before v3.0 takes upstream's changes in three steps. Upstream
82
+
lands the split as one commit. Everything before it merges normally first:
83
+
`-s ours` marks a commit and all its ancestors as merged, so a change not
84
+
merged before it, such as the path move or a policy fix, is skipped for
# Everything before the split, the path move included, merges normally.
92
+
git merge <split-commit>^
93
+
94
+
# Upstream drops the stacks; the fork keeps them.
95
+
git merge -s ours <split-commit>
96
+
97
+
# Everything after the split merges normally.
98
+
git merge upstream/main
99
+
```
81
100
82
101
## Alternatives considered
83
102
84
-
-**Keep the curated set here** — rejected; it keeps one organisation's
85
-
process in the shared core, and every stack ships in every release.
86
-
-**Stacks as a package or submodule** — rejected; it adds an install step
87
-
for a user who only attaches a file to an agent, and a submodule pins
88
-
rather than merges.
89
-
-**A separate stacks repository that copies the core** — rejected; a copy
90
-
drifts, and nothing carries an upstream fix into it.
91
-
-**A compiler that assembles context files** — rejected; the composition
92
-
stays readable Markdown an agent resolves, and a build step is a new
93
-
dependency for every consumer.
103
+
| Alternative | Why not |
104
+
| ----------- | ------- |
105
+
| Keep the curated set here | One organisation's process stays in the shared core, and every stack ships in every release. |
106
+
| Stacks as a package or submodule | An install step for a user who only attaches a file to an agent, and a submodule pins rather than merges. |
107
+
| A stacks repository that copies the core | A copy drifts, and nothing carries an upstream fix into it. |
108
+
| A compiler that assembles context files | A build step becomes a dependency for every consumer, and the composition stops being Markdown an agent reads. |
94
109
95
110
## Consequences
96
111
97
-
- A boundary record assigns each template to upstream or to forks
98
-
- A compatibility record states what upstream freezes from `3.0.0`, so a
99
-
fork can rely on the IDs it extends
100
-
- Smoke gains a check that fails when a fork edits an upstream manifest key
101
-
- Upstream CI gains a job that simulates a fork, lands an upstream change
102
-
and asserts the merge is clean
103
-
- A fixture stack and platform give the per-stack checks an input once the
104
-
stacks leave
105
-
- The README is rewritten for the fork model, and the issue on capping
106
-
stack scope and defining the extension model closes on this record
107
-
- The migration guide documents the `ours` merge and the ownership rule
112
+
| Consequence | Effect |
113
+
| ----------- | ------ |
114
+
| Boundary record | Assigns each template to upstream or to forks (#1919) |
115
+
| Compatibility record | States what upstream freezes from `3.0.0`, so a fork can rely on the IDs it extends (#1921) |
116
+
| Ownership check | Smoke fails when a fork edits an upstream manifest key (#1923) |
117
+
| Fork-sync CI job | Simulates a fork, lands an upstream change, and asserts the merge is clean (#1924) |
118
+
| Fixture stack and platform | The per-stack checks keep an input once the stacks leave (#1925) |
119
+
| README rewrite | The fork model replaces the stacks table; the extension-model issue closed on this record (#305) |
120
+
| Migration guide | Documents the merge steps above and the ownership rule (#1292) |
108
121
109
122
## Compatibility
110
123
111
-
Not assessed: this record predates the section.
124
+
- Until v3.0 nothing changes. `v2.90.0` stays the pin a consumer holds
125
+
until it migrates.
126
+
- From v3.0, a project that resolves a stack, a platform, the interview or
127
+
a generated chain from upstream finds them gone. It re-pins to a fork that
128
+
carries them; Imbra's fork keeps today's IDs, so the project's EXTEND and
129
+
OVERRIDE directives still resolve.
130
+
- A project that builds only on upstream's shared policy keeps working
131
+
against upstream, on the IDs the compatibility record freezes.
132
+
- A fork made before the split loses every stack it left unchanged if it
133
+
merges the split normally; the merge steps above prevent that.
134
+
- The removal ships as a major release, under `Breaking changes` in the
135
+
CHANGELOG. How long 2.x receives fixes is the compatibility record's
136
+
call (#1921).
112
137
113
138
## Security
114
139
115
-
Not assessed: this record predates the section.
140
+
- Trust moves to the fork's maintainer. A context file instructs an agent
141
+
that can run commands, and a shipped check is code the agent runs, so a
142
+
project trusts whoever maintains the fork it pins. A project SHOULD pin a
143
+
fork by tag or commit, not by branch.
144
+
- The ownership rule guards upstream's manifest keys, not what they mean
145
+
in a chain. A fork can OVERRIDE an upstream security section from one of
146
+
its own stacks, and no upstream check sees it.
147
+
-`SECURITY.md` routes reports about upstream only. Each fork needs its
148
+
own disclosure route for the content it adds.
149
+
- No credentials or secrets are involved.
150
+
151
+
## Related
152
+
153
+
- ADR-009 - the curated stack set this record supersedes.
154
+
-solid-ai-dev/solid-ai-templates#1919 - the boundary record.
155
+
-solid-ai-dev/solid-ai-templates#1921 - the compatibility record.
156
+
-solid-ai-dev/solid-ai-templates#305 - the extension model this record
0 commit comments