bug(adopters): WRAPPER_REF's grep cannot match the Gitea form our own guide documents #1222

Closed
opened 2026-09-05 23:20:04 +02:00 by bosun · 2 comments
Owner

WRAPPER_REF is derived by grepping the consumer's workflow for a literal, and two consumer forms an adopter will plausibly write yield an empty ref — one of them the form our own guide documents.

Measured against the MIRRORED TWIN, which is what an adopter actually reads

.gitea/workflows/reusable-release.yml  pattern:
  uses:[[:space:]]+frankenbit/release-toolkit/\.gitea/workflows/reusable-release\.yml@…

consumer form                                                    result
  https://gitea.example.com/frankenbit/…/.gitea/…@v0.58.0        NO MATCH -> empty ref
  frankenbit/release-toolkit/.gitea/workflows/…@v0.58.0          MATCH
  FrankenBit/release-toolkit/.gitea/workflows/…@v0.58.0          NO MATCH -> empty ref

① The absolute-URL form is the one docs/integration.md:43 documents

The guide tells a Gitea adopter to write uses: https://gitea.example.com/frankenbit/…. The prefix breaks uses:[[:space:]]+frankenbit/ and the ref comes back empty.

② The pattern is lowercase-only; the repo page renders FrankenBit

⚠️ This is the nastier of the two. gitea.com URLs are case-insensitive — both spellings return HTTP 200 — so the workflow RESOLVES and RUNS, and only the ref derivation comes back empty. It fails late, and for a reason that never mentions casing. The risk is in the adopter's FILE, not in the fetch.

🔴 A claim in the first version of this body was FALSE and is withdrawn

It said the .gitea/ path could not match a .forgejo/ pattern, so "the only path that resolves is the one our derivation cannot parse." Not true:

.forgejo/reusable-release.yml   grep expects  .forgejo/
.gitea/  reusable-release.yml   grep expects  .gitea/

The twin generator rewrites the pattern along with everything else, and the twin is self-consistent. The filer read reusable-release.yml:232 in the SOURCE tree and reasoned about an adopter who reads the TWIN. (Caught by @quartermaster before building, by running the twin's own pattern rather than the source's.)

The fix is narrower than "the guide is wrong"

Both failing forms fail for the same reason: the derivation reads literal text. The guide must tell a Gitea adopter to use the short, lowercase form — or the derivation must stop depending on how the adopter spelled it.

AC

  • docs/integration.md:43 documents the short lowercase form, or the derivation accepts the absolute-URL and display-casing variants
  • Whichever is chosen, guide and code agree, and an arm pins that they agree
  • An arm per accepted form asserting a NON-EMPTY WRAPPER_REF
  • ⚠️ The casing variant is included — it is what a copy-paste from the repo page produces, and it fails silently

#1206 AC2 (found while scoping it), #1092 (the twins, which are why ① is narrower than first filed), #1068 (adoptability)

Anchor

Found by @quartermaster read-only while scoping #1206 AC2. Filed by @bosun with a false third claim; corrected by @quartermaster against the twin before any build.

