mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-11 23:49:01 +02:00
fix: adversarial review fixes (Claude pass, 14 findings, 1 verified-live critical)
The fresh-context adversarial pass caught a live bug in this branch's own
performance fix: gstack-wtree exported GIT_INDEX_FILE BEFORE resolving the
real index path, so `git rev-parse --git-path index` returned the temp index
itself, the stat-cache copy self-copied and failed, and every invocation fell
back to the full re-hash — the fast path was dead code (verified with bash -x).
Resolution now happens before the export; measured 0.08s per call on this repo.
Also fixed: careful fails to an ASK (not silence) when its own helper file is
missing (same partial-install state freeze already defends against); the
--source label is sanitized inside the envelope lib (newline-stripped,
sentinel-defused, length-capped — it sits in trusted framing); the HIGH rm
tokenizer skips redirections/backgrounding/`--` (rm -rf / 2>/dev/null now
denies) and knows ${HOME}; user pattern lines starting with a dash work
(grep --); greptile bodies carry per-comment id headers inside the envelope so
multi-comment PRs stay attributable (ids verified against raw metadata, never
trusted in-body); the release-body tripwire fails CLOSED when its input files
are missing (separate-shell $$ reality); land 3.5b gets the same allow-paths
as ship; the "either side dirty" fallback leftover is gone from both grading
surfaces; the evidence pump races drain against error (EPIPE consumers can't
hang the wrapper); an unset HOME skips bookkeeping instead of creating a
literal ~ dir inside the repo; a write-failure log ends with a visible marker;
freeze expands a literal leading ~ in the boundary; review-log documents its
log-time binding window.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
232a912afb
commit
7c90368229
+20
-2
@@ -92,7 +92,10 @@ function currentWtree(): string | undefined {
|
||||
}
|
||||
|
||||
function ledgerPath(): { dir: string; file: string; logsDir: string } {
|
||||
const home = process.env.GSTACK_HOME || join(process.env.HOME || "~", ".gstack");
|
||||
const home = process.env.GSTACK_HOME || (process.env.HOME ? join(process.env.HOME, ".gstack") : undefined);
|
||||
// No resolvable home: skip bookkeeping (a literal "~" dir in cwd would land
|
||||
// inside the repo and perturb the fingerprint it exists to compute).
|
||||
if (!home) throw new Error("no GSTACK_HOME/HOME — bookkeeping skipped");
|
||||
// ONE gstack-slug spawn: its output carries both SLUG= and BRANCH= lines
|
||||
// (same branch→filename sanitization as reviews.jsonl).
|
||||
const slugOut = spawnSync(join(BIN_DIR, "gstack-slug"), { encoding: "utf-8" });
|
||||
@@ -212,6 +215,9 @@ async function cmdRun(argv: string[]): Promise<number> {
|
||||
}
|
||||
} catch {
|
||||
truncated = true; // stop teeing on any write failure; console stream continues
|
||||
try {
|
||||
writeSync(log.fd, Buffer.from("\n\n[gstack-evidence: log ended early (write failure) — output continued on console]\n"));
|
||||
} catch {}
|
||||
}
|
||||
};
|
||||
const pump = async (stream: ReadableStream<Uint8Array> | undefined, out: NodeJS.WriteStream) => {
|
||||
@@ -220,7 +226,19 @@ async function cmdRun(argv: string[]): Promise<number> {
|
||||
// Honor backpressure: when the console consumer is slower than the child
|
||||
// (piped into a pager/log collector), wait for drain instead of queueing
|
||||
// unbounded chunks in the WriteStream buffer.
|
||||
if (!out.write(chunk)) await new Promise((r) => out.once("drain", r));
|
||||
if (!out.write(chunk)) {
|
||||
// Race drain against error: a dying consumer (EPIPE from `| head`)
|
||||
// never drains — resolve either way and stop forwarding on error.
|
||||
await new Promise<void>((r) => {
|
||||
const done = () => {
|
||||
out.off("drain", done);
|
||||
out.off("error", done);
|
||||
r();
|
||||
};
|
||||
out.once("drain", done);
|
||||
out.once("error", done);
|
||||
});
|
||||
}
|
||||
teeToLog(chunk);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
# 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).
|
||||
#
|
||||
# Known limitation: binding happens at LOG time, not review-START time — edits
|
||||
# made between finishing a review and logging it (including fixes the review
|
||||
# itself applied) are certified by the stamped fingerprint. gstack-evidence
|
||||
# closes this window for test runs (before/after capture); review flows log
|
||||
# immediately after reviewing, which keeps the window small but nonzero.
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
|
||||
|
||||
+4
-2
@@ -29,11 +29,13 @@
|
||||
set -euo pipefail
|
||||
|
||||
TOP=$(git rev-parse --show-toplevel 2>/dev/null) || exit 1
|
||||
# Resolve the REAL index path BEFORE exporting GIT_INDEX_FILE — with the env
|
||||
# var set, `git rev-parse --git-path index` returns the temp index itself and
|
||||
# the stat-cache seed silently self-copies into a dead fast path.
|
||||
REAL_INDEX=$(git -C "$TOP" rev-parse --git-path index 2>/dev/null || true)
|
||||
TMPIDX=$(mktemp "${TMPDIR:-/tmp}/gstack-wtree-XXXXXX")
|
||||
trap 'rm -f "$TMPIDX"' EXIT
|
||||
export GIT_INDEX_FILE="$TMPIDX"
|
||||
|
||||
REAL_INDEX=$(git -C "$TOP" rev-parse --git-path index 2>/dev/null || true)
|
||||
# Resolve relative --git-path output against the repo root.
|
||||
case "$REAL_INDEX" in
|
||||
""|/*) ;;
|
||||
|
||||
Reference in New Issue
Block a user