Commit Graph
511 Commits
Author SHA1 Message Date
garrytan ec97187d96 I1: run paid eval containers with seccomp unconfined so Codex's sandbox can start
Docker's default seccomp profile blocks the user namespaces bubblewrap needs,
so every Codex command in a paid eval failed with 'bwrap: No permissions to
create a new namespace' (codex-review-findings, run 37151477069). Reproduced
in the CI image locally: default profile fails, seccomp=unconfined runs the
command. The runner stays non-root.
2026-10-03 22:23:57 +00:00
garrytan 3a13b6d0c0 I1: Codex evals fail a review whose commands never ran and stop reading tool errors as skill-load problems
validateCodexReview accepted codex-review-findings in periodic run 37151477069
although its only command failed in bwrap ('I couldn't run the review'); it
now requires execution evidence from classifyOutsideReview (B1's INV-1
classifier). codex-sol-scope-termination failed on 'apply_patch verification
failed: invalid hunk' because the skill-load check matched any 'invalid';
it now matches Codex 0.160's skill-loader diagnostics only.
2026-10-03 22:23:57 +00:00
garrytan ed5260a254 I1: give hermetic Codex runs a temp dir beside CODEX_HOME so Codex can create its PATH aliases
Codex 0.160 refuses to create its helper aliases (codex-linux-sandbox among
them) when CODEX_HOME sits under its temp dir, and the runner put the
hermetic home under the shard TMPDIR. Periodic run 37151477069 shows the
warning and 'Unable to spawn codex-linux-sandbox ... No viable candidates
found in PATH' for every exec_command in codex-sol-scope-termination.
2026-10-03 22:23:57 +00:00
garrytan aab8009b68 I1: grade the AUQ matrix's (recommended) marker on option labels, the field the auto-decide hook reads
The decision-brief format puts a Pros / cons block with 'A) ... (recommended)'
in the question text and the same marker on the option label. The matrix
counted both and failed all six skills in periodic run 37151477069 with
'expected exactly one (recommended) option, found 2'. The question-preference
hook reads labels only, so the gate now checks the native question: a
Recommendation line in the question text and exactly one label ending in
(recommended). Fixtures move to the native question shape and add the real
spec capture plus a marker-only-in-text negative control.
2026-10-03 22:15:44 +00:00
garrytan b8d08f1f4d G2/G3/INV-1: skill-start former-bucket notice and visible learnings failure; TMPDIR mktemp in gbrain bins; best-effort reasons 2026-10-03 21:44:06 +00:00
garrytan 8857089e85 Merge lane wave/setup 2026-10-03 21:43:08 +00:00
garrytan c05c796bc9 Merge lane wave/redaction 2026-10-03 21:43:08 +00:00
garrytan 67d5685ee3 Merge lane wave/ship-review 2026-10-03 21:43:08 +00:00
garrytan 5302d7a1bd Merge lane wave/browse-platform 2026-10-03 21:43:08 +00:00
garrytan 44e03d52aa Merge lane wave/memory 2026-10-03 21:43:08 +00:00
garrytan 93742a1ae2 Merge lane wave/inv1-codex 2026-10-03 21:43:07 +00:00
garrytan 8d1b6dc470 A2: treat db-unreachable like timeout in gbrain-refresh
The memory lane's new db-unreachable status (network or DNS failure, config
intact) is transient, so gbrain-refresh keeps rendering brain-aware blocks
for it exactly as it does for timeout instead of suppressing them.
2026-10-03 21:41:25 +00:00
garrytan 4527c9b93f C3: guard Kiro's router copies on a present source; give the QA pointer adapter the copy and dist helpers
A copy fails where a symlink dangled, so the Kiro router and upgrade copies
are written only when their render exists (as every other runtime root
already does). test/qa-lazy-sections' extracted Kiro installer now supplies
_link_runtime_dists (C2) and the SKILL.md copy helpers (C3).
2026-10-03 21:38:56 +00:00
garrytan 8ae92b2bd0 C7: keep the required-mode hook's exit-2 deny
Copilot CLI treats a preToolUse exit 2 as deny (its hooks reference), and
#2413 established exit 2 plus hookSpecificOutput as the shape Claude Code
enforces, so the deny output stays as on main; only the matcher and the
in-place upgrade of older 'Skill' entries change.
2026-10-03 21:38:56 +00:00
garrytan 7a04d4c708 A2: key the dot-slug catalog entry on the message users actually saw 2026-10-03 21:34:36 +00:00
garrytanandbenjamin beres 6c0917aed2 B8: read gbrain JSON with bun instead of jq in install and wireup
gstack-gbrain-install read package.json with jq but never checked for it,
so on a machine without jq a successful install failed with "cannot read
version". gstack-gbrain-source-wireup hard-failed without jq ("brew
install jq" is not actionable on git-bash), so the wireup was skipped on
every run. Both now read the JSON with bun, which they already require.

