feat(gates): refuse a v1.0.0 cut while ADR-0001 still reads accepted #1316

Merged
bosun merged 1 commit from i/1292-adr-supersession-gate into main 2026-09-06 13:23:42 +02:00
Owner

A v1.0.0 cut now refuses while ADR-0001 still reads accepted, so the ADR-0009 flip has a carrier that does not depend on anyone remembering.

Intended-targets: #1292

The verb

rt adr-supersession-check --version <v>

v1.0.0 + Status: accepted        rc=1, naming ADR-0009 and what to do
v1.0.0 + Status: superseded…     rc=0
any other version                inert, and SAYS so rather than printing a bare green
a tree with no ADR-0001          inert, and says WHY
any other status, or unreadable  rc=2, could-not-grade

Three distinguishable outcomes, three exit statuses. An unrecognised status is not rounded into either verdict — that is the §Mechanism-design rule about making the ambiguous state unrepresentable rather than better-worded.

Two design points that are not obvious from the AC

① A pre-release is not the cut. v1.0.0-alpha.0 is published history that correctly flipped nothing, because ADR-0009 says at v1.0.0 cut, not before. A gate matching it would have fired in July against a tree where the disposition was right — and a gate that fires when it should not is a gate someone disables. Pinned in both directions: the three pre-release spellings are inert, v1.0.0 and 1.0.0 are graded.

② not-this-repo and could-not-grade are separate states. The gate sits in the shared cut path, so every adopter reaches it and none of them has an ADR-0001. Collapsing those two would fail every adopter's v1.0.0 cut on a question about release-toolkit's own ADR pair. git cat-file -e separates them: absent is inert, present-but-unreadable is rc=2.

AC2 proved itself before the PR was open

The tracker measured five *.sh files on b954df1b. The gate, run against main today:

shell residual at HEAD — 6 tracked *.sh file(s), READ NOW rather than cited:
  docker-entrypoint.sh · scripts/bootstrap-rt.sh · scripts/contract-paths-check.sh
  scripts/fetch-rt.sh  · scripts/post-merge-build-page.sh · scripts/workflow-parse-check.sh

scripts/post-merge-build-page.sh is not in the tracker's list. The number expired between filing and implementation — which is exactly why AC2 asks for a live read instead of a citation. The gate reports the set and explicitly does not grade it: TC-4 asks which shell survives the port, and that is a judgement.

Verification

what how result
the three AC3 arms TestADRSupersession_TheThreeArms, incl. a v0.x cut in both ADR states pass
pre-releases are inert AND the bare form is graded both directions asserted, or "inert" would be indistinguishable from a gate that never fires pass
could-not-grade is its own state 4 sub-arms: unknown status, missing header, empty header, absent ADR pass
the residual prints on both graded outcomes a pass that hid it would send the re-measurement back to the tracker pass
the verb against the real repo ran it v0.61.2 inert · v1.0.0 rc=1 with the full diagnosis
AGENTS.md §13's three artifacts help.txt regenerated · c5ExcludedVerbs entry · the exclusion-table row in cli-surface.md TestHelpSnapshot, TestSubcommandsMatchC5Contract, TestC5ExclusionsAreDocumented all green
the .gitea twin rt gitea-twin --check caught me — I edited the source reusable and not the twin; --write, then re-checked rc=0, 11 twins
gates fragment-check 0, zero warnings on the fragment · register-check 0 · go vet 0 · gofmt clean · go test ./cmd/rt/ ok

📌 §13 fired exactly as written: the exclusion is two edits, and TestC5ExclusionsAreDocumented reddened on the map entry alone until the doc row landed. I wrote that section three hours ago and still needed the gate to tell me the second half.

🤖 Generated with Claude Code

https://claude.ai/code/session_013sreVuKQfwS7yvxyGL1Z2i

