Waivers settle once per page after both tiers, so a blocking rule only the
render tier suspects is waivable and one it measures is refused; a claim in a
stylesheet answers for that stylesheet on every page that links it (no
shared-word check), so a sheet shared by two pages is no longer waived on one
and refused on the other. Every printed field is one line with control
characters stripped; the waiver regex is linear and ends at a carriage
return; a root-relative href cannot climb out of the lint root. The ancestor
map closes optional end tags implicitly and pops to the matching open tag, so
unclosed <li> no longer makes it quadratic. The static tier reports outline:
none with no ring anywhere as missing-focus-visible at its line;
literal-outside-tokens needs a --color-* or --font-* token to exist; the
banned gradient includes indigo-to-violet; a new banned-font rule reads
gstack's BANNED_FONTS; MONO_FACE matches whole words; bold keywords and
tokens count as weight 700 for the contrast threshold. stylesFor reads only
the entries that can match; glOcclusion memoises the pinned walk; the
confirm screenshot is taken at 1x; a page that throws in the render tier is a
render finding and the CLI exits 3 on an internal error. Docs name the token
conventions and what the lint does not cover.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Waivers reach render findings; a blocking rule the lint only suspected is
waivable like any ask, a measured or absent Floor stays refused. A stylesheet
a page links from another directory belongs to that page and is not linted
again on its own; a stylesheet linted alone keeps its waivers. Root-relative
hrefs resolve against the lint root. Stylesheets are read and parsed once per
run. A rule family that throws reports internal-error at ask instead of a
silent pass; aria-labelledby and probe tag names are escaped before they
reach a RegExp; a probe result naming an unknown rule is a render finding,
not a crash; fix strings are one line. overused-font follows gstack's
catalog of display faces; one MONO_FACE list for every monospace check.
parseCss caps nesting depth; medianRgb uses histograms; glHide batches its
layout reads. Dead exports removed (isPage, openTags, over, ComponentTag,
PixelRect, the ids re-exports).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Ports hallmark's sloplint-render.mjs onto lib/aside-render: one tab per
page, the in-page probes installed once and run at each viewport, a second
pass with full-page screenshots only when a contrast claim needs the painted
pixels (a small PNG reader replaces canvas sampling). Gates 23, 25, 26a, 34,
40, 41, 44a-d, 49a/b, 58, 71, 72, 73, 75, 77-83, F17-F20, plus the page that
did not render. The stamp's posture, hero-shape, photo-shape and genre
guards are gone: the strict form applies. Focus rings are read by focusing
each control in turn (programmatic focus matches :focus-visible on the
daemon with no prior pointer input; a stylesheet scan is the fallback).
lib/aside-render: an eval step takes width/height like a screenshot step
(device metrics on Aside, viewport on browse, cleared after), and spec.file
may be an http(s) URL, opened as it is with nothing served.
The clean fixture gained border-box on its hero, a centred, taller hero
visual, a wrapping actions row, a statement-sized close head and a shorter
story paragraph: the browser showed the action below the 1280x800 fold, a
dead band under the hero, a 600px image spilling past a phone screen and a
thin close section.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Chrome (gates 19 42 46a 47 54 63 68 69 70 85): gate 19 split by tell onto
aphoristic-cadence, generic-hero-copy, generic-cta-copy, em-dash-overuse and
template-footer-line in rules/chrome-copy.ts (with the two-filled-buttons half
of F4 and the shared prose mask); the eyebrow in rules/chrome-eyebrow.ts; the
nav and footer shapes, invented proof, drawn chrome, placeholder services,
template punctuation, wireframe slots, repeated facts, the fake send and a
static version of the email-band close in rules/chrome.ts.
Assets (gates 30 33 40 41 49 76): emoji icons, mixed icon libraries, unlabelled
svg/canvas, contrast pairs and surface inks (suspected at ask in the static
tier), wrapping labels split into button-label-wraps and link-wraps, broken
images and stock hotlinks.
Finish (F1-F9 F15 F16 F21-F24): all polish except fake-avatar.
Tests cover every id with a negative control and a planted positive; the clean
fixture gains scrollbar-color so its committed palette themes every browser
surface.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Replaces the tailwind.ts stub with sloplint's utility reader (twParse,
twInfo, twGroup, variants, stops, sizes, tracking, families, shared
project tokens) and the tells it feeds, and fills rules/component.ts
with checkTailwind and checkComponentText: layout-transition,
bounce-easing, purple-blue-gradient, gradient-text, glow-wash,
literal-outside-tokens, hover-tells, wide-tracking, kicker-above-heading,
monospace-costume, framework-palette, vh-height, template-cards,
template-punctuation and emoji-decoration over class strings in HTML,
JSX, Vue, Svelte and Astro files and cn()/clsx()/cva() calls.
test/design-lint-tailwind.test.ts holds a negative control and a planted
tell per rule plus the tailwind-fail, tailwind-pass and clean fixtures.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
rules/color.ts: gates 2a 2b 7a 7b 22 23 29 48 65 74 (check2, check7, check22,
check23, check29Glow, check48, check65, check65Tailwind). rules/type.ts: gates
1 25 37 38i 38ii 38iii 55a 55b 64 67 (check1, check25, check37, check38a,
check38c, check55, check64, check67, check67Html). Thresholds and heuristics
are hallmark's; evidence and fixes are rewritten in gstack's voice; the stamp,
genre and posture guards are gone, so every check runs in its strict form.
The clean fixture carried two real tells hallmark's own sloplint also flags:
an oklch literal on .button:hover (48) and the cream paper + Fraunces + clay
accent look (65). The hover colour is now a token and the display face is
Literata.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(windows): shell bins pass NUL as Bun's empty config when MSYS path conversion is off (#3415)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(windows): detect Git Bash/MSYS2/Cygwin from OSTYPE, as gstack-doctor does, so uname stubs in setup fixtures stay untouched
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (#3415)
- Choose NUL only when cygpath is also on PATH, so an OSTYPE=msys inherited
by a POSIX bash keeps /dev/null instead of a cwd-relative NUL file.
- gstack-developer-profile --log-session reports a Bun failure instead of
skipping it as invalid input, like gstack-timeline-log.
- learnings-injection tests check that their anchored bun -e block exists.
- CHANGELOG names the callers this fix does not cover; curation reason fixed.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes, cycle 2 (#3415)
- timeline-log and developer-profile validators print their verdict; any
non-zero Bun exit is a reported failure (a Bun crash on Windows exits 3).
- timeline-log keeps the original event when ts stamping fails.
- The definition ratchet scopes a local GSTACK_BUN_CONFIG to its function.
- The shell-bins fixture clears its preload marker per test.
- CHANGELOG states the callers that discard the report and the Bun 1.3.x case.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: CHANGELOG notes Bun 1.3.10 evidence and remaining literal /dev/null callers (#3415)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(design-html): craft section and free craft check, adapted from Elaya design skills (GSTA-92)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(GSTA-92): restore the full CHANGELOG under the Unreleased entry; drop a $-digit literal from craft.md; count only craft-check executions in design-html-slop-gate
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(pregate): user-owned policy file and local lanes
A repo that keeps .gstack/ out of git can hold its pregate policy at
<GSTACK_HOME>/projects/<slug>/pregate.json. gstack-pregate run reads it only
under --policy-from base when the base carries no .gstack/pregate.json, so a
reviewed base copy always wins and a PR still cannot reach the policy. A
missing file falls back; any other read error, and a non-null sealed or
price_file (read only from the git copies), refuse with PREGATE_CONFIG_INVALID
and a fix that names the file.
A new `local` key lists <workflow.yml>/<job> lanes a local run satisfies: a
platform lane named there runs here (tier unit) instead of becoming a
requires-remote obligation. Lane ids share one LANE_ID check with selection.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(pregate): the user-owned policy file and local lanes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): policy fixes name the user-owned file when it is the active policy
With no .gstack/pregate.json on the base, an edit to that path is never read,
so the no-lane, runner, stall_timeout_s, remote_gate and strays fixes now name
ctx.configFile: the user-owned path when it is the active policy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pregate): the remote_gate, strays and stall fixes name the active policy file
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): pre-landing review fixes for the user-owned policy
Ignore a user policy path that is relative or inside the checkout, fingerprint
the active user file into check inputs, name the user file in its JSON errors
and the refusal lead, add --explain lines for an absent user file and an
unknown local id, and document the state-root location and slug lookup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): containment edges and explain wording for the user policy
A state root under an in-repo directory named ..something passed the
inside-the-repo check, and realpath kept the caller's casing on macOS.
The unknown-local explain line now says workflow lane, and the state-root
chain in explain and docs names every source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): a base copy git cannot read, or a dangling user symlink, refuses
Any git show failure read as no base policy, which now hands the run to
the unreviewed user file; it is absent only when cat-file says so, and a
spawn error (stdout cut at the buffer limit) counts as a failure. A user
pregate.json that is a dangling symlink refuses instead of reading as
absent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): decide a missing base policy from the tree, and catch dangling parent links
cat-file -e checks the blob, so a missing or corrupt object still read as
no base copy; ls-tree reads the tree entry, and any failure refuses. The
dangling-symlink check now covers every path component, not just the file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(result-codes): POLICY_SOURCE_UNAVAILABLE names an unreadable committed pin file
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(pregate): the active policy may be the user-owned file; new refusals
Guards, remote_gate, stall timeouts and lane fixes name the user-owned file
when it is the active policy; the trust boundary says run alone reads it;
the dangling-symlink and unreadable-base-copy refusals are documented, and
state-root lists the bucket's pregate.json.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): a checkout's .env cannot pick the user policy; verify re-checks it
Bun loads .env from the working directory, so a branch could set
GSTACK_PROJECT_SLUG or a state root and choose which pregate.json governs
it. The shebang now passes --no-env-file, scriptInvocation carries that
flag over when it launches the bin as bun <script>, and a bare bun launch
beside any dotenv file refuses (POLICY_SOURCE_UNAVAILABLE).
A recorded pass also outlived its policy: pregate.json now records the
user file's digest (or, under the defaults, the path that was absent), and
verify and the ship receipt treat an edited, deleted or newly present user
file as PREGATE_STALE, reading both paths from the record.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): keep the POLICY_SOURCE_UNAVAILABLE summary's pin-files wording
The added '(or .gstack/pregate.json)' broke describeRefusal's rewrite to
'the reviewed pin files cannot be read', which pregate-wtree-refusal pins.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pregate): pick the host-foreign lane in the user-policy local-lane test
On a Windows host the windows lane is native, so it never became
requires-remote and the test failed on the Windows shards.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): Rust crate lanes and nested JS package runners
lanes reported PREGATE_NO_LANE for every touched .rs file and ran a nested
pnpm+vitest package's tests as `bun test` from the repo root.
- Rust: a .rs file of a crate (nearest Cargo.toml with [package]) is a test
under <crate>/tests/ or when it holds a #[cfg(test)]; every .rs file of a
crate and its Cargo.toml select the crate's tests and those of every crate
depending on it (lib/pregate/rust.ts). Selected tests run per crate as
`cargo test -p <name>` from the workspace root, judged on the summed
`test result:` lines (doc-tests included); zero tests stays ZERO-RUN and a
missing cargo is incomplete, like a missing Dart SDK.
- JS/TS: a test owned by a nested package.json that declares vitest or jest
runs from that package with package-relative paths, through the package
manager its packageManager field or nearest lockfile names (pnpm exec,
yarn, bun x, else npx). Root detection and a declared runner are unchanged.
- init notes that Rust tests run per crate; docs/pregate.md updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): parse Cargo manifests as TOML; follow workspace membership
The line scan of Cargo.toml missed dependents (a false green) and picked the
wrong workspace:
- an inherited renamed dependency (`base = { workspace = true }` with
`[workspace.dependencies] base = { package = "alpha", path = ... }`);
- dotted keys (`alpha.path = "../a"`), `[dependencies.<name>]` tables and
target-specific tables, matched by key name only;
- a crate the workspace excludes ran `cargo test -p` from the workspace root.
Manifests are now parsed with Bun.TOML. A dependency resolves by path
(relative to the manifest declaring it, or to the workspace root when
inherited), else by package name. A crate runs from the workspace it is a
member of under Cargo's rules (package.workspace, the nearest [workspace],
members globs, exclude, literal members, path dependencies of members),
else from its own directory. Nothing runs cargo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pregate): the Rust fixture's cargo shim wins PATH on Windows and beside a real cargo
windows-free-shard (5) failed 'a touched src file runs its crate...' and
'zero tests is ZERO-RUN...' deterministically: the shim PATH was joined with
':' so Git Bash never saw the shim dir, and the runner's real cargo ran
against the fixture (exit 1, no test result lines). On POSIX hosts where
Bun and cargo share a directory (/usr/local/bin on Capy's image), the lane
puts Bun's directory first and the real cargo wins the same way.
Join with path.delimiter, add cargo.cmd for Bun.which on Windows, and on
POSIX put the shim first again in the lane's own bash through BASH_ENV.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): quote the crate name in cargoRunner
The crate name is read from the repo's Cargo.toml and was interpolated into
'cargo test -p <name>', which the lane runs through bash. A name like
'evil;touch pwned' ran the second command. Quote it like every file and cwd
the lane already passes; a new end-to-end case checks the name reaches cargo
as one argument and runs nothing.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): the nested-package pnpm shim wins PATH beside a real pnpm
'a touched file in a nested pnpm+vitest package runs vitest there' ran the
host's real pnpm wherever Bun and pnpm share a directory (/usr/local/bin on
Capy's image): the lane puts Bun's directory first, so pnpm installed vitest
from the network, dirtied the fixture tree and the check came back
incomplete. Put the shim first again in the lane's bash through BASH_ENV,
as the Rust fixture does.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): pregate Rust crate lanes and nested package runners (#3344)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): a crate name Cargo would reject never reaches the lane's shell
Port review (outside voice): quoting alone was not enough, because the lane
expands {files} after the runner string is built, so a crate named
'evil{files}' spliced the quoted file list into the quoted name and a file
name like tests/$(cmd).rs then ran. A name outside Cargo's grammar
(letters, digits, _ and -) now gets no runner: its files are unclaimed and
the lane is incomplete, as Cargo itself would refuse the manifest. A valid
name, Unicode included, still runs quoted.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): match Cargo members globs per path component, without a backtracking regex
Port review (outside voice): members globs went through ship-policy's
matchesAny, which escapes [...] classes (crates/[ab] matched nothing, so the
crate was no member, lost its inherited [workspace.dependencies] path and its
dependents' tests were never selected: a false green) and backtracks
exponentially on a hostile glob such as '*a*a...*ab' (over 5 s for one crate,
before any runner deadline). A small dynamic-programming matcher handles *,
?, [..] with negation and ranges, and ** across components, in
O(pattern x path).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): a plain #[test] in src is a Rust test; bound the cfg attribute scan
Port review (outside voice): only #[cfg(test)] modules and tests/ files
counted, so a dependent crate whose tests are plain #[test] or #[tokio::test]
functions in src never ran when its dependency changed (a false green). The
cfg scan also went quadratic on a run of unclosed '#[cfg(' (about 3 s on
120 KB). Test attributes now count, and the cfg predicate and its strings are
length-bounded so the scan stays linear.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(pregate): Rust test attributes, workspace membership and rejected crate names; changelog for the port review fixes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): match members globs by code point in one pass, and admit every crate past a size cap
Second port review round (outside voice): the matcher counted UTF-16 units, so
'crates/?' missed a crate directory named with a supplementary character and
dropped its inherited dependencies (a false green); and each unmatched '['
rescanned the rest of the glob (5 s for one crate with a million of them).
Tokenize by code point with a precomputed next-']' table, and past 4096
characters of members globs admit every crate under the workspace: a wrong
member fails loudly in cargo, a dropped one is silent. The new supervised
probe kills a super-linear matcher at 30 s instead of hanging the file.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): scan cfg attributes once without truncating them; an unclosable one counts as a test
Second port review round (outside voice): the length bound from the first
round dropped a valid cfg(any(test, feature = "<257 chars>")), so its crate's
tests were no longer selected (a false green). Read each attribute once to
its closing ']' and resume after it, which keeps the scan linear without a
bound; an attribute the scan cannot close (an unterminated string, no ']')
counts as a test, which selects more, never fewer.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): second port review round (code-point member globs, unbounded linear cfg scan)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): past the members size cap, a crate's run root is undecided and its tests unclaimed
Third port review round (outside voice): admitting every crate past the cap
made a non-member run as 'cargo test -p <name>' from the workspace root,
where a same-named member answered and its passing tests stood in for the
orphan's failing one (a false green). Keep the conservative membership for
dependency edges, but leave such a crate's workspace undecided (null):
planRuns leaves its files unclaimed and the lane incomplete.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): the Rust end-to-end runs put the cargo shim under Windows' own Path key
windows-free-shard (5) still failed both end-to-end cases at fe99b200 with
the same symptom (the runner's real cargo, exit 1, no test result lines).
runBin merges process.env, whose Windows key is 'Path', with the shim's
'PATH', so the child got two path variables and read the original. Write the
shim under the key process.env actually uses, as test/helpers/unreachable-gbrain.ts
and sync-gbrain-readiness-fixture.ts do.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): run the cargo stand-in cases on POSIX only
windows-free-shard (5) still failed both end-to-end cargo-lane cases after the
delimiter, cargo.cmd and Path-key repairs: the lane's Git Bash exits 1 with an
empty log, and that log is not visible from CI. Skip the two cases that run the
bash stand-in on win32 (test.skipIf, as other POSIX-shim pregate fixtures are
handled) and drop the unproven cargo.cmd and Path-key changes. Selection,
planning and the hostile-name case still run on Windows.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): TODO(#3380) on the two win32-skipped cargo-lane cases
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): refuse a user policy whose link chain passes through the checkout
userConfigRejection checked the lexical path and the final realpath only. A
state root linked into the checkout, or a link hop inside it, let a branch pick
which existing out-of-repo policy governs it. Every hop of the resolution chain
is now checked. Found by the security review of #3286.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): verify goes stale when a link on the way to the absent user policy dangles
A fresh run refuses a user policy path with a dangling parent link, but verify
looked only at the leaf, so the parent's ENOENT read as continued absence and
an old defaults pass stayed publishable. The loader and verify now share one
absence check. Found by the security review of #3286.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(pregate): CHANGELOG entry for #3286 and the link-chain and dangling-parent rules
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.206.0 stamp
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: arlophoenix <arlo.phoenix@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: vilano93 <244097767+vilano93@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(ship): Step 9 fix-range re-review with a mandatory final full pass (#3339)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(review-log): fix-range base is the commit the fixing pass started from; follow Step 9.4's real order (#3339 review)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* honor not-ready review verdicts with advisory findings
The classifier now honors the last recognized not-ready verdict
regardless of parsed severity, returning findings and exit code 3 while
retaining the highest severity in the summary. Advisory findings with a
ready verdict or no verdict keep their existing behavior. Regression
coverage and troubleshooting documentation describe this behavior across
the execution, structured, and review gates.
Fixes#3329
* docs(changelog): outside reviewer not-ready verdict floors advisory findings (#3329, port of #3364)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): Rust crate lanes and nested JS package runners
lanes reported PREGATE_NO_LANE for every touched .rs file and ran a nested
pnpm+vitest package's tests as `bun test` from the repo root.
- Rust: a .rs file of a crate (nearest Cargo.toml with [package]) is a test
under <crate>/tests/ or when it holds a #[cfg(test)]; every .rs file of a
crate and its Cargo.toml select the crate's tests and those of every crate
depending on it (lib/pregate/rust.ts). Selected tests run per crate as
`cargo test -p <name>` from the workspace root, judged on the summed
`test result:` lines (doc-tests included); zero tests stays ZERO-RUN and a
missing cargo is incomplete, like a missing Dart SDK.
- JS/TS: a test owned by a nested package.json that declares vitest or jest
runs from that package with package-relative paths, through the package
manager its packageManager field or nearest lockfile names (pnpm exec,
yarn, bun x, else npx). Root detection and a declared runner are unchanged.
- init notes that Rust tests run per crate; docs/pregate.md updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): parse Cargo manifests as TOML; follow workspace membership
The line scan of Cargo.toml missed dependents (a false green) and picked the
wrong workspace:
- an inherited renamed dependency (`base = { workspace = true }` with
`[workspace.dependencies] base = { package = "alpha", path = ... }`);
- dotted keys (`alpha.path = "../a"`), `[dependencies.<name>]` tables and
target-specific tables, matched by key name only;
- a crate the workspace excludes ran `cargo test -p` from the workspace root.
Manifests are now parsed with Bun.TOML. A dependency resolves by path
(relative to the manifest declaring it, or to the workspace root when
inherited), else by package name. A crate runs from the workspace it is a
member of under Cargo's rules (package.workspace, the nearest [workspace],
members globs, exclude, literal members, path dependencies of members),
else from its own directory. Nothing runs cargo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(pregate): the Rust fixture's cargo shim wins PATH on Windows and beside a real cargo
windows-free-shard (5) failed 'a touched src file runs its crate...' and
'zero tests is ZERO-RUN...' deterministically: the shim PATH was joined with
':' so Git Bash never saw the shim dir, and the runner's real cargo ran
against the fixture (exit 1, no test result lines). On POSIX hosts where
Bun and cargo share a directory (/usr/local/bin on Capy's image), the lane
puts Bun's directory first and the real cargo wins the same way.
Join with path.delimiter, add cargo.cmd for Bun.which on Windows, and on
POSIX put the shim first again in the lane's own bash through BASH_ENV.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): quote the crate name in cargoRunner
The crate name is read from the repo's Cargo.toml and was interpolated into
'cargo test -p <name>', which the lane runs through bash. A name like
'evil;touch pwned' ran the second command. Quote it like every file and cwd
the lane already passes; a new end-to-end case checks the name reaches cargo
as one argument and runs nothing.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): the nested-package pnpm shim wins PATH beside a real pnpm
'a touched file in a nested pnpm+vitest package runs vitest there' ran the
host's real pnpm wherever Bun and pnpm share a directory (/usr/local/bin on
Capy's image): the lane puts Bun's directory first, so pnpm installed vitest
from the network, dirtied the fixture tree and the check came back
incomplete. Put the shim first again in the lane's bash through BASH_ENV,
as the Rust fixture does.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): pregate Rust crate lanes and nested package runners (#3344)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): a crate name Cargo would reject never reaches the lane's shell
Port review (outside voice): quoting alone was not enough, because the lane
expands {files} after the runner string is built, so a crate named
'evil{files}' spliced the quoted file list into the quoted name and a file
name like tests/$(cmd).rs then ran. A name outside Cargo's grammar
(letters, digits, _ and -) now gets no runner: its files are unclaimed and
the lane is incomplete, as Cargo itself would refuse the manifest. A valid
name, Unicode included, still runs quoted.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): match Cargo members globs per path component, without a backtracking regex
Port review (outside voice): members globs went through ship-policy's
matchesAny, which escapes [...] classes (crates/[ab] matched nothing, so the
crate was no member, lost its inherited [workspace.dependencies] path and its
dependents' tests were never selected: a false green) and backtracks
exponentially on a hostile glob such as '*a*a...*ab' (over 5 s for one crate,
before any runner deadline). A small dynamic-programming matcher handles *,
?, [..] with negation and ranges, and ** across components, in
O(pattern x path).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): a plain #[test] in src is a Rust test; bound the cfg attribute scan
Port review (outside voice): only #[cfg(test)] modules and tests/ files
counted, so a dependent crate whose tests are plain #[test] or #[tokio::test]
functions in src never ran when its dependency changed (a false green). The
cfg scan also went quadratic on a run of unclosed '#[cfg(' (about 3 s on
120 KB). Test attributes now count, and the cfg predicate and its strings are
length-bounded so the scan stays linear.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(pregate): Rust test attributes, workspace membership and rejected crate names; changelog for the port review fixes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): match members globs by code point in one pass, and admit every crate past a size cap
Second port review round (outside voice): the matcher counted UTF-16 units, so
'crates/?' missed a crate directory named with a supplementary character and
dropped its inherited dependencies (a false green); and each unmatched '['
rescanned the rest of the glob (5 s for one crate with a million of them).
Tokenize by code point with a precomputed next-']' table, and past 4096
characters of members globs admit every crate under the workspace: a wrong
member fails loudly in cargo, a dropped one is silent. The new supervised
probe kills a super-linear matcher at 30 s instead of hanging the file.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): scan cfg attributes once without truncating them; an unclosable one counts as a test
Second port review round (outside voice): the length bound from the first
round dropped a valid cfg(any(test, feature = "<257 chars>")), so its crate's
tests were no longer selected (a false green). Read each attribute once to
its closing ']' and resume after it, which keeps the scan linear without a
bound; an attribute the scan cannot close (an unterminated string, no ']')
counts as a test, which selects more, never fewer.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): second port review round (code-point member globs, unbounded linear cfg scan)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): past the members size cap, a crate's run root is undecided and its tests unclaimed
Third port review round (outside voice): admitting every crate past the cap
made a non-member run as 'cargo test -p <name>' from the workspace root,
where a same-named member answered and its passing tests stood in for the
orphan's failing one (a false green). Keep the conservative membership for
dependency edges, but leave such a crate's workspace undecided (null):
planRuns leaves its files unclaimed and the lane incomplete.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): the Rust end-to-end runs put the cargo shim under Windows' own Path key
windows-free-shard (5) still failed both end-to-end cases at fe99b200 with
the same symptom (the runner's real cargo, exit 1, no test result lines).
runBin merges process.env, whose Windows key is 'Path', with the shim's
'PATH', so the child got two path variables and read the original. Write the
shim under the key process.env actually uses, as test/helpers/unreachable-gbrain.ts
and sync-gbrain-readiness-fixture.ts do.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): run the cargo stand-in cases on POSIX only
windows-free-shard (5) still failed both end-to-end cargo-lane cases after the
delimiter, cargo.cmd and Path-key repairs: the lane's Git Bash exits 1 with an
empty log, and that log is not visible from CI. Skip the two cases that run the
bash stand-in on win32 (test.skipIf, as other POSIX-shim pregate fixtures are
handled) and drop the unproven cargo.cmd and Path-key changes. Selection,
planning and the hostile-name case still run on Windows.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.197.0 stamp
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: vilano93 <244097767+vilano93@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(memorable): per-remote recall opt-in for read-only repos; recall veto fails closed on a corrupt policy store (#3359)
Closes#3359
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(repo-policy): reserve only the two metadata keys, so the _unattributed sentinel stays a valid policy key
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(memorable): recall lookup is a pure snapshot read that fails closed on malformed, dangling or unsearchable stores, and keys on the configured origin URL (security review)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(memorable): check every configured origin URL, and confirm a missing store through its ancestors (security review, second pass)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(memorable): read origin URLs NUL-delimited, and keep a dangling ancestor symlink off the no-store fast path (security review, third pass)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(memorable): use each NUL-delimited origin URL verbatim (security review, fourth pass)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): resolve extensionless .jsx, .mts, .cts and index.jsx/tsx/mjs imports (#3340)
RESOLVE_EXT had no .jsx and no index.jsx/index.tsx/index.mjs, so on a JSX repo
every extensionless component import resolved nowhere and lanes failed with
'has no test lane'. Existing entries keep their order (it decides precedence).
Fixes#3340
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.188.0 stamp
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(qa): materialize names the next write; fixture states the write boundary (GSTA-63)
qa-functional-webhook-fix (gate 39646086155) and qa-functional-cli-fix
(gate 39166935531) each wrote a stray placeholder beside the fixture
right after a fail verdict that read "final for this report root".
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.178.0 stamp
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(evals): the gate reruns failed cases once and reports a flaky green (GSTA-49 F1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ci: retrigger after retargeting to main
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(evals): a case red twice stays a real red for the report, the run, reuse and the train verdict (GSTA-49 F1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): keep a lone rerun-plan artifact off the plan manifest (run 39363705692)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: stamp v1.91.163.0
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): Dart import graph and test lanes (#3285)
Port of arlophoenix's #3285. The import graph reads Dart import/export/part
directives and resolves package: URIs through every tracked pubspec.yaml;
_test.dart files under test/ are tests. lanes runs each Dart package's
selected tests from its own root with flutter test or dart test (through fvm
when the package pins it). flutter/dart/melos/very_good CI jobs are lanes,
and run-step test paths resolve against working-directory and literal cd.
A missing Dart SDK or a .dart file outside any package leaves the lane
incomplete with a fix line; device tests (integration_test/, test_driver/)
are not unit lanes.
Co-authored-by: arlophoenix <arlo.phoenix@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): a --base that names a commit gets a branch fix, not an impossible fetch (#3269)
gstack-pregate --base <sha> refused with "fix: git fetch origin <sha>
--depth=1". That fetch can never create origin/<sha>: a short SHA fails
with "couldn't find remote ref", and a full SHA only reaches FETCH_HEAD.
A fork clone hits the same wall with --base upstream/main.
When origin/<base> does not resolve but <base> names a commit here and
no local branch (a SHA, a tag, another remote's ref), the refusal now
says --base takes a branch name on origin and suggests origin/HEAD's
branch. A local branch, or a name that resolves nowhere, keeps the
fetch fix: that is the unfetched or shallow checkout it repairs. Same
code, same exit 3, and pin files are still read only from the reviewed
origin/<base>.
Fixes#3269
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(pregate): Django, asset and tool-config lanes; init drafts from the repo (#3266, #3267, #3268)
- Django: settings modules, settings strings, include(), app migrations,
admin, templates, static files and project templates get framework edges
(lib/pregate/django.ts).
- Assets, stylesheets and dotfile tool config take a no-tests empty lane;
licence text under any name is documentation.
- gstack-pregate init drafts languages, runner notes and nearest-test
dependencies; never writes [].
- Review fixes on the #3285 port: untracked shell scopes leave a lane
unknown; Dart directives read to their semicolon; nested comments.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(pregate): init draft API is exercised directly, so init-draft.ts has a lane
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): restore the history a truncated rewrite dropped
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): outside-voice review fixes for the non-JS lanes
- Tool config is an allowlist: unknown dotfiles (.rspec, .husky hooks) and
stylesheets still need a lane; snapshot, golden and fixture trees and
.gstack/ are never inert.
- Django edges need Django evidence (manage.py or code importing django)
and settings assignments in code, not strings or comments.
- A cd after ||, &, control flow or braces leaves a lane unknown.
- Dart directives allow metadata and quoted semicolons.
- init drafts at most 256 dependencies (the schema limit); the rest are TODO.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(windows): pregate-dart and pregate-non-js join the POSIX-run pregate fixtures
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: release v1.91.161.0
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: arlophoenix <arlo.phoenix@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: y$un_ <forrest.sun527@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(scope,review,ship): recognise Dart and Flutter in diff scope and test detection (#3284)
Port of arlophoenix's #3284 onto current main, squashed:
- gstack-diff-scope: .dart is frontend and backend; pubspec.lock is config.
- lib/frontend-scope.ts mirrors the frontend half; gstack-design-detect
never sends .dart to the impeccable engine.
- Test bootstrap, coverage audits and review-army detect Dart/Flutter
(RUNTIME:dart, FRAMEWORK:flutter, dart_test.yaml, *_test.dart).
- Adversarial DIFF_SIZE sums git diff --numstat.
On top of the contributor's diff: shorten the bootstrap's ecosystem-marker
comment so /design-review stays at its SKILL.md size pin, lower the 31 pins
that shrank, and add the CHANGELOG entry.
Co-authored-by: arlophoenix <arlo.phoenix@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.160.0 fix(scope,review,ship): recognise Dart and Flutter in diff scope and test detection (#3300)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: arlophoenix <arlo.phoenix@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* security: isolate every gstack Bun entry point from the audited checkout's .env and bunfig.toml
Bun auto-loads .env, .env.local and .env.<NODE_ENV> from its cwd and runs a
cwd bunfig.toml preload before the program starts. gstack runs inside the repo
it audits, so a committed .env could steer state roots, the claude binary or
spend caps, and a bunfig preload ran arbitrary code in every bin and hook.
Every bun shebang, shell and skill caller, TypeScript spawn and compiled build
now disables both (--no-env-file --config=/dev/null, bunIsolationArgs(),
--no-compile-autoload-dotenv/bunfig), with a ratchet and hostile-fixture
regressions.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: name the directly executed scripts in the isolation ratchet
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: follow the isolation flags in touchfiles, copy lists, recipe assertions and the harness pin
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: keep browse/src/bun-child-config.ts unchanged so the native cookie qualification still binds
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(windows): the empty bunfig outlives its process so the timeline hook's detached repair child can read it
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.159.0 security: gstack's Bun entry points ignore the audited repo's .env and bunfig.toml (S1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: plan-mode render pattern accepts the isolation flags
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(cso): withhold excluded credential files from retained history; name failed witness assertions ASSERTION_FAILED
* fix(cso): Rails verify replaces read-only copied config instead of writing into it
* fix(cso): security expectations may list several safe statuses while excluding the vulnerable marker
(cherry picked from commit aa9f45e0ece0e12152e7d02bf88e1559ee42b1eb)
* docs(changelog): safe status sets
* v1.91.154.0 stamp
* style(cso): format merged snapshot history capture
* fix(outside-review): no-findings counts only as the review's conclusion; add regressions/defects (#3294)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(outside-review): a trailing ', and' clause can conclude; elsewhere/otherwise are exceptions; real codex captures
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(outside-review): whitelist the conclusion's qualifier; join wrapped Recommendation clauses; outside-review findings as controls
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(outside-review): join a wrapped line only when it continues in lowercase
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(cso): record a nested repository as an explicit snapshot exclusion
An untracked nested repository makes gstack-cso start fail with
UNSAFE_PATH. Git lists it as one entry with a trailing slash, so
relativePath() rejected the empty segment and aborted the run. A
registered submodule gitlink already failed one step later for the same
reason: it is a directory, and the capture loop only reads regular
files.
Accept the boundary under its own name and record it like a host
dependency tree: one manifest entry, originalHash not-read, an
excluded: transformation that discloses the omission in the report's
snapshot-inputs coverage, no payload copied, and an identity check
during capture so a swapped or symlinked boundary fails closed. Nested
repository contents are never audited with the outer repository because
Git never descends into them.
* fix(cso): keep the newest whole commits when history exceeds the 1 MiB bound (#3255)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(cso): regressions and negative controls for nested repos, long history and macOS sockets (#3255, #3248)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): blank line before 1.91.149.0
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(cso): set GSTACK_HOME in beforeAll, not at module scope
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: stamp v1.91.152.0
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: Chao Chen <209239467+surlymochan@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(evals): Opus 5.5 is the paid gate's model under test; judge stays Fable (GSTA-49 TM1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.140.0 chore: stamp TM1 (Opus 5.5 model under test) and CHANGELOG
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): repair the five Opus gate reds from run 39161502626
- coverage audit: owned cd; followed by one && chain, wc -l on in-cwd files
- shared-libs: Claude Code 2.1.292 git --version probe, exact argv only
- ship hook: accept 'integrate the hook yourself' / 'combine ... by hand'
- qa-only: deadline starts only after the charter Write completes
- plan floor: tool-only parent session identifies the owned Create grant;
floor runner fails fast with PERMISSION_DIALOG_UNANSWERED
Each repair replays its captured run as a free regression with negative
controls. HARNESS_VERSION stays 6 (re-recorded from main's 5).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): ship hook manual-integration sentence rule; qa-only inspection uses Read/Glob; tool-only permission tests join their owner file
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): tpa-absent-linux accepts instructions the user follows themselves as the manual option
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): owned plan Edit menu binds to exactly one pending Edit, including unpublished ones
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): shared-libs read evidence counts a literal path loop whose output names each file
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: restamp to v1.91.142.0 (queue slot moved)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): investigate boundary fixture identifies the owner question by its continue/abort options
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): plan-design-with-ui focus check accepts the skill's design-completeness rating in the question body
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): phrasing sweep across the 108 gate rule cases; replay captured Opus paraphrases with negative controls
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evals): command-detector sweep — exact-count anchor, label slot, 2.1.292 worktree probe
- coverage audit (gate 39207508651 plan-eng-coverage-audit): output of exactly
known length (wc -l over literal in-cwd files) anchors the next owned read
at that line; a label's slot counts from the end and a later complete copy
voids the credit (review/specialists/testing.md prints '---')
- shared-libs-unsupported-git (39161502626): Claude Code 2.1.292's askPass-first
'worktree list --porcelain -z' cwd probe is Claude's own; the read-only Git
check is shared (repoGitRequests, isReadOnlyRepoGitRequest) and the free
regression replays every Git request of that capture
Each fix replays its captured command with negative controls. No threshold,
trial count, case kind or judge changed. HARNESS_VERSION stays 6.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>