Co-authored-by: benjamin beres <benjamin.beres@bienpreter.com>
2026-10-03 21:34:15 +00:00
garrytanandBrandon Pugsley c612f28339 A8: rename the artifacts repo with OWNER/REPO, rewrite the remote only after it
The v1.27.0.0 migration passed a bare repo name to gh repo rename / gh
repo edit, which always fails (gh wants [HOST/]OWNER/REPO), then step 2
rewrote ~/.gstack-artifacts-remote.txt to the never-renamed repository.

- Qualify both names with the owner from the recorded remote URL (else
  the signed-in gh user) and surface gh's error.
- Step 2 moves the remote file but rewrites the URL only once the rename
  is confirmed; a later successful retry rewrites it then.
- A pending journal now counts as state to migrate, so the #1383 retry
  actually re-runs step 1 (it used to see no legacy file and declare the
  migration done).
- The v1.91.17.0 migration (placeholder name) repairs installs already
  hit: when the remote names gstack-artifacts-<user> that does not exist
  but gstack-brain-<user> does, it restores the old URL in the remote
  file and ~/.gstack's origin and says so. It only calls gh for such a
  remote and never fails the upgrade.

Co-authored-by: Brandon Pugsley <aibpaem@gmail.com>
2026-10-03 21:32:42 +00:00
garrytan 4034a55029 F1: ship and review count unverified/unavailable outside reviews as missing coverage
INV-1 consumers in this lane's templates: /ship's readiness note, its
PR body Pre-Landing Review section and /review's completion rule now say
an outside review reporting unverified or unavailable is missing
coverage, never a pass. The PR body's Plan Completion section prints
F1's not-run line instead of the old 'No plan file detected.' The /ship
union-size cap moves to 1.415 for these lines (measured 1.4148).
2026-10-03 21:31:56 +00:00
garrytan a05965fb0a B9: read cycle_freshness from a doctor run that includes it
/sync-gbrain Step 3.5 and the --full auto-dream decision read CYCLE from
gbrain doctor --json --fast, which skips the DB checks that carry
cycle_freshness, so the answer was always "unknown". Both now read
gbrain doctor --json --scope=brain (DB checks, no skill-file walk), parse
its JSON even when doctor exits 1 for a failing check, and match the
issue that names this source: "never completed" is never, "last cycled
Nh ago" is completed. When the installed gbrain does not report the
check, they say "unknown: installed gbrain does not expose
cycle_freshness" (lib readCycleStatus carries the reason to the --full
SKIP row).

The source-probe fixture that pinned the --fast call and a made-up
message format now answers --scope=brain with gbrain's real message.
2026-10-03 21:30:04 +00:00
garrytan 4c0436376b D0: keep the dotenv isolation test runnable on the Windows lane
The compiled probe gets its .exe name on Windows, and the terminal-agent
case (owner identity comes from ps) is skipped there.
2026-10-03 21:29:10 +00:00
garrytanandliutiming 76bf72d89f A7: run only the resolve_symbol_edges dream phase, detected first
/sync-gbrain --dream and the --full auto-build ran gbrain's full dream
cycle (~35 minutes, LLM phases) when the call graph needs only the
resolve_symbol_edges phase. The stage now runs
gbrain dream [--source <id>] --phase resolve_symbol_edges when the
installed gbrain accepts that phase (detected by behavior: gbrain
validates --phase before printing --help). Otherwise it skips the forced
dream and says the full cycle costs about 35 minutes and how to run it,
instead of starting it.

