Merge origin/main into gsta203-pr4-oxlint-ratchet (rule 19 grant 3)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

# Conflicts:
#	CONTRIBUTING.md
This commit is contained in:
garrytan committed 2026-11-01 10:34:48 +00:00
commit 89fa633a58
275 files changed
+13903 -1516

No files matched your search

+15
View File
@@ -60,6 +60,21 @@ RUN curl --retry 5 --retry-delay 5 --retry-connrefused -fsSL \
&& rm -rf /var/lib/apt/lists/* \
&& git --no-lazy-fetch --version
# Partial clone: the eval jobs check out with `filter: blob:none` and read
# older files through on-demand blob fetches (.github/scripts/history-read.sh).
# Prove this Git makes a blobless clone and fetches a missing blob, so the image
# fails here instead of in a slice's history read.
RUN set -e; d=$(mktemp -d); \
git init -q -b main "$d/src"; echo one > "$d/src/f"; git -C "$d/src" add f; \
git -C "$d/src" -c user.name=ci -c user.email=ci@localhost commit -qm one; \
echo two > "$d/src/f"; git -C "$d/src" -c user.name=ci -c user.email=ci@localhost commit -qam two; \
git -C "$d/src" config uploadpack.allowFilter true; \
git clone -q --filter=blob:none --no-local "file://$d/src" "$d/clone"; \
test "$(git -C "$d/clone" config remote.origin.promisor)" = true; \
if GIT_NO_LAZY_FETCH=1 git -C "$d/clone" cat-file -e HEAD~1:f 2>/dev/null; then echo "blob present: not a partial clone" >&2; exit 1; fi; \
test "$(git -C "$d/clone" show HEAD~1:f)" = one; \
rm -rf "$d"; echo "partial clone: ok ($(git --version))"
RUN python3 -m venv /tmp/gstack-ci-venv \
&& /tmp/gstack-ci-venv/bin/python -m pip --version \
&& rm -rf /tmp/gstack-ci-venv
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Read one file at a commit in a CI checkout that may be a blobless clone
# (actions/checkout `filter: blob:none`), where git fetches an old file's
# contents on demand and that fetch can fail. lib/history-read.ts is the
# TypeScript twin.
#
# Usage: history-read.sh <ref> <path> [--absent <text>]
#
# A read that `git show` answers is the file. When it fails, existence comes
# from the ref's tree (`git ls-tree --full-tree`, local data only): a path the
# tree does not list is absent, so this prints <text> (default: nothing) and
# exits 0. A listed path is retried, 3 tries in all in a partial clone (only a
# fetch can recover) and none otherwise, waiting HISTORY_READ_BACKOFF_SECONDS
# (default 2) times the attempt between tries. Anything else (a ref that does
# not resolve, a fetch that keeps failing) exits 1 with HISTORY_READ_FAILED
# naming the ref, the path and the git version, and never reads as absent.
# docs/troubleshooting.md#history-read-failed
set -euo pipefail
if [ "$#" -ne 2 ] && { [ "$#" -ne 4 ] || [ "$3" != --absent ]; }; then
echo "usage: history-read.sh <ref> <path> [--absent <text>]" >&2
exit 2
fi
ref=$1 file=$2 absent=${4:-}
out=$(mktemp) err=$(mktemp)
trap 'rm -f "$out" "$err"' EXIT
fail() {
echo "::error::cannot read ${file} at ${ref}. $1 ($(git --version)). Fix: see docs/troubleshooting.md#history-read-failed (HISTORY_READ_FAILED)" >&2
exit 1
}
if git show "${ref}:${file}" >"$out" 2>"$err"; then cat "$out"; exit 0; fi
listed=$(git ls-tree --full-tree "$ref" -- "$file" 2>"$err") || fail "git ls-tree failed: $(head -n 1 "$err")"
if [ -z "$listed" ]; then
printf '%s' "$absent"
exit 0
fi
tries=1
if git config --get-regexp '^(remote\..+\.promisor|extensions\.partialclone)$' | grep -qvi ' false$'; then tries=3; fi
try=1
while [ "$try" -lt "$tries" ]; do
sleep "$(( try * ${HISTORY_READ_BACKOFF_SECONDS:-2} ))"
if git show "${ref}:${file}" >"$out" 2>"$err"; then cat "$out"; exit 0; fi
try=$(( try + 1 ))
done
fail "git show failed ${tries} time(s): $(head -n 1 "$err")"
+11 -1
View File
@@ -49,7 +49,17 @@ jobs:
- name: Read the train policy (main)
id: policy
run: |
train=$(git show "${GITHUB_SHA}:.gstack/ship-policy.json" 2>/dev/null | jq -c 'if (.train | type) == "object" then .train else null end' 2>/dev/null || true)
ref="$GITHUB_SHA" file=.gstack/ship-policy.json policy=null
read_failed() { echo "::error::cannot read ${file} at ${ref}. $1 ($(git --version)). Fix: see docs/troubleshooting.md#history-read-failed (HISTORY_READ_FAILED)" >&2; exit 1; }
listed=$(git ls-tree --full-tree "$ref" -- "$file") || read_failed "git ls-tree failed"
if [ -n "$listed" ]; then
for try in 1 2 3; do
policy=$(git show "${ref}:${file}") && break
if [ "$try" = 3 ]; then read_failed "git show failed 3 times"; fi
sleep $((try * 2))
done
fi
train=$(jq -c 'if (.train | type) == "object" then .train else null end' <<<"$policy") || { echo "::error::${GITHUB_SHA}:.gstack/ship-policy.json is not valid JSON; fix the policy file" >&2; exit 1; }
if [ -z "$train" ] || [ "$train" = null ]; then
echo "train=false" >> "$GITHUB_OUTPUT"
echo "- Backstop inert: main's .gstack/ship-policy.json declares no train block; per-PR gates cover main" >> "$GITHUB_STEP_SUMMARY"
+20 -3
View File
@@ -179,6 +179,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
filter: blob:none
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
@@ -193,9 +194,19 @@ jobs:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
base="${BASE_SHA:-origin/${DEFAULT_BRANCH}}"
train=$(git show "${base}:.gstack/ship-policy.json" 2>/dev/null | jq -c 'if (.train | type) == "object" then .train else null end' 2>/dev/null || true)
artifact=$(jq -r '.record_artifact // ""' <<<"${train:-null}" 2>/dev/null || true)
check=$(jq -r '.full_gate_check // ""' <<<"${train:-null}" 2>/dev/null || true)
ref="$base" file=.gstack/ship-policy.json policy=null
read_failed() { echo "::error::cannot read ${file} at ${ref}. $1 ($(git --version)). Fix: see docs/troubleshooting.md#history-read-failed (HISTORY_READ_FAILED)" >&2; exit 1; }
listed=$(git ls-tree --full-tree "$ref" -- "$file") || read_failed "git ls-tree failed"
if [ -n "$listed" ]; then
for try in 1 2 3; do
policy=$(git show "${ref}:${file}") && break
if [ "$try" = 3 ]; then read_failed "git show failed 3 times"; fi
sleep $((try * 2))
done
fi
train=$(jq -c 'if (.train | type) == "object" then .train else null end' <<<"$policy") || { echo "::error::${base}:.gstack/ship-policy.json is not valid JSON; fix the policy file" >&2; exit 1; }
artifact=$(jq -r '.record_artifact // ""' <<<"${train:-null}")
check=$(jq -r '.full_gate_check // ""' <<<"${train:-null}")
if [ -z "$train" ] || [ "$train" = null ]; then
echo "train=false" >> "$GITHUB_OUTPUT"
echo "- Train policy: none at ${base}; this run routes as before" >> "$GITHUB_STEP_SUMMARY"
@@ -470,6 +481,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
filter: blob:none
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
@@ -528,6 +540,7 @@ jobs:
# Preserve full history for merge-base diff selection. Moving the
# planner off the eval image must not change its selection inputs.
fetch-depth: 0
filter: blob:none
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
@@ -670,6 +683,7 @@ jobs:
# shards on the lane's first live run ("ambiguous argument
# 'main...HEAD'"). The manifest still governs WHICH shards run.
fetch-depth: 0
filter: blob:none
persist-credentials: false
- name: Fix bun temp
@@ -903,6 +917,7 @@ jobs:
with:
ref: ${{ inputs.screen_merge_sha }}
fetch-depth: 0
filter: blob:none
persist-credentials: false
- name: Fix bun temp
@@ -1029,6 +1044,7 @@ jobs:
with:
ref: ${{ fromJSON(needs.route.outputs.bisect_refs)[matrix.slice] }}
fetch-depth: 0
filter: blob:none
persist-credentials: false
- name: Verify the prefix checkout
@@ -1173,6 +1189,7 @@ jobs:
# history of its prefix commits T1..Tk for the train record.
ref: ${{ inputs.screen_merge_sha }}
fetch-depth: ${{ needs.plan-slices.outputs.mode == 'train' && '0' || '1' }}
filter: blob:none
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
+3 -1
View File
@@ -65,8 +65,10 @@ jobs:
with:
persist-credentials: false
# Full history: the seed ratchet compares the allowlist with its
# merge-base copy, which a depth-1 checkout cannot read.
# merge-base copy, which a depth-1 checkout cannot read. Blobless:
# that copy is fetched on demand, and a failed read fails the ratchet.
fetch-depth: 0
filter: blob:none
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.2
+9 -2
View File
@@ -23,6 +23,9 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
# Blobless: full history with file contents fetched on demand; the
# reads below fail loudly when a fetch fails (.github/scripts/history-read.sh).
filter: blob:none
ref: ${{ github.event.pull_request.head.sha }}
# The head's release_tool runs inside the gate (lib/version-gate-train.ts);
# no token may sit in the checkout it stages. The base fetch below is public.
@@ -49,8 +52,12 @@ jobs:
set -euo pipefail
PR_VERSION=$(cat VERSION | tr -d '[:space:]')
BASE_REF="${{ github.event.pull_request.base.ref }}"
git fetch origin "$BASE_REF" --quiet || true
BASE_VERSION=$(git show "origin/$BASE_REF:VERSION" 2>/dev/null | tr -d '[:space:]' || echo "0.0.0.0")
for try in 1 2 3; do
git fetch origin "$BASE_REF" --quiet && break
if [ "$try" = 3 ]; then echo "::error::git fetch origin $BASE_REF failed 3 times ($(git --version)). Fix: see docs/troubleshooting.md#history-read-failed (HISTORY_READ_FAILED)"; exit 1; fi
sleep $((try * 2))
done
BASE_VERSION=$(bash .version-gate/.github/scripts/history-read.sh "origin/$BASE_REF" VERSION --absent 0.0.0.0 | tr -d '[:space:]')
{
echo "pr_version=$PR_VERSION"
echo "base_version=$BASE_VERSION"