Files
gstack/bin/gstack-design-claim
Garry TanandMatt Van Horn fe6d1ae62a v1.91.17.0 fix: mvanhorn wave (checkpoint provenance, never-overwrite design images) (#3022)
* fix: mark Remaining Work provenance so restore verifies guessed steps first (#3004)

/context-save now starts every Remaining Work item with `Open.` and ends it
with how this session knows it: `(path run)` with the observed outcome,
`(path read)` or `(path assumed)` for concrete paths, and
`(target state checked)`, `(code read)` or `(path assumed)` for writing
steps. /context-restore keeps saved order and original text but splits the
list into Next steps and Verify first (assumed, code-read, failed runs and
unmarked concrete or writing items), prints a banner for pre-marker
checkpoints, and option A walks saved order so an unverified first item is
verified before any later step runs.

Adds a prompt-byte contract test for the marker wire format and a periodic
behavior E2E (context-restore-provenance-order) that seeds an assumed item
ahead of a run item plus a code-read write.

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

* fix(design): never overwrite a paid design image (#1529)

Every image the API returns now goes through one persistence path
(design/src/persist.ts): mkdir, exclusive `wx` claim that bumps
x.png -> x-2.png ... x-999.png, write, fsync, close. A failure after the
bytes arrived removes the claimed file and keeps a 0600 recovery copy in
the temp dir; empty image data is a failure, never a 0-byte PNG. The API
call is the only thing inside each retry loop, so a local save failure
never buys a second image (variants, iterate fallback, generate --retry).

generate, iterate, evolve and variants (both branches) print the same run
fields (requested, saved, selected, failures, recovered) on every exit,
with exit 0 / 2 (nothing saved) / 3 (stopped after saving). Each
generate --retry attempt is its own saved image listed in `attempts`.
compare accepts --images-file and JSON-array --images. The gallery lists
bumped names, orders history by mtime then board-images.json, and marks
approvals by approved_path. New bin/gstack-design-claim publishes staged
images without clobbering; bin/gstack-design-approved resolves an
approval record (legacy letter-only records still resolve; a missing
approved_path is an error, never a substitute).

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>

* fix(design skills): read the paths $D printed, never fixed variant names (#1529)

Every design flow now captures each generating $D command's JSON and exit
code without set -e, does round accounting before the first board, check
or inline view (stopping when nothing was saved), and carries the printed
paths forward. Boards are built from board-images.json via
compare --images-file after archiving any earlier feedback.json, and
approvals map the confirmed letter through that file and record
approved_path. design-shotgun subagents generate into a per-run mktemp
staging directory and publish with bin/gstack-design-claim instead of a
shared /tmp/variant-X.png plus cp. design-html and taste memory resolve
approvals with gstack-design-approved; design-review verifies against the
printed target path.

test/design-printed-paths.test.ts bans fixed variant names, variant globs,
variant-{letter} reads, cp/mv of $D output and literal check paths in the
generated skills and resolvers (one content-anchored allowlist entry: the
design-html discovery probe), and pins the accounting/board marker order.
test/design-approval-flow.test.ts runs the generated board and approval
blocks through a stubbed two-round flow.

* chore: release v1.91.17.0 (mvanhorn fix wave: checkpoint provenance, never-overwrite design images)

* fix(design): keep iterate sessions in the OS temp dir and normalize tripwire paths on Windows

* fix(setup-deploy): report failing status commands, specify merge-method, health and workflow checks

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-10-03 16:13:45 -07:00

56 lines
2.1 KiB
Bash
Executable File

#!/bin/sh
# gstack-design-claim — publish a staged design image without overwriting.
#
# Usage: gstack-design-claim <staged-image> <destination>
#
# Creates <destination> with an exclusive, non-overwriting create (set -C
# noclobber, which opens with O_EXCL). When the name is taken it tries
# <stem>-2<ext>, <stem>-3<ext> ... <stem>-999<ext>, the same rule as
# $D's claimOutputPath (x-2.png bumps to x-2-2.png). Prints the final path.
# On any failure it exits non-zero with problem/cause/fix and leaves the staged
# image in place, so the paid bytes survive. On success the staged copy is
# removed.
set -u
fail() {
printf 'gstack-design-claim: %s\ncause: %s\nfix: %s\n' "$1" "$2" "$3" >&2
exit 1
}
[ "$#" -eq 2 ] || fail "expected 2 arguments, got $#" "usage: gstack-design-claim <staged-image> <destination>" "pass the staged image path, then the destination path"
src=$1
dest=$2
[ -f "$src" ] && [ -s "$src" ] || fail "staged image $src is missing or empty" "the generating command did not save an image there" "use the outputPath the \$D command printed"
dir=$(dirname "$dest")
base=$(basename "$dest")
case "$base" in
?*.*) stem=${base%.*}; ext=".${base##*.}" ;;
*) stem=$base; ext="" ;;
esac
err=$(mkdir -p "$dir" 2>&1) || fail "cannot create $dir; staged image kept at $src" "$err" "make $dir writable or choose another destination"
n=1
candidate=$dest
while :; do
if err=$( (set -C; : > "$candidate") 2>&1 ); then
if err=$(cat "$src" 2>&1 > "$candidate"); then
rm -f "$src"
printf '%s\n' "$candidate"
exit 0
fi
rm -f "$candidate"
fail "cannot write $candidate; staged image kept at $src" "$err" "free disk space or make $dir writable, then rerun"
fi
if [ -e "$candidate" ] || [ -L "$candidate" ]; then
n=$((n + 1))
[ "$n" -le 999 ] || fail "$dest and every name through $stem-999$ext already exist; staged image kept at $src" "999 images already use this name" "choose a new destination name or move older images out of $dir"
candidate="$dir/$stem-$n$ext"
continue
fi
fail "cannot create $candidate; staged image kept at $src" "$err" "make $dir writable or choose another destination"
done