Co-authored-by: liutiming <timingliu@outlook.com>
2026-10-03 21:26:00 +00:00
garrytan 3995f0ebf2 D2: give the memory-leak reproducer's fake request isNavigationRequest()
wirePageEvents now runs the navigation guard on every request event; the
fake request adapter supplies the method real Playwright requests have.
2026-10-03 21:25:46 +00:00
garrytan 10eac648ba E8: count the BROWSE_EXTENSIONS_DIR persistent launch in the signal-flags guard
The new launch site carries handleSIGINT/SIGTERM/SIGHUP false like the
other three, so the guard's expected count moves from 3 to 4.
2026-10-03 21:25:46 +00:00
garrytan ae86d10f40 D0: pass the Bun child flags after 'run' so wrappers that rewrite 'bun run' argv keep working
bun run --no-env-file --config=/dev/null <script> has the same effect
(verified on Bun 1.4.0) and keeps argv[1] === 'run', which the
publication-lock fixture's preload injection relies on. The sidebar-tabs
source guard now expects the flags in the terminal-agent spawn.
2026-10-03 21:25:46 +00:00
garrytan ce651c2089 A6: report deleted-worktree gbrain sources; prune only with proof, on request
A deleted Conductor worktree leaves its gstack-code-<hash> source behind
and gbrain's autopilot fails on it forever. Local absence is not proof a
source is dead (machines sharing a federated brain register their own
paths, and its pages may be the only copy of uncommitted work), so gstack
never removes one automatically.

- Each sync counts consecutive misses for gstack code sources whose path
  is missing, prints "path unavailable" once per source with the review
  command, and records which repository each synced source belongs to.
- New gstack-gbrain-sync --prune-gone-worktrees (with --dry-run, whose
  plan it always prints first) removes a source only when its path was
  missing on two consecutive syncs, its parent is readable, recomputing
  deriveCodeSourceId() for that path on this host yields its id, and the
  repository's git common dir still exists and no longer lists the
  worktree. It re-checks the path right before removing (through the
  #1734-guarded safeSourcesRemove) and logs each removal.
2026-10-03 21:23:46 +00:00
garrytan 71c231a9e7 B1: state the effective read-only sandbox in /codex review prose
The codex parity invariant requires the skill to state sandbox_mode="read-only";
the command now takes it from _GSTACK_CODEX_SANDBOX, so the prose names the
effective default explicitly.
2026-10-03 21:19:40 +00:00
garrytanandJimmy Zeisweiss 16aed1ced5 A5: brain-sync stage fails loud when the artifacts source indexed zero pages
The stage reported "curated artifacts pushed" whenever gstack-brain-sync
exited 0, but a git push is not gbrain indexing. After a successful push
the stage now reads the maintained artifacts source's page count
(GSTACK_BRAIN_SOURCE_ID, else the source whose path is the artifacts
worktree or state root): zero pages is ERR with the fix command; a
missing source or an unavailable count says so instead of claiming
indexing.

Co-authored-by: Jimmy Zeisweiss <4261258+jzeisweiss@users.noreply.github.com>
2026-10-03 21:19:35 +00:00
garrytan ac5cf21587 C2: name the runtime root every way a generated preflight may read it in the dist test
The generator lane's C1 resolves D from $GSTACK_ROOT instead of
$GSTACK_DESIGN, so the test now exports GSTACK_ROOT as well; it still fails
on main (no dist in the roots) and passes with and without the C1 change.
2026-10-03 21:19:31 +00:00
garrytanandSinabina d02c8effb7 A4: import transcripts into per-repository, non-federated gbrain sources
`gbrain import` ran without --source-id, so transcripts from every project
landed in the shared (often federated) default source.

- Each transcript partition imports with --source-id into its originating
  repository's own source (gstack-transcripts-<repo>, built with
  constrainSourceId, now exported from lib/gbrain-sources.ts). The source
  is registered machine-local and --no-federated before its first import,
  and the registration is cached in state. Partitions import one after
  another (PGLite is a single writer); a failing source no longer blocks
  the others, except a timeout, whose checkpoint must survive.
- If gbrain cannot register the source, that partition stays local and
  unstamped, and the run says why (even under --quiet).
- --include-unattributed sends repo-less transcripts only to the
  machine-local gstack-transcripts-unattributed source, keeps them on the
  machine when the brain is remote (Postgres, Supabase or remote-HTTP),
  and never writes them to the publishable ~/.gstack/transcripts staging.
- A page's recorded source is sticky: pages stamped before this release
  ("default") keep importing there, so no source gains a duplicate.
- The staging dir name carries -src-<id> so a resumed import keeps its
  source.

