Commit Graph
632 Commits
Author SHA1 Message Date
garrytanandcapy-ai[bot] 9bb348df77 design-lint: document the third-cycle limits and waiver scope
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 08:27:41 +00:00
garrytanandcapy-ai[bot] fc2685b528 design-lint: third review cycle tests; render keeps the measured horizontal-scroll when merging widths
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 08:26:23 +00:00
garrytanandcapy-ai[bot] 6100d6e94d design-lint: third review cycle fixes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 08:21:13 +00:00
garrytanandcapy-ai[bot] ddaeabe1f4 design-lint: pair open and close tags once per document, scan markup in linear time, keep commented-out style and script dead
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 08:05:55 +00:00
garrytanandcapy-ai[bot] df6cd725c2 design-lint: second review cycle
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>
2026-10-26 07:44:56 +00:00
garrytanandcapy-ai[bot] 2bf81ad1f1 design-lint: name the tracked-caps thresholds once, string-aware brace scan, drop an unused parameter, clean up test tmpdirs
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 07:18:23 +00:00
garrytanandcapy-ai[bot] 31682440fe design-lint: ship review fixes
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>
2026-10-26 07:14:50 +00:00
garrytanandcapy-ai[bot] 54d415bd2d design-lint: mark hallmark PAGE_ONLY gates and craft page checks pageOnly so --scope component drops them
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 07:00:05 +00:00
garrytanandcapy-ai[bot] a088fc3d8c feat(design-lint): section-gap measured in the render tier (gate 59, with the six-to-nine section count) and the hero action count; a free test over the recorded review slop page; usage, render glue, file walk, multi-page ownership and copy-tier tests; NOTICE and licences leave FREE_ONLY_PR_FILES so the paid-free boundary test stands
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 06:50:23 +00:00
garrytanandcapy-ai[bot] bf9d9c5b04 test(design-lint): register the lint fixtures as free fixtures and the hallmark licence texts as free-only PR files, so the PR paid lane stays narrow and test/free-fixtures.test.ts passes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 06:35:05 +00:00
garrytanandcapy-ai[bot] e7b2521148 feat(design-lint): render tier merged; four probe modules join the ratchet; the clean hero sits at a fixed measure so text and visual stand together; CHANGELOG names the aside-render eval viewport
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 06:27:06 +00:00
garrytan 5232f86770 Merge remote-tracking branch 'origin/feat/design-lint-render' into feat/design-lint 2026-10-26 06:18:21 +00:00
garrytanandcapy-ai[bot] 07b2aa6527 feat(design-lint): render tier on gstack's own browser (sloplint-render port)
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>
2026-10-26 06:17:03 +00:00
garrytanandcapy-ai[bot] 9be95cf33e test(design-lint): the eyebrow-pass and tailwind-pass fixtures carry a skip link, main id and aria-current so the copy tier passes them too; waiver fixture gets a meta description
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 06:13:52 +00:00
garrytanandcapy-ai[bot] 22d39449d1 feat(design-lint): chrome, assets and finish families merged; maskedProse moves to html.ts; isTokenRule takes a Pick; ratchet watches every lint module
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 06:06:26 +00:00
garrytan 69a7ec0e82 Merge remote-tracking branch 'origin/feat/design-lint-chrome-assets-finish' into feat/design-lint 2026-10-26 06:03:12 +00:00
garrytanandcapy-ai[bot] 6dda84e531 feat(design-lint): port the chrome, assets and finish rule families from sloplint
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>
2026-10-26 06:02:06 +00:00
garrytanandcapy-ai[bot] e8e61f2dba chore(design-lint): drop unused colour test imports
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:52:29 +00:00
garrytanandcapy-ai[bot] 95eee7e4e1 chore(design-lint): tidy the colour test imports; control-height page-only; lazy-lcp title
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:52:11 +00:00
garrytan 95b19fdbca Merge remote-tracking branch 'origin/feat/design-lint-structure-motion' into feat/design-lint 2026-10-26 05:51:29 +00:00
garrytanandcapy-ai[bot] aed2b149e6 fix(design-lint): the Tailwind gradient half of 2a/2b lives in the component family only
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:51:29 +00:00
garrytanandcapy-ai[bot] 3113f54d55 feat(design-lint): port the structure and motion rule families from sloplint
Structure: template-cards, nested-cards, vh-height, raw-spacing, off-scale-spacing, overflow-x-unclipped (static half), bare-fr-track, display-head-unwrapped, radio-tab-jump, double-sticky, screen-word-budget (static half), and a conservative static half of wide-container. Motion: layout-transition, spacing-transition, hover-tells, bounce-easing, focus-ring-fade, tooltip-focus-delay, autorotate-no-pause, missing-focus-visible, missing-states, missing-reduced-motion, autoplay-unmuted, lazy-lcp, video-without-poster, input-state-shift, control-height (static half), content-hidden-at-rest. Every rule has a planted positive and a negative control; the clean fixture lede drops to eleven words so the hero-paragraph budget holds.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:50:22 +00:00
garrytan dfd6693d51 Merge remote-tracking branch 'origin/feat/design-lint-tailwind' into feat/design-lint 2026-10-26 05:50:06 +00:00
garrytanandcapy-ai[bot] ab8bb491ac fix(design-lint): mark line-length, cream-palette and the caps leading rules page-only
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:50:05 +00:00
garrytan 56ce4aeb0d Merge remote-tracking branch 'origin/feat/design-lint-color-type' into feat/design-lint 2026-10-26 05:49:50 +00:00
garrytanandcapy-ai[bot] 69ac84f2e4 feat(design-lint): port the Tailwind reader and component rules
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>
2026-10-26 05:49:02 +00:00
garrytanandcapy-ai[bot] 3807370452 feat(design-lint): port the colour and type rule families from sloplint
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>
2026-10-26 05:48:48 +00:00
garrytanandcapy-ai[bot] bf632b6996 docs(design-lint): CHANGELOG entry, NOTICE and MIT-hallmark licence, module-size ratchet entries
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:36:15 +00:00
garrytanandcapy-ai[bot] 1ba2ae0425 feat(design-lint): core of the bundled free design lint (parsers, colour, tokens, reporter, waivers, CLI)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:31:11 +00:00
Garry Tanandcapy-ai[bot] 5128ec1469 ci(scorecard): bump github/codeql-action/upload-sarif from 4.38.3 to 4.39.0 (#3401)
Recreates Dependabot's #3307 on a crew branch so it can take a version stamp
at merge. 6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee is the commit the
annotated tag v4.39.0 points to.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 05:01:10 +00:00
Garry Tanandcapy-ai[bot] e622075a18 v1.91.228.0 fix(gstack-lease): take the lease lock with mkdir, not ln -s, so Git Bash on Windows stops waiting out 300 tries (#3330) (#3424)
* fix(gstack-lease): take the lease lock with mkdir, not ln -s, so Git Bash on Windows stops waiting out 300 tries (#3330)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(gstack-lease): count lock retries instead of timing them

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(lease): a dead lock that cannot be renamed aside no longer spins lock()

break_lock ignored drop()'s failure and returned 0, so lock() continued past
the tries limit forever when a dead holder's .lock could not be renamed aside
(a Windows file in use). It now removes the lock in place under .lock.break,
and returns 1 when that also fails so the try is counted. touch no longer calls
a dead holder 'live' in its exit-3 message.

Adds the /ship coverage-audit tests for the lock's failure paths.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(lease): pre-landing review fixes

- drop() reports a lock released once it is renamed aside, so a failed
  delete of the renamed copy never makes unlock or break_lock rm -rf a new
  taker's lock at .lock.
- An ownerless lock is broken only once it is 2 s old, so a live taker whose
  claim landed after a breaker read the claims keeps the lock it is about to
  publish. An empty owner, an invalid pid or a stray file counts as ownerless.
- touch's prune stays out of the lock (top-level lease files only) and clears
  leftover renamed-aside locks; a failed claim write leaves no claim.
- Docs and CHANGELOG state the mixed-version and dead-break-lock limits
  instead of claiming exclusion that does not hold.

Tests pin each fix (each fails against the previous bin), make the exclusion
case wait on a release file, prove the parallel case is mutually exclusive,
and check the Git Bash holder keeps its lock.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(lease): second /ship review pass

- orphaned() reads the clock before the lock's mtime and requires the mtime
  unchanged at the end, so a lock made meanwhile is never removed; an mtime
  a minute or more ahead (clock skew) counts as old.
- Claims older than 2 minutes are abandoned and pruned by touch.
- A waiter skips the claim and mkdir while the lock is visibly held; the
  wait is bounded at 300 tries or 30 s; a non-numeric tries value falls back
  to 300; ten quick retries (not three) before a lock nobody holds is
  reported as untakeable; pid 1 is a valid holder again.
- Tests: deterministic young-lock clock, skew and non-numeric owner shapes,
  abandoned claims, the deadline, explicit 30 s timeouts.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(lease): third /ship review pass

- A claim is honored while its claimant lives; only a claim with no start
  identity expires after 2 minutes, so a stalled live taker keeps its lock on
  hosts that record identities (the remaining case is a documented limit).
- A late taker never overwrites an owner already in its directory, and does
  not remove a directory that has one.
- A lock whose owner file exists but cannot be read is never ownerless.
- Zero-padded owner pids count as dead; --help prints the whole usage;
  touch prunes only claims whose claimant is gone or recorded no identity.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(lease): scope 'never by age' to locks that name a holder

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>
2026-10-26 04:46:42 +00:00
Garry Tanandcapy-ai[bot] 9dc1dfb729 v1.91.227.0 fix(windows): shell bins pass NUL as Bun's empty config when MSYS path conversion is off (#3415) (#3431)
* 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>
2026-10-26 04:32:27 +00:00
Garry Tanandcapy-ai[bot] 8d9501373b v1.91.226.0 feat(review): /review re-reviews only its fixes after an edited pass, with a final full pass (#3339) (#3414)
* feat(review): /review re-reviews only its fixes after an edited pass, with a final full pass (#3339)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(review): fix-range narrows only DIFF_BASE outside Step 4.8; Step 5.0 ignores this invocation's records (#3339)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(review): fix-range walk logs each pass's Step 4.8 attempt in /review's real order (#3339)

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>
2026-10-26 00:43:12 +00:00
Garry Tanandcapy-ai[bot] 7bd3fb4a40 v1.91.225.0 feat(design-html): craft section and free craft check, adapted from Elaya's design skills (GSTA-92) (#3420)
* 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>
2026-10-26 00:29:01 +00:00
2853304d17 v1.91.224.0 fix(context): record the save commit and flag work that landed after it (port of #3316) (#3396)
* fix(context): record the save commit and flag work that landed after it

/context-save recorded the branch, a timestamp and the modified files, but not
the commit, so /context-restore could not tell that work landed after the save.
A checkpoint saved before a step was committed came back with that step still
listed as the plan.

- gstack-slug --stamp-checkpoint also writes head:, the commit the save
  describes, next to remote:/project_root:/worktree:.
- context-restore compares head: with HEAD before presenting. When commits
  landed after the save it prints how many and lists them, and moves Remaining
  Work under Verify first; a saved commit that left the branch history is
  reported the same way. Checkpoints saved before this keep their old sorting
  with a one-line note.
- test/context-restore-head.test.ts runs the real save-path, stamp and
  head-check blocks in fixture repos: unchanged, moved, diverged after a reset,
  pre-tracking, and a malformed head: that must never execute.

* fix(context-restore): name another branch as a cause when the saved commit is not in history

Cross-branch resume (Conductor handoff) is a supported restore path, and there
the checkpoint's commit is usually not an ancestor of HEAD. The diverged line
said only 'rebased, reset, or not fetched'. It now names 'saved on another
branch' first; the new test case covers a save on a feature branch restored
from main.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(changelog): unreleased entry for the context head check (port of #3316)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(context-restore): head check passes the fence lint, reads frontmatter only, prefers worktree:, and overrides provenance sorting

- The block used a free-text placeholder, <the chosen file>, which the
  generated-bash lint (test/env-host-fence-conformance.test.ts) refuses on
  every host. It now uses the allowlisted <the FILE path printed above>, with
  prose naming the Step 2 choice.
- head:, worktree: and project_root: are read from the leading frontmatter
  only (sed, no positional $N tokens Claude Code would rewrite), so a head:
  line in a checkpoint's notes no longer counts.
- Outside git, the comparison uses the saved worktree: before project_root:,
  so a save from a nested linked worktree is not compared with the main tree.
- The provenance rules now say they are skipped after HEAD_MOVED,
  HEAD_DIVERGED or HEAD_UNKNOWN, instead of contradicting the head check.
- The re-stamp test checks the exit status and that the head moves.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Yao Amevi A. Sossou <47247401+soyames@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-26 00:14:08 +00:00
Garry Tanandcapy-ai[bot] 1c28c09b76 fix(plan-tune): map the clicked AskUserQuestion label to the registered option key at capture (#2623) (#3394)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 23:54:50 +00:00
Garry Tanandcapy-ai[bot] f4536ed4d5 v1.91.222.0 test: daily flaky-fix pass: qa-only late clock, fragment-match verdict, install-admission timeout, ff-update reap, judge parse diagnostics (GSTA-91) (#3413)
* test: flaky-fix pass — fragment-match reads the agent's report, ff-update reap counts its own sleepers, install-admission gets a measured timeout, judge parse errors name the judge (GSTA-91)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(qa-only): late scenarios freeze the fixture clock during setup and register their real outer budget (GSTA-91)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(harness): record the llm-judge parse-message change as non-behavioral (GSTA-91)

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>
2026-10-25 23:39:42 +00:00
Garry Tanandcapy-ai[bot] c23d7d48fe fix(session-update): the starting session's own lease never skips its update; autostash fixtures own their lease dir and state root (GSTA-91) (#3412)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 22:45:05 +00:00
Garry Tanandcapy-ai[bot] 956a3f5484 v1.91.220.0 fix(office-hours,plan-reviews): write the plan-mode copy through to the design doc and warn when it is newer (#542) (#3408)
* fix(office-hours,plan-reviews): write the host plan-mode copy through to the design doc and warn when it is newer (#542)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(changelog): #542 under [Unreleased]

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(instruction-facts): drop the office-hours allowlist row for the removed cross-team sentence

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>
2026-10-25 22:31:08 +00:00
Garry Tanandcapy-ai[bot] f73f75ce55 v1.91.219.0 fix(eval-bg): local lanes export EVALS_RUN_ID so native-capture cases start (GSTA-70) (#3391)
* fix(eval-bg): local lanes export EVALS_RUN_ID so native-capture cases start (GSTA-70)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* v1.91.219.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>
2026-10-25 21:33:43 +00:00
Garry Tanandcapy-ai[bot] d73b547066 fix(team-init): register the required Skill hook with onFailure: block (#3319) (#3393)
Without node on PATH the node -e launcher exits 127, and with check-gstack.cjs
missing it exits 1; Claude Code treats both as non-blocking and lets the Skill
call through. Register the handler with onFailure: block (Claude Code 2.1.295+),
upgrade existing registrations in place, and tell the agent and the developer
what the two block reasons mean.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 21:21:10 +00:00
Garry Tanandcapy-ai[bot] 2d27b482d2 v1.91.217.0 fix(ci): run Windows free tests on every push to main (GSTA-68 follow-up) (#3390)
* fix(ci): run Windows free tests on every push to main (GSTA-68 follow-up)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* v1.91.217.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>
2026-10-25 21:07:18 +00:00
64d82101ca v1.91.216.0 fix(sync-gbrain): refuse an active autopilot before touching the source list (#3360 part 2, port of #3362) (#3386)
* fix(sync-gbrain): refuse on an active autopilot before the code stage registers a source

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* docs(changelog): sync-gbrain autopilot refusal before source registration (#3360, port of #3362)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(sync-gbrain): the early autopilot refusal check matches #3377's pid-naming wording (#3360)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Evgenii Lopatin <e75533@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 16:35:45 +00:00
Garry Tanandcapy-ai[bot] 5ac0f56934 fix(ship): unattended handoff writes the receipt to a file the parent reads (GSTA-88) (#3409)
Step 18-H's receipt write gains --out .gstack/tmp/ship-receipt.md; skill-start
prints a ship-only UNATTENDED_SHIP line; docs/unattended.md sends the parent to
read --body on that file and to compare head to the branch SHA.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 16:22:14 +00:00
Garry Tanandcapy-ai[bot] 08301328e9 v1.91.214.0 fix(brain-sync): --publish-removals cleans up its temp list and lock without 'list: unbound variable' (GSTA-87) (#3405)
* fix(brain-sync): --publish-removals trap expands its temp paths at install, so cleanup and lock release run after the function returns (GSTA-87)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* v1.91.214.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>
2026-10-25 16:09:15 +00:00
5bbe538bdc v1.91.213.0 fix(ci): Node.js 22.23.4 in the CI image and Ubicloud free-suite VMs, SHA-256 verified (port #3355, fixes #3354) (#3400)
* fix(ci): bump Node.js to 22.23.4 for CVE-2026-111497

* fix(ci): pin Node.js 22.23.4 in the Ubicloud free-suite bootstrap too, and verify both archives by SHA-256

#3355 bumped Dockerfile.ci only; scripts/ubicloud/setup-free-suite.sh still
installed 22.20.0. Both now pin the same version and the linux-x64 SHA-256
from the release's signed SHASUMS256.txt, check the archive before unpacking,
and test/ci-image-cli-pin.test.ts keeps the two pins equal (#3354).

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

Co-authored-by: Michael Sumner <75835774+michael-sumner@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(changelog): Node.js 22.23.4 CI pin (#3354)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(ci-image): name Dockerfile.ci in a form pregate resolves; assert the image hash in the parity case

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Michael Sumner <75835774+michael-sumner@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 15:57:06 +00:00
f00b8bc79b v1.91.212.0 fix(careful): mask git commit's own message before the MEDIUM checks (#1060, port of #3221) (#3389)
* fix(careful): mask git commit -m content to prevent MEDIUM-tier false positives (#1060)

MEDIUM-tier checks matched the full command string including quoted -m text.
A commit like 'git commit -m fix: prevent drop table in migration' triggered
the SQL DROP warning even though no SQL was being executed.

Build CMD_MEDIUM by stripping -m quoted content from git commit commands
before MEDIUM checks. Real destructive commands outside the quoted string
still match, so true positives are unaffected.

Add tests: commit message patterns do not warn; chained real DROP/TRUNCATE still warns.

* fix(careful): replace sed masking with quote-aware awk scanner (#1060)

The sed-based -m content masker had two bypass paths that capy-ai identified:

  1. Single-quoted message containing a double-quote boundary:
       git commit -m 'note -m "' && rm -rf build && echo '"'
     The double-quote pass matched '-m "' inside the single-quoted string,
     swallowing '&& rm -rf build && echo '; the rm vanished from CMD_MEDIUM.

  2. Double-quoted message with a command substitution:
       git commit -m "$(rm -rf build)"
     sed replaced the content including the $(...), so the substitution
     — which executes in the shell — was masked away.

Replace the sed substitution with a quote-aware awk scanner that:
- Walks the command string tracking single-quote, double-quote, and
  backslash state, so it only treats a delimiter as a message boundary
  when the shell would.
- Masks single-quoted messages (always literal) and double-quoted messages
  that contain no $, backtick, or backslash (safe to mask — no expansion).
- Leaves double-quoted messages with $, backtick, or backslash unmasked
  so command substitutions stay visible to the MEDIUM checks.
- Handles -m, -am, --message, and --message= forms.

Four new tests added as requested (alongside the original six):
- single-quoted message with embedded double-quote + chained rm → warns
- commit message with $(rm -rf build) → warns
- git push --force chained after commit → warns
- git commit -am "drop table notes" → silent (message masked)

* fix(careful): read the commit-message masker from a file, so bash 3.2 can parse the hook (#1060)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(careful): scan the command as one string, so a newline still separates commands from the message (#1060)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(careful): mask only git commit's own message; a piped commit or another command's -m stays visible (#1060)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(careful): mask a quoted-delimiter heredoc message; any other substitution or heredoc leaves the command unmasked (#1060)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(careful): a pipe, process substitution or parameter expansion after the message unmasks it; redirections and comments parse like bash (#1060)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* docs(changelog): careful masks git commit's own message (#1060, port of #3221)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Bhumika-1432006 <guravbhumika808@gmail.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 15:44:07 +00:00
Garry Tanandcapy-ai[bot] cb99df4a2f fix(diff-scope): count Python test_*.py and nested test dirs as tests (#3335) (#3382)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 12:39:53 +00:00
Garry Tanandcapy-ai[bot] c279ce045d fix(autoplan): linked worktrees resolve from a project directory below the repo root (#3296) (#3383)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 12:27:01 +00:00
Garry Tanandcapy-ai[bot] 0ea3dc8986 test(redact): fixture git and hook installs share gitEnv(), so a global core.hooksPath is never rewritten (#3353) (#3384)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-25 12:14:02 +00:00