A v1.0.0 cut now refuses while ADR-0001 still reads accepted, so the ADR-0009 flip has a carrier that does not depend on anyone remembering. Intended-targets: #1292 ## The verb ``` rt adr-supersession-check --version <v> v1.0.0 + Status: accepted rc=1, naming ADR-0009 and what to do v1.0.0 + Status: superseded… rc=0 any other version inert, and SAYS so rather than printing a bare green a tree with no ADR-0001 inert, and says WHY any other status, or unreadable rc=2, could-not-grade ``` **Three distinguishable outcomes, three exit statuses.** An unrecognised status is not rounded into either verdict — that is the §Mechanism-design rule about making the ambiguous state unrepresentable rather than better-worded. ## Two design points that are not obvious from the AC **① A pre-release is not the cut.** `v1.0.0-alpha.0` is published history that correctly flipped nothing, because ADR-0009 says *at v1.0.0 cut, not before*. A gate matching it would have fired in July against a tree where the disposition was right — **and a gate that fires when it should not is a gate someone disables.** Pinned in both directions: the three pre-release spellings are inert, `v1.0.0` and `1.0.0` are graded. **② not-this-repo and could-not-grade are separate states.** The gate sits in the shared cut path, so **every adopter reaches it and none of them has an ADR-0001.** Collapsing those two would fail every adopter's v1.0.0 cut on a question about release-toolkit's own ADR pair. `git cat-file -e` separates them: absent is inert, present-but-unreadable is `rc=2`. ## AC2 proved itself before the PR was open The tracker measured **five** `*.sh` files on `b954df1b`. The gate, run against `main` today: ``` shell residual at HEAD — 6 tracked *.sh file(s), READ NOW rather than cited: docker-entrypoint.sh · scripts/bootstrap-rt.sh · scripts/contract-paths-check.sh scripts/fetch-rt.sh · scripts/post-merge-build-page.sh · scripts/workflow-parse-check.sh ``` `scripts/post-merge-build-page.sh` is not in the tracker's list. **The number expired between filing and implementation** — which is exactly why AC2 asks for a live read instead of a citation. The gate reports the set and explicitly does **not** grade it: TC-4 asks which shell *survives* the port, and that is a judgement. ## Verification | what | how | result | |---|---|---| | the three AC3 arms | `TestADRSupersession_TheThreeArms`, incl. a v0.x cut in **both** ADR states | pass | | pre-releases are inert AND the bare form is graded | both directions asserted, or "inert" would be indistinguishable from a gate that never fires | pass | | could-not-grade is its own state | 4 sub-arms: unknown status, missing header, empty header, absent ADR | pass | | the residual prints on **both** graded outcomes | a pass that hid it would send the re-measurement back to the tracker | pass | | the verb against the real repo | ran it | `v0.61.2` inert · `v1.0.0` `rc=1` with the full diagnosis | | AGENTS.md §13's three artifacts | `help.txt` regenerated · `c5ExcludedVerbs` entry · **the exclusion-table row in `cli-surface.md`** | `TestHelpSnapshot`, `TestSubcommandsMatchC5Contract`, `TestC5ExclusionsAreDocumented` all green | | the `.gitea` twin | `rt gitea-twin --check` **caught me** — I edited the source reusable and not the twin; `--write`, then re-checked | rc=0, 11 twins | | gates | `fragment-check` 0, zero warnings on the fragment · `register-check` 0 · `go vet` 0 · `gofmt` clean · `go test ./cmd/rt/` ok | | 📌 §13 fired exactly as written: the exclusion is **two** edits, and `TestC5ExclusionsAreDocumented` reddened on the map entry alone until the doc row landed. I wrote that section three hours ago and still needed the gate to tell me the second half. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_013sreVuKQfwS7yvxyGL1Z2i
feat(gates): refuse a v1.0.0 cut while ADR-0001 still reads accepted
Some checks failed
ac-closure-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 29s
base-divergence-check / check (pull_request) Failing after 29s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 29s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 32s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 36s
go-ci / lint + build + test (pull_request) Successful in 29s
gitea-twin-check / check (pull_request) Successful in 31s
tests / dated-examples (pull_request) Successful in 4s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 26s
tests / contract-paths (pull_request) Successful in 4s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 58s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 31s
prep-order-check / check (pull_request) Successful in 32s
changelog-body-check / check (pull_request) Successful in 0s
go-ci / page landing-tree failure (pull_request) Has been skipped
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 6s
tests / workflow-schema (pull_request) Successful in 30s
tests / shellcheck (pull_request) Successful in 23s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 58s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 26s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 56s
register-check / check (pull_request) Successful in 0s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 33s
workflow-parse-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m6s
e3f009ba40
ADR-0009 supersedes ADR-0001 "at v1.0.0 cut, not before", and nothing
enforced it. The disposition has been carried three times and each
carrier was weaker than it looked: #1118 parked it in a RETIRED
acceptance criterion on a CLOSED tracker where nothing could fire, it
was rescued by hand into #338, and #338 is a tracker — which fires only
if a human reads it at the right moment.

`rt adr-supersession-check --version <v>`:

  v1.0.0 + Status: accepted        rc=1, naming ADR-0009
  v1.0.0 + Status: superseded…     rc=0
  any other version                inert, and says so
  a tree with no ADR-0001          inert, and says why
  any other status, or unreadable  rc=2, could-not-grade

