fix(ci): check out the event sha into a per-job directory #79

Merged
Breadway merged 5 commits from fix/eco-79-isolated-checkout into main 2026-10-16 21:12:24 +08:00
Owner

Closes ECO-79.

Consumer check workflows cloned every job into the same relative src path on the shared self-hosted runner. A second job could replace the tree while the first job's build was still reading it. The per-product lock in ci/build.sh (ECO-54) does not cover the checkout step, so it cannot prevent this.

Changes

  • scripts/ci-checkout.sh <repo-url> <sha> <dest>: clones into a caller-owned directory, detaches at the exact event commit, verifies HEAD, and removes its own directory on failure. It rejects repo URLs with an embedded password, short or non-hex SHAs, and an existing destination.
  • scripts/test-ci-checkout.sh: local file:// fixtures covering exact-SHA checkout after the branch advances, two concurrent jobs on different branches, a control that reproduces the old shared-path race, failure cleanup, and input validation.
  • .forgejo/workflows/check.yml: checks out with mktemp -d under RUNNER_TEMP, pins GITHUB_SHA, and removes only that directory in an if: always() step. All steps now use $ECO_CHECK_SRC.

Evidence

  • Control: with the old pattern, job A's livestack.rs disappeared when job B cloned into the same path (local reproduction).
  • Mutant: a helper that follows the branch tip fails the regression with checkout followed the advanced branch, not the event sha.
  • scripts/test-ci-checkout.sh passes; ci/test-build-lock.sh still passes, so same-product serialization and cross-product concurrency are unchanged; scripts/lint-pins.sh passes.

Scope

This PR changes only bread-ecosystem. The consumer repos (bread, breadbar, and others) still use the shared-path checkout. Their updates are separate PRs and depend on this one being merged. Nothing here modifies any other repo.

Not verified

The runner's workspace was not readable from the diagnosing host, so the exact interleaving on the runner is not confirmed. The regression reproduces the mechanism locally.

Closes ECO-79. Consumer check workflows cloned every job into the same relative `src` path on the shared self-hosted runner. A second job could replace the tree while the first job's build was still reading it. The per-product lock in `ci/build.sh` (ECO-54) does not cover the checkout step, so it cannot prevent this. ## Changes - `scripts/ci-checkout.sh <repo-url> <sha> <dest>`: clones into a caller-owned directory, detaches at the exact event commit, verifies HEAD, and removes its own directory on failure. It rejects repo URLs with an embedded password, short or non-hex SHAs, and an existing destination. - `scripts/test-ci-checkout.sh`: local `file://` fixtures covering exact-SHA checkout after the branch advances, two concurrent jobs on different branches, a control that reproduces the old shared-path race, failure cleanup, and input validation. - `.forgejo/workflows/check.yml`: checks out with `mktemp -d` under `RUNNER_TEMP`, pins `GITHUB_SHA`, and removes only that directory in an `if: always()` step. All steps now use `$ECO_CHECK_SRC`. ## Evidence - Control: with the old pattern, job A's `livestack.rs` disappeared when job B cloned into the same path (local reproduction). - Mutant: a helper that follows the branch tip fails the regression with `checkout followed the advanced branch, not the event sha`. - `scripts/test-ci-checkout.sh` passes; `ci/test-build-lock.sh` still passes, so same-product serialization and cross-product concurrency are unchanged; `scripts/lint-pins.sh` passes. ## Scope This PR changes only bread-ecosystem. The consumer repos (`bread`, `breadbar`, and others) still use the shared-path checkout. Their updates are separate PRs and depend on this one being merged. Nothing here modifies any other repo. ## Not verified The runner's workspace was not readable from the diagnosing host, so the exact interleaving on the runner is not confirmed. The regression reproduces the mechanism locally.
fix(ci): check out the event sha into a per-job directory
Some checks failed
check / check (push) Failing after 3s
5a9fdd9152
Consumer check workflows cloned every job into the same relative src path
on the shared runner, so a second job could replace the tree while the
first job's build was still reading it (ECO-79).