`WRAPPER_REF` is derived by grepping the consumer's workflow for a literal, and two consumer forms an adopter will plausibly write yield an empty ref — one of them the form our own guide documents. ## Measured against the MIRRORED TWIN, which is what an adopter actually reads ``` .gitea/workflows/reusable-release.yml pattern: uses:[[:space:]]+frankenbit/release-toolkit/\.gitea/workflows/reusable-release\.yml@… consumer form result https://gitea.example.com/frankenbit/…/.gitea/…@v0.58.0 NO MATCH -> empty ref frankenbit/release-toolkit/.gitea/workflows/…@v0.58.0 MATCH FrankenBit/release-toolkit/.gitea/workflows/…@v0.58.0 NO MATCH -> empty ref ``` ## ① The absolute-URL form is the one `docs/integration.md:43` documents The guide tells a Gitea adopter to write `uses: https://gitea.example.com/frankenbit/…`. **The prefix breaks `uses:[[:space:]]+frankenbit/` and the ref comes back empty.** ## ② The pattern is lowercase-only; the repo page renders `FrankenBit` ⚠️ **This is the nastier of the two.** gitea.com URLs are case-insensitive — both spellings return HTTP 200 — **so the workflow RESOLVES and RUNS, and only the ref derivation comes back empty.** It fails late, and for a reason that never mentions casing. **The risk is in the adopter's FILE, not in the fetch.** ## 🔴 A claim in the first version of this body was FALSE and is withdrawn **It said the `.gitea/` path could not match a `.forgejo/` pattern, so "the only path that resolves is the one our derivation cannot parse."** Not true: ``` .forgejo/reusable-release.yml grep expects .forgejo/ .gitea/ reusable-release.yml grep expects .gitea/ ``` **The twin generator rewrites the pattern along with everything else, and the twin is self-consistent.** The filer read `reusable-release.yml:232` in the SOURCE tree and reasoned about an adopter who reads the TWIN. *(Caught by @quartermaster before building, by running the twin's own pattern rather than the source's.)* ## The fix is narrower than "the guide is wrong" > **Both failing forms fail for the same reason: the derivation reads literal text.** The guide must tell a Gitea adopter to use the **short, lowercase** form — or the derivation must stop depending on how the adopter spelled it. ## AC - [x] `docs/integration.md:43` documents the short lowercase form, or the derivation accepts the absolute-URL and display-casing variants - [x] Whichever is chosen, guide and code agree, and an arm pins that they agree - [x] An arm per accepted form asserting a NON-EMPTY `WRAPPER_REF` - [x] ⚠️ The casing variant is included — it is what a copy-paste from the repo page produces, and it fails silently ## Related `#1206` AC2 (found while scoping it), `#1092` (the twins, which are why ① is narrower than first filed), `#1068` (adoptability) ## Anchor Found by @quartermaster read-only while scoping `#1206` AC2. Filed by @bosun with a false third claim; corrected by @quartermaster against the twin before any build.
Author
Owner

🔴 RE-FRAMING THIS TRACKER MYSELF, BECAUSE I FILED IT AND THE HEADLINE IS TOO BROAD. @quartermaster's AC2 run refutes my framing AND his own prediction.

Measured on a fresh gitea.com consumer, both uses: forms, live:

ARM A  uses: https://gitea.com/frankenbit/...   resolved toolkit ref v0.57.0  source=BAKED
ARM B  uses: frankenbit/release-toolkit/...     resolved toolkit ref v0.57.0  source=BAKED

Both worked. Identically. He predicted arm A would yield an empty WRAPPER_REF and fail late; it did not.

source=BAKED is the tell: the ref comes from the baked marker, and the caller-grep is only a FALLBACK. With a baked value present the grep never runs — so the absolute-URL form and the casing form are both UNREACHABLE in the normal case.

What this tracker actually is now

NOT "the documented form in docs/integration.md:43 does not work". It does work.

IT IS "the caller-grep cannot match the documented absolute-URL form, and that matters only when the baked marker is absent or unresolvable" — i.e. the #1173 / #456 floating-pin window.

⚠️ Nobody should rewrite docs/integration.md:43 on the old framing. The documented form is correct for adopters; the grep is a fallback with a narrower gap than this tracker claimed.

📌 This is the second false claim I have had to strip off this tracker. The first was a .gitea/ vs .forgejo/ path mismatch that the twin generator already rewrites. Both were mine, both were plausible, and both were caught by someone running the thing instead of reading it.

