Skip to content

Commit 1a4f0c9

Browse files
garrytanclaude
andauthored
v1.33.1.0 fix(learnings): token-OR query + task-shaped retrieval in 3 long skills (#1442)
* fix(learnings): use token-OR matching in gstack-learnings-search --query Split the query on whitespace into tokens; a learning matches if ANY token appears as a substring in ANY of key/insight/files. Previously the whole query was a single substring, so multi-word queries like "debug investigation" only matched learnings whose insight contained that exact contiguous phrase, which is usually nothing. Whitespace-only query falls through to no-query (matches today's no-flag behavior). Single-word queries behave exactly as before. Adds test/gstack-learnings-search.test.ts: 3 assertions covering multi-token, single-token, and no-query backwards compat. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(resolver): parameterized LEARNINGS_SEARCH with shell-injection guard The {{LEARNINGS_SEARCH}} macro now accepts a query=KEYWORD argument that gets interpolated as --query "<keyword>" into the generated bash. Empty value falls through to no-query (principle of least surprise: a stray {{LEARNINGS_SEARCH:query=}} placeholder gets today's behavior, not a build failure). Pattern reuses the parameterized-macro parsing from composition.ts. The 13 templates that don't pass a query stay byte-identical in their generated SKILL.md output. Shell-injection guard: the query value is whitelisted to ^[A-Za-z0-9 _-]+$ at gen-skill-docs time. Any \$(), backticks, semicolons, or quotes throw a loud build error instead of emitting executable bash. Static template queries are safe by inspection; this defends against future contributors writing dangerous values. Adds 5 assertions to test/gen-skill-docs.test.ts covering no-args, claude+query=foo bar on both cross-project and project-scoped branches, codex host variant, empty value semantics, and shell-injection payloads (\$(whoami), backticks, ;, &, ", \\, \$x) throwing build errors. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(skills): task-shaped queries + mid-flow refresh in /investigate /qa /ship The three long skills now pull learnings keyed to their theme at the top, then re-pull at phase boundaries as work shifts to new sub-tasks. Top-of-skill queries (5-6 token unions, token-OR matched): - investigate: "debug investigation root cause hypothesis bug fix" - qa: "qa testing bug regression flake fixture" - ship: "release ship version changelog merge pr" Mid-flow refresh blocks (concrete keyword recipe + worked examples): - investigate: between Phase 1 (hypothesis) and Phase 2 (analysis), keyed to the hypothesis noun. Examples: auth-cookie, session-expiry. - qa: between Phase 7 (triage) and Phase 8 (fix loop), keyed to the buggy component name. Examples: checkout-button, signup-form. - ship: just before Step 12 (VERSION bump), keyed to the headline feature. Examples: learnings-search, pacing, worktree-ship. Keyword recipe enforces alphanumeric+hyphen only (no quotes, slashes, dots, colons) so dynamic queries cannot inject shell metacharacters. The other 13 short-lived skills keep the bare {{LEARNINGS_SEARCH}} form. Backwards-compat verified via diff: their generated SKILL.md output is byte-identical to before this change. Golden ship fixtures regenerated to match the new ship/SKILL.md output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: bump version and changelog (v1.33.1.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test: refresh codex+factory ship golden fixtures Follow-up to 513c966 — the codex and factory host outputs needed regeneration too, missed in the initial commit because gen:skill-docs was only run for the claude host. Now matches gen:skill-docs --host all. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent d21ba06 commit 1a4f0c9

16 files changed

Lines changed: 365 additions & 27 deletions

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,47 @@
11
# Changelog
22

3+
## [1.33.1.0] - 2026-05-11
4+
5+
## **Long skills stop drifting away from their starting context.**
6+
## **`/investigate`, `/qa`, and `/ship` now pull learnings keyed to what they're actually about, and refresh that pull mid-flow as work shifts to new sub-tasks.**
7+
8+
For the last 30+ versions, every gstack skill loaded learnings the same way: `gstack-learnings-search --limit 10` at the top, generic top-10 by confidence, no query, no refresh. Short skills were fine, they finish before the loaded learnings go stale. Long skills (`/investigate` walks 4 phases, `/qa` runs a multi-bug fix loop, `/ship` covers ~20 steps from test to bump to PR) drifted away from whatever was loaded at minute zero. By the time `/ship` reaches Step 12 (VERSION bump), the learnings it pulled at Step 1 are about whatever was the highest-confidence entry in your project, not about the headline feature you're shipping.
9+
10+
Two changes ship in this release: per-skill task-shaped queries at the top of the three long skills, and a mid-flow refresh checkpoint inside each one that re-pulls learnings keyed to the sub-task that's about to begin. Both rely on a fix to `bin/gstack-learnings-search` itself. The binary's `--query` flag previously used whole-string substring match against key/insight/files, so a query like `"debug investigation"` would only match a learning whose insight contained that exact contiguous phrase. The flag is now token-OR: split on whitespace, match if ANY token appears in any haystack field. This is what most users expect from a search flag.
11+
12+
### The numbers that matter
13+
14+
Source: this project's local `learnings.jsonl` (35 entries as of this release). Same query, same flag, before vs after the binary fix:
15+
16+
| Query | Before (substring) | After (token-OR) | Δ |
17+
|-------|-------------------|------------------|---|
18+
| `"debug investigation root cause"` | 0 entries matched | 5 entries matched | +5 |
19+
| `"qa testing bug regression"` | 0 entries matched | 2 entries matched | +2 |
20+
| `"release ship version changelog"` | 0 entries matched | 8 entries matched | +8 |
21+
| `"skill resolver"` | 0 entries matched | 12 entries matched | +12 |
22+
23+
Recall on the static skill-shaped queries went from zero to relevant. Without this fix, the rest of the change would have been silent. The bash would run, the binary would exit 0 with no output, and the skill would render the same empty section it always rendered.
24+
25+
### What this means for builders
26+
27+
If you run `/investigate` on a bug, the top-of-skill learnings pull now surfaces prior investigation patterns instead of unrelated top-10 confidence entries. When you finish Phase 1 (naming a root-cause hypothesis), a mid-flow refresh fires and re-pulls learnings keyed to your hypothesis keyword, so prior fixes for the same problem-shape land in the agent's context right when they're relevant. Same pattern for `/qa` (refresh before the fix loop, keyed to the buggy component) and `/ship` (refresh before the VERSION/CHANGELOG step, keyed to the headline feature). The other 13 short-lived skills are unchanged: their existing top-10 generic pull is still right for their attention span.
28+
29+
### Itemized changes
30+
31+
#### Changed
32+
33+
- **`bin/gstack-learnings-search`** now uses token-OR `--query` semantics. Multi-word queries split on whitespace and match if ANY token appears as a substring in ANY of key/insight/files. Single-word queries behave exactly as before. No flag changes; same CLI surface. The old whole-string substring behavior was a silent footgun that returned nothing on real-world learnings stores. New test file `test/gstack-learnings-search.test.ts` covers the three branches (multi-token, single-token, no-query backwards compat).
34+
- **`scripts/resolvers/learnings.ts`** `{{LEARNINGS_SEARCH}}` macro now accepts a `query=KEYWORD` argument. Empty value falls through to no-query (principle of least surprise: a stray `{{LEARNINGS_SEARCH:query=}}` placeholder gets today's behavior, not a build failure). Pattern reuses the parameterized-macro infrastructure from `composition.ts`. The 13 templates that don't pass a query stay byte-identical in their generated SKILL.md output. Shell-injection guard: the query value is whitelisted to `^[A-Za-z0-9 _-]+$` at gen-skill-docs time, so any `$()`, backticks, semicolons, or quotes in a future template throw a loud build error instead of emitting executable bash.
35+
- **`investigate/SKILL.md.tmpl`** top-of-skill learnings pull keyed to `debug investigation root cause hypothesis bug fix`. New mid-flow refresh block between Phase 1 (hypothesis) and Phase 2 (analysis) instructs the agent to pick one alphanumeric-only keyword from the hypothesis and re-pull. Worked examples included (good: `auth-cookie`, `session-expiry`; bad: `auth.ts:47`, `<hypothesis-keyword>`).
36+
- **`qa/SKILL.md.tmpl`** top-of-skill pull keyed to `qa testing bug regression flake fixture`. Mid-flow refresh inserted between Phase 7 (triage) and Phase 8 (fix loop), keyed to the buggy component name.
37+
- **`ship/SKILL.md.tmpl`** top-of-skill pull keyed to `release ship version changelog merge pr`. Mid-flow refresh inserted just before Step 12 (VERSION bump), keyed to the headline feature on this branch.
38+
- **`test/gen-skill-docs.test.ts`** 5 new resolver assertions: no-args has no `--query`, claude+query=foo bar appears in BOTH cross-project and project-scoped branches, codex host gets `--query` in the codex bash variant, empty value `query=` falls through to no-query, AND shell-injection payloads (`$(whoami)`, backticks, `;`, `&`, `"`, `\`, `$x`) throw a build error.
39+
- **All generated `SKILL.md` files for the 3 long skills + 4 host outputs** regenerated. The other 13 skills' generated output is byte-identical (backwards-compat verified via diff).
40+
41+
#### For contributors
42+
43+
- Contributed by @Fergtic ([chronicle-write-up](https://github.com/Fergtic/chronicle-write-up)) who flagged the load-once + no-refresh pattern and the spend-per-success data point that motivated this work. The static-skill query expansion was also informed by a key fact-check from Codex outside-voice review: the binary's `--query` was single-substring match, not token-OR, which silently invalidated any multi-word query in the wild.
44+
345
## [1.33.0.0] - 2026-05-11
446

547
## **`/sync-gbrain` memory stage no longer infinite-loops or silently throws away progress.**

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.33.0.0
1+
1.33.1.0

bin/gstack-learnings-search

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ cat "${FILES[@]}" 2>/dev/null | GSTACK_SEARCH_TYPE="$TYPE" GSTACK_SEARCH_QUERY="
4848
const lines = (await Bun.stdin.text()).trim().split('\n').filter(Boolean);
4949
const now = Date.now();
5050
const type = process.env.GSTACK_SEARCH_TYPE || '';
51-
const query = (process.env.GSTACK_SEARCH_QUERY || '').toLowerCase();
51+
const queryRaw = (process.env.GSTACK_SEARCH_QUERY || '').toLowerCase();
52+
const queryTokens = queryRaw.split(/\s+/).filter(Boolean);
5253
const limit = parseInt(process.env.GSTACK_SEARCH_LIMIT || '10', 10);
5354
const slug = process.env.GSTACK_SEARCH_SLUG || '';
5455
@@ -94,12 +95,11 @@ let results = Array.from(seen.values());
9495
// Filter by type
9596
if (type) results = results.filter(e => e.type === type);
9697
97-
// Filter by query
98-
if (query) results = results.filter(e =>
99-
(e.key || '').toLowerCase().includes(query) ||
100-
(e.insight || '').toLowerCase().includes(query) ||
101-
(e.files || []).some(f => f.toLowerCase().includes(query))
102-
);
98+
// Filter by query (token-OR: match if ANY whitespace-split token appears in ANY haystack)
99+
if (queryTokens.length > 0) results = results.filter(e => {
100+
const haystacks = [(e.key || '').toLowerCase(), (e.insight || '').toLowerCase(), ...(e.files || []).map(f => f.toLowerCase())];
101+
return queryTokens.some(tok => haystacks.some(h => h.includes(tok)));
102+
});
103103
104104
// Sort by effective confidence desc, then recency
105105
results.sort((a, b) => {

investigate/SKILL.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,9 @@ Search for relevant learnings from previous sessions:
823823
_CROSS_PROJ=$(~/.claude/skills/gstack/bin/gstack-config get cross_project_learnings 2>/dev/null || echo "unset")
824824
echo "CROSS_PROJECT: $_CROSS_PROJ"
825825
if [ "$_CROSS_PROJ" = "true" ]; then
826-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --cross-project 2>/dev/null || true
826+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "debug investigation root cause hypothesis bug fix" --cross-project 2>/dev/null || true
827827
else
828-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 2>/dev/null || true
828+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "debug investigation root cause hypothesis bug fix" 2>/dev/null || true
829829
fi
830830
```
831831

@@ -855,6 +855,20 @@ smarter on their codebase over time.
855855

856856
Output: **"Root cause hypothesis: ..."** — a specific, testable claim about what is wrong and why.
857857

858+
### Refresh learnings for the hypothesis you just named
859+
860+
The top-of-skill learnings pull above is keyed to "debug investigation" broadly. Now that you have a specific hypothesis, re-pull learnings keyed to that hypothesis so prior fixes for the same problem-shape surface.
861+
862+
Pick ONE keyword from the hypothesis. The keyword should be a noun: the failing component name, the basename of the file you suspect (without extension), or the bug noun. The keyword MUST be alphanumeric or hyphen only — no quotes, slashes, dots, colons, or whitespace. If your candidate has any of those, simplify to just the alphanumeric stem.
863+
864+
Worked examples (investigate-specific): good keywords are `auth-cookie`, `session-expiry`, `redirect-loop`. Bad: `auth.ts:47`, `fix the auth bug`, `<hypothesis-keyword>`.
865+
866+
```bash
867+
~/.claude/skills/gstack/bin/gstack-learnings-search --query "<your-keyword>" --limit 5 2>/dev/null || true
868+
```
869+
870+
If any learnings come back, name which one applies to your investigation in one sentence. If none come back, continue without reference — the absence of a matching prior learning is itself useful information.
871+
858872
---
859873

860874
## Scope Lock

investigate/SKILL.md.tmpl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,24 @@ Gather context before forming any hypothesis.
9393

9494
5. **Check investigation history:** Search prior learnings for investigations on the same files. Recurring bugs in the same area are an architectural smell. If prior investigations exist, note patterns and check if the root cause was structural.
9595

96-
{{LEARNINGS_SEARCH}}
96+
{{LEARNINGS_SEARCH:query=debug investigation root cause hypothesis bug fix}}
9797

9898
Output: **"Root cause hypothesis: ..."** — a specific, testable claim about what is wrong and why.
9999

100+
### Refresh learnings for the hypothesis you just named
101+
102+
The top-of-skill learnings pull above is keyed to "debug investigation" broadly. Now that you have a specific hypothesis, re-pull learnings keyed to that hypothesis so prior fixes for the same problem-shape surface.
103+
104+
Pick ONE keyword from the hypothesis. The keyword should be a noun: the failing component name, the basename of the file you suspect (without extension), or the bug noun. The keyword MUST be alphanumeric or hyphen only — no quotes, slashes, dots, colons, or whitespace. If your candidate has any of those, simplify to just the alphanumeric stem.
105+
106+
Worked examples (investigate-specific): good keywords are `auth-cookie`, `session-expiry`, `redirect-loop`. Bad: `auth.ts:47`, `fix the auth bug`, `<hypothesis-keyword>`.
107+
108+
```bash
109+
~/.claude/skills/gstack/bin/gstack-learnings-search --query "<your-keyword>" --limit 5 2>/dev/null || true
110+
```
111+
112+
If any learnings come back, name which one applies to your investigation in one sentence. If none come back, continue without reference — the absence of a matching prior learning is itself useful information.
113+
100114
---
101115

102116
## Scope Lock

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gstack",
3-
"version": "1.33.0.0",
3+
"version": "1.33.1.0",
44
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
55
"license": "MIT",
66
"type": "module",

qa/SKILL.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,9 +1068,9 @@ Search for relevant learnings from previous sessions:
10681068
_CROSS_PROJ=$(~/.claude/skills/gstack/bin/gstack-config get cross_project_learnings 2>/dev/null || echo "unset")
10691069
echo "CROSS_PROJECT: $_CROSS_PROJ"
10701070
if [ "$_CROSS_PROJ" = "true" ]; then
1071-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --cross-project 2>/dev/null || true
1071+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "qa testing bug regression flake fixture" --cross-project 2>/dev/null || true
10721072
else
1073-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 2>/dev/null || true
1073+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "qa testing bug regression flake fixture" 2>/dev/null || true
10741074
fi
10751075
```
10761076

@@ -1426,6 +1426,20 @@ Sort all discovered issues by severity, then decide which to fix based on the se
14261426

14271427
Mark issues that cannot be fixed from source code (e.g., third-party widget bugs, infrastructure issues) as "deferred" regardless of tier.
14281428

1429+
### Refresh learnings for the component/page where the bug lives
1430+
1431+
The top-of-skill learnings pull was keyed to "qa testing" broadly. Before the fix loop, re-pull learnings keyed to the component or page where the bug you're about to fix lives so prior fixes for the same component-shape surface.
1432+
1433+
Pick ONE keyword that names the buggy component or page. The keyword should be a noun: the failing component name, the page route base, or the feature noun. The keyword MUST be alphanumeric or hyphen only — no quotes, slashes, dots, colons, or whitespace. If your candidate has any of those, simplify to just the alphanumeric stem.
1434+
1435+
Worked examples (qa-specific): good keywords are `checkout-button`, `signup-form`, `payment`. Bad: `tests are failing`, `<failing-test>`, `app/views/_checkout.html.erb`.
1436+
1437+
```bash
1438+
~/.claude/skills/gstack/bin/gstack-learnings-search --query "<your-keyword>" --limit 5 2>/dev/null || true
1439+
```
1440+
1441+
If any learnings come back, name which one applies to the fix you're about to make in one sentence. If none come back, continue without reference — the absence is itself useful information.
1442+
14291443
---
14301444

14311445
## Phase 8: Fix Loop

qa/SKILL.md.tmpl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ mkdir -p .gstack/qa-reports/screenshots
100100

101101
---
102102

103-
{{LEARNINGS_SEARCH}}
103+
{{LEARNINGS_SEARCH:query=qa testing bug regression flake fixture}}
104104

105105
## Test Plan Context
106106

@@ -154,6 +154,20 @@ Sort all discovered issues by severity, then decide which to fix based on the se
154154

155155
Mark issues that cannot be fixed from source code (e.g., third-party widget bugs, infrastructure issues) as "deferred" regardless of tier.
156156

157+
### Refresh learnings for the component/page where the bug lives
158+
159+
The top-of-skill learnings pull was keyed to "qa testing" broadly. Before the fix loop, re-pull learnings keyed to the component or page where the bug you're about to fix lives so prior fixes for the same component-shape surface.
160+
161+
Pick ONE keyword that names the buggy component or page. The keyword should be a noun: the failing component name, the page route base, or the feature noun. The keyword MUST be alphanumeric or hyphen only — no quotes, slashes, dots, colons, or whitespace. If your candidate has any of those, simplify to just the alphanumeric stem.
162+
163+
Worked examples (qa-specific): good keywords are `checkout-button`, `signup-form`, `payment`. Bad: `tests are failing`, `<failing-test>`, `app/views/_checkout.html.erb`.
164+
165+
```bash
166+
~/.claude/skills/gstack/bin/gstack-learnings-search --query "<your-keyword>" --limit 5 2>/dev/null || true
167+
```
168+
169+
If any learnings come back, name which one applies to the fix you're about to make in one sentence. If none come back, continue without reference — the absence is itself useful information.
170+
157171
---
158172

159173
## Phase 8: Fix Loop

scripts/resolvers/learnings.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,35 @@
1313
*/
1414
import type { TemplateContext } from './types';
1515

16-
export function generateLearningsSearch(ctx: TemplateContext): string {
16+
// Whitelist for query= macro values. Allows alphanumeric, space, hyphen, underscore.
17+
// Anything else (e.g. $, backticks, quotes, ;) is a shell-injection vector when the
18+
// emitted bash interpolates the value into `--query "${queryArg}"`. Static template
19+
// queries hand-written in gstack are safe, but the resolver API must defend against
20+
// future contributors writing dangerous values.
21+
const QUERY_SAFE_RE = /^[A-Za-z0-9 _-]+$/;
22+
23+
export function generateLearningsSearch(ctx: TemplateContext, args?: string[]): string {
24+
// Parse query= arg. Empty value falls through to no-query (principle of least surprise:
25+
// a stray {{LEARNINGS_SEARCH:query=}} placeholder gets today's behavior, not a build error).
26+
const queryArg = (args || [])
27+
.filter(a => a.startsWith('query='))
28+
.map(a => a.slice(6))
29+
.filter(Boolean)[0];
30+
if (queryArg && !QUERY_SAFE_RE.test(queryArg)) {
31+
throw new Error(
32+
`{{LEARNINGS_SEARCH:query=...}} value must match ${QUERY_SAFE_RE} (alphanumeric, space, hyphen, underscore). Got: ${JSON.stringify(queryArg)}`
33+
);
34+
}
35+
const queryFlag = queryArg ? ` --query "${queryArg}"` : '';
36+
1737
if (ctx.host === 'codex') {
1838
// Codex: simpler version, no cross-project, uses $GSTACK_BIN
1939
return `## Prior Learnings
2040
2141
Search for relevant learnings from previous sessions on this project:
2242
2343
\`\`\`bash
24-
$GSTACK_BIN/gstack-learnings-search --limit 10 2>/dev/null || true
44+
$GSTACK_BIN/gstack-learnings-search --limit 10${queryFlag} 2>/dev/null || true
2545
\`\`\`
2646
2747
If learnings are found, incorporate them into your analysis. When a review finding
@@ -36,9 +56,9 @@ Search for relevant learnings from previous sessions:
3656
_CROSS_PROJ=$(${ctx.paths.binDir}/gstack-config get cross_project_learnings 2>/dev/null || echo "unset")
3757
echo "CROSS_PROJECT: $_CROSS_PROJ"
3858
if [ "$_CROSS_PROJ" = "true" ]; then
39-
${ctx.paths.binDir}/gstack-learnings-search --limit 10 --cross-project 2>/dev/null || true
59+
${ctx.paths.binDir}/gstack-learnings-search --limit 10${queryFlag} --cross-project 2>/dev/null || true
4060
else
41-
${ctx.paths.binDir}/gstack-learnings-search --limit 10 2>/dev/null || true
61+
${ctx.paths.binDir}/gstack-learnings-search --limit 10${queryFlag} 2>/dev/null || true
4262
fi
4363
\`\`\`
4464

ship/SKILL.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,9 +1824,9 @@ Search for relevant learnings from previous sessions:
18241824
_CROSS_PROJ=$(~/.claude/skills/gstack/bin/gstack-config get cross_project_learnings 2>/dev/null || echo "unset")
18251825
echo "CROSS_PROJECT: $_CROSS_PROJ"
18261826
if [ "$_CROSS_PROJ" = "true" ]; then
1827-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --cross-project 2>/dev/null || true
1827+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "release ship version changelog merge pr" --cross-project 2>/dev/null || true
18281828
else
1829-
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 2>/dev/null || true
1829+
~/.claude/skills/gstack/bin/gstack-learnings-search --limit 10 --query "release ship version changelog merge pr" 2>/dev/null || true
18301830
fi
18311831
```
18321832
@@ -2459,6 +2459,20 @@ already knows. A good test: would this insight save time in a future session? If
24592459
24602460
24612461
2462+
### Refresh learnings for the headline feature on this branch
2463+
2464+
The top-of-skill learnings pull was keyed to "release ship" broadly. Before the VERSION/CHANGELOG step, re-pull learnings keyed to THIS branch's headline feature so any prior version-bump or CHANGELOG pitfalls for similar features surface.
2465+
2466+
Pick ONE keyword that names the headline feature you're shipping. The keyword should be a noun: the primary skill or module name, the central feature noun, or the binary you changed. The keyword MUST be alphanumeric or hyphen only — no quotes, slashes, dots, colons, or whitespace. If your candidate has any of those, simplify to just the alphanumeric stem.
2467+
2468+
Worked examples (ship-specific): good keywords are `learnings-search`, `pacing`, `worktree-ship`. Bad: `the branch headline`, `v1.31.1.0`, `feat: token-or search`.
2469+
2470+
```bash
2471+
~/.claude/skills/gstack/bin/gstack-learnings-search --query "<your-keyword>" --limit 5 2>/dev/null || true
2472+
```
2473+
2474+
If any learnings come back, name which one applies to the version bump or CHANGELOG framing in one sentence. If none come back, continue without reference — the absence is itself useful information.
2475+
24622476
## Step 12: Version bump (auto-decide)
24632477
24642478
**Idempotency check:** Before bumping, classify the state by comparing `VERSION` against the base branch AND against `package.json`'s `version` field. Four states: FRESH (do bump), ALREADY_BUMPED (skip bump), DRIFT_STALE_PKG (sync pkg only, no re-bump), DRIFT_UNEXPECTED (stop and ask).

0 commit comments

Comments
 (0)