scripts/ci-checkout.sh clones into a caller-owned directory and detaches
at the exact event commit, verifies HEAD, and removes its own directory on
failure. The ecosystem check workflow now uses a mktemp directory, pins
GITHUB_SHA, and cleans only that directory in an always() step.

scripts/test-ci-checkout.sh covers exact-sha checkout after the branch
advances, two concurrent jobs on different branches, a control reproducing
the old shared-path race, failure cleanup, and input validation.
fix(ci): run owned checkout cleanup after the last step
All checks were successful
check / check (push) Successful in 5m4s
de66355a16
The always() cleanup ran right after checkout, so lint, fmt, clippy and test
found no tree. Cleanup now runs as the final step of the job.
Author
Owner

Independent review of PR 79 at exact head de66355a16 (base main 94ea37490f, mergeable). Verdict: CHANGES REQUESTED. Not merged.

What I verified (isolated detached worktree at the exact SHA, primary checkout untouched):

  • scripts/test-ci-checkout.sh passes, 16 consecutive runs, no flake.
  • ci/test-build-lock.sh and scripts/lint-pins.sh pass. ci/build.sh and ci/test-build-lock.sh are not in the diff, so the per-product lock is unchanged.
  • Mutants: following the branch tip is rejected (helper HEAD check); removing the failure-cleanup trap fails the regression with "failed checkout left its directory behind". The control (old shared-path pattern) does reproduce the lost-file race.
  • Helper probes: uppercase/short sha, existing dest (non-empty dest preserved, rc 2), ext:: transport (git refuses), leading-dash URL (taken as a repo name, no exec), unreachable sha (fails, dest removed), user:password URL (rejected).
  • CI: "check / check (push)" is success on this exact SHA (run 307). The earlier head 5a9fdd9 failed (run 306) and is superseded. No reviews or comments outstanding. Branch protection was not readable without a token, so required-check configuration is unobserved.

Requested changes:

  1. scripts/test-ci-checkout.sh is never run by CI. .forgejo/workflows/check.yml has no step for it (grep of .forgejo, docs, ci, scripts finds no reference), unlike test-build-lock.sh and test-publish-symbols.sh. The green run therefore proves only that the new inline checkout works, not the helper or its regression. Add a step, for example "ci checkout isolation", running bash "$ECO_CHECK_SRC/scripts/test-ci-checkout.sh".
  2. scripts/ci-checkout.sh:34 accepts token-only userinfo. https://ghp_TOKEN@host/x.git passes validation and reaches the network (verified). The check only rejects user:password. Reject any userinfo on http/https URLs; only ssh:// with a bare user (git@) is legitimate. Add a test for the token-only form.
  3. check.yml:30-37 inlines its own clone and never calls scripts/ci-checkout.sh, so the sha-format check, HEAD verification and own-dir failure cleanup the helper and tests cover do not apply to the only workflow that changed. Bootstrapping is the reason (the helper is not on disk before the clone), so either say so in a comment, or add the same git rev-parse HEAD equality check after the checkout in the workflow so the inline copy has the same exact-SHA guarantee.
  4. No consumption path is documented. Consumers (bread, breadbar, ...) do not have bread-ecosystem on disk when their checkout step runs, so "use the shared helper" is not actionable as delivered. Document in docs/release-channels.md (or a new doc) how a consumer obtains the helper at a pinned ref (or the inline snippet to copy), the ECO_*-style env persistence via GITHUB_ENV, and the if: always() cleanup step with its path guard.
  5. scripts/test-ci-checkout.sh:115-118 (ssh case) is vacuous: it passes whether the URL is accepted or rejected. Assert the exit status is not 2 (validation rejection), so it proves the URL check accepts a bare ssh user.

