mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-02 06:54:50 +01:00
v1.92.44.0 fix(pregate): literals stops treating same-stem sibling files as the changed module (GST-820) (#3814)
* fix(pregate): literals stops treating a same-stem sibling file as the changed module (GST-820)
A path names the module only when its stem is followed by a quote, the line end, or the module's own or a JS/TS extension; test/<stem>.txt no longer makes a file a consumer. Red first on main 4f5b043.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): literals keeps a stem followed by a space, bracket, sentence end or .d.ts as the module (GST-820 review)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(pregate): literals keeps JS/TS aliases to JS/TS modules and stops matching a file name with a further extension (GST-820 review)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(pregate): literals matches the module only for old values longer than one character (GST-820 docs audit)
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>
This commit is contained in:
1 parent
775fe2737c
commit
4d388f44bd
7 files changed
+64
-7
No files matched your search
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [1.92.44.0] - 2026-11-01
|
||||
|
||||
**`literals` stops treating a same-name sibling file as the changed module (GST-820).** A test that only mentioned `test/postgres-unit-arms.txt` was counted as a consumer of `scripts/postgres-unit-arms.ts`, so any `12` in it failed `PREGATE_LITERALS` when `ARM_SHARDS` moved from 12 to 18. In gbrain #8372 that gave 17 false files. A path now names the module only when its stem is followed by the module's own extension (for a JS/TS module, any JS/TS extension), or by anything other than a letter, digit, `_`, `-` or another extension, and the full file name no longer matches with a further extension such as `.snap`. Extensionless imports, `.js` imports and the module's own path still count.
|
||||
|
||||
### Fixed
|
||||
- **`literals` module matching.** A sibling file that shares the module's stem (`<stem>.txt`, `<stem>.json`, `<stem>-v2.ts`, `<file>.snap`, or `<stem>.ts` beside a shell script) is no longer the module.
|
||||
|
||||
## [1.92.43.0] - 2026-11-01
|
||||
|
||||
**New page: [docs/support-tiers.md](docs/support-tiers.md) says what gstack supports fully and what it supports minimally.** macOS and Linux, with Claude and OpenAI models, get full support: the whole free suite and the paid evals. Windows (Git Bash or MSYS) and Gemini models get minimal support: install and the core skills (`/ship`, `/review`, `/qa-only`, `/investigate`, `/browse` on gstack's own browser) work without errors, checked on Windows by the `windows-smoke` job, which replaces the six-shard suite as the required Windows check when it lands, and by hand or one cheap smoke run on Gemini. Windows-only and Gemini-only reports that don't break install, startup or a core workflow close as won't fix with a link to the page.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.92.43.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.92.44.0 — regenerate/re-copy after upgrading gstack
|
||||
|
||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||
for agent hosts without a full skill install. The full skills add workflows,
|
||||
|
||||
+8
-1
@@ -200,7 +200,14 @@ Two stages with separate clocks, both printed:
|
||||
scratch name (`zz-*`, `tmp*`, `scratch*`) anywhere.
|
||||
- `literals`: for every changed exported constant or named timeout/retry
|
||||
literal, the whole test tree (nightly- and Heavy-only files included) is
|
||||
searched for the old value; a consumer the branch did not update fails with
|
||||
searched for the old value in files that name the constant or, when the old
|
||||
value is longer than one character, its module (the module's file name not
|
||||
followed by another extension, or a path ending
|
||||
in its stem followed by its own extension, for a JS/TS module also any JS/TS
|
||||
extension or `.d.ts`, a sentence-ending `.`, or anything but a word
|
||||
character, `.` or `-`; so a sibling `<stem>.txt`, `<stem>-v2.ts` or
|
||||
`<file>.snap`, or `<stem>.ts` beside a shell module, is not the module); a
|
||||
consumer the branch did not update fails with
|
||||
`file:line`. A version-history row, a line that starts a bracketed row with
|
||||
the old value (`[45, "<digest>"]`), is skipped when the same table (a run of
|
||||
consecutive lines starting with `[`) also holds a row for the new value that
|
||||
|
||||
@@ -61,8 +61,12 @@ function unquote(v: string): string { return /^['"`]/.test(v) ? v.slice(1, -1) :
|
||||
|
||||
/**
|
||||
* Test files that still carry the old literal beside the constant's name or
|
||||
* its module. The module counts as its full file name (`install.sh`) or as a
|
||||
* path fragment (`/retry.js`, `/retry'`): a bare stem such as `install` or `retry` is an
|
||||
* its module. The module counts as its full file name (`install.sh`, not
|
||||
* `install.sh.tmpl`) or as a path fragment (`/retry.js`, `/retry'`) whose stem is
|
||||
* followed by the module's own extension (for a JS/TS module also any JS/TS
|
||||
* extension or `.d.ts`), a sentence-ending `.`, or anything but a word
|
||||
* character, `.` or `-`, so a sibling `/retry.txt`, `/retry-v2.ts` or
|
||||
* `/retry.ts.snap`, or `lib/install.ts` for `install.sh`, is not the module (GST-820): a bare stem such as `install` or `retry` is an
|
||||
* English word in half the test tree, and a one-character old value (`2`)
|
||||
* sits in every test, so that value needs the constant's name (a wrapper
|
||||
* version 2 → 3 flagged 575 consumers through the stem alone).
|
||||
@@ -83,7 +87,11 @@ export function consumersOf(repoRoot: string, testFiles: readonly string[], chan
|
||||
const newRowRe = row(change.new);
|
||||
const base = path.basename(change.file);
|
||||
const stem = base.replace(/\.[^.]+$/, '');
|
||||
const moduleRe = new RegExp(`(?:(?:^|[/\\\\])${escape(stem)}|(?<![\\w-])${escape(base)})(?![\\w-])`, 'm');
|
||||
const own = base.slice(stem.length + 1);
|
||||
const jsLike = /^[cm]?[jt]sx?$/.test(own);
|
||||
const exts = (jsLike ? [...new Set([own, 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'mts', 'cts'])] : [own]).map(escape).join('|');
|
||||
const dts = jsLike ? '(?:d\\.)?' : '';
|
||||
const moduleRe = new RegExp(`(?:^|[/\\\\])${escape(stem)}(?=[^\\w.-]|$|\\.${dts}(?:${exts})(?![\\w.-])|\\.(?!\\w))|(?<![\\w-])${escape(base)}(?![\\w-]|\\.\\w)`, 'm');
|
||||
const nameRe = new RegExp(`\\b${escape(change.name)}\\b`);
|
||||
const nameRequired = value.length < 2;
|
||||
const hits: string[] = [];
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.92.43",
|
||||
"version": "1.92.44",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -201,6 +201,41 @@ describe('literals (pure)', () => {
|
||||
{ name: 'MAX', old: '3', new: '4', file: 'f.ts' }, { name: 'timeout', old: '5000', new: '9000', file: 'f.ts' },
|
||||
]);
|
||||
});
|
||||
// Value: protects=a sibling file that shares the module's stem (`postgres-unit-arms.txt` beside `postgres-unit-arms.ts`) is not the
|
||||
// module, so a test that only names it is not a consumer, while an extensionless import, a JS/TS import extension, the module's own
|
||||
// file name and a path ending at the stem (then a quote, space, bracket, sentence end or `.d.ts`) still are, and neither `<file>.snap` nor a JS twin of a
|
||||
// shell module is; fails_when=`/<stem>` again accepts any following `.<word>`, the file name accepts a further extension,
|
||||
// a non-JS module takes JS/TS extensions, or stops accepting a following space, bracket or sentence end
|
||||
// (GST-820: 17 false files in gbrain #8372 on ARM_SHARDS 12 -> 18); why_new=no test had a same-stem sibling; seam=none;
|
||||
// no_claim=name-gated hits (a file naming ARM_SHARDS still counts any 12)
|
||||
test('consumersOf: a sibling file sharing the module stem is not the module; real imports of it still are (GST-820)', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-literals-stem-'));
|
||||
const nl = String.fromCharCode(10);
|
||||
const files: Record<string, string> = {
|
||||
'test/a.test.ts': ['// listed in test/postgres-unit-arms.txt', 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/json.test.ts': ["const arms = read('fixtures/postgres-unit-arms.json');", 'expect(arms.length).toBe(12);', ''].join(nl),
|
||||
'test/longer.test.ts': ["run('scripts/postgres-unit-arms-v2.ts');", 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/import.test.ts': ["import { shards } from '../scripts/postgres-unit-arms';", 'expect(shards()).toBe(12);', ''].join(nl),
|
||||
'test/import-js.test.ts': ["import { shards } from '../scripts/postgres-unit-arms.js';", 'expect(shards()).toBe(12);', ''].join(nl),
|
||||
'test/own.test.ts': ["const out = run('scripts/postgres-unit-arms.ts');", 'expect(out).toBe(12);', ''].join(nl),
|
||||
'test/line-end.test.ts': ['// covers scripts/postgres-unit-arms', 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/prose.test.ts': ['// covers scripts/postgres-unit-arms and more', 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/paren.test.ts': ['// (scripts/postgres-unit-arms)', 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/sentence.test.ts': ['// see scripts/postgres-unit-arms.', 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/dts.test.ts': ["import type { Arms } from '../scripts/postgres-unit-arms.d.ts';", 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/sibling-test.test.ts': ["run('scripts/postgres-unit-arms.test.ts');", 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/snap.test.ts': ["read('scripts/__snapshots__/postgres-unit-arms.ts.snap');", 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/sh-twin.test.ts': ["import { arms } from '../lib/arms-tool.ts';", 'expect(n).toBe(12);', ''].join(nl),
|
||||
'test/sh-own.test.ts': ["run('scripts/arms-tool.sh');", 'expect(n).toBe(12);', ''].join(nl),
|
||||
};
|
||||
for (const [rel, text] of Object.entries(files)) { fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true }); fs.writeFileSync(path.join(root, rel), text); }
|
||||
expect(consumersOf(root, Object.keys(files), { name: 'ARM_SHARDS', old: '12', new: '18', file: 'scripts/postgres-unit-arms.ts' })).toEqual([
|
||||
'test/import.test.ts:2', 'test/import-js.test.ts:2', 'test/own.test.ts:2', 'test/line-end.test.ts:2',
|
||||
'test/prose.test.ts:2', 'test/paren.test.ts:2', 'test/sentence.test.ts:2', 'test/dts.test.ts:2',
|
||||
]);
|
||||
expect(consumersOf(root, ['test/sh-twin.test.ts', 'test/sh-own.test.ts'], { name: 'ARMS', old: '12', new: '18', file: 'scripts/arms-tool.sh' })).toEqual(['test/sh-own.test.ts:2']);
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
});
|
||||
test('consumersOf: a module stem is a path fragment, never a bare word, and a one-character old value needs the constant name (GSTA-114 flood: install.sh 2 -> 3 flagged 575 consumers)', () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-literals-'));
|
||||
const nl = String.fromCharCode(10);
|
||||
|
||||
Reference in new issue
Block a user