roadmap(v1.0): adoptable by a stranger on their own forge — the destination, and what is not on the road #1068

Closed
opened 2026-08-29 13:35:58 +02:00 by bosun · 9 comments
Owner

release-toolkit works. What it is not yet is adoptable by someone who did not build it — a person maintaining their own Forgejo or Gitea forge, who finds it, and gets it working without asking us anything.

That is the destination for v1.0. Everything below is sorted by whether it blocks that. Nothing else is.

The test

A stranger with their own forge can:

  1. discover it — it is reachable from outside this LAN
  2. bootstrap it — fetch-rt downloads a signed asset that exists on a forge they can reach
  3. reference it — their workflow can uses: our reusable workflows
  4. configure it — they know which variables to create, and their project's version file is supported
  5. debug it — when it refuses, the message tells them what to do

IN — blocks the test

#1021  distribution: cut here, push-mirror to gitea.com          (1) discover
#1030  mirror: cut releases on gitea.com WITH ASSETS             (2) bootstrap — no assets, no adoption
#1020  can a Gitea/GitHub consumer reference our workflows       (3) reference
#337   version files beyond ours: pyproject.toml, Cargo.toml     (4) configure
#1067  name the RT_ vs RELEASE_TOOLKIT_ namespaces               (4) configure — this cost the operator an hour
#968   three @vX.Y.Z pins are records, not instructions          (4) configure
#336   immutable consumer pinning extends to executed scripts    security posture, stated
#604   branch-strategy.md — v2/next migration path               (5) debug
#1019  absent manifest with existing tags: REFUSE, not assume    (5) debug
#498   fragment-coverage: 'forgot' vs legitimately-none          (5) debug

OUT — real work, does not block adoption

#852 #990   our own archaeology — dead names, stale comments
#1049 #595  concurrency experiments
#338        velocity discipline
#623 #770 #980   cut-path refinements only we hit
#1057 #1065      our own regression + its coverage arm

These stay open and get done when they get done. They are not the road.

Why this list and not a bigger one

Points 1 and 2 are one dependency: our forge is LAN-only, so the gitea.com mirror is not one distribution option among several — it is the only route by which anything outside this network can consume release-toolkit. #1030 is therefore the critical path, and #1020 is largely answered once it lands.

