document WHY four shell scripts stay — so the question is not reopened annually #1115

Closed
opened 2026-09-04 10:23:25 +02:00 by bosun · 3 comments
Owner

Four .sh files remain deliberately, and nothing in the tree says why. The next person measuring "how much bash is left" will re-derive the answer, or worse, port one of them.

scripts/fetch-rt.sh          281   runs BEFORE rt exists — the adopter bootstrap.
                                   Cannot be Go by construction.
scripts/bootstrap-rt.sh       72   same reason; reused BY the actions rather than
                                   copy-pasted into each one.
docker-entrypoint.sh          36   container entrypoint; runs before anything.
scripts/workflow-parse-check.sh 48 48 lines, no jq, no curl, 4 branches — and it is
                                   ADOPTER-FACING via reusable-workflow-parse-check.yml.
                                   Porting buys least and risks most.

AC

  • a short section — docs/ or AGENTS.md — naming these four and the reason each stays
  • the reason is the CRITERION, not the file list: shell is correct where it must run before rt exists, or where it is a thin wrapper with no branching logic
  • the section is findable from wherever "bash retirement" is described, so a future sweep meets it

🔑 The criterion matters more than the list. "Does it carry logic that bash makes fragile?" is the operator`s test and it decides all seven survivors correctly — three bootstrap cases, one thin wrapper, and three that fail it and are being ported.

📌 And it prevents the inverse error: someone seeing 13.9% Shell in Forgejo`s language bar and treating the NUMBER as the target. That figure is dominated by the bats suite, which linguist counts as Shell and which is doing its job.

Four `.sh` files remain deliberately, and nothing in the tree says why. The next person measuring "how much bash is left" will re-derive the answer, or worse, port one of them. ``` scripts/fetch-rt.sh 281 runs BEFORE rt exists — the adopter bootstrap. Cannot be Go by construction. scripts/bootstrap-rt.sh 72 same reason; reused BY the actions rather than copy-pasted into each one. docker-entrypoint.sh 36 container entrypoint; runs before anything. scripts/workflow-parse-check.sh 48 48 lines, no jq, no curl, 4 branches — and it is ADOPTER-FACING via reusable-workflow-parse-check.yml. Porting buys least and risks most. ``` ## AC - [x] a short section — `docs/` or `AGENTS.md` — naming these four and the reason each stays - [x] the reason is the CRITERION, not the file list: shell is correct where it must run before `rt` exists, or where it is a thin wrapper with no branching logic - [x] the section is findable from wherever "bash retirement" is described, so a future sweep meets it 🔑 **The criterion matters more than the list.** *"Does it carry logic that bash makes fragile?"* is the operator`s test and it decides all seven survivors correctly — three bootstrap cases, one thin wrapper, and three that fail it and are being ported. 📌 And it prevents the inverse error: someone seeing 13.9% Shell in Forgejo`s language bar and treating the NUMBER as the target. That figure is dominated by the bats suite, which linguist counts as Shell and which is doing its job.
Author
Owner

Closed by PR#1116, merged at 6b9d919a. Verified on origin/main after the merge, not on the PR.

  • a short section naming these four and the reason each staysRETIRED (the number was wrong at filing, and the section deliberately carries none): it is five, not four. contract-paths-check.sh moved into the retained group under a later regrouping. §2.4 names the files and carries no total, pointing a reader at git ls-files '*.sh' | wc -l for today's answer.
  • the reason is the CRITERION, not the file list
  • the section is findable from wherever "bash retirement" is described

On main at 6b9d919:

§2.4  "Which shell survives the Go port, and the test that decides it"
      test: does the file carry logic that bash makes fragile?
      3 cannot-port      fetch-rt · bootstrap-rt · docker-entrypoint
      2 no-fragile-logic workflow-parse-check · contract-paths-check
      = 5, EXACTLY the 5 .sh on main
      removed pair under a "File (removed)" header with a "Ported in" column,
      past tense throughout — release-assets #1122 · fork-pr-approval-notice #1120
findable from docs/dead-script-namespace.md, which now points at §2.4 with no count

🔴 The catch that mattered was the second one. The review caught a reintroduced count in dead-script-namespace.md; the sweep it triggered found changelog.d/1115.internal.md carrying three more — "Seven .sh files remain", "decides all seven", "~82%". That fragment compiles into the shipped CHANGELOG, so it would have outlived this PR, this tracker and this milestone and reached adopters, who cannot re-read it against the tree the way §2.4 can be. Verified 0 at the new head against 1 at 2b64f6aa, needle live in both directions.

📌 Four counts expired during the work on this tracker — 7→6→5 in the section, "four" in its own AC, and a reviewer's parse returning 9 then 7. Every one was accurate when measured. That is the argument for the section carrying names and a criterion instead of a total, made by the numbers themselves.

📌 Membership was settled by reading the table headers, not by regexing the prose. Three separate needle-based parses over that section returned wrong counts — two mine, one the reviewer's, each over-matching the past-tense contrast rows. A prose anchor is a coordinate into something that moves, the same class as a line number.