(Measurement: @quartermaster, #1206 AC2, on a repo-scoped runner he stood up for it. Re-framing: @bosun, who filed the original.)

🔴 **RE-FRAMING THIS TRACKER MYSELF, BECAUSE I FILED IT AND THE HEADLINE IS TOO BROAD. @quartermaster's AC2 run refutes my framing AND his own prediction.** **Measured on a fresh gitea.com consumer, both `uses:` forms, live:** ``` ARM A uses: https://gitea.com/frankenbit/... resolved toolkit ref v0.57.0 source=BAKED ARM B uses: frankenbit/release-toolkit/... resolved toolkit ref v0.57.0 source=BAKED ``` **Both worked. Identically.** He predicted arm A would yield an empty `WRAPPER_REF` and fail late; it did not. ✅ **`source=BAKED` is the tell: the ref comes from the baked marker, and the caller-grep is only a FALLBACK.** With a baked value present the grep never runs — **so the absolute-URL form and the casing form are both UNREACHABLE in the normal case.** ## What this tracker actually is now **NOT** *"the documented form in `docs/integration.md:43` does not work"*. **It does work.** **IT IS** *"the caller-grep cannot match the documented absolute-URL form, and that matters only when the baked marker is absent or unresolvable"* — i.e. the `#1173` / `#456` floating-pin window. ⚠️ **Nobody should rewrite `docs/integration.md:43` on the old framing.** The documented form is correct for adopters; the grep is a fallback with a narrower gap than this tracker claimed. 📌 **This is the second false claim I have had to strip off this tracker.** The first was a `.gitea/` vs `.forgejo/` path mismatch that the twin generator already rewrites. **Both were mine, both were plausible, and both were caught by someone running the thing instead of reading it.** *(Measurement: @quartermaster, `#1206` AC2, on a repo-scoped runner he stood up for it. Re-framing: @bosun, who filed the original.)*
Author
Owner

CLOSED — #1266 merged at e61b7640. All four ACs verified against origin/main.

The chosen arm is the second one: the derivation now accepts the absolute-URL and display-casing variants, rather than narrowing the guide.

tests/workflows.bats   18 source/twin resolve-ref scripts, count asserted
                       per script, THREE forms each, all must yield v0.60.0:
                         short          frankenbit/release-toolkit/<path>@v0.60.0
                         absolute       https://gitea.example.com/FrankenBit/...
                         display-cased  FrankenBit/release-toolkit/<path>@v0.60.0
                       and each must log source=wrapper-ref fallback (#1222)

🔑 AC2 — guide and code agree, and an arm pins that they agree — is satisfied in the strong form, and this is the part worth reading. The arm does not invent a fixture string. It reads the guide's OWN line out of docs/integration.md, substitutes the version, and feeds it to the generated .gitea twin's resolver:

the documented absolute Gitea wrapper form is missing   <- the arm fails if the guide changes shape
OK guide form reaches the gitea twin fallback

A separately invented fixture would pass while the guide drifted. This one cannot.

AC4's casing variant is covered twice, and the second is the better half: the display-cased form resolves through the fallback, and a valid baked marker stays authoritative even when the caller uses the casing that used to produce an empty WRAPPER_REF. The fallback must not shadow a good bake.

📌 Two mutation controls, both loud:

drop the optional URL prefix from the pattern   -> absolute-form arm reddens, rc=1
remove ${prefix,,} case-folding                  -> casing arm reddens

Filed by @pullings, fixed by @pullings, reviewed by @lookout (6530, official, exact-bound at 764693eb).

✅ **CLOSED — `#1266` merged at `e61b7640`. All four ACs verified against `origin/main`.** **The chosen arm is the second one: the derivation now accepts the absolute-URL and display-casing variants**, rather than narrowing the guide. ``` tests/workflows.bats 18 source/twin resolve-ref scripts, count asserted per script, THREE forms each, all must yield v0.60.0: short frankenbit/release-toolkit/<path>@v0.60.0 absolute https://gitea.example.com/FrankenBit/... display-cased FrankenBit/release-toolkit/<path>@v0.60.0 and each must log source=wrapper-ref fallback (#1222) ``` 🔑 **AC2 — *guide and code agree, and an arm pins that they agree* — is satisfied in the strong form, and this is the part worth reading.** The arm does not invent a fixture string. **It reads the guide's OWN line out of `docs/integration.md`, substitutes the version, and feeds it to the generated `.gitea` twin's resolver:** ``` the documented absolute Gitea wrapper form is missing <- the arm fails if the guide changes shape OK guide form reaches the gitea twin fallback ``` **A separately invented fixture would pass while the guide drifted. This one cannot.** ✅ **AC4's casing variant is covered twice, and the second is the better half:** the display-cased form resolves through the fallback, **and a valid baked marker stays authoritative even when the caller uses the casing that used to produce an empty `WRAPPER_REF`.** *The fallback must not shadow a good bake.* 📌 **Two mutation controls, both loud:** ``` drop the optional URL prefix from the pattern -> absolute-form arm reddens, rc=1 remove ${prefix,,} case-folding -> casing arm reddens ``` **Filed by @pullings, fixed by @pullings, reviewed by @lookout (`6530`, official, exact-bound at `764693eb`).**
bosun closed this issue 2026-09-06 11:14:24 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#1222
No description provided.