Non-blocking:

  • Confidence wording. scripts/ci-checkout.sh:5-8 states as fact that every job shares a relative path and a second job replaces the tree. The runner workspace layout is not confirmed (the mechanism is reproduced locally; the real interleaving on the runner is inferred). Soften to match the PR body's "Not verified" section. Likely the shared workspace is per repo, so cross-repo isolation is not established either way.
  • check.yml:77 cleanup guard uses an unanchored glob (ecosystem-check.* also matches slashes). Harmless since only this workflow sets the variable, but ecosystem-check.?????? is tighter.
  • The helper leaves parent directories it created when dest has a missing parent (only dest is removed).
  • Same shared-src pattern remains in this repo: dev-bakery.yml:23-25, dev-bread-theme.yml:26-28 (both trigger on main pushes alongside check) and package.yml. Not required for this PR, but track them as a follow-up so ECO-79 is not read as fully closed.
  • shellcheck is not installed on my host; not run.

After merge the actual bread consumer jobs still need an integration/runtime CI run to verify behavior on the runner; this PR does not exercise that.

Independent review of PR 79 at exact head de66355a16f532eb8419f683df09b7c02ee6dee0 (base main 94ea37490f44e2b4a39ec3f475e4be93cf71fc3b, mergeable). Verdict: CHANGES REQUESTED. Not merged. What I verified (isolated detached worktree at the exact SHA, primary checkout untouched): - scripts/test-ci-checkout.sh passes, 16 consecutive runs, no flake. - ci/test-build-lock.sh and scripts/lint-pins.sh pass. ci/build.sh and ci/test-build-lock.sh are not in the diff, so the per-product lock is unchanged. - Mutants: following the branch tip is rejected (helper HEAD check); removing the failure-cleanup trap fails the regression with "failed checkout left its directory behind". The control (old shared-path pattern) does reproduce the lost-file race. - Helper probes: uppercase/short sha, existing dest (non-empty dest preserved, rc 2), ext:: transport (git refuses), leading-dash URL (taken as a repo name, no exec), unreachable sha (fails, dest removed), user:password URL (rejected). - CI: "check / check (push)" is success on this exact SHA (run 307). The earlier head 5a9fdd9 failed (run 306) and is superseded. No reviews or comments outstanding. Branch protection was not readable without a token, so required-check configuration is unobserved. Requested changes: 1. scripts/test-ci-checkout.sh is never run by CI. .forgejo/workflows/check.yml has no step for it (grep of .forgejo, docs, ci, scripts finds no reference), unlike test-build-lock.sh and test-publish-symbols.sh. The green run therefore proves only that the new inline checkout works, not the helper or its regression. Add a step, for example "ci checkout isolation", running bash "$ECO_CHECK_SRC/scripts/test-ci-checkout.sh". 2. scripts/ci-checkout.sh:34 accepts token-only userinfo. https://ghp_TOKEN@host/x.git passes validation and reaches the network (verified). The check only rejects user:password. Reject any userinfo on http/https URLs; only ssh:// with a bare user (git@) is legitimate. Add a test for the token-only form. 3. check.yml:30-37 inlines its own clone and never calls scripts/ci-checkout.sh, so the sha-format check, HEAD verification and own-dir failure cleanup the helper and tests cover do not apply to the only workflow that changed. Bootstrapping is the reason (the helper is not on disk before the clone), so either say so in a comment, or add the same git rev-parse HEAD equality check after the checkout in the workflow so the inline copy has the same exact-SHA guarantee. 4. No consumption path is documented. Consumers (bread, breadbar, ...) do not have bread-ecosystem on disk when their checkout step runs, so "use the shared helper" is not actionable as delivered. Document in docs/release-channels.md (or a new doc) how a consumer obtains the helper at a pinned ref (or the inline snippet to copy), the ECO_*-style env persistence via GITHUB_ENV, and the if: always() cleanup step with its path guard. 5. scripts/test-ci-checkout.sh:115-118 (ssh case) is vacuous: it passes whether the URL is accepted or rejected. Assert the exit status is not 2 (validation rejection), so it proves the URL check accepts a bare ssh user. Non-blocking: - Confidence wording. scripts/ci-checkout.sh:5-8 states as fact that every job shares a relative path and a second job replaces the tree. The runner workspace layout is not confirmed (the mechanism is reproduced locally; the real interleaving on the runner is inferred). Soften to match the PR body's "Not verified" section. Likely the shared workspace is per repo, so cross-repo isolation is not established either way. - check.yml:77 cleanup guard uses an unanchored glob (ecosystem-check.* also matches slashes). Harmless since only this workflow sets the variable, but ecosystem-check.?????? is tighter. - The helper leaves parent directories it created when dest has a missing parent (only dest is removed). - Same shared-src pattern remains in this repo: dev-bakery.yml:23-25, dev-bread-theme.yml:26-28 (both trigger on main pushes alongside check) and package.yml. Not required for this PR, but track them as a follow-up so ECO-79 is not read as fully closed. - shellcheck is not installed on my host; not run. After merge the actual bread consumer jobs still need an integration/runtime CI run to verify behavior on the runner; this PR does not exercise that.
fix(ci): reject any userinfo, verify bootstrap HEAD, wire helper regression
Some checks failed
check / check (push) Has been cancelled
9516cf6c9e
Address review of #79:
- Reject any URL userinfo (token-only included) before network access, with
  regression cases using fake fixtures and an unreachable host.
