ceremony/lib
cluade-reviewer-andresmgsl 21c70e06a4 fix(forge): an empty REPO cannot become a fact, and the backend verbs are tested
Both panel blockers on c63a550.

@kimi found the one that mattered: facts.sh got the REPO fix, release.yml's
own four call sites did not. A workflow `run:` shell carries no `set -u`, so
an unset REPO expands empty and the verb addresses `repos//…` — which 404s,
and the 404 is then read as an ANSWER. Reproduced read-only against this
instance before fixing:

  forge_release_exists 0.4.1   -> "no", rc 0
  forge_commit_pulls 7fc9afe4  -> "[]", rc 0    (the !189 merge, which HAS a
                                                 merged PR behind it)

The first would have let the nothing-exists assert proceed to CREATE; the
second is the drill's original fabricated `labeled=no`, one step after the
fix meant to kill it.

Fixed once rather than at four call sites, as kimi suggested: forge_select
defaults REPO from GITHUB_REPOSITORY, and forgejo_api_base — which every
verb reaches the network through — refuses an empty REPO outright. No fifth
call site can forget it.

@grok and @kimi both blocked on the same AC gap: the backend suite did not
cover the five new verbs, so the two measured asymmetries had no offline
coverage. test/forge-backends.test.sh now has 15 cases for them — singular
/pull wrapped to an array, 404 as an empty array, 500 refusing, release
present/absent/unreadable, POST /tags vs /git/refs, the publish body, and
the REPO-empty must-fail. Mutation-checked: reading the plural path fails
one case, dropping the REPO guard fails the two must-fails.

1029 assertions, 22 suites, shellcheck-all and actionlint clean.

Refs #191

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 11:53:28 +00:00
..
changelog.sh fix: the sentinel's one-line contract is checked on the file, not the $(cat) word 2026-07-25 13:29:02 +00:00
closes_references.sh feat(forge): replace both gh api graphql sites with REST + a body parser 2026-08-02 18:41:03 +00:00
decide.sh feat: lib/decide.sh — the merge door's decision, pure and exhaustively tested 2026-07-22 18:59:29 +00:00
facts.sh fix(forge): facts.sh must set REPO, and the fragment must fit the bound 2026-08-04 11:37:00 +00:00
forge-forgejo.sh fix(forge): an empty REPO cannot become a fact, and the backend verbs are tested 2026-08-04 11:53:28 +00:00
forge-github.sh fix(forge): the release doors speak the shim, and an unread fact refuses (#191) 2026-08-04 11:31:06 +00:00
forge.sh fix(forge): an empty REPO cannot become a fact, and the backend verbs are tested 2026-08-04 11:53:28 +00:00
ruling.sh feat(forge): timeline normalizer, portable PR activity, shellcheck install (#188) 2026-08-03 15:13:30 +00:00
version.sh feat: lib/version.sh — one version abstraction, two backends 2026-07-22 18:19:50 +00:00