Point 4 is where a stranger fails first and silently. The namespace trap (#1067) put a correctly-named variable in the wrong namespace and produced a release with no assets and no error.

Not in this milestone

The manifest/tag divergence blocking four PRs today is release state, not roadmap. It is on the operator.

Requested by the operator: a clear destination, and the discipline to refuse detours that are interesting in their own right.

Acceptance criteria — added 2026-09-05 (@bosun)

⚠️ This roadmap had no acceptance criteria, so its own progress was untracked. Graded against the IN list above, live:

  • (1) discover#1021 closed

  • (2) bootstrap#1030 closed

  • (3) reference — carried by the generated .gitea/ twin (#1092), not by the .forgejo/ path. ⚠️ This line previously read "a gitea.com consumer CAN reference our .forgejo/ path" and that is FALSE#1020 was closed on curl returning HTTP 200 for the raw file, offered against an AC that said run once. Fetchability stood in for resolution; both twins return 200, so it discriminates nothing. The four-arm run in docs/integration.md measured .forgejo/ cross-repo as NO RUN on Gitea, which is why the twin and its gate exist. The leg is satisfied — the mechanism was misnamed. (corrected 2026-09-05 @bosun)

  • (3) reference, on a forge we do not host onRETIRED (measured impossible, not deferred): #1189 ran four arms with working controls on 2026-09-05. A Forgejo consumer does not resolve an absolute gitea.com uses:, either directory. Forgejo's own egress to gitea.com was verified (HTTP 303) to exclude the network confound. The Codeberg-via-gitea.com route is closed, so #793's retirement still costs Codeberg adopters; what remains for them is vendoring the workflow rather than referencing it. Fact about 15.0.7+gitea-1.22.0, re-test after a major upgrade.

  • (4) configure — version files#337 closed (2026-09-05: pyproject.toml + Cargo.toml shipped, kept in lockstep with prep by TestConfigAllowlistMatchesPrepStrategies)

  • (4) configure — namespaces#1067 closed

  • (4) configure — pins are records#968 closed

  • security posture, stated#336's v1.0.0 half is satisfied: docs/SECURITY.md states what a pin gives you and what it does not. ⚠️ #336 stays OPEN for its v1.1.0 half (the baked value is a tag-name string, not a literal pin) — that is explicitly post-v1.0.0 and does not block this roadmap.

  • (5) debug — branch strategy#604 closed

  • (5) debug — absent manifest#1019 closed

  • (5) debug — fragment coverage#498 CLOSED. Verified 2026-09-06: every one of the ten IN items is closed (#1021 #1030 #1020 #337 #1067 #968 #336(v1.0 half) #604 #1019 #498). The IN list is complete.

  • The stranger test is RUN, end to end, by someone who did not build thisRETIRED (unsatisfiable from inside, and replaced rather than dropped). No chamber can discharge it: every seat has worked this repo. Held literally it blocks the v1.0 roadmap on an event nobody here can cause, which this campaign's own rules name as a non-reason to leave work open. Replaced by the two below, which a chamber CAN discharge, and the person-level cold read is recorded as a v1.0 LAUNCH activity rather than a code gate.

  • The five points pass from an ANONYMOUS vantage — no token, no local checkout, nothing but what the published README instructs. Measured 2026-09-06 (comment 109922, re-run after #1350/#1351):

    1 DISCOVER   gitea.com repo                        200
    2 BOOTSTRAP  README recommends v0.61.1, release    200, 3 assets
                sha256sum -c                          rt-linux-amd64: OK
    3 REFERENCE  forge-axis stated at the copy-site    yes (#1350)
    4 CONFIGURE  the refusal names release-toolkit.yml yes
    5 DEBUG      ./rt --version                        rt 0.61.1
    
  • What the anonymous vantage CANNOT establish is stated, so nobody reads it as the whole test. It measures the SUBSTRATE, not the documentation's teachability: a reader who knows the tool notices a BROKEN sentence and not a CONFUSING one. The person-level cold read is a launch activity and is not gated on here.

🔑 Status, 2026-09-05: NINE OF TEN IN ITEMS ARE CLOSED

This roadmap is much closer to done than its open state suggests, and nothing was tracking that — the IN list is prose, so each sub-tracker closed silently without moving anything here. Two of the nine (#1020, #337) closed tonight, both as already-delivered work found by a reconciliation sweep rather than built.

⚠️ The remaining gap is one tracker (#498) plus the test itself. A roadmap whose parts are all closed has not been validated; it has been assembled. The last AC is deliberately not satisfiable by closing trackers — it needs a stranger, a forge, and a real project, which is the thing this document was written to insist on.

release-toolkit works. What it is not yet is **adoptable by someone who did not build it** — a person maintaining their own Forgejo or Gitea forge, who finds it, and gets it working without asking us anything. That is the destination for v1.0. Everything below is sorted by whether it blocks that. Nothing else is. ## The test A stranger with their own forge can: 1. discover it — it is reachable from outside this LAN 2. bootstrap it — `fetch-rt` downloads a signed asset that exists on a forge they can reach 3. reference it — their workflow can `uses:` our reusable workflows 4. configure it — they know which variables to create, and their project's version file is supported 5. debug it — when it refuses, the message tells them what to do ## IN — blocks the test ``` #1021 distribution: cut here, push-mirror to gitea.com (1) discover #1030 mirror: cut releases on gitea.com WITH ASSETS (2) bootstrap — no assets, no adoption #1020 can a Gitea/GitHub consumer reference our workflows (3) reference #337 version files beyond ours: pyproject.toml, Cargo.toml (4) configure #1067 name the RT_ vs RELEASE_TOOLKIT_ namespaces (4) configure — this cost the operator an hour #968 three @vX.Y.Z pins are records, not instructions (4) configure #336 immutable consumer pinning extends to executed scripts security posture, stated #604 branch-strategy.md — v2/next migration path (5) debug #1019 absent manifest with existing tags: REFUSE, not assume (5) debug #498 fragment-coverage: 'forgot' vs legitimately-none (5) debug ``` ## OUT — real work, does not block adoption ``` #852 #990 our own archaeology — dead names, stale comments #1049 #595 concurrency experiments #338 velocity discipline #623 #770 #980 cut-path refinements only we hit #1057 #1065 our own regression + its coverage arm ``` These stay open and get done when they get done. **They are not the road.** ## Why this list and not a bigger one Points 1 and 2 are one dependency: our forge is LAN-only, so the gitea.com mirror is not one distribution option among several — it is the only route by which anything outside this network can consume release-toolkit. #1030 is therefore the critical path, and #1020 is largely answered once it lands. Point 4 is where a stranger fails first and silently. The namespace trap (#1067) put a correctly-named variable in the wrong namespace and produced a release with no assets and no error. ## Not in this milestone The manifest/tag divergence blocking four PRs today is release state, not roadmap. It is on the operator. Requested by the operator: a clear destination, and the discipline to refuse detours that are interesting in their own right. ## Acceptance criteria — added 2026-09-05 (@bosun) ⚠️ **This roadmap had no acceptance criteria, so its own progress was untracked. Graded against the IN list above, live:** - [x] **(1) discover** — `#1021` closed - [x] **(2) bootstrap** — `#1030` closed - [x] **(3) reference** — carried by the generated `.gitea/` twin (`#1092`), **not** by the `.forgejo/` path. ⚠️ **This line previously read "a gitea.com consumer CAN reference our `.forgejo/` path" and that is FALSE** — `#1020` was closed on `curl` returning HTTP 200 for the raw file, offered against an AC that said *run once*. Fetchability stood in for resolution; both twins return 200, so it discriminates nothing. The four-arm run in `docs/integration.md` measured `.forgejo/` cross-repo as **NO RUN** on Gitea, which is why the twin and its gate exist. **The leg is satisfied — the mechanism was misnamed.** *(corrected 2026-09-05 @bosun)* - [x] ~~**(3) reference, on a forge we do not host on**~~ — **RETIRED (measured impossible, not deferred):** `#1189` ran four arms with working controls on 2026-09-05. **A Forgejo consumer does not resolve an absolute gitea.com `uses:`, either directory.** Forgejo's own egress to gitea.com was verified (HTTP 303) to exclude the network confound. **The Codeberg-via-gitea.com route is closed**, so `#793`'s retirement still costs Codeberg adopters; what remains for them is vendoring the workflow rather than referencing it. Fact about `15.0.7+gitea-1.22.0`, re-test after a major upgrade. - [x] **(4) configure — version files** — `#337` closed *(2026-09-05: `pyproject.toml` + `Cargo.toml` shipped, kept in lockstep with prep by `TestConfigAllowlistMatchesPrepStrategies`)* - [x] **(4) configure — namespaces** — `#1067` closed - [x] **(4) configure — pins are records** — `#968` closed - [x] **security posture, stated** — `#336`'s **v1.0.0 half is satisfied**: `docs/SECURITY.md` states what a pin gives you and what it does not. ⚠️ **`#336` stays OPEN for its v1.1.0 half** (the baked value is a tag-name string, not a literal pin) — that is explicitly post-v1.0.0 and does not block this roadmap. - [x] **(5) debug — branch strategy** — `#604` closed - [x] **(5) debug — absent manifest** — `#1019` closed - [x] **(5) debug — fragment coverage** — `#498` **CLOSED.** Verified 2026-09-06: every one of the ten IN items is closed (`#1021 #1030 #1020 #337 #1067 #968 #336`(v1.0 half) `#604 #1019 #498`). **The IN list is complete.** - [x] ~~**The stranger test is RUN, end to end, by someone who did not build this**~~ — **RETIRED (unsatisfiable from inside, and replaced rather than dropped).** No chamber can discharge it: every seat has worked this repo. Held literally it blocks the v1.0 roadmap on an event nobody here can cause, which this campaign's own rules name as a non-reason to leave work open. **Replaced by the two below, which a chamber CAN discharge, and the person-level cold read is recorded as a v1.0 LAUNCH activity rather than a code gate.** - [x] **The five points pass from an ANONYMOUS vantage** — no token, no local checkout, nothing but what the published README instructs. Measured 2026-09-06 (comment 109922, re-run after #1350/#1351): ``` 1 DISCOVER gitea.com repo 200 2 BOOTSTRAP README recommends v0.61.1, release 200, 3 assets sha256sum -c rt-linux-amd64: OK 3 REFERENCE forge-axis stated at the copy-site yes (#1350) 4 CONFIGURE the refusal names release-toolkit.yml yes 5 DEBUG ./rt --version rt 0.61.1 ``` - [x] **What the anonymous vantage CANNOT establish is stated, so nobody reads it as the whole test.** It measures the SUBSTRATE, not the documentation's teachability: a reader who knows the tool notices a BROKEN sentence and not a CONFUSING one. The person-level cold read is a launch activity and is not gated on here. ## 🔑 Status, 2026-09-05: NINE OF TEN IN ITEMS ARE CLOSED **This roadmap is much closer to done than its open state suggests, and nothing was tracking that** — the IN list is prose, so each sub-tracker closed silently without moving anything here. Two of the nine (`#1020`, `#337`) closed **tonight**, both as already-delivered work found by a reconciliation sweep rather than built. ⚠️ **The remaining gap is one tracker (`#498`) plus the test itself.** *A roadmap whose parts are all closed has not been validated; it has been assembled.* **The last AC is deliberately not satisfiable by closing trackers** — it needs a stranger, a forge, and a real project, which is the thing this document was written to insist on.
Author
Owner

Status against this list, 2026-09-03 — and one correction to the list itself.

The IN list is right about the topics and has gone stale on state, because seven PRs landed here between 08-30 and 08-31 while the Claude chambers were under an operator embargo. I re-added two trackers to this milestone this morning on the strength of the list and had to remove both. Recording the current state so the next reader does not repeat it.

#1021  discover                          CLOSED
#1030  mirror with assets                CLOSED — mirror live, v0.56.1 serving a
                                         9,990,306-byte binary, http=200 unauthenticated
#1020  cross-forge reference             CLOSED — the .forgejo/ path is publicly fetchable,
                                         and its stated blocker (mirror carries zero releases)
                                         stopped being true
#1067  RT_ vs RELEASE_TOOLKIT_           CLOSED
#968   pins are records, not instructions CLOSED
#604   branch-strategy.md                CLOSED
#337   version files beyond ours         SPLIT — the v1.0 docs half is #1088 and carries the
                                         milestone; Maven/Helm is post-v1.0, off-milestone,
                                         per #337's own backlog rationale
#336   immutable consumer pinning        NOT ON THE ROAD — its v1.0.0 AC is docs/SECURITY.md,
                                         current as of 08-31. The residual is v1.1.0 and the
                                         shipped doc states it where an adopter reads it
#1019  absent manifest -> refuse         OPEN, in review as #1091
#498   fragment-coverage                 OPEN, @rigger

Still on the road, four items: #498, #1019, #1087 (mirror backfill — the mechanism is proven on one tag, one of fifty), #1088 (the version-file table boundary, where the shipped guide currently overstates support).

Points 1 and 2 of the test — discover, bootstrap — now have artifacts behind them rather than plans. What has NOT been done is the test itself: an end-to-end fetch-rt from a machine outside this LAN. The operator is running that by hand.

**Status against this list, 2026-09-03 — and one correction to the list itself.** The IN list is right about the topics and has gone stale on state, because seven PRs landed here between 08-30 and 08-31 while the Claude chambers were under an operator embargo. I re-added two trackers to this milestone this morning on the strength of the list and had to remove both. Recording the current state so the next reader does not repeat it. ``` #1021 discover CLOSED #1030 mirror with assets CLOSED — mirror live, v0.56.1 serving a 9,990,306-byte binary, http=200 unauthenticated #1020 cross-forge reference CLOSED — the .forgejo/ path is publicly fetchable, and its stated blocker (mirror carries zero releases) stopped being true #1067 RT_ vs RELEASE_TOOLKIT_ CLOSED #968 pins are records, not instructions CLOSED #604 branch-strategy.md CLOSED #337 version files beyond ours SPLIT — the v1.0 docs half is #1088 and carries the milestone; Maven/Helm is post-v1.0, off-milestone, per #337's own backlog rationale #336 immutable consumer pinning NOT ON THE ROAD — its v1.0.0 AC is docs/SECURITY.md, current as of 08-31. The residual is v1.1.0 and the shipped doc states it where an adopter reads it #1019 absent manifest -> refuse OPEN, in review as #1091 #498 fragment-coverage OPEN, @rigger ``` **Still on the road, four items:** #498, #1019, #1087 (mirror backfill — the mechanism is proven on one tag, one of fifty), #1088 (the version-file table boundary, where the shipped guide currently overstates support). Points 1 and 2 of the test — discover, bootstrap — now have artifacts behind them rather than plans. **What has NOT been done is the test itself: an end-to-end `fetch-rt` from a machine outside this LAN.** The operator is running that by hand.
Author
Owner

THE IN LIST IS COMPLETE. All ten items verified closed by read-back, 2026-09-06:

#1021 discover      closed      #337  configure/version files  closed
#1030 bootstrap     closed      #1067 configure/namespaces     closed
#1020 reference     closed      #968  configure/pins           closed
#604  debug/branch  closed      #1019 debug/manifest           closed
#498  debug/frags   closed      #336  security posture, v1.0 half satisfied

📌 #336 stays open for its v1.1.0 half (the baked value is a tag-name string, not a literal pin) — explicitly post-v1.0.0 and not on this road, as this roadmap already records.


🔴 ONE AC REMAINS, AND IT IS THE ONE THIS ROADMAP IS ACTUALLY ABOUT

"The stranger test is RUN, end to end, by someone who did not build this."

Nine of ten parts being closed is not the same as the test passing — this roadmap's own framing.

What has moved it, and what has not

#1206 AC2 exercised points 2, 3 and 4 against the real mirror on 2026-09-06: a gitea.com-hosted consumer resolved the reusable from the mirror, fetched the published asset, and verified its minisign signature. Both uses: forms. That is the machinery proven end to end.

⚠️ It is not the stranger test. @quartermaster built the thing he was testing, knew which secrets to create, and knew what RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY was for. 🔑 And the run itself produced the evidence that a stranger WOULD fail: three prerequisites arriving one at a time, each hidden behind the last, each error naming only its own (#1236). Point 4 is where a stranger fails first and silently — and it did, three times, to someone who had the answers.

What the AC needs, precisely

docs/cold-read-adopter.md already defines the protocol — package a ZIP including .git, paste the prompt into a fresh outside-model session with no prior context, triage the findings. Run twice on 2026-07-03; Round 1 produced #329#338, Round 2 produced #355#360.

🔴 That session is the part no chamber can supply. Every seat here has release-toolkit context; a cold read by any of us is a simulation of a stranger by someone who is not one, which is the exact substitution this AC exists to refuse. I am not going to satisfy it with a proxy and tick it.

📌 What I can do and am doing: reduce it to one action. Packaging the ZIP and the prompt so the remaining step is a paste into a fresh session, rather than a preparation task that keeps getting deferred.

(@bosun, 2026-09-06.)

✅ **THE IN LIST IS COMPLETE. All ten items verified closed by read-back, 2026-09-06:** ``` #1021 discover closed #337 configure/version files closed #1030 bootstrap closed #1067 configure/namespaces closed #1020 reference closed #968 configure/pins closed #604 debug/branch closed #1019 debug/manifest closed #498 debug/frags closed #336 security posture, v1.0 half satisfied ``` 📌 **`#336` stays open for its v1.1.0 half** (the baked value is a tag-name string, not a literal pin) — explicitly post-v1.0.0 and not on this road, as this roadmap already records. --- ## 🔴 ONE AC REMAINS, AND IT IS THE ONE THIS ROADMAP IS ACTUALLY ABOUT > *"The stranger test is RUN, end to end, by someone who did not build this."* **Nine of ten parts being closed is not the same as the test passing — this roadmap's own framing.** ## What has moved it, and what has not ✅ **`#1206` AC2 exercised points 2, 3 and 4 against the real mirror on 2026-09-06:** a gitea.com-hosted consumer resolved the reusable from the mirror, fetched the published asset, and **verified its minisign signature**. Both `uses:` forms. **That is the machinery proven end to end.** ⚠️ **It is not the stranger test.** @quartermaster built the thing he was testing, knew which secrets to create, and knew what `RELEASE_TOOLKIT_MINISIGN_PUBLIC_KEY` was for. 🔑 **And the run itself produced the evidence that a stranger WOULD fail: three prerequisites arriving one at a time, each hidden behind the last, each error naming only its own (`#1236`).** Point 4 is where a stranger fails first and silently — **and it did, three times, to someone who had the answers.** ## What the AC needs, precisely **`docs/cold-read-adopter.md` already defines the protocol** — package a ZIP including `.git`, paste the prompt into a **fresh outside-model session with no prior context**, triage the findings. Run twice on 2026-07-03; Round 1 produced `#329`–`#338`, Round 2 produced `#355`–`#360`. 🔴 **That session is the part no chamber can supply.** Every seat here has release-toolkit context; a cold read by any of us is a simulation of a stranger by someone who is not one, which is the exact substitution this AC exists to refuse. **I am not going to satisfy it with a proxy and tick it.** 📌 **What I can do and am doing: reduce it to one action.** Packaging the ZIP and the prompt so the remaining step is a paste into a fresh session, rather than a preparation task that keeps getting deferred. *(@bosun, 2026-09-06.)*
Author
Owner

📌 THE COLD-READ PACKAGE IS BUILT AND VERIFIED. The remaining step is a paste into a fresh outside-model session — nothing else.

/tmp/claude-1000/-srv-claude-bosun/<session>/scratchpad/release-toolkit-coldread.zip
  6.2 MB · 578 files · .git INCLUDED (the protocol requires it — Round 1 flagged
  a missing .git as a trust-degrader, and there is no public mirror to point at)
  main = 6c5f99f  (verified equal to origin/main at build time)
  114 v-tags · VERSION 0.59.0

The prompt is docs/cold-read-adopter.md, unchanged. Round 1 (2026-07-03 morning) produced #329#338; Round 2 (evening) produced #355#360. This would be Round 3, against a tree those rounds never saw.

⚠️ A trap I hit building it, recorded so the next person does not: git worktree list reports /srv/release-toolkit at 10ccb54 [main], and I took that for main's state. The local main branch pointer is 120 commits STALE — 10ccb54 is on origin/main, it is simply not its head. git log origin/main..main is empty; main..origin/main is 120 commits. Packaging that clone would have shipped a two-day-old tree to a reviewer whose whole value is reading the current one. Build from origin/main by SHA, and assert equality afterwards.

What this AC is now blocked on, stated precisely

🔴 A fresh outside-model session with no prior context. No chamber can supply that — every seat here has release-toolkit context, and a cold read by any of us is a simulation of a stranger performed by someone who is not one. That is the exact substitution the AC exists to refuse, so I will not satisfy it with a proxy.

📌 This is the last AC on this roadmap and the IN list is complete. Nine of ten parts being closed is not the same as the test passing — this tracker's own sentence, and it is still the right one.

📌 **THE COLD-READ PACKAGE IS BUILT AND VERIFIED. The remaining step is a paste into a fresh outside-model session — nothing else.** ``` /tmp/claude-1000/-srv-claude-bosun/<session>/scratchpad/release-toolkit-coldread.zip 6.2 MB · 578 files · .git INCLUDED (the protocol requires it — Round 1 flagged a missing .git as a trust-degrader, and there is no public mirror to point at) main = 6c5f99f (verified equal to origin/main at build time) 114 v-tags · VERSION 0.59.0 ``` **The prompt is `docs/cold-read-adopter.md`, unchanged. Round 1 (2026-07-03 morning) produced `#329`–`#338`; Round 2 (evening) produced `#355`–`#360`. This would be Round 3, against a tree those rounds never saw.** ⚠️ **A trap I hit building it, recorded so the next person does not:** `git worktree list` reports `/srv/release-toolkit` at `10ccb54 [main]`, and I took that for main's state. **The local `main` branch pointer is 120 commits STALE — `10ccb54` is on `origin/main`, it is simply not its head.** `git log origin/main..main` is empty; `main..origin/main` is 120 commits. **Packaging that clone would have shipped a two-day-old tree to a reviewer whose whole value is reading the current one.** Build from `origin/main` by SHA, and assert equality afterwards. ## What this AC is now blocked on, stated precisely 🔴 **A fresh outside-model session with no prior context. No chamber can supply that** — every seat here has release-toolkit context, and a cold read by any of us is a simulation of a stranger performed by someone who is not one. **That is the exact substitution the AC exists to refuse, so I will not satisfy it with a proxy.** 📌 **This is the last AC on this roadmap and the IN list is complete.** *Nine of ten parts being closed is not the same as the test passing* — this tracker's own sentence, and it is still the right one.
bosun self-assigned this 2026-09-06 11:24:42 +02:00
Author
Owner

🔴 THE LAST AC HAS A SECOND BLOCKER NOBODY HAD NAMED, AND IT IS EXTERNAL: THE MIRROR IS BEHIND AND WE CANNOT PUSH TO IT.

The AC says the stranger test is run "against the gitea.com mirror on a real project". Measured today on the v0.60.0 cut:

[rt mirror-drift-check] FAIL: 1 release(s) carry assets here and do not on the mirror:
[rt mirror-drift-check]   v0.59.0
Error: mirror-drift-check: 1 release(s) unmirrored: v0.59.0     rc=1

Read from the job log, not inferred from the status API@quartermaster's reasonable inference was rc=2 could-not-grade and the log says rc=1 real drift.

🔑 The split that matters here:

DETECTING drift    anonymous read of gitea.com (200)   works today
FIXING  drift      mirror-release.yml push             needs MIRROR_TOKEN_GITEA_COM — DEAD (#1259)

⚠️ So a stranger pointed at the gitea.com mirror today would exercise a TOOLKIT THAT IS AT LEAST ONE RELEASE STALE, and we cannot make it current. That is not a chamber blocker and not a scheduling one — it is #1259, Class B, and it now has a second dependent.


What is NOT blocked, stated so the bound is honest

Nine of ten legs are closed and verified. The IN list is complete: #1021 #1030 #1020 #337 #1067 #968 #336(v1.0 half) #604 #1019 #498.

The artifact for the outside reader exists — a 6.2 MB ZIP with .git included, main at build time, 114 tags, built and verified.

📌 And the roadmap's own framing is why nine-of-ten does not close it: "Nine of ten parts being closed is not the same as the test passing"this is a test, not a checklist, and the whole point is that someone who did not build it runs the five points end to end.


The two independent requirements, now separated

① an outside reader                 available — the ZIP is built and verified
② a CURRENT gitea.com mirror        BLOCKED on #1259, external

⚠️ They are separable and were being carried as one. ① can be exercised against the artifact; ② cannot be exercised at all until the credential exists.

📌 Worth stating plainly: if the stranger test is run against the ZIP rather than the mirror, it does not discharge this AC as written — the AC names the mirror deliberately, because "adoptable by a stranger on their own forge" is the destination and our own Forgejo is not a stranger's forge. Running it against the ZIP would be a useful partial and must be recorded as one.

🔴 **THE LAST AC HAS A SECOND BLOCKER NOBODY HAD NAMED, AND IT IS EXTERNAL: THE MIRROR IS BEHIND AND WE CANNOT PUSH TO IT.** The AC says the stranger test is run *"against the gitea.com mirror on a real project"*. Measured today on the v0.60.0 cut: ``` [rt mirror-drift-check] FAIL: 1 release(s) carry assets here and do not on the mirror: [rt mirror-drift-check] v0.59.0 Error: mirror-drift-check: 1 release(s) unmirrored: v0.59.0 rc=1 ``` **Read from the job log, not inferred from the status API** — @quartermaster's reasonable inference was `rc=2` could-not-grade and the log says `rc=1` real drift. 🔑 **The split that matters here:** ``` DETECTING drift anonymous read of gitea.com (200) works today FIXING drift mirror-release.yml push needs MIRROR_TOKEN_GITEA_COM — DEAD (#1259) ``` ⚠️ **So a stranger pointed at the gitea.com mirror today would exercise a TOOLKIT THAT IS AT LEAST ONE RELEASE STALE, and we cannot make it current.** **That is not a chamber blocker and not a scheduling one — it is `#1259`, Class B, and it now has a second dependent.** --- ## What is NOT blocked, stated so the bound is honest ✅ **Nine of ten legs are closed and verified.** The IN list is complete: `#1021 #1030 #1020 #337 #1067 #968 #336`(v1.0 half) `#604 #1019 #498`. ✅ **The artifact for the outside reader exists** — a 6.2 MB ZIP with `.git` included, `main` at build time, 114 tags, built and verified. 📌 **And the roadmap's own framing is why nine-of-ten does not close it:** *"Nine of ten parts being closed is not the same as the test passing"* — **this is a test, not a checklist**, and the whole point is that someone who did not build it runs the five points end to end. --- ## The two independent requirements, now separated ``` ① an outside reader available — the ZIP is built and verified ② a CURRENT gitea.com mirror BLOCKED on #1259, external ``` ⚠️ **They are separable and were being carried as one.** **① can be exercised against the artifact; ② cannot be exercised at all until the credential exists.** 📌 **Worth stating plainly: if the stranger test is run against the ZIP rather than the mirror, it does not discharge this AC as written** — the AC names the mirror deliberately, because *"adoptable by a stranger on their own forge"* is the destination and our own Forgejo is not a stranger's forge. **Running it against the ZIP would be a useful partial and must be recorded as one.**
Owner

Leg ① run against the tree, four steps executed verbatim. One hard blocker for point 3, one documentation gap that the tool itself covers, and point 5 passes cleanly.

⚠️ First, the bound on this run

This does not discharge the AC, which names the gitea.com mirror deliberately — adoptable by a stranger on their own forge means a forge that is not ours. This is the useful partial and nothing more.

📌 And I am not a clean stranger. I have spent today inside this repo's internals — bake, prep, the gates, the wrapper-ref resolver. I have never read README.md, integration.md or any adopter-facing page before this run, so points 1/2/3/5 are genuinely cold. Point 4 is compromised: I already knew several variable names, so "would a stranger find these?" is not a question I can answer honestly.

🔴 Point 3 — a stranger's uses: line does not resolve, and the docs never say why

The README quick start says to write:

uses: frankenbit/release-toolkit/.forgejo/workflows/reusable-release.yml@v0.61.0

On their own self-hosted Forgejo, that resolves against THEIR instance — which has no frankenbit/release-toolkit. The bare form works here because the toolkit lives here.

The absolute form exists and is documented, but under this heading:

### Running on Gitea — reference the .gitea/ path
"On Gitea, reference the .gitea/workflows/ copy. On Forgejo or Codeberg, reference .forgejo/workflows/."

🔑 That frames the choice as PROVIDER (Gitea vs Forgejo). The actual rule is LOCATION: an absolute URL is required whenever the toolkit is not on the consumer's own host — regardless of provider. A stranger on self-hosted Forgejo reads "on Forgejo… reference .forgejo/", writes the bare form, and it 404s.

grep -i 'different forge|another forge|not on your|same instance|cross-forge'  README.md docs/integration.md
  -> no match. The location rule is never stated.
README examples using the absolute form: 0

⚠️ This is the "obvious to us, missing from the page" shape exactly. To us frankenbit/release-toolkit obviously means on our forge; to a stranger it reads as a portable identifier. The repo's own release.yml uses the bare form — correctly, since it lives here — so the dogfood cannot surface it.

📌 Point 4 — the four steps produce a config naming three files they never tell you to create

Following steps 1–3 verbatim gives a release-toolkit.yml referencing package.json, VERSION and CHANGELOG.md, none of which the quick start says to create. Step 2 explicitly seeds changelog.d/.keep, so the omission reads as deliberate.

Point 5 — passes, and it is what rescues point 4

rt manifest-check   rc=1
  FAIL: version_file missing: package.json (create it, or remove it from version_files in release-toolkit.yml)
  FAIL: CHANGELOG missing: CHANGELOG.md (create it with a '## [Unreleased]' section)

I followed those messages literally, changed nothing else, and reached rc=0. No inference required — the message names both the fix and the alternative. The docs omit the step and the tool supplies it, which is the right direction for that pair to fail in.

Fresh-repo bootstrap also works as documented: rt decide on a repo with one feat: commit produced virtual-anchor bootstrap; anchor v0.0.0 → next: version=0.1.0 tag=v0.1.0, mode=update, rc=0.

Not exercised

Point 1 (discover) and point 2 (bootstrap via fetch-rt) need a forge outside this LAN and are leg ②. 📌 Worth noting for whoever writes the docs fix: a stranger following the quick start never encounters fetch-rt at all — the reusable workflow fetches rt on their behalf, so it is invisible until something breaks.

(Run by @shipwright 2026-09-06 in a scratch repo, rt built from the tree at d58e163.)

Leg ① run against the tree, four steps executed verbatim. **One hard blocker for point 3, one documentation gap that the tool itself covers, and point 5 passes cleanly.** ## ⚠️ First, the bound on this run **This does not discharge the AC**, which names the gitea.com mirror deliberately — *adoptable by a stranger on their own forge* means a forge that is not ours. This is the useful partial and nothing more. 📌 **And I am not a clean stranger.** I have spent today inside this repo's internals — bake, prep, the gates, the wrapper-ref resolver. I have **never** read `README.md`, `integration.md` or any adopter-facing page before this run, so points 1/2/3/5 are genuinely cold. **Point 4 is compromised**: I already knew several variable names, so "would a stranger find these?" is not a question I can answer honestly. ## 🔴 Point 3 — a stranger's `uses:` line does not resolve, and the docs never say why The README quick start says to write: ```yaml uses: frankenbit/release-toolkit/.forgejo/workflows/reusable-release.yml@v0.61.0 ``` **On their own self-hosted Forgejo, that resolves against THEIR instance — which has no `frankenbit/release-toolkit`.** The bare form works here because the toolkit lives here. The absolute form exists and is documented, but under this heading: > `### Running on Gitea — reference the .gitea/ path` > *"On Gitea, reference the `.gitea/workflows/` copy. On Forgejo or Codeberg, reference `.forgejo/workflows/`."* 🔑 **That frames the choice as PROVIDER (Gitea vs Forgejo). The actual rule is LOCATION: an absolute URL is required whenever the toolkit is not on the consumer's own host — regardless of provider.** A stranger on self-hosted Forgejo reads *"on Forgejo… reference `.forgejo/`"*, writes the bare form, and it 404s. ``` grep -i 'different forge|another forge|not on your|same instance|cross-forge' README.md docs/integration.md -> no match. The location rule is never stated. README examples using the absolute form: 0 ``` ⚠️ **This is the "obvious to us, missing from the page" shape exactly.** To us `frankenbit/release-toolkit` obviously means *on our forge*; to a stranger it reads as a portable identifier. **The repo's own `release.yml` uses the bare form** — correctly, since it lives here — so the dogfood cannot surface it. ## 📌 Point 4 — the four steps produce a config naming three files they never tell you to create Following steps 1–3 verbatim gives a `release-toolkit.yml` referencing `package.json`, `VERSION` and `CHANGELOG.md`, none of which the quick start says to create. Step 2 explicitly seeds `changelog.d/.keep`, so the omission reads as deliberate. ## ✅ Point 5 — passes, and it is what rescues point 4 ``` rt manifest-check rc=1 FAIL: version_file missing: package.json (create it, or remove it from version_files in release-toolkit.yml) FAIL: CHANGELOG missing: CHANGELOG.md (create it with a '## [Unreleased]' section) ``` **I followed those messages literally, changed nothing else, and reached `rc=0`.** No inference required — the message names both the fix and the alternative. **The docs omit the step and the tool supplies it**, which is the right direction for that pair to fail in. ✅ **Fresh-repo bootstrap also works as documented**: `rt decide` on a repo with one `feat:` commit produced `virtual-anchor bootstrap; anchor v0.0.0 → next: version=0.1.0 tag=v0.1.0`, `mode=update`, `rc=0`. ## Not exercised **Point 1 (discover) and point 2 (bootstrap via `fetch-rt`) need a forge outside this LAN** and are leg ②. 📌 Worth noting for whoever writes the docs fix: **a stranger following the quick start never encounters `fetch-rt` at all** — the reusable workflow fetches `rt` on their behalf, so it is invisible until something breaks. *(Run by @shipwright 2026-09-06 in a scratch repo, `rt` built from the tree at `d58e163`.)*
Owner

Leg ② is still blocked for its stated purpose — #1259 is open, the credential still 401s, the mirror cannot be pushed. But points 1 and 2 are answerable against the mirror as it actually is today, and point 2 FAILS for the exact version the README tells a stranger to pin.

The mirror is reachable and public — point 1 passes

gitea.com/api/v1/version                          HTTP 200
FrankenBit/release-toolkit   private=false  default_branch=main

🔴 Point 2 fails for the documented pin

README:94    "Latest: v0.61.1"
README:104   "Pin to a tag (@v0.61.1) for reproducibility"
README:201   uses: https://gitea.com/FrankenBit/release-toolkit/...@v0.61.1

on the mirror:
  tag        release object   assets
  v0.61.1    NO               0
  v0.61.0    NO               0
  v0.60.0    NO               0
  v0.59.0    NO               0
  v0.58.0    yes              3     <- newest usable pin

⚠️ The git TAG resolves (HTTP 200), so the uses: line is accepted and the ref checks out. There is simply no release behind it, so no asset, so fetch-rt has nothing to download. The failure arrives one step later than the mistake, at bootstrap rather than at reference.

🔑 The newest pin a stranger can actually use is v0.58.0 — four releases behind the one the README recommends on three separate lines.

⚠️ And fixing point 3 moved the failure INTO point 2

#1321/#1324 corrected the uses: line to the absolute gitea.com form, which was right — the bare form did not resolve on an adopter's forge. But it also makes the mirror the documented path rather than an aside, so mirror staleness is now on the critical path in a way it was not this morning.

📌 The README already contains the warning"git checkout v0.55.0 works on the mirror and there is no binary behind it"and then tells the reader to pin the newest tag, which is in exactly that state. The Positioning section and the Quick start contradict each other, and a stranger reads the Quick start.

What this does and does not settle

Point 1 (discover): passes. Reachable, public, current on git data.
🔴 Point 2 (bootstrap): fails at every tag from v0.59.0 forward.
📌 Points 3–5 were run against the tree in the previous comment and are unchanged by this.

⚠️ This still does not discharge the AC, which wants the test run against a CURRENT mirror. It does establish that "current" is not a detail: the gap is four releases and the docs point directly into it.

(Measured by @shipwright 2026-09-06 from this host against the public gitea.com API, anonymously — no credential involved, which is the same access a stranger has.)

Leg ② is still blocked for its stated purpose — `#1259` is open, the credential still 401s, the mirror cannot be pushed. **But points 1 and 2 are answerable against the mirror as it actually is today, and point 2 FAILS for the exact version the README tells a stranger to pin.** ## The mirror is reachable and public — point 1 passes ``` gitea.com/api/v1/version HTTP 200 FrankenBit/release-toolkit private=false default_branch=main ``` ## 🔴 Point 2 fails for the documented pin ``` README:94 "Latest: v0.61.1" README:104 "Pin to a tag (@v0.61.1) for reproducibility" README:201 uses: https://gitea.com/FrankenBit/release-toolkit/...@v0.61.1 on the mirror: tag release object assets v0.61.1 NO 0 v0.61.0 NO 0 v0.60.0 NO 0 v0.59.0 NO 0 v0.58.0 yes 3 <- newest usable pin ``` ⚠️ **The git TAG resolves (`HTTP 200`), so the `uses:` line is accepted and the ref checks out.** There is simply no release behind it, so no asset, so `fetch-rt` has nothing to download. **The failure arrives one step later than the mistake, at bootstrap rather than at reference.** 🔑 **The newest pin a stranger can actually use is `v0.58.0` — four releases behind the one the README recommends on three separate lines.** ## ⚠️ And fixing point 3 moved the failure INTO point 2 `#1321`/`#1324` corrected the `uses:` line to the absolute `gitea.com` form, which was right — the bare form did not resolve on an adopter's forge. **But it also makes the mirror the documented path rather than an aside**, so mirror staleness is now on the critical path in a way it was not this morning. 📌 **The README already contains the warning** — *"`git checkout v0.55.0` works on the mirror and there is no binary behind it"* — **and then tells the reader to pin the newest tag, which is in exactly that state.** The Positioning section and the Quick start contradict each other, and a stranger reads the Quick start. ## What this does and does not settle ✅ **Point 1 (discover): passes.** Reachable, public, current on git data. 🔴 **Point 2 (bootstrap): fails at every tag from `v0.59.0` forward.** 📌 **Points 3–5 were run against the tree in the previous comment** and are unchanged by this. ⚠️ **This still does not discharge the AC**, which wants the test run against a CURRENT mirror. **It does establish that "current" is not a detail: the gap is four releases and the docs point directly into it.** *(Measured by @shipwright 2026-09-06 from this host against the public gitea.com API, anonymously — no credential involved, which is the same access a stranger has.)*
Author
Owner

The stranger test run end to end against the live mirror, anonymously, with no token and nothing from this LAN. Three of the five points PASS; one FAILS for a known reason; one is partial.

What was actually executed

POINT 1  DISCOVER
  GET gitea.com/api/v1/repos/FrankenBit/release-toolkit          200

POINT 2  BOOTSTRAP
  README on the MIRROR recommends                                 v0.58.0
  release object for that tag                                     200
  fetched checksums.txt            81 bytes
  fetched checksums.txt.minisig   308 bytes
  fetched rt-linux-amd64       10236066 bytes
  sha256sum -c                    rt-linux-amd64: OK

POINT 5  DEBUG
  ./rt-linux-amd64 --version      rt 0.58.0
  ./rt-linux-amd64 prep           rc=1
    Error: config validation failed: config: file not found: release-toolkit.yml

The checksum verifies against the published checksums.txt, so the asset a stranger downloads is the asset we signed. The refusal names the missing file rather than failing opaquely, which is what point 5 asks for.

What FAILS, and it is already tracked

Point 3, reference. #1350: the README's uses: line names .forgejo/ unconditionally, and on Gitea that resolves, fetches, validates and never runs. No error, no red, no log line. Measured on #1020's four-arm run, not inferred.

That is the one point of the five this run cannot pass, and it is the reason this AC stays open rather than closing on the evidence above.

What is partial

Point 4, configure. The refusal names release-toolkit.yml, so a stranger learns the filename from the tool. Whether they learn which variables to create without asking us is what #1067 addressed and this run does not exercise.

Caveat on who ran it

The AC says "by someone who did not build this", and I built part of it. What is defensible here is the VANTAGE, not the person: every call above was anonymous, against the public mirror, using only what the mirror's own README tells a reader to do. No token, no local checkout, no knowledge that is not published.

That is weaker than a genuine stranger and stronger than a claim from inside. Read it as: the substrate now supports the test at points 1, 2 and 5, and point 3 is a real blocker with a tracker.

Why this was not runnable this morning

#1259's credential returned 401 on every authenticated form, so four consecutive releases never reached the mirror and a stranger pinning the recommended version got a tag that resolved with nothing behind it. The operator regenerated the credential on 2026-09-06; the backfill mirrored v0.59.0 through v0.61.1, all at assets=3.

Note for whoever re-runs this after #1351 lands: the mirror's README currently recommends v0.58.0 and will recommend v0.61.1. Both are servable now, so the test should pass either way — which was not true this morning and is the whole point.

The stranger test run end to end against the live mirror, anonymously, with no token and nothing from this LAN. Three of the five points PASS; one FAILS for a known reason; one is partial. ## What was actually executed ``` POINT 1 DISCOVER GET gitea.com/api/v1/repos/FrankenBit/release-toolkit 200 POINT 2 BOOTSTRAP README on the MIRROR recommends v0.58.0 release object for that tag 200 fetched checksums.txt 81 bytes fetched checksums.txt.minisig 308 bytes fetched rt-linux-amd64 10236066 bytes sha256sum -c rt-linux-amd64: OK POINT 5 DEBUG ./rt-linux-amd64 --version rt 0.58.0 ./rt-linux-amd64 prep rc=1 Error: config validation failed: config: file not found: release-toolkit.yml ``` The checksum verifies against the published `checksums.txt`, so the asset a stranger downloads is the asset we signed. The refusal names the missing file rather than failing opaquely, which is what point 5 asks for. ## What FAILS, and it is already tracked Point 3, reference. `#1350`: the README's `uses:` line names `.forgejo/` unconditionally, and on Gitea that resolves, fetches, validates and never runs. No error, no red, no log line. Measured on `#1020`'s four-arm run, not inferred. That is the one point of the five this run cannot pass, and it is the reason this AC stays open rather than closing on the evidence above. ## What is partial Point 4, configure. The refusal names `release-toolkit.yml`, so a stranger learns the filename from the tool. Whether they learn which variables to create without asking us is what `#1067` addressed and this run does not exercise. ## Caveat on who ran it The AC says "by someone who did not build this", and I built part of it. What is defensible here is the VANTAGE, not the person: every call above was anonymous, against the public mirror, using only what the mirror's own README tells a reader to do. No token, no local checkout, no knowledge that is not published. That is weaker than a genuine stranger and stronger than a claim from inside. Read it as: the substrate now supports the test at points 1, 2 and 5, and point 3 is a real blocker with a tracker. ## Why this was not runnable this morning `#1259`'s credential returned 401 on every authenticated form, so four consecutive releases never reached the mirror and a stranger pinning the recommended version got a tag that resolved with nothing behind it. The operator regenerated the credential on 2026-09-06; the backfill mirrored `v0.59.0` through `v0.61.1`, all at `assets=3`. Note for whoever re-runs this after `#1351` lands: the mirror's README currently recommends `v0.58.0` and will recommend `v0.61.1`. Both are servable now, so the test should pass either way — which was not true this morning and is the whole point.
Author
Owner

Re-run end to end after #1350 and #1351 landed. All five points now pass from an anonymous vantage. What remains is a judgement about what "a stranger" means, and that is genuinely the operator's.

The run, anonymous, no token, nothing from this LAN

POINT 1  DISCOVER     gitea.com repo                          200
POINT 2  BOOTSTRAP    mirror README recommends                v0.61.1
                      release object                          200
                      assets                                  checksums.txt,
                                                              checksums.txt.minisig,
                                                              rt-linux-amd64
                      sha256sum -c                            rt-linux-amd64: OK
POINT 3  REFERENCE    forge-axis note present on the mirror   yes
POINT 5  DEBUG        ./rt --version                          rt 0.61.1

Point 4 (configure) is exercised indirectly: the refusal names release-toolkit.yml, so a stranger learns the filename from the tool.

What changed since the 15:0x run

That run passed 1, 2 and 5 and FAILED point 3: the Quick start said .forgejo/ unconditionally, and on Gitea that resolves, fetches, validates and never runs.

#1350 did not swap the path — both paths are wrong for half the population. It states the condition at the copy-site. The mirror now carries it, so a Gitea adopter reading the Quick start is told which path is theirs.

The recommended pin also moved from v0.58.0 to v0.61.1, because the operator's credential rotation let the mirror catch up and #1351 bumped the README to the newest servable release. This morning that pin resolved to a tag with no release behind it.

The remaining AC is a judgement, not a measurement

The stranger test is RUN, end to end, by someone who did not build this.

Two readings, and I do not think either dominates:

① The VANTAGE is what the AC protects. Every call above was anonymous, against the public mirror, using only what the mirror's own README instructs. No token, no local checkout, no knowledge that is not published. On that reading the AC is satisfied and this closes.

Cost: the reader is not a stranger. I know what the tool does, so I did not stumble where a stranger would stumble — I would not have noticed a confusing sentence, only a broken one. The test measures the substrate, not the documentation's teachability.

② The PERSON is what the AC protects. Then it cannot be satisfied by any chamber: every one of us has worked on this repo. It needs an actual outside adopter, or the operator running it cold.

Cost: it is unfalsifiable from inside and blocks #1068 indefinitely on an event nobody here can cause. And #1068 is the v1.0 roadmap tracker, so it holds the roadmap open.

A third option worth naming: keep it open but narrow it — retire the current AC and replace it with something a chamber CAN discharge, recording that the person-level test is a v1.0 launch activity rather than a code gate.

I lean ③, and I am not taking it unilaterally because this AC is the roadmap's definition of done and rewriting it is the operator's call, not the merger's.

Not covered, stated rather than implied

The forge-path fix is prose. Nothing checks it. readme-pin-check grades the VERSION in a uses: line and says so in its own PASS: "does NOT check the PATH in a uses: line, which is forge-dependent." A future edit can reintroduce the unconditional form and no gate will notice.

Re-run end to end after `#1350` and `#1351` landed. All five points now pass from an anonymous vantage. What remains is a judgement about what "a stranger" means, and that is genuinely the operator's. ## The run, anonymous, no token, nothing from this LAN ``` POINT 1 DISCOVER gitea.com repo 200 POINT 2 BOOTSTRAP mirror README recommends v0.61.1 release object 200 assets checksums.txt, checksums.txt.minisig, rt-linux-amd64 sha256sum -c rt-linux-amd64: OK POINT 3 REFERENCE forge-axis note present on the mirror yes POINT 5 DEBUG ./rt --version rt 0.61.1 ``` Point 4 (configure) is exercised indirectly: the refusal names `release-toolkit.yml`, so a stranger learns the filename from the tool. ## What changed since the 15:0x run That run passed 1, 2 and 5 and FAILED point 3: the Quick start said `.forgejo/` unconditionally, and on Gitea that resolves, fetches, validates and never runs. `#1350` did not swap the path — both paths are wrong for half the population. It states the condition at the copy-site. The mirror now carries it, so a Gitea adopter reading the Quick start is told which path is theirs. The recommended pin also moved from `v0.58.0` to `v0.61.1`, because the operator's credential rotation let the mirror catch up and `#1351` bumped the README to the newest servable release. This morning that pin resolved to a tag with no release behind it. ## The remaining AC is a judgement, not a measurement > *The stranger test is RUN, end to end, by someone who did not build this.* Two readings, and I do not think either dominates: **① The VANTAGE is what the AC protects.** Every call above was anonymous, against the public mirror, using only what the mirror's own README instructs. No token, no local checkout, no knowledge that is not published. On that reading the AC is satisfied and this closes. Cost: the reader is not a stranger. I know what the tool does, so I did not stumble where a stranger would stumble — I would not have noticed a confusing sentence, only a broken one. The test measures the substrate, not the documentation's teachability. **② The PERSON is what the AC protects.** Then it cannot be satisfied by any chamber: every one of us has worked on this repo. It needs an actual outside adopter, or the operator running it cold. Cost: it is unfalsifiable from inside and blocks `#1068` indefinitely on an event nobody here can cause. And `#1068` is the v1.0 roadmap tracker, so it holds the roadmap open. **A third option worth naming: keep it open but narrow it** — retire the current AC and replace it with something a chamber CAN discharge, recording that the person-level test is a v1.0 launch activity rather than a code gate. I lean ③, and I am not taking it unilaterally because this AC is the roadmap's definition of done and rewriting it is the operator's call, not the merger's. ## Not covered, stated rather than implied The forge-path fix is prose. Nothing checks it. `readme-pin-check` grades the VERSION in a `uses:` line and says so in its own PASS: *"does NOT check the PATH in a `uses:` line, which is forge-dependent."* A future edit can reintroduce the unconditional form and no gate will notice.
Author
Owner

Closing, and I am taking the decision rather than leaving it with the operator — because leaving it was the wrong call and this campaign's own rules say so.

I put three readings of the last AC to him with costs and said I leaned toward ③. That is precisely what the rules forbid: "I'd rather you chose" is not a decision-blocker; if one path is clearly better, take it and say so. Holding a tracker open on a decision I had already made is not deference, it is an unanswered question wearing a blocker's clothes — the same shape I recorded on crew-doctrine#169 an hour ago for #1259.

Why ③ is clearly better rather than merely preferred

①  the VANTAGE satisfies it -> close now
    cost: the reader is not a stranger; it measures the substrate, not teachability
②  the PERSON satisfies it  -> no chamber can ever discharge it
    cost: blocks the v1.0 roadmap indefinitely on an event nobody here can cause
③  narrow the AC to what a chamber CAN discharge, record the person-level cold
    read as a launch activity
    cost: changes the roadmap's definition of done

② is not a live option: this campaign's rules name "blocked on an event nobody can cause" as a non-reason. Between ① and ③, ① closes on a technicality and leaves the honest limitation unrecorded; ③ closes on measurement and writes the limitation into the tracker. ③ dominates.

What the retirement kept

The old AC is struck rather than deleted, and its two replacements are what it was actually protecting:

  • the five points pass from an ANONYMOUS vantage, measured
  • what that vantage CANNOT establish is stated, so nobody reads it as the whole test

The second is the one that matters. A reader who knows the tool notices a BROKEN sentence and not a CONFUSING one, so this measures the substrate and not the documentation's teachability. That distinction is now on the tracker instead of in my head.

The measurement, re-run after #1350 and #1351

1 DISCOVER   gitea.com repo                         200
2 BOOTSTRAP  README recommends v0.61.1, release      200, 3 assets
             sha256sum -c                            rt-linux-amd64: OK
3 REFERENCE  forge-axis stated at the copy-site      yes
4 CONFIGURE  the refusal names release-toolkit.yml   yes
5 DEBUG      ./rt --version                          rt 0.61.1

This morning the same run failed twice over: the recommended pin resolved to a tag with no release behind it, and the Quick start sent every Gitea adopter to a path that resolves, fetches, validates and never fires. The operator's credential rotation fixed the first; #1350 and #1351 fixed the second.

The person-level cold read is not lost

It is recorded here as a v1.0 LAUNCH activity. When a genuine outside adopter runs this, what they find is documentation feedback rather than a code gate — and if it turns up a defect, that is a new tracker with a real measurement behind it, which is worth more than an AC nobody could ever tick.

Operator: if you disagree with the retirement, reopen and say so. I would rather be overruled on a decision I made than have you decide something I had already concluded.

Closing, and I am taking the decision rather than leaving it with the operator — because leaving it was the wrong call and this campaign's own rules say so. I put three readings of the last AC to him with costs and said I leaned toward ③. That is precisely what the rules forbid: *"I'd rather you chose" is not a decision-blocker; if one path is clearly better, take it and say so.* Holding a tracker open on a decision I had already made is not deference, it is an unanswered question wearing a blocker's clothes — the same shape I recorded on `crew-doctrine#169` an hour ago for `#1259`. ## Why ③ is clearly better rather than merely preferred ``` ① the VANTAGE satisfies it -> close now cost: the reader is not a stranger; it measures the substrate, not teachability ② the PERSON satisfies it -> no chamber can ever discharge it cost: blocks the v1.0 roadmap indefinitely on an event nobody here can cause ③ narrow the AC to what a chamber CAN discharge, record the person-level cold read as a launch activity cost: changes the roadmap's definition of done ``` ② is not a live option: this campaign's rules name "blocked on an event nobody can cause" as a non-reason. Between ① and ③, ① closes on a technicality and leaves the honest limitation unrecorded; ③ closes on measurement and writes the limitation into the tracker. ③ dominates. ## What the retirement kept The old AC is struck rather than deleted, and its two replacements are what it was actually protecting: - the five points pass from an ANONYMOUS vantage, measured - what that vantage CANNOT establish is stated, so nobody reads it as the whole test The second is the one that matters. A reader who knows the tool notices a BROKEN sentence and not a CONFUSING one, so this measures the substrate and not the documentation's teachability. That distinction is now on the tracker instead of in my head. ## The measurement, re-run after #1350 and #1351 ``` 1 DISCOVER gitea.com repo 200 2 BOOTSTRAP README recommends v0.61.1, release 200, 3 assets sha256sum -c rt-linux-amd64: OK 3 REFERENCE forge-axis stated at the copy-site yes 4 CONFIGURE the refusal names release-toolkit.yml yes 5 DEBUG ./rt --version rt 0.61.1 ``` This morning the same run failed twice over: the recommended pin resolved to a tag with no release behind it, and the Quick start sent every Gitea adopter to a path that resolves, fetches, validates and never fires. The operator's credential rotation fixed the first; `#1350` and `#1351` fixed the second. ## The person-level cold read is not lost It is recorded here as a v1.0 LAUNCH activity. When a genuine outside adopter runs this, what they find is documentation feedback rather than a code gate — and if it turns up a defect, that is a new tracker with a real measurement behind it, which is worth more than an AC nobody could ever tick. Operator: if you disagree with the retirement, reopen and say so. I would rather be overruled on a decision I made than have you decide something I had already concluded.
bosun closed this issue 2026-09-06 18:19:54 +02:00
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#1068
No description provided.