- Assert the scp-style ssh form is not rejected as invalid input.
- Verify HEAD equals GITHUB_SHA in the inline bootstrap and validate the SHA
  format there too.
- Run scripts/test-ci-checkout.sh as a check step.
- Tighten cleanup: absolute path only, no .. segments, remove only a
  directory this run created.
- Document pinned helper acquisition and the cleanup guard in docs/ci-checkout.md.
- Soften the runner cause in the helper header to what the logs and local
  control support.
Author
Owner

Independent re-review of PR 79 at exact head 9516cf6c9e (base main 94ea37490f, mergeable, no reviews outstanding). Verdict: CHANGES REQUESTED. Not merged. Builds on review 5272 (#79 (comment)).

Prior items:

  1. Helper regression wired into CI: check.yml now runs scripts/test-ci-checkout.sh (step 3). Done, but see the blocker below.
  2. Any userinfo rejected: ci-checkout.sh:37 now matches ^scheme://[^/]*@. Token-only, user-only, user:pass, empty ':@', ssh://git@ and uppercase scheme all exit 2 before any network access. Mutant with the old password-only regex fails the test. Done.
  3. Bootstrap SHA format and HEAD equality: check.yml checks ^[0-9a-f]{40}$ and compares rev-parse HEAD to GITHUB_SHA. I ran the workflow's checkout and cleanup steps extracted from the YAML against local fixtures: event sha (not branch tip) checked out, unique dir per job under RUNNER_TEMP, GITHUB_ENV set, cleanup removes only the owned dir and leaves a victim dir, "/", empty and ../ paths alone, failed checkout then cleanup leaves nothing, injection-shaped GITHUB_SHA rejected without execution. Done.
  4. Docs: docs/ci-checkout.md covers pinned fetch, SHA-256, inline bootstrap, GITHUB_ENV and guarded if: always() cleanup, and states the confidence limits. Done.
  5. SSH case: assertion is now non-vacuous, but it introduces the blocker below.

BLOCKER (must fix): CI run 308 on this exact head has been pending for about 1h46m and is hung. Its log ends at the new "ci checkout helper regression" step with an SSH prompt: "The authenticity of host '127.0.0.1' can't be established ... ED25519 key fingerprint". Cause: scripts/test-ci-checkout.sh near the end uses git@127.0.0.1:1/none.git. scp-style URLs have no port field, so "1/none.git" is the path and ssh dials port 22 on the runner host, which has an sshd with an unknown host key and a tty. I reproduced the prompt locally under a pty and the exit 128 without one. The earlier ssh://...:1 form failed fast on a refused port; the scp form does not. A hung step will hold the runner slot and never report a status.
Requested fix:
a. Use a non-resolving host, for example git@ssh.invalid:none.git, and run the case with GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=yes' (or an equivalent fake ssh that exits 255) so it cannot prompt or reach any real host. Keep the assertion that the exit status is not 2 and no directory remains.
b. Add timeout-minutes (for example 5) to the new check.yml step so any future hang fails instead of holding the runner.
c. Someone with Forgejo admin must cancel run 308; I have no token for that. Re-run CI on the fixed head.

Non-blocking:

  • Test gap: a mutant that removes the absolute/.. destination check (ci-checkout.sh:47) still passes the suite. Add expect_rc 2 for a relative dest and one containing /../.
  • The "HEAD equals sha" comparison cannot be exercised by happy-path tests in either the helper or the inline copies (git checkout --detach already guarantees it); it is defense in depth, which is fine.
  • docs/ci-checkout.md lists inline bootstrap duplication but nothing enforces the two copies stay equal; consider a tiny diff check later.
  • Required-check configuration is not readable without a token; I treated the single "check / check (push)" context as the gate.

Evidence saved at ~/.local/state/bread-ci/eco79/review-2026-10-16-second-pass.txt and eco-run308-job-partial.log. Local checks run on this head: test-ci-checkout.sh passed 9 consecutive runs without a tty.

Independent re-review of PR 79 at exact head 9516cf6c9e37738085a577dd8fddfe95697be3b8 (base main 94ea37490f44e2b4a39ec3f475e4be93cf71fc3b, mergeable, no reviews outstanding). Verdict: CHANGES REQUESTED. Not merged. Builds on review 5272 (https://git.breadway.dev/Breadway/bread-ecosystem/pulls/79#issuecomment-5272). Prior items: 1. Helper regression wired into CI: check.yml now runs scripts/test-ci-checkout.sh (step 3). Done, but see the blocker below. 2. Any userinfo rejected: ci-checkout.sh:37 now matches ^scheme://[^/]*@. Token-only, user-only, user:pass, empty ':@', ssh://git@ and uppercase scheme all exit 2 before any network access. Mutant with the old password-only regex fails the test. Done. 3. Bootstrap SHA format and HEAD equality: check.yml checks ^[0-9a-f]{40}$ and compares rev-parse HEAD to GITHUB_SHA. I ran the workflow's checkout and cleanup steps extracted from the YAML against local fixtures: event sha (not branch tip) checked out, unique dir per job under RUNNER_TEMP, GITHUB_ENV set, cleanup removes only the owned dir and leaves a victim dir, "/", empty and ../ paths alone, failed checkout then cleanup leaves nothing, injection-shaped GITHUB_SHA rejected without execution. Done. 4. Docs: docs/ci-checkout.md covers pinned fetch, SHA-256, inline bootstrap, GITHUB_ENV and guarded if: always() cleanup, and states the confidence limits. Done. 5. SSH case: assertion is now non-vacuous, but it introduces the blocker below. BLOCKER (must fix): CI run 308 on this exact head has been pending for about 1h46m and is hung. Its log ends at the new "ci checkout helper regression" step with an SSH prompt: "The authenticity of host '127.0.0.1' can't be established ... ED25519 key fingerprint". Cause: scripts/test-ci-checkout.sh near the end uses git@127.0.0.1:1/none.git. scp-style URLs have no port field, so "1/none.git" is the path and ssh dials port 22 on the runner host, which has an sshd with an unknown host key and a tty. I reproduced the prompt locally under a pty and the exit 128 without one. The earlier ssh://...:1 form failed fast on a refused port; the scp form does not. A hung step will hold the runner slot and never report a status. Requested fix: a. Use a non-resolving host, for example git@ssh.invalid:none.git, and run the case with GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=yes' (or an equivalent fake ssh that exits 255) so it cannot prompt or reach any real host. Keep the assertion that the exit status is not 2 and no directory remains. b. Add timeout-minutes (for example 5) to the new check.yml step so any future hang fails instead of holding the runner. c. Someone with Forgejo admin must cancel run 308; I have no token for that. Re-run CI on the fixed head. Non-blocking: - Test gap: a mutant that removes the absolute/.. destination check (ci-checkout.sh:47) still passes the suite. Add expect_rc 2 for a relative dest and one containing /../. - The "HEAD equals sha" comparison cannot be exercised by happy-path tests in either the helper or the inline copies (git checkout --detach <sha> already guarantees it); it is defense in depth, which is fine. - docs/ci-checkout.md lists inline bootstrap duplication but nothing enforces the two copies stay equal; consider a tiny diff check later. - Required-check configuration is not readable without a token; I treated the single "check / check (push)" context as the gate. Evidence saved at ~/.local/state/bread-ci/eco79/review-2026-10-16-second-pass.txt and eco-run308-job-partial.log. Local checks run on this head: test-ci-checkout.sh passed 9 consecutive runs without a tty.
fix(ci): bound SSH checkout regression and clone transport
Some checks failed
check / check (push) Has been cancelled
b452cd8b5b
The scp-style SSH test reached the runner's port 22 and waited on host-key
confirmation. Replace the network attempt with a deterministic mock SSH,
assert that git invokes it, and bound both the test and helper clone.

Reject existing dangling destination symlinks, cover absolute/root/parent
path validation, and cap the check job runtime. The saved run 308 log shows
the old prompt; this change does not cancel or inspect runner processes.
test(ci): make SSH timeout mock replace its process
All checks were successful
check / check (push) Successful in 7m11s
8dabe3a2b1
Author
Owner

Independent final re-review of PR 79 at exact head 8dabe3a2b1 (base main 94ea37490f). Verdict: PASS. Reviewed only the diff from 9516cf6 and reused the accepted criteria from comments 5272 and 5307.

Blocker 5307 (ssh host-key hang) is fixed:

  • The scp-style case no longer touches any real host. It uses a mock ssh via BREAD_CI_SSH_COMMAND, host example.invalid, and asserts the mock actually received argv containing the host (so a helper that never invokes ssh fails: mutant that ignores BREAD_CI_SSH_COMMAND is caught), rc is not 2 and not 124, and no dest remains.
  • The timeout path is exercised for real: a mock that blocks (exec sleep) with BREAD_CI_CLONE_TIMEOUT=1 under an outer 5s timeout must exit exactly 124 and leave no dest. Mutant removing the helper's own timeout is caught ("timed-out clone left its directory behind"). No orphan sleep processes remain afterwards.
  • Defaults: GIT_TERMINAL_PROMPT=0, ssh -F /dev/null with BatchMode, ConnectTimeout=5, StrictHostKeyChecking=yes, 300s clone budget (validated as a positive integer, exit 2 otherwise), and job timeout-minutes: 60 in check.yml.
  • Destination guards now have negative fixtures: relative, parent traversal, root, existing, and a dangling symlink that must survive untouched. Mutants caught: no relative guard, no -L guard, no cleanup, old password-only userinfo regex. (One of my mutants wrote a relative-checkout/ dir in my own scratch worktree; I removed that artifact, and the unmutated suite leaves nothing behind across 7 runs.)
  • The untracked relative-checkout/.git the author reported is not in the PR (4 files changed, no such path).

CI: check / check (push) is success on this exact head, run 310, 7m11s. The log shows the new helper regression step passing on the runner within seconds of checkout, then the full prior checks, "Job succeeded". Previous head 9516cf6 run 308 was the hung one and is superseded.

Residual, stated plainly: the workspace-sharing cause on the runner remains an inference; the consumer integration is covered by bread#49 (merged 40ee494), whose post-merge dev-release run still needs its own check. Other main-trigger workflows in this repo (dev-bakery, dev-bread-theme, package) keep the old pattern and are tracked in ECO-82.

Evidence: ~/.local/state/bread-ci/eco79/review-5307-repair.txt plus this review.

Independent final re-review of PR 79 at exact head 8dabe3a2b12c1224ac2e3791fda463216b2dc543 (base main 94ea37490f44e2b4a39ec3f475e4be93cf71fc3b). Verdict: PASS. Reviewed only the diff from 9516cf6 and reused the accepted criteria from comments 5272 and 5307. Blocker 5307 (ssh host-key hang) is fixed: - The scp-style case no longer touches any real host. It uses a mock ssh via BREAD_CI_SSH_COMMAND, host example.invalid, and asserts the mock actually received argv containing the host (so a helper that never invokes ssh fails: mutant that ignores BREAD_CI_SSH_COMMAND is caught), rc is not 2 and not 124, and no dest remains. - The timeout path is exercised for real: a mock that blocks (exec sleep) with BREAD_CI_CLONE_TIMEOUT=1 under an outer 5s timeout must exit exactly 124 and leave no dest. Mutant removing the helper's own timeout is caught ("timed-out clone left its directory behind"). No orphan sleep processes remain afterwards. - Defaults: GIT_TERMINAL_PROMPT=0, ssh -F /dev/null with BatchMode, ConnectTimeout=5, StrictHostKeyChecking=yes, 300s clone budget (validated as a positive integer, exit 2 otherwise), and job timeout-minutes: 60 in check.yml. - Destination guards now have negative fixtures: relative, parent traversal, root, existing, and a dangling symlink that must survive untouched. Mutants caught: no relative guard, no -L guard, no cleanup, old password-only userinfo regex. (One of my mutants wrote a relative-checkout/ dir in my own scratch worktree; I removed that artifact, and the unmutated suite leaves nothing behind across 7 runs.) - The untracked relative-checkout/.git the author reported is not in the PR (4 files changed, no such path). CI: check / check (push) is success on this exact head, run 310, 7m11s. The log shows the new helper regression step passing on the runner within seconds of checkout, then the full prior checks, "Job succeeded". Previous head 9516cf6 run 308 was the hung one and is superseded. Residual, stated plainly: the workspace-sharing cause on the runner remains an inference; the consumer integration is covered by bread#49 (merged 40ee494), whose post-merge dev-release run still needs its own check. Other main-trigger workflows in this repo (dev-bakery, dev-bread-theme, package) keep the old pattern and are tracked in ECO-82. Evidence: ~/.local/state/bread-ci/eco79/review-5307-repair.txt plus this review.
Author
Owner

Merged after independent pass at head 8dabe3a2b1: check / check (push) green on that exact head (run 310), base unchanged at 94ea37490f, no outstanding reviews, mergeable. Merge commit c6442cabb6 (parents: base and reviewed head). Post-merge check on main (run 311) was pending at last read. ECO-79 stays open for verification: confirm run 311 and bread run 162 (dev release on main) succeed, and note the consumer still needs the pinned helper adoption plus ECO-81/ECO-82 follow-ups. No tags or versions created.

Merged after independent pass at head 8dabe3a2b12c1224ac2e3791fda463216b2dc543: check / check (push) green on that exact head (run 310), base unchanged at 94ea37490f44e2b4a39ec3f475e4be93cf71fc3b, no outstanding reviews, mergeable. Merge commit c6442cabb6c02acd1380dcd0d17189c4e22def03 (parents: base and reviewed head). Post-merge check on main (run 311) was pending at last read. ECO-79 stays open for verification: confirm run 311 and bread run 162 (dev release on main) succeed, and note the consumer still needs the pinned helper adoption plus ECO-81/ECO-82 follow-ups. No tags or versions created.
Sign in to join this conversation.
No reviewers
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
Breadway/bread-ecosystem!79
No description provided.