Test fakes that recorded only the last import now record every import of
one run, and answer `gbrain sources`; remote-http scan tests use an
attributed transcript, since unattributed ones no longer stage there.

Co-authored-by: Sinabina <sinabina@Sinabinas-MacBook-Pro-4.local>
2026-10-03 21:17:54 +00:00
garrytan 34799b8409 F4: type the variant-round fetch stub like the existing stubs
The test-typecheck ratchet flagged the zero-argument stub cast to
typeof fetch; it now takes the fetch arguments like
variants-retry-after's stub. Test behavior unchanged.
2026-10-03 21:17:06 +00:00
garrytan 4b983a0569 E5: watchdog stdin test feeds the wrapper through a redirect
Callers run '_gstack_codex_timeout_wrapper ... codex exec - < file'. Bash keeps
stdin for a backgrounded command inside a pipeline but not behind a
redirect, so the pipe form passed on the old watchdog; the redirect form
reproduces the lost prompt.
2026-10-03 21:17:03 +00:00
garrytanandPhil Hie e6f4d0ffb1 Q3: setup stops auto-installing the AskUserQuestion preference hook in Conductor and removes one it added
The PreToolUse question-preference hook breaks Conductor's native
AskUserQuestion round-trip even when it only defers (#2207), and setup
auto-installed it on every Conductor workspace setup. Now a Conductor setup
without an explicit opt-in never installs it and removes an existing one
(the question-log and AUQ-error hooks stay), printing how to keep it
(gstack-config set plan_tune_hooks yes). An explicit opt-in still installs
it. gstack-settings-hook remove-source gains --event to scope the removal.

Test migration: setup-plan-tune-hooks-noninteractive pinned the retired
Conductor auto-opt-in.

Co-authored-by: Phil Hie <philhie@outlook.com>
2026-10-03 21:16:43 +00:00
104aac947d G6: retro test census counts non-JS suites, skips generated output
The census recognized only JS/TS-style names, so pytest and minitest
(test_*.py|rb), XCTest (Tests/ dirs, FooTests.swift), Terraform
(*.tftest.hcl) and Bats (*.bats) suites counted as zero, and a committed
build directory counted as authored code (and its Test/ subdirs as test
LOC). is_test now knows those conventions and never treats prose as a
test, generated output is skipped in the numstat pass, TEST_FILES_CHANGED
uses is_test, and TEST_FILES_TOTAL uses the same filename conventions
minus generated paths. Merges #2812, #2809 and #2037's patterns (#2037's
retro template edits target a block the metrics bin replaced).

