mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-09 22:48:57 +02:00
Review records now bind to the content they were made on. bin/gstack-review-log
stamps every appended record with commit_full, tree, dirty (informational) and
wtree — a working-tree fingerprint from the new bin/gstack-wtree (temp index
seeded from HEAD + git add -A + write-tree). The binding fields are computed
authoritatively; caller-supplied values for those keys are ignored, so a stale
rendered template or a forged field can't bind a record to content it wasn't
made on.
Why a working-tree fingerprint instead of HEAD^{tree}: committing identical
content doesn't change it (a record made on a dirty tree stays valid after the
same content is committed), untracked new source files DO change it (new code
can't hide from freshness), and gitignored scratch stays out. Rebase, amend
and squash with identical content grade CURRENT instead of stale.
Grading: the dashboard (scripts/resolvers/review.ts) and /land-and-deploy Step
3.5a apply a content-first rule to diff-scoped review rows — wtree match with
both sides clean is CURRENT, full stop. Plan-tier reviews grade a plan file,
not the repo tree, so they keep the 7-day logic (optional plan_sha256 caller
field noted). The rev-list fallback no longer errors when the stored commit
was rebased away: it grades UNKNOWN and treats it as stale.
bin/gstack-review-read emits ---WTREE---/---TREE---/---DIRTY--- so graders
consume one tool output. Old records without wtree fall back to the existing
heuristics; no migration.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
28 lines
1.3 KiB
Bash
Executable File
28 lines
1.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gstack-wtree — print a working-tree CONTENT fingerprint (a git tree hash).
|
|
#
|
|
# Builds a temp index seeded from HEAD, stages the full working tree into it
|
|
# (`git add -A`, so .gitignore'd scratch stays out and UNTRACKED source is
|
|
# included), and prints `git write-tree` of that index. Properties that make
|
|
# this the right staleness fingerprint, vs `git rev-parse HEAD^{tree}`:
|
|
#
|
|
# - Committing identical content does NOT change the fingerprint, so a
|
|
# record made on a dirty tree stays valid after the exact same content is
|
|
# committed (the /ship Step 5 -> Step 16 case).
|
|
# - Untracked new source files DO change the fingerprint, so "tests passed"
|
|
# can't stay FRESH after a new file appears.
|
|
# - Rebase/amend/squash that preserve content do not change it.
|
|
#
|
|
# The real repo index is never touched. Staged blobs land in the object store
|
|
# as unreachable objects and get gc'd like stash churn. Exit 1 outside a git
|
|
# repo or in a repo with no commits — callers treat that as "no fingerprint".
|
|
set -euo pipefail
|
|
|
|
TOP=$(git rev-parse --show-toplevel 2>/dev/null) || exit 1
|
|
TMPIDX=$(mktemp "${TMPDIR:-/tmp}/gstack-wtree-XXXXXX")
|
|
trap 'rm -f "$TMPIDX"' EXIT
|
|
export GIT_INDEX_FILE="$TMPIDX"
|
|
git -C "$TOP" read-tree HEAD 2>/dev/null || exit 1
|
|
git -C "$TOP" add -A 2>/dev/null || exit 1
|
|
git -C "$TOP" write-tree 2>/dev/null
|