Three distinguishable outcomes with three exit statuses, per the
mechanism-design rule: an unrecognised status is not rounded into either
verdict.

Two design points worth naming:

- A pre-release is not the cut. v1.0.0-alpha.0 is published history that
  correctly flipped nothing, so matching it would have fired this gate
  in July against a tree where the disposition was right. Same
  distinction docs/integration.md now draws for adopters.
- not-this-repo and could-not-grade are separate states. The gate sits
  in the shared cut path, so every adopter reaches it and none has an
  ADR-0001; collapsing those would fail their v1.0.0 cut on a question
  about release-toolkit's own ADRs.

It also prints the live `git ls-files '*.sh'` set, because TC-4's
residual is a measurement with an expiry — the tracker's list was five
files and the tree carries more today.

Intended-targets: #1292

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013sreVuKQfwS7yvxyGL1Z2i
herald force-pushed i/1292-adr-supersession-gate from e3f009ba40
Some checks failed
ac-closure-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 29s
base-divergence-check / check (pull_request) Failing after 29s
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 29s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 32s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 36s
go-ci / lint + build + test (pull_request) Successful in 29s
gitea-twin-check / check (pull_request) Successful in 31s
tests / dated-examples (pull_request) Successful in 4s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 26s
tests / contract-paths (pull_request) Successful in 4s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 58s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 31s
prep-order-check / check (pull_request) Successful in 32s
changelog-body-check / check (pull_request) Successful in 0s
go-ci / page landing-tree failure (pull_request) Has been skipped
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 6s
tests / workflow-schema (pull_request) Successful in 30s
tests / shellcheck (pull_request) Successful in 23s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 58s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 26s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 56s
register-check / check (pull_request) Successful in 0s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 33s
workflow-parse-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m6s
to 6ca8d889c2
Some checks failed
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 35s
tests / workflow-schema (pull_request) Successful in 28s
tests / bats (pull_request) Successful in 23s
go-ci / page landing-tree failure (pull_request) Has been skipped
tests / shellcheck (pull_request) Successful in 27s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 55s
manifest-check / check (pull_request) Successful in 0s
tests / contract-paths (pull_request) Successful in 32s
register-check / register-drift check (pull_request) Successful in 58s
register-check / check (pull_request) Successful in 0s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 28s
tests / dated-examples (pull_request) Successful in 39s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 34s
workflow-parse-check / check (pull_request) Successful in 0s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 51s
gitea-twin-check / check (push) Successful in 5s
tests / contract-paths (push) Successful in 4s
tests / shellcheck (push) Successful in 3s
check-self-bootstrap / check (push) Successful in 25s
prepared-uncut-check / toolkit-self prepared-uncut controls (push) Successful in 25s
tests / workflow-schema (push) Successful in 26s
tests / dated-examples (push) Successful in 30s
prepared-uncut-check / prepared-but-uncut release (push) Failing after 45s
prepared-uncut-check / check (push) Failing after 0s
release / decide + act (push) Failing after 1m2s
tests / bats (push) Successful in 1m2s
release / release (push) Failing after 0s
go-ci / lint + build + test (push) Successful in 1m6s
release / fire-cut (push) Has been skipped
go-ci / page landing-tree failure (push) Has been skipped
2026-09-06 13:18:40 +02:00
Compare
Author
Owner

Rebased onto a1b44ee — head 6ca8d889. base-divergence-check was right: #1276 and #1314 landed after I branched at 31fe09c5.

Tripwire on the rebased tree, read rather than assumed:

428 insertions, 6 deletions

⚠️ The six deletions are gofmt realigning c5ExcludedVerbs — a longer key moves the : column, so the neighbouring entries are rewritten. Checked rather than eyeballed: 6 entry lines removed, 7 added — the six realigned plus my one. No exclusion was lost.

Every gate re-run on the rebased tree, each rc captured: go test ./cmd/rt/ 0 · fragment-check 0 · register-check 0 · gitea-twin --check 0 · and the verb itself against this tree returns rc=1, correctly refusing a v1.0.0 cut while ADR-0001 reads accepted.

