mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
* fix(pregate): recognise bats test files so lanes does not fail in bats repos (#3161) gstack-pregate never treated a .bats file as a test, so in a repository whose tests are bats files the lanes check failed every run with PREGATE_NO_LANE: a .gstack/pregate.json dependency pointing at tests/foo.bats selected nothing, a selection manifest printing .bats paths yielded 0 files, and a bats run that executed no tests could not trip the zero-run rule. Recognise .bats in the test-file pattern and in the manifest-output parser, and read the bats TAP plan and pretty summary (as a last resort, after every existing runner's summary) so a run that reports zero tests is a failure. Fixes #3161. Cherry-picked from #3177 (d355c116b). Conflicts resolved as in the author's own merges (b09476beb,444f4e768): lane-selection.ts keeps main's isTestFile-based manifest parser, and lanes.ts carries the bats summary on main's supervised runner. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(pregate): a nested .bats file is selected and run end to end (#3161) Reviewer test for #3177: touched itself with no declaration, and through a declared dependency; a failing nested bats run reports the bats counts. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(pregate): a wtree failure is WTREE_UNAVAILABLE, not an unresolvable base (#3197) The pregate consumers of the working-tree fingerprint (buildContext, withFingerprint, verifyPregate) move to lib/script-invocation.ts's {tree}|{error} form, and lib/regen.ts drops its string-returning wrapper. - A fingerprint failure was reported as "policy source unavailable: origin/<base> is not a resolvable commit" with git fetch as the fix. It is now WTREE_UNAVAILABLE: a launch failure lists each Windows bash candidate with its rejection reason and names GSTACK_GIT_BASH; a gstack-wtree exit keeps the repair it printed (set TMPDIR to a writable directory). - A fingerprint failing after a check is incomplete with that cause, not "working tree changed"; verify says the tree cannot be fingerprinted. - #3190's gstack-config read (test_backend) goes through runScriptSync, so Windows reaches it through Git Bash. The tripwire learns the bin-constant shape that let it through. - Under --json every context refusal is one envelope on stdout ({ok:false,status:'refused',code,detail,fix,docs}, exit 3); the run object carries ok and status too, and GSTACK_RESULT goes to stderr. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * ci(pregate): gstack-pregate joins the Windows pregate job; pregate tests return to the Windows lane (#3197) - windows-pregate-e2e runs gstack-pregate run (preflight: regen, secrets through the gstack-redact bun bin, literals, guards) in both journeys, and asserts a missing GSTACK_GIT_BASH refuses with one WTREE_UNAVAILABLE --json envelope. - test/helpers/pregate-fixture.ts and restamp-fixture.ts runBin launch bins through lib/script-invocation.ts (bun bins as Bun argv, bash bins through Git Bash on Windows), which removes the "shebang via CreateProcess" reason for the pregate tests; they move from KNOWN_WINDOWS_INCOMPATIBLE to KNOWN_WINDOWS_SAFE. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * doctor: list rescue refs and warn about CLAUDE.md skill lists gstack-doctor's plain report gains two rows. 'rescue refs' lists each refs/gstack/rescue/* commit in the install checkout, newest first, with its date, a needs-manual-resolution label when the rescue held unmerged files, and the shell-quoted inspect and delete commands bin/gstack-ff-update's banner prints. 'CLAUDE.md' warns when a gstack section in ~/.claude/CLAUDE.md or the project's CLAUDE.md enumerates skills (#3169) and prints the short block to paste instead; docs/troubleshooting.md#claude-md-skill-list explains it. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * doctor: name the Windows bash gstack resolves and what chose it On Windows (OSTYPE msys/cygwin) gstack-doctor adds a 'windows bash' row from lib/script-invocation.ts resolveWindowsBash, run through the new thin bin/gstack-windows-bash.ts with the bun on PATH: the resolved bash and the override or discovery step that chose it, a warn when GSTACK_GIT_BASH and GSTACK_BASH differ, and a fail carrying the BASH_UNAVAILABLE line (every candidate with its rejection reason) when none qualifies. Tests inject the platform (GSTACK_DOCTOR_PLATFORM) and the discovery inputs (GSTACK_DOCTOR_BASH_PROBE) so the row runs on every OS. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * doctor --check: name the held-install recovery on Windows, not bin/gstack-upgrade bin/gstack-upgrade compares a pwd -P path (/c/...) with git's toplevel (C:/...) and refuses on every Git Bash install, so on Windows the revision row's upgrade fix (REVISION_BELOW_MINIMUM, the Capy-wrapper variant and REVISION_UNMET) names the held-install recovery forms from docs/troubleshooting.md#auto-update-held-install-recovery instead: the Git Bash form and the Windows PowerShell 5.1 form, each labelled by shell with the install path quoted for that shell. Other platforms keep bin/gstack-upgrade. A test pins both printed forms to the documented ones. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(skills): omit the plan-mode section on hosts without plan mode (#3168) generatePlanModeInfo now honours capabilities.planMode. Hosts that declare planMode:false (codex, agy, hermes, openclaw, and define-host's default: factory, kiro, slate, cursor, gbrain) no longer render the '## Plan Mode Safe Operations' and '## Skill Invocation During Plan Mode' preamble sections. Claude, copilot and opencode are unchanged. The codex, factory and agy ship goldens are regenerated. The clarity test that pinned the plan-mode entry-order prose on every host now pins it on planMode hosts and asserts its absence elsewhere (intentional contract change). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(skills): guard generated SKILL.md size at 100,000 chars on every host (#3199) A free test renders every host and fails when a generated SKILL.md exceeds 100,000 characters, naming host, skill, actual size, limit and the fix. The 89 current offenders are pinned at their exact size in test/fixtures/skill-md-size-allowlist.json: growth past a pin fails, and a shrink fails until the pin is lowered. The shared-preamble hoist is deferred (owner Garry, revisit 2026-11-15). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(pregate): keep #3177's bats tests beside the nested-directory test Moves #3177's bats describe block verbatim from test/pregate-selection.test.ts into test/pregate-bats-nested.test.ts, so pregate-selection.test.ts is unchanged on this branch and the in-flight field-list-2 pregate lane (capy/fl2-L6-pregate, which edits that file's imports and adds cases) merges without a conflict. No assertion changes. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * doctor --check: keep bin/gstack-upgrade as the Windows fix (path spelling fixed on main) Reverts37bac07f8. Plan item D named the held-install recovery forms on Windows only until bin/gstack-upgrade stopped refusing Git Bash installs. bin/gstack-upgrade:63-67 now compares with gstack_path_same from bin/gstack-path-spelling.sh, pinned by test/gstack-upgrade-path-spelling.test.ts, so bin/gstack-upgrade is the right fix on every platform again. * test(skills): measure the size-guard pins on v1.91.109.0 #3225 (merged into this branch) grew 53 pinned skills: 3 characters each from the Aside driver resolver, and about 340 more in plan-design-review and plan-devex-review from the #3219 summary sections. The pins are this PR's starting measurement, so they are taken on the merged base; no skill this PR renders grew. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * ci(windows): only the pregate tests that pass on windows-latest join the lane windows-free-tests run 38984824731 (this branch at8ed6da402) ran the moved files. gstack-regen and the new pregate-wtree-refusal passed. pregate-guards, -remote, -regate, -invalidation, -selection and -bats-nested launched gstack-pregate fine but fail on Linux-host expectations: their fixture lanes are Linux workflow jobs, which a Windows host records as requires-remote obligations. They go back to KNOWN_WINDOWS_INCOMPATIBLE with that reason instead of "shebang via CreateProcess". Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * windows curation: keep CI run ids out of reason prose (pii.phone false positive) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * skill-md size pins: follow #3231's review-army line (+21 chars on five inlining hosts) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * doctor test: drop the reverted Windows upgrade-fix wording from item D's describe Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * skill-md size pins: follow #3226 (plan-devex-review +3324) and #3234 (autoplan +59) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * WTREE_UNAVAILABLE moves to lib/result-codes-release.ts (#3235 split; result-codes.ts stays at 796 of 800 lines); doctor fixture copies the release table; size pins follow #3235's review +1 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): fix wave PR 5 release notes Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * v1.91.117.0 fix: fix wave PR 5 (pregate bats + WTREE_UNAVAILABLE, doctor rows, SKILL.md size guard, planMode hosts) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(qa): an invalid-input probe breaks only the rule it tests The paid gate's qa-functional-cli-report failed again on #3236 (run 39001107574): the agent probed the digits-only amount rule with -5, which the positivity check rejected first, so the planted parseInt defect stayed hidden and it reported no defect. The contract map's invalid-input row now asks for each input to break only the rule it tests, so another check cannot reject it first. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: harjothkhara <48686985+harjothkhara@users.noreply.github.com> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
246 lines
14 KiB
YAML
246 lines
14 KiB
YAML
name: Windows Pregate E2E
|
|
|
|
# Native proof for #3197 on windows-latest: Bun on Windows cannot execute an
|
|
# extensionless shebang bin (bin/gstack-wtree, gstack-slug, gstack-redact),
|
|
# so every TypeScript caller goes through lib/script-invocation.ts, which
|
|
# hands bash bins to Git Bash and bun bins to Bun. This job drives the real
|
|
# CLIs from TypeScript entry points against a fixture repository:
|
|
# - the resolver finds Git Bash from `git --exec-path`;
|
|
# - gstack-restamp --dry-run fingerprints the tree and stamps;
|
|
# - gstack-regen check (scratch worktree from the fingerprint, the entry's
|
|
# command through `bash -c`) and write (the no-scratch path);
|
|
# - gstack-evidence records a content fingerprint, its command through bash -c;
|
|
# - gstack-gate-diff records a candidate with a tree id, not `+nowtree`;
|
|
# - gstack-pregate run fingerprints the tree and runs its preflight checks
|
|
# (secrets through the gstack-redact bun bin, regen and guards);
|
|
# - a hook invocation is timed cold and warm (the cached resolution);
|
|
# - a missing GSTACK_GIT_BASH refuses with BASH_UNAVAILABLE, not `()`, and
|
|
# gstack-pregate --json refuses with one WTREE_UNAVAILABLE envelope;
|
|
# - the same journey under a pinned, checksum-verified PortableGit found
|
|
# only through `git --exec-path`.
|
|
#
|
|
# Runner: GitHub-hosted free windows-latest. ~4-6 min.
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
paths:
|
|
- 'lib/script-invocation.ts'
|
|
- 'lib/regen.ts'
|
|
- 'lib/restamp.ts'
|
|
- 'lib/gbrain-exec.ts'
|
|
- 'lib/gate-diff/**'
|
|
- 'lib/pregate/**'
|
|
- 'lib/result-codes.ts'
|
|
- 'lib/result-codes-release.ts'
|
|
- 'bin/gstack-wtree'
|
|
- 'bin/gstack-slug'
|
|
- 'bin/gstack-path-spelling.sh'
|
|
- 'bin/gstack-restamp'
|
|
- 'bin/gstack-regen'
|
|
- 'bin/gstack-evidence'
|
|
- 'bin/gstack-gate-diff'
|
|
- 'bin/gstack-redact'
|
|
- 'bin/gstack-pregate'
|
|
- 'hosts/claude/hooks/**'
|
|
- '.github/workflows/windows-pregate-e2e.yml'
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: windows-pregate-e2e-${{ github.event.pull_request.number || github.run_id }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
PORTABLE_GIT_VERSION: 2.56.0.windows.2
|
|
PORTABLE_GIT_FILE: PortableGit-2.56.0.2-64-bit.7z.exe
|
|
PORTABLE_GIT_SHA256: 075e158ef8e1f0ab80b347e245405d3eca735c2dc88fd8e032e137d0ca61f61b
|
|
|
|
jobs:
|
|
windows-pregate:
|
|
runs-on: windows-latest
|
|
timeout-minutes: 20
|
|
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
|
|
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
|
with:
|
|
bun-version: 1.4.2
|
|
|
|
- name: Configure git identity
|
|
run: |
|
|
git config --global user.email "windows-pregate-e2e@gstack.test"
|
|
git config --global user.name "Windows Pregate E2E"
|
|
git config --global init.defaultBranch main
|
|
git config --global commit.gpgsign false
|
|
shell: bash
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
shell: bash
|
|
|
|
- name: Build the fixture repository
|
|
# A VERSION + CHANGELOG + ship policy + generated-file registry, a
|
|
# bare origin and a feature branch with an [Unreleased] entry.
|
|
run: |
|
|
set -euo pipefail
|
|
T="$RUNNER_TEMP/pregate-e2e"
|
|
rm -rf "$T"; mkdir -p "$T/home"
|
|
git init -q --bare -b main "$T/origin.git"
|
|
git init -q -b main "$T/work"
|
|
cd "$T/work"
|
|
mkdir -p generated .gstack
|
|
echo 1.2.3.0 > VERSION
|
|
printf '{ "name": "fixture", "version": "1.2.3" }\n' > package.json
|
|
printf '%s\n' "const fs=require('fs');const v=fs.readFileSync('VERSION','utf8').trim();fs.writeFileSync('generated/digest.md','# digest v'+v+'\\n');" > gen.js
|
|
node gen.js
|
|
printf '# Changelog\n\n## [1.2.3.0] - 2026-10-01\n\n- base release\n' > CHANGELOG.md
|
|
cat > .gstack/ship-policy.json <<'JSON'
|
|
{ "$schema": "https://github.com/garrytan/gstack/docs/ship-policy.md#schema-v1", "bump": "patch", "queue_mode": "stamp-at-merge", "release_tool": "node gen.js", "release_outputs": ["generated/**"], "stamp_paths": [], "changelog": "CHANGELOG.md", "history": "squash-ok", "stamp_sensitive_gates": [] }
|
|
JSON
|
|
cat > .gstack/generated.json <<'JSON'
|
|
{ "$schema": "https://github.com/garrytan/gstack/docs/pregate.md#generated-v1", "entries": [ { "id": "digest", "command": "node gen.js", "outputs": ["generated/**"], "inputs": ["VERSION", "gen.js"] } ] }
|
|
JSON
|
|
git add -A && git commit -qm base
|
|
git remote add origin "$T/origin.git" && git push -q origin main && git remote set-head origin main
|
|
git checkout -qb feature
|
|
echo feature > feature.txt
|
|
printf '# Changelog\n\n## [Unreleased]\n\n- feature change\n\n## [1.2.3.0] - 2026-10-01\n\n- base release\n' > CHANGELOG.md
|
|
git add -A && git commit -qm feature
|
|
shell: bash
|
|
|
|
- name: The resolver finds the runner's Git Bash from git --exec-path
|
|
run: |
|
|
set -euo pipefail
|
|
git --version
|
|
OUT=$(bun -e 'import { resolveWindowsBash } from "./lib/script-invocation"; const r = resolveWindowsBash(); console.log(JSON.stringify(r)); process.exit(r.ok ? 0 : 1);')
|
|
echo "$OUT"
|
|
echo "$OUT" | grep -q '"source":"git --exec-path"' || (echo "Git Bash was not found through git --exec-path" && exit 1)
|
|
echo "$OUT" | grep -qiE '"bash":"[^"]*/(usr/)?bin/bash\.exe"' || (echo "the resolved bash is not a Git Bash bash.exe" && exit 1)
|
|
shell: bash
|
|
|
|
- name: A hook invocation, timed cold and warm (cached Git Bash resolution)
|
|
run: |
|
|
set -euo pipefail
|
|
T="$RUNNER_TEMP/hook-timing"
|
|
rm -rf "$T"; mkdir -p "$T"
|
|
PAYLOAD='{"session_id":"e2e","hook_event_name":"PostToolUse","tool_name":"AskUserQuestion","tool_use_id":"TOOL_ID","tool_input":{"questions":[{"question":"Ship it?","options":[{"label":"Ship now (recommended)"},{"label":"Hold"}]}]},"tool_response":{"answers":[{"option_label":"Ship now"}]}}'
|
|
run_hook() {
|
|
local start end
|
|
start=$(date +%s%3N)
|
|
printf '%s' "${PAYLOAD/TOOL_ID/$1}" | (cd "$T" && GSTACK_STATE_ROOT="$T" GSTACK_QUESTION_LOG_NO_DERIVE=1 bun "$GITHUB_WORKSPACE/hosts/claude/hooks/question-log-hook.ts")
|
|
end=$(date +%s%3N)
|
|
echo $((end - start))
|
|
}
|
|
COLD=$(run_hook toolu_cold)
|
|
test -f "$T/cache/windows-bash.json" || (echo "the hook did not cache its Git Bash resolution" && exit 1)
|
|
cat "$T/cache/windows-bash.json"
|
|
WARM=$(run_hook toolu_warm)
|
|
echo "question-log-hook: cold ${COLD} ms, warm ${WARM} ms"
|
|
echo "### question-log-hook on windows-latest: cold ${COLD} ms, warm ${WARM} ms" >> "$GITHUB_STEP_SUMMARY"
|
|
LOGS=$(find "$T/projects" -name question-log.jsonl | head -n 1)
|
|
test -n "$LOGS" || (echo "the hook wrote no question-log.jsonl" && exit 1)
|
|
test "$(wc -l < "$LOGS")" -eq 2 || (echo "expected two logged events" && exit 1)
|
|
test ! -s "$T/hook-errors.log" || { cat "$T/hook-errors.log"; echo "the hook logged errors"; exit 1; }
|
|
shell: bash
|
|
|
|
- name: A missing GSTACK_GIT_BASH refuses with BASH_UNAVAILABLE and names every candidate
|
|
run: |
|
|
set -uo pipefail
|
|
T="$RUNNER_TEMP/pregate-e2e"
|
|
cd "$T/work"
|
|
OUT=$(GSTACK_HOME="$T/home" GSTACK_GIT_BASH='C:\no-such-git\bin\bash.exe' bun "$GITHUB_WORKSPACE/bin/gstack-restamp" --base main --allow-repo-commands --next --dry-run 2>&1) && CODE=0 || CODE=$?
|
|
echo "$OUT" | tail -n 3
|
|
test "$CODE" -ne 0 || (echo "restamp passed without a bash" && exit 1)
|
|
echo "$OUT" | grep -q 'cannot fingerprint the working tree (gstack-wtree could not start: gstack: no Git Bash found' || (echo "the refusal does not say why" && exit 1)
|
|
echo "$OUT" | grep -q 'GSTACK_GIT_BASH C:/no-such-git/bin/bash.exe: does not exist' || (echo "the refusal does not list the override" && exit 1)
|
|
echo "$OUT" | grep -q '(BASH_UNAVAILABLE)' || (echo "the refusal has no result code" && exit 1)
|
|
OUT=$(GSTACK_HOME="$T/home" GSTACK_GIT_BASH='C:\no-such-git\bin\bash.exe' bun "$GITHUB_WORKSPACE/bin/gstack-pregate" run --base main --stage preflight --json 2>/dev/null) && CODE=0 || CODE=$?
|
|
echo "$OUT"
|
|
test "$CODE" -eq 3 || (echo "gstack-pregate exited $CODE, expected 3 (refused)" && exit 1)
|
|
echo "$OUT" | bun -e 'const j = JSON.parse(await Bun.stdin.text()); const ok = j.ok === false && j.status === "refused" && j.code === "WTREE_UNAVAILABLE" && j.detail.includes("GSTACK_GIT_BASH C:/no-such-git/bin/bash.exe: does not exist") && j.fix.includes("GSTACK_GIT_BASH"); process.exit(ok ? 0 : 1);' || (echo "gstack-pregate --json did not refuse with one WTREE_UNAVAILABLE envelope" && exit 1)
|
|
shell: bash
|
|
|
|
- name: Download the pinned PortableGit and verify its checksum
|
|
run: |
|
|
set -euo pipefail
|
|
PG="$RUNNER_TEMP/PortableGit"
|
|
curl -fsSL -o "$RUNNER_TEMP/$PORTABLE_GIT_FILE" "https://github.com/git-for-windows/git/releases/download/v${PORTABLE_GIT_VERSION}/${PORTABLE_GIT_FILE}"
|
|
echo "$PORTABLE_GIT_SHA256 $RUNNER_TEMP/$PORTABLE_GIT_FILE" | sha256sum -c -
|
|
"$RUNNER_TEMP/$PORTABLE_GIT_FILE" -o"$(cygpath -w "$PG")" -y
|
|
test -f "$PG/bin/bash.exe" || (echo "PortableGit has no bin/bash.exe" && exit 1)
|
|
"$PG/cmd/git.exe" --version
|
|
shell: bash
|
|
|
|
- name: The resolver finds the PortableGit bash through git --exec-path alone
|
|
run: |
|
|
set -euo pipefail
|
|
PG=$(cygpath -u "$RUNNER_TEMP/PortableGit")
|
|
export PATH="$PG/cmd:$PATH"
|
|
git --version
|
|
WANT=$(cygpath -m "$PG/bin/bash.exe")
|
|
OUT=$(bun -e 'import { resolveWindowsBash } from "./lib/script-invocation"; const r = resolveWindowsBash(); console.log(JSON.stringify(r)); process.exit(r.ok ? 0 : 1);')
|
|
echo "$OUT"
|
|
echo "$OUT" | grep -qiF "\"bash\":\"$WANT\"" || (echo "expected $WANT" && exit 1)
|
|
echo "$OUT" | grep -q '"source":"git --exec-path"' || (echo "PortableGit was not found through git --exec-path" && exit 1)
|
|
shell: bash
|
|
|
|
- name: The fixture journey (restamp, regen, evidence, gate-diff) under the runner's Git and the pinned PortableGit
|
|
run: |
|
|
set -euo pipefail
|
|
journey() {
|
|
G="$PWD"
|
|
T="$RUNNER_TEMP/pregate-e2e"
|
|
export GSTACK_HOME="$T/home" GSTACK_STATE_ROOT="$T/home"
|
|
cd "$T/work"
|
|
git reset -q --hard && git clean -fdq
|
|
rm -rf "$T/home/projects"
|
|
|
|
OUT=$(bun "$G/bin/gstack-restamp" --base main --allow-repo-commands --next --dry-run 2>&1) || { echo "$OUT"; echo "gstack-restamp --dry-run failed"; exit 1; }
|
|
echo "$OUT" | tail -n 8
|
|
echo "$OUT" | grep -q '^+1\.2\.4\.0$' || (echo "restamp did not stamp VERSION" && exit 1)
|
|
echo "$OUT" | grep -q '^+# digest v1\.2\.4\.0$' || (echo "restamp did not run the release tool" && exit 1)
|
|
echo "$OUT" | grep -q 'GSTACK_RESULT: skill=restamp status=complete' || (echo "restamp did not complete" && exit 1)
|
|
test -z "$(git status --porcelain)" || (echo "--dry-run wrote to the tree" && exit 1)
|
|
|
|
OUT=$(bun "$G/bin/gstack-regen" check --allow-repo-commands 2>&1) || { echo "$OUT"; echo "gstack-regen check failed"; exit 1; }
|
|
echo "$OUT"
|
|
echo "$OUT" | grep -q '^regen digest: fresh' || (echo "the regen command did not run fresh in the scratch worktree" && exit 1)
|
|
echo "$OUT" | grep -qE 'GSTACK_RESULT: skill=regen status=complete run=[0-9a-f]{40}$' || (echo "regen check has no tree fingerprint" && exit 1)
|
|
OUT=$(bun "$G/bin/gstack-regen" write --allow-repo-commands 2>&1) || { echo "$OUT"; echo "gstack-regen write failed"; exit 1; }
|
|
echo "$OUT" | grep -qE 'GSTACK_RESULT: skill=regen status=complete run=[0-9a-f]{40}$' || (echo "regen write has no tree fingerprint" && exit 1)
|
|
|
|
bun "$G/bin/gstack-evidence" run --label tests -- 'echo evidence-ok && test -f VERSION'
|
|
LEDGER=$(find "$T/home/projects" -name '*-evidence.jsonl' | head -n 1)
|
|
test -n "$LEDGER" || (echo "no evidence ledger written" && exit 1)
|
|
tail -n 1 "$LEDGER"
|
|
tail -n 1 "$LEDGER" | grep -qE '"exit":0,' || (echo "the evidence command did not exit 0 through bash -c" && exit 1)
|
|
tail -n 1 "$LEDGER" | grep -qE '"wtree":"[0-9a-f]{40}"' || (echo "evidence recorded no content fingerprint" && exit 1)
|
|
|
|
set +e
|
|
OUT=$(bun "$G/bin/gstack-gate-diff" main 2>&1)
|
|
CODE=$?
|
|
set -e
|
|
echo "$OUT" | tail -n 3
|
|
test "$CODE" -eq 0 || (echo "gstack-gate-diff exited $CODE" && exit 1)
|
|
! echo "$OUT" | grep -q 'fingerprint unavailable' || (echo "gate-diff could not fingerprint the tree" && exit 1)
|
|
echo "$OUT" | grep -qE 'candidate=[0-9a-f]{12}\+[0-9a-f]{12} ' || (echo "gate-diff candidate has no tree id" && exit 1)
|
|
|
|
OUT=$(bun "$G/bin/gstack-pregate" run --base main --stage preflight --only regen,secrets,literals,guards --allow-repo-commands 2>&1) || { echo "$OUT"; echo "gstack-pregate run failed"; exit 1; }
|
|
echo "$OUT" | tail -n 10
|
|
echo "$OUT" | grep -qE '^preflight secrets pass .* added lines clean' || (echo "pregate secrets did not scan through gstack-redact" && exit 1)
|
|
echo "$OUT" | grep -q 'GSTACK_RESULT: skill=pregate status=complete run=' || (echo "pregate did not complete" && exit 1)
|
|
grep -qE '"tree": "[0-9a-f]{40}"' .gstack/tmp/pregate.json || (echo "pregate.json has no tree fingerprint" && exit 1)
|
|
}
|
|
echo "::group::runner Git for Windows ($(git --version))"
|
|
(journey)
|
|
echo "::endgroup::"
|
|
echo "::group::pinned PortableGit $PORTABLE_GIT_VERSION"
|
|
PG_CMD=$(cygpath -u "$RUNNER_TEMP/PortableGit/cmd")
|
|
(export PATH="$PG_CMD:$PATH"; git --version; journey)
|
|
echo "::endgroup::"
|
|
shell: bash
|