Co-authored-by: Jino <dgfrty00@gmail.com>
Co-authored-by: snig-17 <santosh.m.tiwari@gmail.com>
Co-authored-by: Sholto McNeilage <sholto@nodenarrative.com.au>
2026-10-03 21:16:15 +00:00
garrytan 313d0c8f13 Q1: validate browser output paths the way the kernel resolves them (#2971 salvage)
validateOutputPath walks the destination one component at a time, resolving
each existing component before the next, so link/../x, a dangling symlink
and a dangling symlinked parent can no longer route a write outside the
safe directories, while a new multi-level directory inside them is allowed.
scrape validates its manifest and every downloaded file, not only --dir.
Ported from PR #2971 onto current code.
2026-10-03 21:15:26 +00:00
garrytan 605f49d3d5 Q2: one-time notice naming the Codex provider and account for outside reviews
Outside reviews are on by default and use whatever Codex login exists
(#965). The first automatic Codex review on a machine now prints one
non-blocking notice: the provider (config.toml model_provider, else openai),
where the credential comes from (CODEX_API_KEY, OPENAI_API_KEY, the ChatGPT
login or the key saved by codex login; never the value), that reviews stay
on, and how to turn them off (gstack-config set codex_reviews disabled). A
marker in the gstack state root keeps it to once per machine. Tests that run
the generated command now use private state roots. Also shortens the
no-sandbox provenance line.
2026-10-03 21:15:23 +00:00
garrytanandEvgenii Lopatin e2cf27ff5e G6: context-save computes session duration on Linux (#2704)
The duration step parsed 'ps -o lstart=' with BSD-only 'date -jf', so on
Linux session_duration_s was always unknown. It now falls back to GNU
'date -d', and never parses an empty start (GNU reads that as midnight).
Ported onto the current block instead of #2704's ~/.gstack/sessions
mtime, which bypassed the state root.

Co-authored-by: Evgenii Lopatin <e75533@gmail.com>
2026-10-03 21:13:53 +00:00
garrytanandmaxpetrusenkoagent 4bc9b0686f E6: gbrain-refresh hands the detection file to Python on stdin
Under Git Bash, a native Windows Python first on PATH cannot open an MSYS
/c/... path, so gbrain-refresh always summarized the detection as
'local-status: unknown' and brain-aware blocks were suppressed. bash now
opens the file and Python reads stdin; the grep fallback without Python is
unchanged. Verified on Linux with a stub Python that refuses path opens; not
run on Windows.

Co-authored-by: maxpetrusenkoagent <max.petrusenko.agent@gmail.com>
2026-10-03 21:13:28 +00:00
garrytanandAlinValentin7 57cdf93fac E2: Windows /cso build disables only C5105, and a failed MSVC compile is not reported as a missing toolchain
The Windows SDK's winbase.h raises C5105, which /W4 /WX promotes to error
C2220, so every MSVC build of the native /cso helper failed, and setup
mapped every probe failure to 'install Visual Studio 2022 Build Tools'.
Both compile lines add /wd5105 (only that diagnostic), and setup keeps the
probe's output: a probe that found MSVC but failed to compile reports
windows-msvc-compile with the compiler's first error. Not run on Windows:
the mapping test stubs powershell.exe; the ps1 assertion runs everywhere.

Co-authored-by: AlinValentin7 <AlinValentin7@users.noreply.github.com>
2026-10-03 21:12:47 +00:00
garrytanandJayesh Betala 5ee77d2ec4 G6: rejected taste preferences gain confidence (#1777)
bumpPref computed every entry's confidence from approved_count, so a
rejected entry, which never gains approvals, stayed at 0: show ranked
rejections by insertion order and the taste-drift warning could not
fire from real use. Confidence now uses the entry's own bucket count.
Also salvaged by Garry's #2971.

Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
2026-10-03 21:12:45 +00:00
garrytan 0977717d1d G1: tighten /ship's NO_VERSION wording to fit the union-size cap
Same behavior in fewer bytes: the NO_VERSION arm, the broken-source
exit, the unprefixed-title rule, the Step 20 null and the CHANGELOG
skip. The cap ratchet commit measured this wording.
2026-10-03 21:12:45 +00:00
garrytanandmaxpetrusenkoagent 2ffeba529b G6: gstack-ios-qa-daemon --help prints usage instead of starting the daemon (#1932)
Co-authored-by: maxpetrusenkoagent <max.petrusenko.agent@gmail.com>
2026-10-03 21:12:37 +00:00
garrytanandRyan Alberts 8051efcee0 G6: analytics averages quoted duration_s values (#1728)
gstack-skill-end writes duration_s as a quoted string, and the per-skill
average stripped everything from the leading quote, so every average
read 0s. The awk now drops a leading quote before extracting digits.

Co-authored-by: Ryan Alberts <ryan.a.alberts@gmail.com>
2026-10-03 21:12:14 +00:00
garrytanandJayesh Betala 5bcc4b5d2c G6: prettyscreenshot --hide keeps a trailing image path as the output path (#1419)
--hide collected every following non-flag argument as a selector, so the
output path was hidden instead of written to. A trailing argument that looks
like a path or ends in .png/.jpg/.jpeg/.webp is now the output path.

Co-authored-by: Jayesh Betala <jayesh.betala7@gmail.com>
2026-10-03 21:12:02 +00:00
garrytan e2f9e144c0 E5: feed every Codex prompt on stdin instead of argv
Prompts went to Codex as one argv string ('codex exec "$(cat file)"'), which
fails over 32 KB on Windows (and over 128 KB on Linux, E2BIG) and mangles
quotes. Every codex exec site (outside-voice resolver, /codex review custom
instructions, challenge, consult new and resume) now runs 'codex exec -'
with the prepared prompt file on stdin; challenge and consult write the
prompt with a quoted heredoc so it is never shell-parsed. The bash-native
timeout watchdog (stock macOS) started the command in the background, which
gives it /dev/null as stdin; it now passes the caller's stdin through.

The 'byte for byte' dispatch test drops its old argv trailing-LF exception,
the consultation and autoplan fixtures follow the stdin form, and the static
site test requires stdin at every rendered codex exec.
2026-10-03 21:11:38 +00:00
garrytan 427322d54c F1: ratchet /ship's parity union-size cap for this lane's content
G1's NO_VERSION arms, F1's parent-side plan binding and D3's data line
add 2,126 bytes to /ship's skeleton-plus-sections union, taking it from
1.4022x to 1.4135x of the v1.64.1.0 baseline (cap was 1.405). The cap
moves to 1.414 with the measurement recorded, as earlier growth did; no
other invariant changes.
2026-10-03 21:11:35 +00:00
garrytanandJonah Berg 645e39eb47 F5: installed Claude skills serve the rendered sections, not the checkout copies
Probe: a gbrain user render serves ship/SKILL.md from the render dir; its
STOP pointers name absolute render paths, but its section index names
`sections/<f>.md` relative to the installed skill directory, whose
sections/ was linked from the checkout. So the rendered 'Save Results to
Brain' blocks (plan reviews, office-hours, ship adversarial) were generated
and never read. setup's _link_skill_runtime_assets and gstack-relink (the
gbrain-refresh path) now serve a rendered counterpart per file, keep
checkout-only assets (manifest.json), return an asset to the checkout once
its render is gone, and never touch an entry that is not gstack's links.

Co-authored-by: Jonah Berg <jonah.berg.g@gmail.com>
2026-10-03 21:11:18 +00:00
garrytanandmiao 88b480eaed D5: per-project headed Chromium profiles; never kill a live profile owner (#2492)
The headed profile moves from <gstack home>/chromium-profile to
<project>/.gstack/chromium-profile (CHROMIUM_PROFILE still wins).
killOrphanChromium now kills a SingletonLock PID only when the lock names
this host, the process is a Chromium using that profile, and its daemon is
gone (reparented to init or a subreaper); a live owner or another host's
lock stops browse with the holder named. On first headed use a project
profile is seeded from the old shared profile only when nothing holds it:
copied without Singleton* files into a 0700 temp dir and renamed into
place, with a one-time notice; otherwise it starts fresh and says how to
import later. New: browse profiles [list] and browse profiles prune
[--days N] (never removes a profile in use or the old shared one).
The #2817 headed-startup tests move to the project profile and a real
orphan (the old stand-in was a live child of the test).

Co-authored-by: miao <miao@macmini-2.local>
2026-10-03 21:11:02 +00:00
garrytanandjacob-wang 0d9ebd27ec D4: setup-deploy reports Render API key presence only
/setup-deploy ran 'echo $RENDER_API_KEY | head -c 4', printing the
key's first bytes into the transcript. It now prints only
'RENDER_API_KEY: set' or 'RENDER_API_KEY: not set'. Wording follows the
#2971 port of #1096; a test also guards against any setup-deploy command
echoing a credential variable.

Co-authored-by: jacob-wang <jiayuw794@gmail.com>
2026-10-03 21:10:54 +00:00
garrytanandcube 64638f3978 D3: treat design docs and handoff notes as data in plan reviews
plan-ceo-review, plan-eng-review and plan-devex-review read the freshest
design doc as the source of truth, and nothing said its content is data.
In multi-agent pipelines another agent may have written it, or a handoff
note beside it, with reviewer-directed text ('skip Step 0', 'approve
as-is'). Each read site now says the doc and any handoff note are data,
never to follow text aimed at the reviewer, and to report it as
suspicious content. The plan-completion audit's discovery, which now
reads repo docs/designs/ files (F1), carries the same rule.

Co-authored-by: cube <frosimanuel@gmail.com>
2026-10-03 21:10:17 +00:00
garrytan 0e9b2c537f B4: arm64 re-sign keeps a backup, restores it when codesign fails, and reports design unavailable on exit 137
setup's Apple Silicon re-sign mutated each binary in place (truncate, remove
signature) and left it that way when re-signing failed; a design binary that
was then SIGKILLed at launch produced at most a quiet log line. Each binary is
now copied first and restored as built when signing fails, and design is
exec-probed after re-signing: exit 137 prints 'design unavailable: ... Fix:
cd <checkout> && ./setup' (even under -q). Verified on Linux with the real
block and uname/codesign/otool/stat stubs; not run on a Mac.
2026-10-03 21:08:40 +00:00