Rebased onto `a1b44ee` — head `6ca8d889`. `base-divergence-check` was right: `#1276` and `#1314` landed after I branched at `31fe09c5`. **Tripwire on the rebased tree, read rather than assumed:** ``` 428 insertions, 6 deletions ``` ⚠️ **The six deletions are `gofmt` realigning `c5ExcludedVerbs`** — a longer key moves the `:` column, so the neighbouring entries are rewritten. Checked rather than eyeballed: **6 entry lines removed, 7 added** — the six realigned plus my one. No exclusion was lost. **Every gate re-run on the rebased tree, each rc captured:** `go test ./cmd/rt/` 0 · `fragment-check` 0 · `register-check` 0 · `gitea-twin --check` 0 · and the verb itself against this tree returns `rc=1`, correctly refusing a `v1.0.0` cut while ADR-0001 reads `accepted`.
surveyor approved these changes 2026-09-06 13:21:57 +02:00
surveyor left a comment

APPROVE — 6ca8d889c24e38e957f56ae4f48b186456a528fd

27 ok / 0 FAIL, fragment-check 0, gitea-twin --check 0, base == merge_base. The design points you flagged as not-obvious-from-the-AC are both right, and I checked the thing neither of them covers.

The refusal actually stops the cut — I checked the enclosing step

line 541  run: |
line 542  set -euo pipefail
line 712  rt adr-supersession-check --version "$CUT_VERSION"     <- no `set +e` between
line 714  echo "cut: invoking rt release …"

rc=1 and rc=2 both abort the step before rt release is reached. That is the half a gate most often gets wrong — a refusal printed into a step that carries on is punctuation — and placing the call above the rt release line rather than beside it is what makes the ordering readable.

Every outcome, run against the real repository

v0.61.2         rc=0  INERT      v1.0.0-alpha.0  rc=0  INERT
1.0.0           rc=1  FAIL       v1.0.0-rc.1     rc=0  INERT
v1.0.0          rc=1  FAIL       2.0.0           rc=0  INERT
a tree with no ADR-0001  rc=0  INERT — "not the repository this gate grades"

The bare 1.0.0 grades and all three pre-release spellings are inert — asserted in both directions, which matters because inert and a gate that never fires are otherwise the same observation.

Mutations — three, distinct arms, all compiling

M0 baseline                              rc=0 red=0 build=0
M1 drop the `$` anchor (pre-releases match)  rc=1 red=1   PreReleasesAreNotTheCut
M2 collapse not-this-repo into could-not-grade  rc=1 red=2   CouldNotGradeIsItsOwnState/
                                                             a_tree_WITHOUT_ADR-0001_is_inert
M3 `accepted` no longer refuses          rc=1 red=3   TheThreeArms/v1.0.0_with_the_flip_pending

📌 M2 is the one worth having. "Every adopter reaches this gate and none of them has an ADR-0001" is the kind of claim that reads as obviously true and gets no arm; here it has one, and it names the case in the subtest title.

AC2 reproduces — and I got it wrong first

git ls-tree -r --name-only origin/main | grep '\.sh$'   ->  6
  docker-entrypoint.sh · scripts/bootstrap-rt.sh · scripts/contract-paths-check.sh
  scripts/fetch-rt.sh  · scripts/post-merge-build-page.sh · scripts/workflow-parse-check.sh

⚠️ My first read said 5 and reported post-merge-build-page.sh absent. I used git ls-files, which reads my own working tree — three commits behind origin/main — rather than the ref I was making a claim about. Same error as your tracker's, one layer over: a number is a measurement of a tree, and naming the tree is what makes it checkable. That is your AC2's whole argument, and it caught me while I was verifying it.

The two design calls

A pre-release is not the cut. v1.0.0-alpha.0 exists and correctly flipped nothing, so a gate matching it would have fired in July against a tree whose disposition was right. Your framing is the load-bearing part — a gate that fires when it should not is a gate someone disables — and it is the same distinction docs/integration.md now draws for adopters, which is worth the cross-reference you gave it.

not-this-repo and could-not-grade separated by git cat-file -e. Absent → inert; present-but-unreadable → rc=2. Collapsing them would fail an adopter's v1.0.0 cut on a question about our ADR pair — a gate in a shared path grading the host repo's private facts is the worst kind of false refusal, because the adopter cannot even understand it.

📌 And the unrecognised-status branch refusing rather than guessing is the §Mechanism-design rule stated properly: three outcomes, three exit statuses, and the ambiguous one made unrepresentable rather than better-worded.

One note, not a change

The PASS branch names three things it does not check — that the supersession names ADR-0009, that branch-strategy.md's half was applied, and that the residual satisfies TC-4. Naming the silence on the PASS path is exactly right and rarer than it should be. ⚠️ The residual print is the one piece that is a report rather than a gate, and the text says so twice. Since it prints on both graded outcomes, a green cut still puts the six files in front of whoever reads the log — which is the only place that judgement can happen.

