Record sixteen of the twenty-one undocumented changes in [Unreleased] #266

Merged
stephen merged 2 commits from docs/changelog-unreleased into main 2026-09-07 02:07:10 +00:00
Owner

Four fj improvements sit on main in no deployed binary, and release notes cut today would describe none of them: everything since v0.4.1 except the stack ship and pager work was missing from the CHANGELOG. docs/release.md step 1 says to update it first, and nothing enforces that.

The count

Three numbers here describe three different things, and none of them on its own is the number of entries:

non-merge commits, v0.4.1..f7fdce4                           25
  already recorded (#237, three stack commits; #236, pager)   4
  undocumented                                               21
    excluded as CI / coverage / test-only                      5   #255 #256 #260 #264 #265
    written up                                                16
entries added by this PR                                     16

Sixteen entries, covering sixteen commits, of the twenty-one that were undocumented. The excluded five were established by reading each diff rather than each subject line: #264 and #260 look like source changes and land entirely inside #[cfg(test)]. An earlier version of this body said eight were excluded; it is five. The three unnumbered #233 commits touch only release.yml, so they look like CI by file, but they are described in the release entry rather than dropped.

Entries do not map one to one onto commits, and the matching sixteens are a coincidence that cancels twice over: #251 is one commit producing five bullets (host-scoped FJ_TOKEN_<HOST> / FJ_SESSION_<HOST>, the cross-host FJ_TOKEN scoping, the platform-URL default and global --host, and the FJ_TOKEN-blocks---fjord binding), while the release work is five commits (#230, #233 x3, #234) collapsed into one.

What changed

  • ### Added: fj run logs, the Fjord Commons in fj instances, host-scoped FJ_TOKEN_<HOST> / FJ_SESSION_<HOST>.
  • New ### Changed section for the two that alter behaviour someone may rely on: pr merge now takes its style from the repository default instead of always using merge (#243), and a generic FJ_TOKEN is no longer sent to a host named explicitly with --host (#251).
  • ### Fixed: the discarded PR body on pr merge (#262), the two inert-Ctrl+C fixes (#261, #258), pr checks with no status contexts (#242), Forgejo 16 job logs (#239), negative system-actor ids (#231), named list-decode failures (#247), and the release pipeline and Homebrew formula (#230, #233, #234).

The release entry no longer says brew install fj is still serving 0.3.0. It served 0.3.0 from 22 to 30 July; the v0.4.1 assets were uploaded on 2026-07-30T02:59Z by the recovery dispatch #234 made possible, rasterstate/homebrew-tap moved to version "0.4.1" seven minutes later, and its three digests match the published SHA256SUMS. This file is where a release body comes from (release.yml:353-374), so that sentence would have been published verbatim.

No version chosen and nothing bumped. The section stays [Unreleased] so that decision stays the operator's one-line follow-up.

Testing

cargo fmt --all -- --check clean; the change is CHANGELOG.md only, +116 lines against main, no deletions.

Midwork-Id: lane=claude-7 repo=rasterstate/fj clone=fj-changelog branch=docs/changelog-unreleased head=86309e0d7fab70020bbdf2d0998836fae4b4f205 minted=2026-09-06T21:52:43Z

Four fj improvements sit on `main` in no deployed binary, and release notes cut today would describe none of them: everything since v0.4.1 except the stack ship and pager work was missing from the CHANGELOG. `docs/release.md` step 1 says to update it first, and nothing enforces that. **The count** Three numbers here describe three different things, and none of them on its own is the number of entries: ``` non-merge commits, v0.4.1..f7fdce4 25 already recorded (#237, three stack commits; #236, pager) 4 undocumented 21 excluded as CI / coverage / test-only 5 #255 #256 #260 #264 #265 written up 16 entries added by this PR 16 ``` **Sixteen entries, covering sixteen commits, of the twenty-one that were undocumented.** The excluded five were established by reading each diff rather than each subject line: `#264` and `#260` look like source changes and land entirely inside `#[cfg(test)]`. An earlier version of this body said eight were excluded; it is five. The three unnumbered `#233` commits touch only `release.yml`, so they look like CI by file, but they are described in the release entry rather than dropped. Entries do not map one to one onto commits, and the matching sixteens are a coincidence that cancels twice over: `#251` is one commit producing five bullets (host-scoped `FJ_TOKEN_<HOST>` / `FJ_SESSION_<HOST>`, the cross-host `FJ_TOKEN` scoping, the platform-URL default and global `--host`, and the `FJ_TOKEN`-blocks-`--fjord` binding), while the release work is five commits (#230, #233 x3, #234) collapsed into one. **What changed** - `### Added`: `fj run logs`, the Fjord Commons in `fj instances`, host-scoped `FJ_TOKEN_<HOST>` / `FJ_SESSION_<HOST>`. - New `### Changed` section for the two that alter behaviour someone may rely on: `pr merge` now takes its style from the repository default instead of always using `merge` (#243), and a generic `FJ_TOKEN` is no longer sent to a host named explicitly with `--host` (#251). - `### Fixed`: the discarded PR body on `pr merge` (#262), the two inert-Ctrl+C fixes (#261, #258), `pr checks` with no status contexts (#242), Forgejo 16 job logs (#239), negative system-actor ids (#231), named list-decode failures (#247), and the release pipeline and Homebrew formula (#230, #233, #234). The release entry no longer says `brew install fj` is still serving 0.3.0. It served 0.3.0 from 22 to 30 July; the v0.4.1 assets were uploaded on 2026-07-30T02:59Z by the recovery dispatch `#234` made possible, `rasterstate/homebrew-tap` moved to `version "0.4.1"` seven minutes later, and its three digests match the published SHA256SUMS. This file is where a release body comes from (`release.yml:353-374`), so that sentence would have been published verbatim. No version chosen and nothing bumped. The section stays `[Unreleased]` so that decision stays the operator's one-line follow-up. **Testing** `cargo fmt --all -- --check` clean; the change is CHANGELOG.md only, +116 lines against `main`, no deletions. Midwork-Id: lane=claude-7 repo=rasterstate/fj clone=fj-changelog branch=docs/changelog-unreleased head=86309e0d7fab70020bbdf2d0998836fae4b4f205 minted=2026-09-06T21:52:43Z
docs: record the 21 undocumented changes in [Unreleased]
All checks were successful
ci / check (pull_request) Successful in 11m39s
ci / live-e2e (pull_request) Successful in 2m10s
ci / coverage (pull_request) Successful in 2m33s
86309e0d7f
Everything since v0.4.1 except the stack ship and pager work was missing from
the CHANGELOG, so release notes cut today would have described none of what
people are upgrading for. `docs/release.md` step 1 says to update this first
and nothing enforces it.

25 non-merge commits land between v0.4.1 and f7fdce4. Four were already
recorded; this writes the other 21 up, minus eight that are CI, coverage or
test-only work with nothing in them for a reader deciding whether to upgrade.

Two of them change behaviour rather than fix it, and are filed as such: pr
merge now takes its style from the repository default instead of always using
`merge`, and a generic FJ_TOKEN is no longer sent to a host named explicitly
with --host.

No version chosen and no version bumped. The section stays `[Unreleased]` so
that stays a separate decision.
Author
Owner

CHANGES
Head reviewed: 86309e0d7f

Gate fj#266: the CHANGELOG a release will be cut from

Two things to fix, one of which ships. Everything else holds: I checked all sixteen entries rather
than the third asked for, and fifteen of them are accurate down to the constants. The constraint held
exactly, the format introduces nothing new, and the two behaviour changes are labelled and carry
migration instructions.

1. The count, reconciled

The three numbers describe three different things and none of them is the number of entries.

non-merge commits, v0.4.1..f7fdce4                                        25
  already recorded (#237, three stack commits; #236, the pager commit)     4
  undocumented                                                            21   <- the title's 21
    excluded as CI / coverage / test-only (#255 #256 #260 #264 #265)        5   <- the body says 8
    written up                                                            16
top-level bullets added by the diff                                       16

The title's "21" is right, and it is right about the wrong thing. 21 is the number of
undocumented commits, which is a true statement about main. The body then spends that 21 as though
it were the number this PR records ("writes up the other 21, minus eight"), which lands on 13. The
diff has 16 entries. So the title over-counts what the PR contains and the body under-counts it.

The body's "eight" is wrong. It is five. The excluded set, established by reading each diff
rather than each subject line, is exactly #255, #256, #260, #264, #265. I can see how eight
was reached: the three unnumbered commits from #233 touch only .forgejo/workflows/release.yml, so
by file they look like CI. They are not excluded, though. All three are described in the release
bullet, so counting them as dropped contradicts the diff.

16 commits producing 16 bullets is a coincidence, and the entries are not one to one. Two
offsetting reasons:

  • #251 is one commit and produces five bullets: host-scoped FJ_TOKEN_<HOST>/FJ_SESSION_<HOST>
    (Added), the cross-host FJ_TOKEN scoping and the platform-URL default and global --host for the
    auth subcommands (Changed), and the FJ_TOKEN-blocks---fjord clap binding (Fixed).
  • The release work is five commits collapsed into one bullet: #230 (5d47897), #233
    (754987f, 69697ac, a03aa35) and #234 (c7d8e0f).

Plus four and minus four cancel. That is fine, and it is the right shape for a changelog, but it
means the count has to be stated as entries rather than derived from commits.

Which number is right: sixteen entries, covering sixteen commits, of the twenty-one that were
undocumented.
The title and body should say that. It matters because the PR body is the audit trail
for a file nobody re-reads, and this is the second reader who has had to derive the mapping by hand.

The PR body's mapping is otherwise sound, with one attribution to correct: the brief names #252 as
the gateway/PAT behaviour change, and the PR body names #251. The PR body is right. #252 is
purely additive: before it there was no way to reach the Commons at all, so no one could be relying on
the old behaviour. The behaviour change is #251's token scoping.

2. Every entry, checked

I checked all sixteen against the merged PR, and against the source or the live forge wherever the
claim was checkable there. Fifteen are accurate. Highlights of what I verified independently rather
than by reading the PR body back:

entry independent check
host-scoped env vars Computed 'rasterhub.com'.encode().hex().upper() myself: 7261737465726875622E636F6D. Matches the entry and src/auth/mod.rs:194. host_env_session_var exists, so the FJ_SESSION_<HOST> half is real
fj run logs alias src/cli/workflow_run.rs:29 is #[command(alias = "log")]
pr merge style repo_default_merge_style (src/cli/pr.rs:1023) errors on unreadable AND on unsupported, naming the four supported styles. No fallback, as claimed
pr merge message src/api/pull_core.rs:387 is match opts.message { Some(m) => Some(m), None => <fetch body> }, so --message "" really does still send an empty body
Ctrl+C backstop src/interrupt.rs:43 GRACE = 250ms, :46 EXIT_INTERRUPTED = 130. Exact
OIDC timeouts src/fjord/oidc.rs:57 CALLBACK_TIMEOUT = 300s, :64 REQUEST_LINE_TIMEOUT = 10s. Exact
negative actor ids src/api/user.rs:12 is pub id: i64
the three new release guards All three exist in .forgejo/workflows/release.yml: fail_on_unmatched_files: true (457), the sha256 "" refusal (393-399), and the missing-CHANGELOG-section error (365-379)
the formula generator The heredoc at 428-437 has no cd and installs directly, with the reason in a comment. The generator really is fixed

The prose is close to the source PRs without being copied from them, and where it compresses it does
not distort. The #261 entry ("Ctrl+C was not slow, it was inert"), the #262 entry, and the #252
entry are all good writing for a reader rather than restatements of a diff.

The one that is not true

The release bullet says:

The v0.4.1 release was published with zero assets, which is why brew install fj has been
serving 0.3.0 since July

The first clause is true of July. The second is false now, and has been for five weeks. Checked on
the live forge:

v0.4.1 release:  draft=False   assets=5   published 2026-07-22T20:19:49Z
  SHA256SUMS, fj.rb, and three tarballs, all created 2026-07-30T02:59Z

rasterstate/homebrew-tap  Formula/fj.rb   version "0.4.1"
  sha256 99ee1c6a…  == release  fj-v0.4.1-darwin-aarch64.tar.gz
  sha256 a1a593e7…  == release  fj-v0.4.1-darwin-x86_64.tar.gz
  sha256 624ae2c0…  == release  fj-v0.4.1-linux-x86_64.tar.gz

All three digests match the published SHA256SUMS byte for byte, and the tap's install block carries
the generated comment ("The tarball has a single top-level dir ... that #{version} does not"), so
the tap is running the fixed generator's output rather than a hand-patched formula. brew install fj
installs 0.4.1 and has since 2026-07-30, thirteen minutes after #234 landed:

2026-07-22 20:19   v0.4.1 published, zero assets
2026-07-25 01:33   #230  overwrite: true
2026-07-30 02:10   #233  merged
2026-07-30 02:46   #234  dispatch input type
2026-07-30 02:59   v0.4.1's five assets uploaded by the recovery dispatch

So the outage lasted eight days, 22 to 30 July, and the same bullet describes the machinery that
ended it. As written it tells a reader on the release page that the tap is still stale, which is the
opposite of what shipped, and it invites them to install by hand or to conclude the fix in that
paragraph did not work.

This is the entry that matters most for it, too: the release body is taken from this CHANGELOG
section (release.yml:353-374), so this sentence is published verbatim to everyone who opens the
release page, and the brief's rule applies exactly. A reader trusts it and does not go look.

Fix is one clause: "which is why brew install fj served 0.3.0 from 22 to 30 July", or drop the
clause and keep "The v0.4.1 release was published with zero assets."

3. Nothing material was silently dropped

The five excluded commits, each judged on its diff rather than its subject:

commit PR what it touches verdict
f7fdce4 #265 .forgejo/workflows/ci.yml, CLAUDE.md CI only. Correctly excluded
96b7a13 #264 src/cli/auth_setup_git.rs +59, src/cli/editor.rs +109/-27 Looks like source, is not. Both hunks land inside #[cfg(test)] / mod setup_git_tests. The deletions are a test replacing hand-rolled env save/restore with an EnvVarGuard and a serialising mutex. Correctly excluded
60b51d4 #260 src/fjord/oidc.rs +128 Single hunk at mod tests, zero deletions. Correctly excluded
ba0f96a #256 deletes forseti-review.yml CI only. Correctly excluded
c8c52e0 #255 ci.yml, CLAUDE.md, Makefile, Cargo.lock Coverage calibration. The lockfile moves one transitive dependency, h2 0.4.14 to 0.4.16, which arrived with the toolchain rather than as a deliberate bump and is not a user-facing change under this file's conventions. Correctly excluded

The brief's two candidates are both in the bucket and both belong there. #264 is the one worth the
paragraph above: it has the largest source-file footprint of the five and the only deletions, and it
is still entirely test code.

The check in the other direction found the case that matters. #247's subject is
"pr: cover negative system reviewer ids", which reads test-only, and it is not: it adds
serde_path_to_error in src/client/mod.rs and a dependency in Cargo.toml. It is written up, as
"A failed list decode names where it failed", and the entry is accurate. A subject-line pass would
have dropped it.

#234 (c7d8e0f) is written up implicitly rather than explicitly, and that is the right call. Its
whole content is type: string on the dispatch input, without which Forgejo renders no field and the
recovery path cannot be dispatched at all. The bullet's claim that "a release can be re-run by
workflow_dispatch with a tag input" is only true because of it, so the reader gets the
user-facing fact and is spared the widget.

4. Behaviour changes are labelled

Both of the brief's candidates are in ### Changed and both carry the migration instruction:

  • #243, repo-default merge style. "Scripts that relied on the implicit merge need
    --style merge spelled out.
    " Bolded, in the entry. A reader relying on the old behaviour is
    warned in the sentence that would otherwise catch them out.
  • #251, generic FJ_TOKEN scoping. "Use FJ_TOKEN_<HOST> for that case. FJ_SESSION follows
    the same rule." Not bolded, but it is the whole migration and it is in the entry.

#252 is in ### Added, correctly: it is a capability that did not exist, not a change to one.

One candidate the brief did not name. #262, the merge-message default, is in ### Fixed, and it
changes what every fj pr merge without --message produces. I think Fixed is the right home,
because the old behaviour was silent data loss rather than a contract, and the entry does carry the
escape hatch ("--message "" still produces a deliberately empty body"). Worth knowing that a reader
scanning only ### Changed for things that will bite them will not see it. Not blocking.

The entry also omits something #262's own author flagged as unresolved: the default sits in the
shared merge(), so it applies to merge and rebase-merge as well as squash, where the loss was
measured, and that was "answered by construction rather than deliberately". Verified in
src/api/pull_core.rs:387, which is style-agnostic. One clause would cover it.

5. The four that motivated this

All present, and described for a reader:

  • #258 and #261, the two Ctrl+C entries, kept separate because they are different
    failures with different fixes. Both name the states that were confirmed rather than reasoned about.
  • #260 is not present, and should not be: it is a #[cfg(test)] addition to src/fjord/oidc.rs
    with zero deletions, and the behaviour it covers is #258's entry.
  • #262 says what the brief asked for and says it first: "fj pr merge no longer discards the
    pull request description.
    " It goes on to name the silence, which is the part that makes it worth
    reading: "the merge succeeded and the commit looked normal." Not "default merge message". Correct.

6. Format

Matches, and introduces nothing.

  • ### Added / ### Changed / ### Fixed, in Keep a Changelog order, with Changed inserted
    between the existing two rather than appended.
  • ### Changed is not a new heading here: 0.3.0, 0.2.0, 0.1.3 and 0.1.2 all carry one.
  • Voice matches: bolded lead clause then explanation, and the file's existing plain bullets are left
    alone. Wrapping is 79 columns against the file's existing 82.
  • No link-reference block at the foot of this file, so there is nothing that needed updating.

The constraint held exactly. One file, CHANGELOG.md, +115 / -0. git diff f7fdce4 HEAD over
Cargo.toml, Cargo.lock and README.md is empty. ## [Unreleased] is still ## [Unreleased], and
no version was chosen.

Worth knowing, and it is in this PR's favour: leaving it as [Unreleased] is now enforced rather
than remembered. release.yml:376 fails the run with "CHANGELOG.md has no '## [$VERSION]' section",
so a release cut before someone renames the heading stops at the publish job instead of shipping an
empty release body. The one-line follow-up cannot be skipped by accident, which is the right shape for
leaving that decision to the operator.

Required to land

  1. Correct the brew clause. It is the only false statement in the file, and it publishes.
  2. Restate the count in the title and body: sixteen entries, covering sixteen commits, of the
    twenty-one undocumented; five excluded as CI, coverage or test-only; entries do not map one to one
    onto commits, #251 giving five and the release work collapsing five into one.

Both are text-only and neither touches an entry's substance.

Non-blocking, worth a line each if the file is being edited anyway

  • The #262 entry could say the default applies to every merge style, not only squash.
  • The #251 migration instruction ("Use FJ_TOKEN_<HOST> for that case") is the same kind of
    warning #243 bolds, and is not bolded.
  • #251's own PR records that the README and docs still describe generic FJ_TOKEN as always
    checked first, which this change makes untrue. Out of scope for a CHANGELOG, and out of scope for
    this PR by its own constraint, but it is a real follow-up and nothing else is tracking it here.

Verdict

CHANGES, on two text fixes. The research behind this file is good and the entries are unusually
well checked: I verified every one of the sixteen against its PR and, where the claim named a
constant or a code path, against the source, and only one clause failed. That clause fails in the
direction that matters, in the longest entry, in the part that gets published, and it says a thing is
broken that this fleet fixed five weeks ago.

The count is the second fix and the cheaper one. It does not ship, but the brief is right that a PR
which miscounts its own contents is the shape worth stopping, and the miscount here is real: eight
excluded is five, and the three commits counted as dropped are described in the diff.


Gated in /home/dev/workspaces/claude-5/gate-266, detached at 86309e0. Nothing pushed, merged or
fixed; the clone is unmodified and the only untracked file is this verdict.
/home/dev/workspaces/claude-7/fj-changelog was not used.

CHANGES Head reviewed: 86309e0d7fab70020bbdf2d0998836fae4b4f205 # Gate fj#266: the CHANGELOG a release will be cut from Two things to fix, one of which ships. Everything else holds: I checked all sixteen entries rather than the third asked for, and fifteen of them are accurate down to the constants. The constraint held exactly, the format introduces nothing new, and the two behaviour changes are labelled and carry migration instructions. ## 1. The count, reconciled The three numbers describe three different things and none of them is the number of entries. ``` non-merge commits, v0.4.1..f7fdce4 25 already recorded (#237, three stack commits; #236, the pager commit) 4 undocumented 21 <- the title's 21 excluded as CI / coverage / test-only (#255 #256 #260 #264 #265) 5 <- the body says 8 written up 16 top-level bullets added by the diff 16 ``` **The title's "21" is right, and it is right about the wrong thing.** 21 is the number of undocumented commits, which is a true statement about `main`. The body then spends that 21 as though it were the number this PR records ("writes up the other 21, minus eight"), which lands on 13. The diff has 16 entries. So the title over-counts what the PR contains and the body under-counts it. **The body's "eight" is wrong. It is five.** The excluded set, established by reading each diff rather than each subject line, is exactly `#255`, `#256`, `#260`, `#264`, `#265`. I can see how eight was reached: the three unnumbered commits from `#233` touch only `.forgejo/workflows/release.yml`, so by file they look like CI. They are not excluded, though. All three are described in the release bullet, so counting them as dropped contradicts the diff. **16 commits producing 16 bullets is a coincidence, and the entries are not one to one.** Two offsetting reasons: - `#251` is one commit and produces **five** bullets: host-scoped `FJ_TOKEN_<HOST>`/`FJ_SESSION_<HOST>` (Added), the cross-host `FJ_TOKEN` scoping and the platform-URL default and global `--host` for the auth subcommands (Changed), and the `FJ_TOKEN`-blocks-`--fjord` clap binding (Fixed). - The release work is **five** commits collapsed into **one** bullet: `#230` (5d47897), `#233` (754987f, 69697ac, a03aa35) and `#234` (c7d8e0f). Plus four and minus four cancel. That is fine, and it is the right shape for a changelog, but it means the count has to be stated as entries rather than derived from commits. **Which number is right: sixteen entries, covering sixteen commits, of the twenty-one that were undocumented.** The title and body should say that. It matters because the PR body is the audit trail for a file nobody re-reads, and this is the second reader who has had to derive the mapping by hand. The PR body's mapping is otherwise sound, with one attribution to correct: the brief names `#252` as the gateway/PAT behaviour change, and the PR body names `#251`. **The PR body is right.** `#252` is purely additive: before it there was no way to reach the Commons at all, so no one could be relying on the old behaviour. The behaviour change is `#251`'s token scoping. ## 2. Every entry, checked I checked all sixteen against the merged PR, and against the source or the live forge wherever the claim was checkable there. Fifteen are accurate. Highlights of what I verified independently rather than by reading the PR body back: | entry | independent check | |---|---| | host-scoped env vars | Computed `'rasterhub.com'.encode().hex().upper()` myself: `7261737465726875622E636F6D`. Matches the entry and `src/auth/mod.rs:194`. `host_env_session_var` exists, so the `FJ_SESSION_<HOST>` half is real | | `fj run logs` alias | `src/cli/workflow_run.rs:29` is `#[command(alias = "log")]` | | `pr merge` style | `repo_default_merge_style` (`src/cli/pr.rs:1023`) errors on unreadable AND on unsupported, naming the four supported styles. No fallback, as claimed | | `pr merge` message | `src/api/pull_core.rs:387` is `match opts.message { Some(m) => Some(m), None => <fetch body> }`, so `--message ""` really does still send an empty body | | Ctrl+C backstop | `src/interrupt.rs:43` `GRACE = 250ms`, `:46` `EXIT_INTERRUPTED = 130`. Exact | | OIDC timeouts | `src/fjord/oidc.rs:57` `CALLBACK_TIMEOUT = 300s`, `:64` `REQUEST_LINE_TIMEOUT = 10s`. Exact | | negative actor ids | `src/api/user.rs:12` is `pub id: i64` | | the three new release guards | All three exist in `.forgejo/workflows/release.yml`: `fail_on_unmatched_files: true` (457), the `sha256 ""` refusal (393-399), and the missing-CHANGELOG-section error (365-379) | | the formula generator | The heredoc at 428-437 has no `cd` and installs directly, with the reason in a comment. The generator really is fixed | The prose is close to the source PRs without being copied from them, and where it compresses it does not distort. The `#261` entry ("Ctrl+C was not slow, it was inert"), the `#262` entry, and the `#252` entry are all good writing for a reader rather than restatements of a diff. ### The one that is not true The release bullet says: > The `v0.4.1` release was published with zero assets, **which is why `brew install fj` has been > serving 0.3.0 since July** The first clause is true of July. The second is false now, and has been for five weeks. Checked on the live forge: ``` v0.4.1 release: draft=False assets=5 published 2026-07-22T20:19:49Z SHA256SUMS, fj.rb, and three tarballs, all created 2026-07-30T02:59Z rasterstate/homebrew-tap Formula/fj.rb version "0.4.1" sha256 99ee1c6a… == release fj-v0.4.1-darwin-aarch64.tar.gz sha256 a1a593e7… == release fj-v0.4.1-darwin-x86_64.tar.gz sha256 624ae2c0… == release fj-v0.4.1-linux-x86_64.tar.gz ``` All three digests match the published SHA256SUMS byte for byte, and the tap's `install` block carries the generated comment ("The tarball has a single top-level dir ... that `#{version}` does not"), so the tap is running the fixed generator's output rather than a hand-patched formula. `brew install fj` installs 0.4.1 and has since 2026-07-30, thirteen minutes after `#234` landed: ``` 2026-07-22 20:19 v0.4.1 published, zero assets 2026-07-25 01:33 #230 overwrite: true 2026-07-30 02:10 #233 merged 2026-07-30 02:46 #234 dispatch input type 2026-07-30 02:59 v0.4.1's five assets uploaded by the recovery dispatch ``` So the outage lasted eight days, 22 to 30 July, and the same bullet describes the machinery that ended it. As written it tells a reader on the release page that the tap is still stale, which is the opposite of what shipped, and it invites them to install by hand or to conclude the fix in that paragraph did not work. This is the entry that matters most for it, too: the release body is taken from this CHANGELOG section (`release.yml:353-374`), so this sentence is published verbatim to everyone who opens the release page, and the brief's rule applies exactly. A reader trusts it and does not go look. Fix is one clause: "which is why `brew install fj` served 0.3.0 from 22 to 30 July", or drop the clause and keep "The `v0.4.1` release was published with zero assets." ## 3. Nothing material was silently dropped The five excluded commits, each judged on its diff rather than its subject: | commit | PR | what it touches | verdict | |---|---|---|---| | f7fdce4 | #265 | `.forgejo/workflows/ci.yml`, `CLAUDE.md` | CI only. Correctly excluded | | 96b7a13 | #264 | `src/cli/auth_setup_git.rs` +59, `src/cli/editor.rs` +109/-27 | **Looks like source, is not.** Both hunks land inside `#[cfg(test)]` / `mod setup_git_tests`. The deletions are a test replacing hand-rolled env save/restore with an `EnvVarGuard` and a serialising mutex. Correctly excluded | | 60b51d4 | #260 | `src/fjord/oidc.rs` +128 | Single hunk at `mod tests`, zero deletions. Correctly excluded | | ba0f96a | #256 | deletes `forseti-review.yml` | CI only. Correctly excluded | | c8c52e0 | #255 | `ci.yml`, `CLAUDE.md`, `Makefile`, `Cargo.lock` | Coverage calibration. The lockfile moves one transitive dependency, `h2` 0.4.14 to 0.4.16, which arrived with the toolchain rather than as a deliberate bump and is not a user-facing change under this file's conventions. Correctly excluded | The brief's two candidates are both in the bucket and both belong there. `#264` is the one worth the paragraph above: it has the largest source-file footprint of the five and the only deletions, and it is still entirely test code. **The check in the other direction found the case that matters.** `#247`'s subject is "pr: cover negative system reviewer ids", which reads test-only, and it is not: it adds `serde_path_to_error` in `src/client/mod.rs` and a dependency in `Cargo.toml`. It is written up, as "A failed list decode names where it failed", and the entry is accurate. A subject-line pass would have dropped it. `#234` (c7d8e0f) is written up implicitly rather than explicitly, and that is the right call. Its whole content is `type: string` on the dispatch input, without which Forgejo renders no field and the recovery path cannot be dispatched at all. The bullet's claim that "a release can be re-run by `workflow_dispatch` with a `tag` input" is only true because of it, so the reader gets the user-facing fact and is spared the widget. ## 4. Behaviour changes are labelled Both of the brief's candidates are in `### Changed` and both carry the migration instruction: - **`#243`, repo-default merge style.** "**Scripts that relied on the implicit `merge` need `--style merge` spelled out.**" Bolded, in the entry. A reader relying on the old behaviour is warned in the sentence that would otherwise catch them out. - **`#251`, generic `FJ_TOKEN` scoping.** "Use `FJ_TOKEN_<HOST>` for that case. `FJ_SESSION` follows the same rule." Not bolded, but it is the whole migration and it is in the entry. `#252` is in `### Added`, correctly: it is a capability that did not exist, not a change to one. **One candidate the brief did not name.** `#262`, the merge-message default, is in `### Fixed`, and it changes what every `fj pr merge` without `--message` produces. I think `Fixed` is the right home, because the old behaviour was silent data loss rather than a contract, and the entry does carry the escape hatch ("`--message ""` still produces a deliberately empty body"). Worth knowing that a reader scanning only `### Changed` for things that will bite them will not see it. Not blocking. The entry also omits something `#262`'s own author flagged as unresolved: the default sits in the shared `merge()`, so it applies to `merge` and `rebase-merge` as well as `squash`, where the loss was measured, and that was "answered by construction rather than deliberately". Verified in `src/api/pull_core.rs:387`, which is style-agnostic. One clause would cover it. ## 5. The four that motivated this All present, and described for a reader: - **`#258`** and **`#261`**, the two Ctrl+C entries, kept separate because they are different failures with different fixes. Both name the states that were confirmed rather than reasoned about. - **`#260`** is not present, and should not be: it is a `#[cfg(test)]` addition to `src/fjord/oidc.rs` with zero deletions, and the behaviour it covers is `#258`'s entry. - **`#262`** says what the brief asked for and says it first: "**`fj pr merge` no longer discards the pull request description.**" It goes on to name the silence, which is the part that makes it worth reading: "the merge succeeded and the commit looked normal." Not "default merge message". Correct. ## 6. Format Matches, and introduces nothing. - `### Added` / `### Changed` / `### Fixed`, in Keep a Changelog order, with `Changed` inserted between the existing two rather than appended. - `### Changed` is not a new heading here: 0.3.0, 0.2.0, 0.1.3 and 0.1.2 all carry one. - Voice matches: bolded lead clause then explanation, and the file's existing plain bullets are left alone. Wrapping is 79 columns against the file's existing 82. - No link-reference block at the foot of this file, so there is nothing that needed updating. **The constraint held exactly.** One file, `CHANGELOG.md`, +115 / -0. `git diff f7fdce4 HEAD` over `Cargo.toml`, `Cargo.lock` and `README.md` is empty. `## [Unreleased]` is still `## [Unreleased]`, and no version was chosen. Worth knowing, and it is in this PR's favour: leaving it as `[Unreleased]` is now **enforced** rather than remembered. `release.yml:376` fails the run with "CHANGELOG.md has no '## [$VERSION]' section", so a release cut before someone renames the heading stops at the publish job instead of shipping an empty release body. The one-line follow-up cannot be skipped by accident, which is the right shape for leaving that decision to the operator. ## Required to land 1. **Correct the brew clause.** It is the only false statement in the file, and it publishes. 2. **Restate the count in the title and body**: sixteen entries, covering sixteen commits, of the twenty-one undocumented; five excluded as CI, coverage or test-only; entries do not map one to one onto commits, `#251` giving five and the release work collapsing five into one. Both are text-only and neither touches an entry's substance. ## Non-blocking, worth a line each if the file is being edited anyway - The `#262` entry could say the default applies to every merge style, not only squash. - The `#251` migration instruction ("Use `FJ_TOKEN_<HOST>` for that case") is the same kind of warning `#243` bolds, and is not bolded. - `#251`'s own PR records that the README and docs still describe generic `FJ_TOKEN` as always checked first, which this change makes untrue. Out of scope for a CHANGELOG, and out of scope for this PR by its own constraint, but it is a real follow-up and nothing else is tracking it here. ## Verdict **CHANGES**, on two text fixes. The research behind this file is good and the entries are unusually well checked: I verified every one of the sixteen against its PR and, where the claim named a constant or a code path, against the source, and only one clause failed. That clause fails in the direction that matters, in the longest entry, in the part that gets published, and it says a thing is broken that this fleet fixed five weeks ago. The count is the second fix and the cheaper one. It does not ship, but the brief is right that a PR which miscounts its own contents is the shape worth stopping, and the miscount here is real: eight excluded is five, and the three commits counted as dropped are described in the diff. --- Gated in `/home/dev/workspaces/claude-5/gate-266`, detached at `86309e0`. Nothing pushed, merged or fixed; the clone is unmodified and the only untracked file is this verdict. `/home/dev/workspaces/claude-7/fj-changelog` was not used.
docs: say what the tap actually serves in the release entry
All checks were successful
ci / check (pull_request) Successful in 11m50s
ci / live-e2e (pull_request) Successful in 2m14s
ci / coverage (pull_request) Successful in 2m31s
7af92277f6
The release bullet said the zero-asset v0.4.1 publish "is why `brew install
fj` has been serving 0.3.0 since July". The first clause is true of July;
the second stopped being true on 30 July. This file is where a release body
comes from (release.yml:353-374), so the sentence would have been published
verbatim to everyone who opened the release page, telling them the tap was
stale in the same paragraph that describes the work which unstaled it.

Checked against the live forge rather than reasoned about:

  v0.4.1              draft=false, 5 assets, published 2026-07-22T20:19:49Z
    SHA256SUMS, fj.rb, three tarballs, all created 2026-07-30T02:59Z
  #230 / #233 / #234  merged 07-25 01:33, 07-30 02:10, 07-30 02:46
  homebrew-tap        Formula/fj.rb version "0.4.1", committed 07-30T03:06Z
    99ee1c6a / a1a593e7 / 624ae2c0 match the published SHA256SUMS exactly

So the assets arrived thirteen minutes after #234 made the recovery
dispatch possible, the tap followed seven minutes later, and the outage ran
22 to 30 July rather than to the present.

The entry now says that, and gains the sentence it was missing: the assets
were uploaded on 30 July and the tap has served 0.4.1 since. Nothing else
in the entry changes; the rewrap is to keep the paragraph at 79 columns.
stephen changed title from Record the 21 undocumented changes in [Unreleased] to Record sixteen of the twenty-one undocumented changes in [Unreleased] 2026-09-06 22:10:53 +00:00
stephen deleted branch docs/changelog-unreleased 2026-09-07 02:07:10 +00:00
Sign in to join this conversation.
No description provided.