* feat(proactive): default to the four core skills (core | all | off); docs, prompt and tests (GSTA-99)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(proactive): gstack-skill-start falls back to core, not true, when gstack-config is missing
The PROACTIVE status line's fallback literal still said true (= all) after the default moved to core. Found by /ship's coverage audit; the regression test fails at the previous head and passes at main.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(proactive): STATUS line carries the stored value; every surface names the same core four and three values
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(proactive): off gates the office-hours handoff; the preamble and router scope the setting to unasked suggestions
The office-hours next-review handoff gated on the legacy false only, so an off user was still asked to launch /plan-eng-review. The per-skill preamble now says the setting governs unasked suggestions and this skill's own steps still run (a handoff, a review gate, a dispatched /document-release is not a suggestion), at exactly the previous length, so the 89 size pins return to main's values; the router says the same in full. Found by /ship's specialist and red-team review.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(skill-start): unknown proactive values read as core; first-run tips name core skills and stay quiet under off
A hand-edited config can hold any value and only set validates, so STATUS normalizes anything but core|all|off|true|false to core. The first-run and first-loop tips named /spec, /investigate and /plan-eng-review whatever the setting; they now name the core four and are skipped under off. The fallback regression test folds into test/proactive-skill-start.test.ts, the duplicate header assertion leaves proactive-config, and the frozen-length preamble test is retired (the size guard enforces it).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(proactive): scope note, the unknown-value rule, and the CLAUDE.md routing follow-up; CHANGELOG
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(skill-start): no CLAUDE.md routing offer under proactive off
The one-time offer to append ## Skill routing to the project's CLAUDE.md fired whatever the proactive value, and its rules are the auto-invocation an off user turned off. The offer is skipped under off and the legacy false; a section already in CLAUDE.md is left alone. Under core the offered section still routes every skill, which docs/proactive.md records as the follow-up. Found by /ship's red team.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(proactive): STATUS says only core | all | off, and the preamble carves out only named skills
gstack-skill-start reads the legacy true/false as all/off and tolerates a quoted, upper-case or commented hand edit (proactive: OFF # mine read as core before), so every surface sees one of three values and the off gating lives in one flag. The per-skill preamble drops the legacy spellings and replaces 'This skill's steps still run', which licensed any in-skill offer under off, with 'Skills the user or this skill's steps name run', at the same length, so the 89 size pins stay at main's. Tests run the script for the tips and the routing offer under core and off instead of grepping the source. Found by /ship's fix-range repeat (red team, testing, maintainability).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(config): set proactive is case-insensitive; follow-up #3446 cited; test hygiene
set proactive OFF warned and stored core, the opposite of the opt-out typed; the value is lowercased first, as gstack-skill-start does for a hand edit. The fixture git init carries the tripwire timeout, the source-shape assertion on the private _PROACTIVE_OFF line goes (the routing-offer test proves the behavior), and the CHANGELOG Tests bullets collapse to one per file with the known gap pointing at #3446. Found by /ship's full repeat pass and its tests lane.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(proactive): a stored off answers the one-time prompt; the router names /browse and /investigate under core instead of invoking them
Red team, full repeat pass: with proactive: off stored before the prompt, skill-start still emitted the opt-in prompt; it now writes the marker and asks nothing. The router's Route-first browser step and the Failures branches invoked non-core skills under core while the core block said to answer directly; one sentence in the core block resolves it, pinned by the core-set tests. CHANGELOG and docs/proactive.md say both.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(proactive): the full-catalog skill descriptions are the second surface that still routes every skill under core (#3446)
From /ship's document-release audit: a --catalog-mode=full build and the non-Claude hosts keep the "Proactively suggest when ..." description sentences, which do not follow the setting; the default Claude build trims them.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(proactive): the tips test runs skill-start as an interactive session
GitHub CI sets CI/GITHUB_ACTIONS, which gstack-session-kind reads as headless, and a headless start skips first-task detection, so the first-run tip never fires there (Free Tests shard 16 red at 0d7dbe6; green locally and on the Ubicloud pregate, which have no CI marker). The fixture now sets CLAUDE_CODE_ENTRYPOINT=cli, the positive interactive signal; reproduced locally with CI=1 and fixed.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(proactive): an opt-out never fails open; the preamble carves out invocations, not offers
The YAML yes/no family (yes/on/1, no/none/0/disabled/never) reads as all/off in both gstack-skill-start and gstack-config set, so a typed or hand-edited opt-out cannot land on core. The per-skill preamble says "Skills the user names or this one invokes run" (same 168-char length, pins unchanged): a skill dispatching another is not a suggestion, an in-skill offer to run one still is under off. The stored-off prompt marker is written before STATUS prints PROACTIVE_PROMPTED, so the line is true. docs/proactive.md's table row carves out in-skill handoffs.
Fourth /ship fix cycle, past the skill's three-cycle cap by GStack Minder's decision (2026-10-26) under Garry's "do it" on the proactive core set; items from the Step 11 adversarial pass.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.240.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(gate-diff): resolve the base to origin/<base> when no local branch exists; the no_base fix line fetches into the tracking ref
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(post): the repo's release versions and a receipt's tree hash / run ids are not pii.ip_public or pii.phone.e164
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(evidence): parse the shard runner's and the remote pregate lane's test counts into tests_ran
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(restamp): CHANGELOG_DUPLICATE_HEADING refuses only duplicates the PR introduces
checkChangelog takes the base branch's CHANGELOG: a heading the base already
carries N times may appear N times on the PR (inherited released history), and
only a further copy is a duplicate. gstack-restamp passes origin/<base>'s
CHANGELOG at the plan's base sha, so a base like gbrain's master, which heads
one version twice, can be stamped; a duplicate the PR adds is still refused
with nothing written.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(restamp): the stamp-at-merge next: line no longer asks the lane to edit the CHANGELOG
Under a train the stamp commit may hold only restamp's own output: the train's
verify accepts the CHANGELOG only as the base's plus the PR's own entry
re-headed, and a lane that followed the old "write the CHANGELOG entry text"
prompt froze the queue. The claim-at-open wording is unchanged.
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(version-gate): a release output regenerated at the base VERSION is not a stamp
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(version-gate): run the head release tool with a bare env, drop outputs it must rewrite, prune the staging worktree
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(version-gate): regenerate at the merge base VERSION, read tool output from a file, never follow a VERSION symlink
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(version-gate): kill a release tool that ignores TERM at the limit, read a bounded log
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(ship-queue): require a current /ship receipt before READY, train build and train merge
Garry, 2026-10-25: use the gstack ship skill before merging PRs. ready printed
SHIP_RECEIPT: none as information and returned ok, so the pool was READY'd without
/ship. Now ready, train build (dry run included) and verify --train refuse with
QUEUE_RECEIPT_MISSING or QUEUE_RECEIPT_STALE from the PR body alone; verify accepts
the receipt written for the pinned head when the current head is its stamp commit.
gstack-ship-receipt result is /ship's terminal step (GSTACK_RESULT: skill=ship,
run dir with the head and receipt), unattended /ship may update an existing PR's
body, and INSTALL_UNVERIFIED with no verdict names the project directory to
install from (GSTA-85).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(ship): pin Step 22 in workflow-required-steps and tighten the ship skeleton
Gate edit: test/fixtures/workflow-required-steps.json pins the new
"## Step 22: Terminal line (every run)" heading (strengthens: a later
edit that drops the terminal line turns the required-steps test red).
Steps 14, 16, 18, 20 and 22 prose tightened so the carve-guards raise
shrinks to 81,600 / 1.6740 (measured skeleton 81,535, union 314,027).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (ready at the stamp commit, screen on a stale merge ref, ship-run.json)
- ready accepts the pin's receipt at a slot's stamp commit (plus the slot-2
merge of main), as verify --train already did; a real edit stays STALE
- ready --screen refuses QUEUE_SCREEN_STALE_REF when refs/pull/<n>/merge is
missing or merges an older head; a finished screen that planned 0 cases is
never followed, and train build seats that slot unscreened (GSTA-95 on #3431)
- gstack-ship-receipt result writes ship-run.json (a /ship record, not a run
v1 manifest), validates --head, and prints status=incomplete on gh failures
- bindReceipt takes an optional pr and renders one-line SHIP_RECEIPT lines
- tests for every state-matrix cell the review named; the train fixture's
merge ref is a real merge commit
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: cycle-2 review fixes (private screen scratch, no bare-merge receipt reuse, 12-hex --head, one receipt scrub) and align the unattended hook text with the GSTACK_RESULT writers (GSTA-91)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: adversarial-review fixes (result refuses an unpushed HEAD, resolves --out and reports unwritable records; ready names a failed merge-ref fetch; unattended /ship never runs gh pr ready)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: close review-cycle gaps (a stamp must change a stamp file, result requires a full --head and fails closed without headRefOid, digits-only --pr) with tests for every cycle-3 branch
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: give the fsck-rejected merge-ref spawns a timeout (spawnsync tripwire)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: detect a hollow screen from the plan it uploads (no paid-plan artifact or nothing planned), correct two troubleshooting facts, and normalise result --pr
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(hollow-screen): read manifest.json by name, list artifacts by name, say when the plan is unreadable; lowercase result --head
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(hollow-screen): expired and unreadable run rows, uppercase --head; docs name every SCREEN: literal
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(train build): say when the repository slug is unreadable instead of counting the screen silently
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: name an ls-remote failure in ready --screen, refuse result --pr with --body, cap echoed receipt errors, tell an unreadable install verdict from a missing one
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: ls-remote refusal, --pr with --body, capped receipt errors, unreadable slug and verdict (both twins); docs name the new literals
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: scrub Unicode line separators from receipt text, report an unreadable --body as incomplete, refuse unsupported verdict schemas in the bash twin
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>
* docs(triage): parked issues stay open under the parked label; closing means fixed, duplicate or won't fix (GSTA-99)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(triage): already-fixed reports close as fixed, duplicates use GitHub's duplicate reason
/ship adversarial review on #3427 (outside voice openai/gpt-6.1-sol, native
claude-sonnet-5-5): the non-reproduction rule sent reports that main had
already fixed to "won't fix"; the Duplicate row said close reason "not
planned" although GitHub and gh have a native duplicate reason; a duplicate of
an issue that already shipped had no close path; and TODOS.md's "73 open
feature requests" sat beside the "75 parked" the CHANGELOG and docs/triage.md
state without saying the two extra are #3061 and #3122.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(triage): parked label comes off at close; CHANGELOG entry follows the user-facing style
/ship adversarial review pass 2 on #3427: docs/triage.md said the label "goes
with" a fixed close but nothing about duplicate or won't-fix closes, and a lane
"may" remove it, which left an open lane-owned issue either parked or not. The
CHANGELOG entry named TODOS.md in the user-facing summary and listed the
GitHub-side label under Added; docs/CHANGELOG_STYLE.md keeps contributor
details in a "For contributors" section.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(triage): removing the parked label is a manual step after a merge closes the issue; close labels are added separately
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.235.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(releases): weekly tagged releases and a stable update channel for team mode (GSTA-98)
Every Monday morning .github/workflows/weekly-release.yml tags the newest green
commit on main as v<VERSION>, publishes a GitHub Release from the CHANGELOG
headlines and fast-forwards refs/heads/stable to it (scripts/release-cut.ts;
workflow_dispatch with dry_run, and ref for a hotfix). Team-mode installs
follow stable through the new update_channel key (auto: stable when
team_mode, else main) in bin/gstack-session-update, bin/gstack-update-check,
bin/gstack-upgrade and /gstack-upgrade. Per-merge stamping and the merge
train are unchanged. docs/releases.md explains it.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ci(weekly-release): check out the dispatched ref so a dry run exercises that branch's script
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ci(weekly-release): a PR touching the release tooling runs the dry run against main (read-only); the cut job checks out the dispatched ref
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(gstack-upgrade): no $1 in the rendered skill (Claude Code rewrites $N), trim Step 4 under the size budget, pin the new floor-check literal
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: leave setup untouched (its channel note moves to README and docs/releases.md); the release workflow and script are free-only PR files
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: record the pr-profile free-only classification as non-behavioral (HARNESS_VERSION 6)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(releases): gate the cut on a main-backstop check run, finish half-done cuts, keep team installs on their channel
/ship review fixes (GSTA-98, PR #3429):
- The weekly release read the Main backstop gate run's conclusion, but
scripts/train-backstop.ts exits 0 when main moved past the push before it
was gated (superseded), so a never-gated tree read as green. The backstop
workflow now publishes its verdict on the commit as the `main-backstop`
check run from a code-free checks:write job (success for covered|gated,
neutral for inert|superseded|deferred, failure for frozen|failed), fed by
the new `--outputs` flag; release-cut.ts requires that check run and
free-tests to succeed and holds a commit whose check runs are still going.
- A cut that pushed the tag and stable but failed to create the release can
be finished: stable itself stays a candidate until its release exists, the
notes compare against the release tag behind it, and a dry run with nothing
green exits 0 with the skips named (the real cut still fails).
- weekly-release.yml: the cut job runs only from refs/heads/main, `ref` must
be a full 40-hex SHA, and actions:read is dropped (no workflow-runs call).
- /gstack-upgrade: the destructive fallback requires the carried UPSTREAM_REF
instead of defaulting to origin/main in a fresh shell; a team install past
the release stops with AHEAD_OF_STABLE instead of FF_REFUSED and a reset
backwards. gstack-update-channel.sh --fetch-ref keeps origin/stable on any
fetch failure other than a missing release; dead gstack_update_channel_ref
removed. gstack-update-check follows main before the first release instead
of caching CHECK_FAILED; gstack-upgrade treats a failed ls-remote as a
fetch failure, not an empty answer.
- Tests: release-cut (check-run fixture, partial cut, neutral/pending),
weekly-release-workflow (new), evals-train-workflow and train-backstop
(backstop-check job, --outputs), update-channel (no-release fallback,
offline --fetch-ref), template pins.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(releases): the upgrade skill's ahead-of-stable exit works in depth-1 clones; update-check keeps its cache identity on the pre-release fallback
/ship second-pass review of 73e278d4 (GSTA-98, PR #3429):
- gstack-upgrade/SKILL.md.tmpl: README installs are depth-1 clones, where
origin/stable never connects to HEAD, so the AHEAD_OF_STABLE shortcut now
also fires when HEAD is not behind stable and stable's VERSION is not
higher than the installed one (the order bin/gstack-upgrade uses). The
fence prints the channel helper's warnings instead of discarding them, and
a 'fetching origin/stable failed' line is a STOP. Prose trimmed to stay
under the skill size budget. New behavioral test runs the Step 4 fence on
a depth-1 install past the release (AHEAD_OF_STABLE, nothing moved) and on
one behind it (goes on to the fast-forward).
- bin/gstack-update-check: the no-stable fallback keeps #stable in the
cache identity (so the outcome replays within its TTL instead of two
ls-remote calls per skill start), triggers only when ls-remote answered
with no such branch (a failed ls-remote stays CHECK_FAILED on stable), and
the branch-pinned URL derives from REMOTE_RAW_BASE so tests stay offline.
- scripts/release-cut.ts: a cancelled check run is red; the previous-release
lookups check .ok before using git output. docs/releases.md says which
pushes get no main-backstop check run at all.
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(plan-tune): per-dimension contributing_events in the inferred profile
Port of the provenance part of #2625 by @v639dragoon: --derive records, per
dimension, how many unique log rows moved it, so "no evidence" and
"balanced evidence" no longer both print a bare 0.5. Also ports the test
harness fix: logQuestion sets GSTACK_QUESTION_LOG_NO_DERIVE=1 so the
background derive cannot race the test's own --derive.
The registry-independent autonomy signal from #2625 stays parked, as the
Oct 8 review decided.
Co-authored-by: v639dragoon <matthew@dohma.ai>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(plan-tune): clamp each session's pull on a dimension to one strong answer; trace shares derive's accumulation (#2623)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(plan-tune): shared accumulation JS as a quoted string, not a heredoc (heredoc pipe-deadlock guard)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes
Own-property signal lookups so a logged choice such as constructor cannot
break every later --derive; --trace replaces control characters in the
fields it prints; tests for the negative clamp, empty session_id, an
unmatched answer and both fixes; docs and CHANGELOG say the bound keys on
the writer session_id.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (pass 2)
A session_id that is an unsubstituted placeholder such as SESSION_ID
counts as its own session instead of collapsing every agent-logged
answer into one bound; a log line that parses to null is skipped; the
accumulation tolerates a dimension it did not seed; the trace test covers
DEL and C1 controls; docs and CHANGELOG wording match the code.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(plan-tune): bound each UTC day instead of each session_id
The per-session bound trusted whatever session_id a writer logged. The
PostToolUse hook and the agent log different ids for one review, and an
unsubstituted SESSION_ID placeholder either merged every review into one
bound or left each answer unbounded. Bucketing by the UTC day of ts
stops one burst from pinning a dimension without trusting any id;
several reviews on one day count as one. Decision A from GStack Minder.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (day bound)
Rows without a parseable string ts share one undated bucket instead of
each escaping the bound; a ts without a zone is read as UTC, so the day
does not depend on the machine's zone; days_span counts the same UTC
days; question_id and user_choice must be strings. Tests pin a zone west
of UTC. CHANGELOG says contributing_events is recorded in the profile
JSON and not displayed yet (#3436).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (strict ISO ts)
Only an ISO 8601 date or date-time ts counts as dated; Date alone parses
strings such as "junk 1" as real days, which let junk rows escape the
bound and inflate days_span. A zoneless time, T- or space-separated, is
read as UTC. Tests cover array-valued fields, an offset ts in days_span,
the space separator and every undated row reaching the shared bucket.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: narrow the #2623 TODOS entry to its remaining Gate 1 work (#3442)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: v639dragoon <matthew@dohma.ai>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(judge-calibration): preregistered cookie-workflow corpus, blind second review and adjudication; calibration config (GSTA-91)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(judge-calibration): price the cookie-workflow calibration before dispatch (GSTA-91)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(judge-calibration): record the cookie-workflow comparison-1 run (held: one new false pass) (GSTA-91)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): cookie-workflow calibration recorded as held (GSTA-91)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (GSTA-91)
/ship Step 9 Fix-First on the cookie-workflow calibration record:
- README: scope the "no sample errored" sentence to the 2026-10-03 configurations,
move the W2 pilot and W2 spend sentences back to the W2 paragraph, record the
cookie UC3 prose-step trigger and that its hand-written manifest entry must
survive manifest regeneration.
- TODOS: the cookie configuration now has a corpus and a held comparison-1; add
its triggered prose step to the deferred prose-step entry.
- test: pin the cookie pass rule's actionability floor and validate() rejection,
and guard that the cookie registration sends only COOKIE_WORKFLOW_JUDGE's keys
so the calibrated request stays the request production sends.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes, pass 2 (GSTA-91)
/ship Step 9 Fix-First, second pass:
- README: the blind-review sentence and results heading now fit the cookie corpus
(labels predate any request with the schema; the row carries its own date and
model), and the cookie paragraph records that both valid old-a a07 samples
also scored 4/4/4.
- CHANGELOG: same a07 fact.
- TODOS: today's cookie request false-passes a07 and a08; the deferred prose step
targets those.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(judge-calibration): pin the cookie calibration's prompt and recorded result (GSTA-91)
/ship Step 7 coverage audit:
- the cookie-workflow calibration builds exactly the prompt the cookie eval sends
for the same bundle;
- analyze() reproduces the committed comparison-1 result from its labels,
samples, stop record and request options (request_hash covers model and
options only, so prompt text and bundle bytes are not pinned).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): describe the new cookie calibration tests (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>
* fix(setup): install production dependencies only; contributors and CI keep the full install (GSTA-97)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): production-only install (GSTA-97)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (GSTA-97)
- setup/gstack-browser-ensure: Bun treats --production as frozen, so the
old fallback could never recover a stale lockfile; refresh it with
--lockfile-only, then install production-only again.
- gstack-browser-ensure failure line and the README tip no longer suggest a
full bun install to users.
- Tests: real-Bun stale-lockfile and keep-devDeps contracts, behavioral
browser-ensure install tests, relative-import closure scan, multi-line and
re-export negative controls; CHANGELOG matches.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes, pass 2 (GSTA-97)
- gstack-browser-ensure's failure line and the README tip suggest the
frozen production install (./setup skips the install when the build is
current, and a bare --production install is frozen anyway).
- setup install guard catches quoted and unquoted $BUN_CMD spellings.
- Replace the exact-text gstack-browser-ensure grep with an invariant: no
full bun install; behavior is covered by gstack-browser-ensure.test.ts.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(setup): keep a contributor checkout's dev packages on bun.lock's versions (GSTA-97)
/ship Step 11: a production install over a full install reports "no
changes" and leaves devDependencies at old versions after bun.lock moves,
so the session updater's ./setup left contributors on stale TypeScript,
Prettier and Agent SDK. A checkout with node_modules/typescript gets the
full frozen install. The import-closure scan now follows shipped code into
test/helpers (gstack-model-benchmark loads the providers).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes, ship invocation 2 (GSTA-97)
- Tests: contributor-branch failure row; bun.lock production closure never
reaches the dev-toolchain marker; real-Bun rows isolate HOME,
XDG_CONFIG_HOME and BUN_CONFIG_*; the import walker follows side-effect
imports; file header matches the two install branches.
- BROWSER.md quick start uses the frozen production install.
- CHANGELOG: the reclaim recipe also drops the Agent SDK's cache entries
(Bun hardlinks node_modules into its cache); Tests list is current.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(changelog): stub-bun wording matches what the fixtures check (GSTA-97)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* v1.91.231.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(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>
* feat(design-shotgun,design-html): carry the chosen archetype into approved.json; persist accepted craft exceptions in finalized.json (GSTA-92 phase 2)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(touchfiles): design-html-slop-gate selects on the craft check it runs (GSTA-92)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (GSTA-92)
A malformed or missing --accepted exceptions file now gets the full craft
check with nothing accepted, after a warning, still exiting 2. Before, it
printed nothing, and the craft section treats a missing CRAFT_RESULT as
'check unavailable', so one bad finalized.json switched the gate off
(found by both adversarial passes). The header comment and the craft
section now document the accepted-count suffix on CRAFT_RESULT. Tests
cover duplicate carried-forward exception ids and the slop-gate touchfiles
selection.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: scope --accepted to the same page; record current counts (GSTA-92)
The craft section passed --accepted whenever a finalized.json sat beside
the page, so a same-day Start fresh build inherited the old page's
exceptions. It now passes them only when evolving or rerunning a page it
finalized, records the count the check reports now, and writes [] when
nothing was accepted instead of the template's placeholder entry. A test
pins exit 2 for a clean page with a broken exceptions file.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: note the archetype handoff in the shotgun and design-html loops (GSTA-92)
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>
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>
* 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>
* 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>
second cycle-cap exception: GStack Minder's decision under Garry's 'do it' on phase 2 (GSTA-92, 2026-10-25): one deleted word plus one test
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- craft-audit: linked CSS/JS is unchecked on a saved page (judge by eye);
a mount-node shell is framework source; --accepted takes that screen's
finalized.json or none; on a live page a claim without proof is filed and
asked about, never marked or cut; the saved page is removed whatever the
exit code; shorter fix-order and Tailwind prose keeps the union under cap
- tests: exact-lead red cases, autoFixEntries in the checkerOnly union, the
audit's outcome/exception/session-data clauses; carve guard checks the
session-data rule and records measured sizes (skeleton cap 137_767)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
- craft-audit: no CRAFT_RESULT line means unavailable (exit 2 after a
malformed --accepted record still printed findings); --accepted only for a
/design-html finalized page, never for needs-proof or lorem; never add
[Needs proof] markers to a live page; Aside capture via pg.evaluate; the
saved raw DOM is deleted in the checking block and never reported
- manifest trigger covers an explicit craft audit (skeleton -6 bytes; pins
lowered to measured size, union ratio back under its cap)
- autoFixEntries reads RENDERED; DESIGN_CRAFT_RULE needs exactly one lead
- tests: checkerOnly contract, resolver throw paths, Persuade checks in both
skills, resolver touchfile selection, exception state cells
- CHANGELOG: host counts and the audit's new rules
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
The craft section passed --accepted whenever a finalized.json sat beside
the page, so a same-day Start fresh build inherited the old page's
exceptions. It now passes them only when evolving or rerunning a page it
finalized, records the count the check reports now, and writes [] when
nothing was accepted instead of the template's placeholder entry. A test
pins exit 2 for a clean page with a broken exceptions file.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
A malformed or missing --accepted exceptions file now gets the full craft
check with nothing accepted, after a warning, still exiting 2. Before, it
printed nothing, and the craft section treats a missing CRAFT_RESULT as
'check unavailable', so one bad finalized.json switched the gate off
(found by both adversarial passes). The header comment and the craft
section now document the accepted-count suffix on CRAFT_RESULT. Tests
cover duplicate carried-forward exception ids and the slop-gate touchfiles
selection.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* 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>
* 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>
* 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>
* 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>
* 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>
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>
* 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>
* 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>