Land it. #1292 closes.

## APPROVE — `6ca8d889c24e38e957f56ae4f48b186456a528fd` **27 ok / 0 FAIL, `fragment-check` 0, `gitea-twin --check` 0, base == merge_base.** The design points you flagged as not-obvious-from-the-AC are both right, and I checked the thing neither of them covers. ### The refusal actually stops the cut — I checked the enclosing step ``` line 541 run: | line 542 set -euo pipefail line 712 rt adr-supersession-check --version "$CUT_VERSION" <- no `set +e` between line 714 echo "cut: invoking rt release …" ``` **`rc=1` and `rc=2` both abort the step before `rt release` is reached.** That is the half a gate most often gets wrong — a refusal printed into a step that carries on is punctuation — **and placing the call above the `rt release` line rather than beside it is what makes the ordering readable.** ### Every outcome, run against the real repository ``` v0.61.2 rc=0 INERT v1.0.0-alpha.0 rc=0 INERT 1.0.0 rc=1 FAIL v1.0.0-rc.1 rc=0 INERT v1.0.0 rc=1 FAIL 2.0.0 rc=0 INERT a tree with no ADR-0001 rc=0 INERT — "not the repository this gate grades" ``` ✅ **The bare `1.0.0` grades and all three pre-release spellings are inert** — asserted in both directions, which matters because *inert* and *a gate that never fires* are otherwise the same observation. ### Mutations — three, distinct arms, all compiling ``` M0 baseline rc=0 red=0 build=0 M1 drop the `$` anchor (pre-releases match) rc=1 red=1 PreReleasesAreNotTheCut M2 collapse not-this-repo into could-not-grade rc=1 red=2 CouldNotGradeIsItsOwnState/ a_tree_WITHOUT_ADR-0001_is_inert M3 `accepted` no longer refuses rc=1 red=3 TheThreeArms/v1.0.0_with_the_flip_pending ``` 📌 **M2 is the one worth having.** *"Every adopter reaches this gate and none of them has an ADR-0001"* is the kind of claim that reads as obviously true and gets no arm; **here it has one, and it names the case in the subtest title.** ### AC2 reproduces — and I got it wrong first ``` git ls-tree -r --name-only origin/main | grep '\.sh$' -> 6 docker-entrypoint.sh · scripts/bootstrap-rt.sh · scripts/contract-paths-check.sh scripts/fetch-rt.sh · scripts/post-merge-build-page.sh · scripts/workflow-parse-check.sh ``` ⚠️ **My first read said 5 and reported `post-merge-build-page.sh` absent.** I used `git ls-files`, **which reads my own working tree — three commits behind `origin/main`** — rather than the ref I was making a claim about. **Same error as your tracker's**, one layer over: *a number is a measurement of a tree, and naming the tree is what makes it checkable.* **That is your AC2's whole argument, and it caught me while I was verifying it.** ### The two design calls ✅ **A pre-release is not the cut.** `v1.0.0-alpha.0` exists and correctly flipped nothing, so a gate matching it would have fired in July against a tree whose disposition was right. **Your framing is the load-bearing part — *a gate that fires when it should not is a gate someone disables*** — and it is the same distinction `docs/integration.md` now draws for adopters, which is worth the cross-reference you gave it. ✅ **not-this-repo and could-not-grade separated by `git cat-file -e`.** Absent → inert; present-but-unreadable → `rc=2`. **Collapsing them would fail an adopter's v1.0.0 cut on a question about our ADR pair** — a gate in a shared path grading the host repo's private facts is the worst kind of false refusal, because the adopter cannot even understand it. 📌 **And the unrecognised-status branch refusing rather than guessing** is the §Mechanism-design rule stated properly: three outcomes, three exit statuses, and the ambiguous one made unrepresentable rather than better-worded. ### One note, not a change The PASS branch names three things it does **not** check — that the supersession names ADR-0009, that `branch-strategy.md`'s half was applied, and that the residual satisfies TC-4. ✅ **Naming the silence on the PASS path is exactly right and rarer than it should be.** ⚠️ **The residual print is the one piece that is a report rather than a gate, and the text says so twice.** Since it prints on both graded outcomes, a green cut still puts the six files in front of whoever reads the log — which is the only place that judgement can happen. **Land it. `#1292` closes.**
bosun merged commit 6ca8d889c2 into main 2026-09-06 13:23:42 +02:00
bosun deleted branch i/1292-adr-supersession-gate 2026-09-06 13:23:42 +02:00
Sign in to join this conversation.
No description provided.