From e5b5afae5903a6779c02af50c2c3a9c001b3af10 Mon Sep 17 00:00:00 2001 From: cp-be Date: Fri, 22 May 2026 00:35:37 -0700 Subject: [PATCH 1/2] fix(ci): shellcheck-arm64-pilot runs-on label matches Mac mini's actual registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lint-shellcheck-arm64-pilot.yml workflow was perpetually CANCELLED (task_id=0, runner_id=NULL, no log file) because Gitea couldn't assign any registered runner to `runs-on: [self-hosted, arm64]`. The Mac mini runner registered for this lane ships labels ["self-hosted","macos-self-hosted-arm64","arm64-darwin"] per internal#494's capability-honest-labels directive — there is no plain `arm64` label. Two fix options: 1. Change the workflow's `runs-on` to match the registered labels. 2. Add a plain `arm64` label to the Mac mini's registration. Option 1 (this commit) is the cleaner fix: it's code-reviewable, lives on the repo's commit history, and respects `feedback_pc2_runner_labels_must_stay_narrow` (don't widen runner labels speculatively — selectors should match what's there, not the other way around). Option 2 would silently grow the label surface and make a future runner inadvertently match this workflow. Selector now: `runs-on: [self-hosted, arm64-darwin]` — pinned to the Mac-specific arm64 label so Linux-arm64 runners (when we add them) don't accidentally pick up Mac-only shell scripts. Comment block in the workflow header documents the rationale + the rule that `arm64-darwin` is Mac-specific by design. This workflow is ADDITIVE / NOT in branch_protections required_contexts (per the existing comment at line 8), so this fix is reversible and doesn't gate any merge — but the cancelled noise in the status feed goes away and the lane actually runs on the Mac mini going forward. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../workflows/lint-shellcheck-arm64-pilot.yml | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/lint-shellcheck-arm64-pilot.yml b/.gitea/workflows/lint-shellcheck-arm64-pilot.yml index d36fc6dd7..39caa9310 100644 --- a/.gitea/workflows/lint-shellcheck-arm64-pilot.yml +++ b/.gitea/workflows/lint-shellcheck-arm64-pilot.yml @@ -3,11 +3,26 @@ name: Lint shellcheck (arm64 pilot) # Mac-CI dual-track pilot (#233). ADDITIVE / NOT REQUIRED. # # Validates the arm64 self-hosted lane (no docker.sock, no privileged -# ops) before any required gate moves onto it. Until a Mac arm64 runner -# is registered with the `arm64` label, this workflow sits PENDING — -# that is FINE: `arm64` is NOT in branch_protections required contexts. +# ops) before any required gate moves onto it. # -# Pairs with internal#543 (RFC: Mac arm64 multi-arch runner-base). +# Runner label mapping (2026-05-22 fix): the actual Mac mini runner +# registered in this Gitea ships labels +# ["self-hosted","macos-self-hosted-arm64","arm64-darwin"] +# — no plain `arm64`. The earlier `runs-on: [self-hosted, arm64]` +# could not match any registered runner so every fire of this workflow +# was assigned task_id=0 / runner_id=NULL → Gitea cancelled it. The +# rows showed up as Cancelled in the action status feed (not Failed) +# but the lane never actually ran. Workflow now selects on +# `arm64-darwin` which is the canonical Mac-arm64 label per the +# Mac mini's registration (per internal#494 capability-honest labels). +# +# If we later want to add a Linux-arm64 runner to the same lane, add +# both labels to that runner's registration AND broaden the selector +# here — don't rename `arm64-darwin` (it's Mac-specific by design and +# `feedback_pc2_runner_labels_must_stay_narrow` rule applies). +# +# Pairs with internal#543 (RFC: Mac arm64 multi-arch runner-base) and +# internal#494 (multi-arch runner-base capability-honest labels). # No paths: filter on purpose (feedback_path_filtered_workflow_cant_be_required). on: @@ -25,7 +40,7 @@ permissions: jobs: shellcheck-arm64: name: shellcheck-arm64 (pilot) - runs-on: [self-hosted, arm64] + runs-on: [self-hosted, arm64-darwin] # NOT a required check; safe to sit pending until Mac runner is up. # If the Mac runner has trouble pulling actions/checkout we fall # back to a plain git clone (see step 'fallback clone'). -- 2.52.0 From 1e606494ad1004caa63b51e43f6689b147434caa Mon Sep 17 00:00:00 2001 From: cp-be Date: Fri, 22 May 2026 03:16:59 -0700 Subject: [PATCH 2/2] =?UTF-8?q?fix(ci):=20shellcheck-arm64-pilot=20?= =?UTF-8?q?=E2=80=94=20Bash=203.2=20portable=20file=20enumeration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 79275 / task 145654 on Mac mini runner empirically failed at: workflow/3.sh: line 6: mapfile: command not found Process completed with exit code 127 macOS ships Bash 3.2 (Apple license — won't update to GPLv3+ Bash 4+). `mapfile` is a Bash 4+ builtin; not available on Mac mini's /bin/bash. Earlier steps confirmed the Mac mini runner picks up the job correctly (uname -m = arm64, kernel Darwin 23.5.0, "arm64 confirmed") so the runner-label fix from this PR's first commit was correct — the workflow just needs a portable enumeration pattern. Replaced `mapfile -t TARGETS < <(find ...)` with: TARGETS=() while IFS= read -r f; do TARGETS+=("$f"); done < <(find ...) — works on Bash 3.2 (macOS) AND Bash 4+ (Linux runners we might add later). The `< <(...)` process substitution is Bash 3.2+ so the overall shape stays portable. Comment-documents the empirical reason so a future contributor doesn't reintroduce the Bash 4+ idiom without realising the Mac runner exists on this lane. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/lint-shellcheck-arm64-pilot.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/lint-shellcheck-arm64-pilot.yml b/.gitea/workflows/lint-shellcheck-arm64-pilot.yml index 39caa9310..ab4de5e5a 100644 --- a/.gitea/workflows/lint-shellcheck-arm64-pilot.yml +++ b/.gitea/workflows/lint-shellcheck-arm64-pilot.yml @@ -91,7 +91,16 @@ jobs: # Only the scripts we control under .gitea/scripts. Pilot # scope is intentionally narrow — broaden in a follow-up # once the lane is proven. - mapfile -t TARGETS < <(find .gitea/scripts -maxdepth 2 -type f -name '*.sh' | sort) + # + # NOTE: macOS ships Bash 3.2 (Apple license), no `mapfile` + # (Bash 4+ builtin). Mac mini runner empirically failed at + # `mapfile: command not found` (run 79275 / task 145654). + # Use the portable `while read` pattern instead — works on + # both Bash 3.2 (macOS) and Bash 4+ (Linux). + TARGETS=() + while IFS= read -r f; do + TARGETS+=("$f") + done < <(find .gitea/scripts -maxdepth 2 -type f -name '*.sh' | sort) if [ "${#TARGETS[@]}" -eq 0 ]; then echo "No .sh files found under .gitea/scripts — nothing to check" exit 0 -- 2.52.0