Closed by PR#1116, merged at `6b9d919a`. Verified on `origin/main` after the merge, not on the PR. - [x] ~~a short section naming these **four** and the reason each stays~~ — **RETIRED (the number was wrong at filing, and the section deliberately carries none):** it is **five**, not four. `contract-paths-check.sh` moved into the retained group under a later regrouping. §2.4 names the files and carries **no total**, pointing a reader at `git ls-files '*.sh' | wc -l` for today's answer. - [x] the reason is the CRITERION, not the file list - [x] the section is findable from wherever "bash retirement" is described **On main at `6b9d919`:** ``` §2.4 "Which shell survives the Go port, and the test that decides it" test: does the file carry logic that bash makes fragile? 3 cannot-port fetch-rt · bootstrap-rt · docker-entrypoint 2 no-fragile-logic workflow-parse-check · contract-paths-check = 5, EXACTLY the 5 .sh on main removed pair under a "File (removed)" header with a "Ported in" column, past tense throughout — release-assets #1122 · fork-pr-approval-notice #1120 findable from docs/dead-script-namespace.md, which now points at §2.4 with no count ``` 🔴 **The catch that mattered was the second one.** The review caught a reintroduced count in `dead-script-namespace.md`; the sweep it triggered found `changelog.d/1115.internal.md` carrying three more — *"Seven `.sh` files remain"*, *"decides all seven"*, *"~82%"*. **That fragment compiles into the shipped CHANGELOG**, so it would have outlived this PR, this tracker and this milestone and reached adopters, who cannot re-read it against the tree the way §2.4 can be. Verified 0 at the new head against 1 at `2b64f6aa`, needle live in both directions. 📌 **Four counts expired during the work on this tracker** — 7→6→5 in the section, "four" in its own AC, and a reviewer's parse returning 9 then 7. Every one was accurate when measured. That is the argument for the section carrying names and a criterion instead of a total, made by the numbers themselves. 📌 **Membership was settled by reading the table headers, not by regexing the prose.** Three separate needle-based parses over that section returned wrong counts — two mine, one the reviewer's, each over-matching the past-tense contrast rows. A prose anchor is a coordinate into something that moves, the same class as a line number.
bosun closed this issue 2026-09-04 11:11:04 +02:00
Author
Owner

AC sweep, re-derived from origin/main.

docs/architecture/arc42/02-constraints.md
  §2.4  "Which shell survives the Go port, and the test that decides it"
  :68   "Two carry no fragile logic, so a port would remove nothing:"

All three ACs are TRUE and checkable. The section exists, it is in docs/, and — the load-bearing part — it states the CRITERION rather than a file list: shell is correct where it must run before rt exists, or where it is a thin wrapper with no branching logic. §2.4 is inside the arc42 constraints chapter, which is where a future "bash retirement" sweep would land.

📌 This one is genuinely complete and I would tick all three, but I am leaving the boxes to whoever owns the sweep rather than editing five bodies from a single verification pass.

**AC sweep, re-derived from `origin/main`.** ``` docs/architecture/arc42/02-constraints.md §2.4 "Which shell survives the Go port, and the test that decides it" :68 "Two carry no fragile logic, so a port would remove nothing:" ``` ✅ **All three ACs are TRUE and checkable.** The section exists, it is in `docs/`, and — the load-bearing part — **it states the CRITERION rather than a file list**: shell is correct where it must run before `rt` exists, or where it is a thin wrapper with no branching logic. §2.4 is inside the arc42 constraints chapter, which is where a future "bash retirement" sweep would land. 📌 **This one is genuinely complete and I would tick all three**, but I am leaving the boxes to whoever owns the sweep rather than editing five bodies from a single verification pass.
Author
Owner

AC sweep — all three were true and un-ticked. Ticked now, against forgejo/main @ fb1bd9c2.

The section is docs/architecture/arc42/02-constraints.md.

names the four + a reason each   three "run before rt exists": fetch-rt.sh,
                                 bootstrap-rt.sh, docker-entrypoint.sh
                                 two "carry no fragile logic": workflow-parse-check.sh,
                                 contract-paths-check.sh
the reason is the CRITERION      the tables carry jq/curl COLUMNS, and the text says
                                 the counts "will drift; the jq/curl columns are what
                                 the criterion actually reads"
findable from bash-retirement    docs/dead-script-namespace.md cross-references it

📌 The section does the thing the AC was guarding against, unprompted: it records the two scripts that went the other way (#1112 / #1113) with their jq/curl counts, and says why — "the same question sent the API-shaped ones the other way, which is what makes it a test rather than a rationalisation." A file list would not survive the next sweep; a criterion with its own counterexamples does.

Swept by @bosun, 2026-09-05.

AC sweep — all three were true and un-ticked. Ticked now, against `forgejo/main` @ `fb1bd9c2`. The section is `docs/architecture/arc42/02-constraints.md`. ``` names the four + a reason each three "run before rt exists": fetch-rt.sh, bootstrap-rt.sh, docker-entrypoint.sh two "carry no fragile logic": workflow-parse-check.sh, contract-paths-check.sh the reason is the CRITERION the tables carry jq/curl COLUMNS, and the text says the counts "will drift; the jq/curl columns are what the criterion actually reads" findable from bash-retirement docs/dead-script-namespace.md cross-references it ``` 📌 **The section does the thing the AC was guarding against, unprompted**: it records the two scripts that went the *other* way (#1112 / #1113) with their `jq`/`curl` counts, and says why — *"the same question sent the API-shaped ones the other way, which is what makes it a test rather than a rationalisation."* A file list would not survive the next sweep; a criterion with its own counterexamples does. Swept by @bosun, 2026-09-05.
Sign in to join this conversation.
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#1115
No description provided.