From d616e71d381aa43a2e363dce360dba595608ec3d Mon Sep 17 00:00:00 2001 From: Piotr Laczkowski Date: Thu, 27 Aug 2026 19:49:29 +0200 Subject: [PATCH 1/2] ci(docs): pin the Pages actions back to the pair that works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deploy-pages@v5 aborts this repo's deploy with "Timeout reached" after about a minute of polling — twice in a row, including a clean re-run. The artifact uploads fine and Build MkDocs passes; only the deploy step fails, and the published site is therefore stuck on the previous commit's build. The same workflow on upload-pages-artifact@v3 + deploy-pages@v4 succeeded on a217c63, the commit immediately before the bump, and CI and the vulnerability scan were green on the bumped commit too. The action pair is the variable. Only these two are reverted. The rest of the Actions sweep stays: checkout 7, setup-go 7, setup-node 7, setup-python 7 and action-gh-release 3 are all in use and green — the last is only a Node 20→24 runtime move with no input changes, which matters because it is the step that publishes releases. --- .github/workflows/docs.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 5fc1c48..312f187 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -56,7 +56,8 @@ jobs: - name: Upload Pages artifact if: github.event_name != 'pull_request' - uses: actions/upload-pages-artifact@v5 + # Pinned to the v3+v4 PAIR on purpose — see the deploy step below. + uses: actions/upload-pages-artifact@v3 with: path: site @@ -71,4 +72,14 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + # v4, NOT v5. The bump to upload-pages-artifact@v5 + deploy-pages@v5 in + # ff347b2 broke this deploy twice in a row: the artifact uploads and + # "Build MkDocs" passes, then v5 polls the Pages API, sees + # `updating_pages` for about a minute, reads one empty status and aborts + # with "Timeout reached". The same commit's CI and Vulnerability scan + # were green, and the identical workflow on v3+v4 succeeded on the + # commit immediately before (a217c63), so the pair is the variable. + # + # Re-open the bump when v5 has a fix; nothing else about the Actions + # sweep is reverted. + uses: actions/deploy-pages@v4 From 5f4464da1611b9198e1f5a7197b0a120148bdf1f Mon Sep 17 00:00:00 2001 From: Piotr Laczkowski Date: Thu, 27 Aug 2026 19:59:39 +0200 Subject: [PATCH 2/2] test(cli): remove a start-then-configure race in the hotkey test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StartInputPump launches its read loop immediately; SetHotkeys installs the filter afterwards. With the input already buffered in a strings.Reader, the pump can read and classify 'y' before the filter lands, and the test then sees a plain rune event where it asserted a hotkey: --- FAIL: TestInputPumpHotkeyFilter keys_test.go:177: got {Kind:1 Line: Key:y} The race is in the test's setup, not in the pump — the filter is mutex-guarded either way. A pipe written only after SetHotkeys returns makes the ordering the test means to assert the one it actually gets. Passes 40 consecutive -race runs. Surfaced on a loaded CI runner while merging the dependency backlog; unrelated to those bumps, and it would have kept flaking the release gate. --- pkg/cli/keys_test.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pkg/cli/keys_test.go b/pkg/cli/keys_test.go index 1ca50a8..3603a8e 100644 --- a/pkg/cli/keys_test.go +++ b/pkg/cli/keys_test.go @@ -167,9 +167,27 @@ func TestInputPumpEscapeAndInterrupt(t *testing.T) { func TestInputPumpHotkeyFilter(t *testing.T) { ed := NewLineEditor(nil) - p := StartInputPump(strings.NewReader("y"), ed) + + // A PIPE, not strings.NewReader: StartInputPump launches its read loop + // immediately, and SetHotkeys installs the filter afterwards. With input + // already buffered, the pump can read and classify 'y' before the filter + // lands, and the test then sees a plain rune event instead of a hotkey. + // That is a race in the TEST's setup, not in the pump — the filter itself + // is mutex-guarded — and it failed exactly this way on a loaded CI runner: + // + // --- FAIL: TestInputPumpHotkeyFilter + // keys_test.go:177: got {Kind:1 Line: Key:y} + // + // Writing only after SetHotkeys returns makes the ordering the test means + // to assert the one it actually gets. + pr, pw := io.Pipe() + p := StartInputPump(pr, ed) defer p.Stop() p.SetHotkeys(func(k Key) bool { return k.Type == KeyRune && k.Rune == 'y' }) + go func() { + _, _ = pw.Write([]byte("y")) + _ = pw.Close() + }() select { case ev := <-p.Events():