mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-10 15:09:00 +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>
57 lines
2.4 KiB
Bash
Executable File
57 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gstack-review-log — atomically log a review result
|
|
# Usage: gstack-review-log '{"skill":"...","timestamp":"...","status":"..."}'
|
|
#
|
|
# Binding fields (content-addressed staleness): every appended record is
|
|
# stamped with commit_full, tree, dirty (informational) and wtree (the GATING
|
|
# working-tree fingerprint from bin/gstack-wtree). These are computed
|
|
# AUTHORITATIVELY here — caller-supplied values for the four keys are ignored,
|
|
# so a stale rendered template (or a forged field) cannot bind a record to
|
|
# content it wasn't made on. All other caller fields pass through untouched.
|
|
# Outside a git repo the fields are simply omitted (legacy consumers fall back
|
|
# to their heuristics).
|
|
set -euo pipefail
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
|
|
GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"
|
|
mkdir -p "$GSTACK_HOME/projects/$SLUG"
|
|
|
|
INPUT="$1"
|
|
|
|
# Compute binding fields (best-effort; empty outside a git repo).
|
|
COMMIT_FULL=$(git rev-parse HEAD 2>/dev/null || true)
|
|
TREE=""
|
|
WTREE=""
|
|
DIRTY=""
|
|
if [ -n "$COMMIT_FULL" ]; then
|
|
TREE=$(git rev-parse 'HEAD^{tree}' 2>/dev/null || true)
|
|
WTREE=$("$SCRIPT_DIR/gstack-wtree" 2>/dev/null || true)
|
|
if [ -n "$(git status --porcelain -uno 2>/dev/null | head -1)" ]; then
|
|
DIRTY="true"
|
|
else
|
|
DIRTY="false"
|
|
fi
|
|
fi
|
|
|
|
# Validate (reject malformed or injection attempts) AND stamp in one pass.
|
|
# Caller values for the binding keys are dropped before stamping.
|
|
STAMPED=$(printf '%s' "$INPUT" | GSTACK_STAMP_COMMIT_FULL="$COMMIT_FULL" GSTACK_STAMP_TREE="$TREE" GSTACK_STAMP_WTREE="$WTREE" GSTACK_STAMP_DIRTY="$DIRTY" bun -e "
|
|
const rec = JSON.parse(await Bun.stdin.text());
|
|
for (const k of ['commit_full', 'tree', 'wtree', 'dirty']) delete rec[k];
|
|
const env = process.env;
|
|
if (env.GSTACK_STAMP_COMMIT_FULL) rec.commit_full = env.GSTACK_STAMP_COMMIT_FULL;
|
|
if (env.GSTACK_STAMP_TREE) rec.tree = env.GSTACK_STAMP_TREE;
|
|
if (env.GSTACK_STAMP_WTREE) rec.wtree = env.GSTACK_STAMP_WTREE;
|
|
if (env.GSTACK_STAMP_DIRTY) rec.dirty = env.GSTACK_STAMP_DIRTY === 'true';
|
|
console.log(JSON.stringify(rec));
|
|
" 2>/dev/null) || {
|
|
# Not valid JSON — refuse to append
|
|
echo "gstack-review-log: invalid JSON, skipping" >&2
|
|
exit 1
|
|
}
|
|
|
|
echo "$STAMPED" >> "$GSTACK_HOME/projects/$SLUG/$BRANCH-reviews.jsonl"
|
|
|
|
# gbrain-sync: enqueue for cross-machine sync (no-op if sync is off).
|
|
"$SCRIPT_DIR/gstack-brain-enqueue" "projects/$SLUG/$BRANCH-reviews.jsonl" 2>/dev/null &
|