mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
v1.91.348.0 stamp: train gate.train-bde4bd7321d8-21277291c850-bc510f S3 (#3661)
This commit is contained in:
commit
cf89d64379
10 files changed
+72
-18
No files matched your search
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [1.91.348.0] - 2026-10-31
|
||||
|
||||
- **Pregate now maps tests to dotfiles they name.** A test that reads `../.gitleaks.toml`, `.gitleaks.toml` or `join('.github', 'workflows', 'ci.yml')` used to get no edge to that file, so a branch touching only the dotfile ended in `PREGATE_NO_LANE`. Quoted literals may now start with a dot, and a dot-led literal that isn't `./` or `../` resolves from both the repository root and the folder of the file that names it, so a fixture's own `.github/` keeps its edge. A literal still forms an edge only when it names a file in the repo, so strings like `'.ts'` add nothing. On gstack this adds 179 edges (`buildGraph` over this repository: 16,934 on main 2127729, 17,113 with this change, none removed), all to real dotfiles such as `.github/workflows/*.yml` and `.gstack/*.json`. (GST-246, reported from garrytan/truther#956.)
|
||||
|
||||
## [1.91.347.0] - 2026-10-31
|
||||
|
||||
**A Captain archives only its own crew's threads (R39, amended). A thread outside every crew belongs to the owner and stays as it is, even when the Captain's own automation created it.**
|
||||
|
||||
### Changed
|
||||
- **docs/captain.md and the Capy factory context (`factory.md` point 12)** now say a Captain archives only the threads in its own crew, each when its plan for that thread says the work is done. No Captain archives, flags or lists a thread outside every crew for archiving unless the owner asks. The earlier wording also let a Captain archive threads its automations started outside the crew, and that emptied the owner's unattached threads.
|
||||
|
||||
## [1.91.346.0] - 2026-10-31
|
||||
|
||||
**`sealed.local_path` now flags a home path inside a shell default, `${UBI_RUNNER:-/home/<user>…}`, as it already flagged the same path after `?? "/home/<user>…"` in TypeScript.** gstack-evals `quick/laneb/runner/launch.sh:9` passed the scan because the `-` before the path counted as part of a word (#3568).
|
||||
|
||||
### Fixed
|
||||
- **`sealed.local_path`** (`lib/sealed-guard.ts`): a home path directly after a `${…:-` or `${…-` default now matches, for a name, an array element (`${arr[0]:-`, a subscript of up to 64 characters, so a long line of unclosed `${a[` cannot make the scan quadratic), an indirect name (`${!ref:-`), a positional number or a special parameter (`${@:-`). `:=`, `:+` and `:?` already matched, because `=`, `+` and `?` were never word characters. A hyphen anywhere else still excludes the match, so a path glued to a word (`docs-…`, `$VAR-…`, `${VAR}-…`) stays unflagged; docs/pregate.md lists that as a known limit.
|
||||
|
||||
### Gate integrity
|
||||
- This is a gate edit that only tightens. The guard now refuses lines it passed before. No existing test, threshold or allowlist changed. A new case in `test/sealed-guard.test.ts` covers all five operators, a positional parameter, `${@`, an array element, an indirect name, a Windows path and the TypeScript `??` form. It also checks six negative controls, which are two hyphenated paths, a hyphenated sentence, `$VAR-`, `${VAR}-` and a relative default. Without the fix it misses every `-` form.
|
||||
|
||||
## [1.91.345.0] - 2026-10-31
|
||||
|
||||
**A capped `/ship` on Capy now spends fewer agent turns and counts only its own tokens, while every reviewer still gets exactly the brief 1.91.331.0 gives it.** Two new commands do `/ship`'s fixed shell work, a short driver file replaces reading the whole skill when a parent agent runs `/ship`, and the budget measures each reviewer batch on its own instead of across the parent's work. Replays of gstack-evals #34 and #36 (GSTA-167) spent 12.19M tokens on Steps 12-17 and 0.25-0.4M on each parent turn; these changes cut turns, not reviewer context.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.91.345.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.91.348.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,
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
What seven Captain crews converged on (2026-10-29). Your crew's CREW.md and recorded approvals decide who may merge, update a base, spend or touch production; urgency changes priority, never permissions or gates. With no Captain, ask the person and never merge without their word. Story: capy/README.md; examples: your org Drive's software-factory/README.md, if any.
|
||||
|
||||
1. **Plan, then a yes.** New functionality starts with /autoplan sized to the work; the build waits for "do it". [SKILL.md: Plan, approve, ship]
|
||||
2. **Someone else merges.** Run /ship to a receipt on your final pushed head, send one READY quoting gstack's verify output word for word, and stop. The merge owner merges on green and assigns versions. [docs/captain.md: The READY contract]
|
||||
3. **Block only on the floor.** A finding blocks if it would fail a test, break production, or lose data or secrets; the rest goes in the PR body or the next wave. [docs/review-policy.md]
|
||||
4. **Fix waves.** When main goes red, hold /ship while one owner finds the root cause; bring main in once, as your rules allow. Fold deferred findings and test follow-ups into one wave PR. [docs/triage.md]
|
||||
5. **Severe first, same gates.** A severe user-facing bug jumps the queue; the plan can be short, but receipt, checks and merge owner stay.
|
||||
6. **Trade findings, not small talk.** A finding that belongs to another crew goes to its Captain, through yours, with the evidence.
|
||||
2. **Someone else merges.** Run /ship to a receipt on your final pushed head, send one READY quoting gstack's verify output verbatim, and stop. The merge owner merges on green and assigns versions. [docs/captain.md: The READY contract]
|
||||
3. **Block only on the floor.** A finding blocks if it would fail a test, break production, or lose data or secrets; the rest goes in the PR body or next wave. [docs/review-policy.md]
|
||||
4. **Fix waves.** When main goes red, hold /ship while one owner finds the root cause; bring main in once, as your rules allow. Fold deferred findings and test follow-ups into one PR. [docs/triage.md]
|
||||
5. **Severe first, same gates.** A severe user-facing bug jumps the queue; the plan can be short; receipt, checks and merge owner stay.
|
||||
6. **Trade findings, not small talk.** Another crew's finding goes to its Captain, through yours, with the evidence.
|
||||
7. **Measure before you act.** Run the real system on the merged tree you ship; a real run outranks a reviewed plan. Each number names its run, commit or uncapped query; say what you did not verify.
|
||||
8. **Evals decide, and losses get reported.** Preregister bars, cap and stop rule before paying [/eval-plan]. Cheap proof (a keyless fake, a smoke) before the paid run. Use controls (no-skill and placebo arms, clean decoys). Report use and pass separately; quote spend from the meter.
|
||||
8. **Evals decide, and losses get reported.** Preregister bars, cap and stop rule before paying [/eval-plan]. Cheap proof (a keyless fake, a smoke) before the paid run. Use controls (no-skill and placebo arms, clean decoys). Report use and pass apart; quote spend from the meter.
|
||||
9. **Flakes: one rerun, a ledger, a daily fix.** Only the rerun the policy allows, never a harness or infra red; a second red is real; no test is loosened. [docs/captain.md: The daily flaky pass]
|
||||
10. **Quiet.** Message on a decision, a blocker, a READY or a finished phase. A broadcast that needs no reply goes in the Captain's notes; never reply just to acknowledge.
|
||||
10. **Quiet.** Message on a decision, a blocker, a READY or a finished phase. A broadcast needing no reply goes in the Captain's notes; never reply just to acknowledge.
|
||||
11. **Ask once, plainly.** One ask per decision, explained like the owner is five: your Captain's name, then a lettered line each: "A: <code> hit problem p, which happens when h. We could do 1) x, 2) y or 3) z. Recommendation x because why. A1 to take recommendation." "do it" takes every recommendation; "A2" takes option 2. Owner tasks: the exact link (in Capy: path and field), numbered simple steps, the reply word. Never re-ask a standing rule; check what you can yourself. [docs/captain.md: The ask format]
|
||||
12. **Fresh threads, closed out.** One thread per unit of work (crew threads ask their Captain); past the context threshold, hand off. Its Captain archives the threads it, its crew or automations start. Size reviews to the diff; read the token counter. [docs/ship-budget.md]
|
||||
12. **Fresh threads, closed out.** One thread per unit of work (crew threads ask their Captain); past the context limit, hand off. Its Captain archives only its crew's threads; threads outside every crew are the owner's, even its automation's. Size reviews to the diff; read the token counter. [docs/ship-budget.md]
|
||||
13. **The owner's model preference.** `gstack-models resolve --role agent` picks agent models, except cross-family voices and eval subjects. [docs/model-policy.md: Your model preference]
|
||||
@@ -1 +0,0 @@
|
||||
- **Pregate now maps tests to dotfiles they name.** A test that reads `../.gitleaks.toml`, `.gitleaks.toml` or `join('.github', 'workflows', 'ci.yml')` used to get no edge to that file, so a branch touching only the dotfile ended in `PREGATE_NO_LANE`. Quoted literals may now start with a dot, and a dot-led literal that isn't `./` or `../` resolves from both the repository root and the folder of the file that names it, so a fixture's own `.github/` keeps its edge. A literal still forms an edge only when it names a file in the repo, so strings like `'.ts'` add nothing. On gstack this adds 179 edges (`buildGraph` over this repository: 16,934 on main 2127729, 17,113 with this change, none removed), all to real dotfiles such as `.github/workflows/*.yml` and `.gstack/*.json`. (GST-246, reported from garrytan/truther#956.)
|
||||
+5
-3
@@ -35,9 +35,11 @@ by a daily pass; nothing is retried into green.
|
||||
rules file, the digest and the notes, validates READYs, builds and merges trains, calls
|
||||
slots, relays asks to the owner in the three shapes, runs the flaky pass, and decides
|
||||
everything that needs no access, credentials, spend over cap or a cited approval. It
|
||||
archives its own child threads, including ones its crew or its automations started
|
||||
outside the crew, when its plan for each thread says that thread's work is done; it
|
||||
knows each thread's next step, so nobody else archives them.
|
||||
archives only its own crew threads, each when its plan for that thread says the work is
|
||||
done; it knows each thread's next step, so nobody else archives them. A thread outside
|
||||
every crew belongs to the owner and stays as it is: no Captain archives it, flags it or
|
||||
lists it for archiving unless the owner asks, even when the Captain's own automation
|
||||
created it.
|
||||
- **A lane** (a crew thread) owns named files, builds on its own branch and machine,
|
||||
runs /ship, sends one READY block, stamps on call (merging the base into its pin only
|
||||
as part of that stamp commit, or when the controller names a real-code conflict),
|
||||
|
||||
+4
-2
@@ -805,8 +805,10 @@ gstack-pregate sealed [--range <a..b>] [--remote origin] [--base <branch>] [--js
|
||||
- **Rules.** `sealed.path` and `sealed.transcript` check every path a commit
|
||||
adds, renames or copies, whatever its content (binary, empty, deleted again
|
||||
in a later commit); `sealed.answer`, `sealed.seed` and `sealed.local_path`
|
||||
(`/home/<user>/`, `/Users/<user>/`, `C:\Users\<user>\`) check each commit's added
|
||||
lines. Findings print rule, `file[:line]` and commit, never the text.
|
||||
(`/home/<user>/`, `/Users/<user>/`, `C:\Users\<user>\`, including after a shell
|
||||
default such as `${VAR:-…}` or `${VAR-…}`) check each commit's added lines.
|
||||
Known limit: a path glued to the text before it, by a hyphen (`docs-…`,
|
||||
`$VAR-…`, `${VAR}-…`) or a letter (`-I…`, `-L…`), is not matched. Findings print rule, `file[:line]` and commit, never the text.
|
||||
- **Globs.** `paths`, `transcripts` and `allow_paths` match the whole
|
||||
repo-relative path from the repository root. `*` and `?` stay inside one
|
||||
path segment; `**/` spans zero or more directories; a `**` not followed by
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ export type Visibility = 'public' | 'private' | 'unknown';
|
||||
const KEYS = ['paths', 'transcripts', 'answer_markers', 'seed_patterns', 'local_paths', 'allow_paths', 'case_insensitive', 'visibility'];
|
||||
const MAX_ENTRIES = 64;
|
||||
const MAX_REGEX = 256;
|
||||
const LOCAL_PATH_RE = /(?:^|[^A-Za-z0-9_.~-])(?:\/home\/[^/\s'"`]+\/|\/Users\/[^/\s'"`]+\/|[A-Za-z]:\\+Users\\+[^\\\s'"`]+\\)/;
|
||||
const LOCAL_PATH_RE = /(?:^|[^A-Za-z0-9_.~-]|\$\{!?(?:[A-Za-z_][A-Za-z0-9_]*(?:\[[^\]\s]{0,64}\])?|[0-9]+|[@*#?$!-]):?-)(?:\/home\/[^/\s'"`]+\/|\/Users\/[^/\s'"`]+\/|[A-Za-z]:\\+Users\\+[^\\\s'"`]+\\)/;
|
||||
const PUBLIC_TTL_MS = 24 * 3600_000;
|
||||
const PRIVATE_TTL_MS = 3600_000;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.91.345",
|
||||
"version": "1.91.348",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -102,6 +102,36 @@ describe('pre-push hook: public destination refuses each kind of sealed output',
|
||||
}
|
||||
});
|
||||
|
||||
test('local_path matches a home path after every shell parameter-expansion operator, and still skips hyphenated words', () => {
|
||||
const positives = [
|
||||
'RUNNER="${UBI_RUNNER:-/home/user/.capy/drive/runner}"',
|
||||
'RUNNER="${UBI_RUNNER-/home/user/runner}"',
|
||||
'RUNNER="${UBI_RUNNER:=/home/user/runner}"',
|
||||
'RUNNER="${UBI_RUNNER:+/Users/bob/runner}"',
|
||||
'RUNNER="${UBI_RUNNER:?/home/user/runner}"',
|
||||
'ROOT="${1:-/Users/bob/work}"',
|
||||
'ROOT="${@:-/home/user/work}"',
|
||||
'ROOT="${arr[0]:-/home/user/work}"',
|
||||
'ROOT="${!ref:-/home/user/work}"',
|
||||
'ROOT="${WIN_ROOT:-C:\\Users\\bob\\work}"',
|
||||
'const dir = process.env.UBI_WORK ?? "/home/ubi/work";',
|
||||
];
|
||||
const negatives = [
|
||||
'see docs-/home/user/x for the old layout',
|
||||
'mount at data-/Users/bob/cache',
|
||||
'RUNNER="$UBI_RUNNER-/home/user/runner"',
|
||||
'RUNNER="${UBI_RUNNER}-/home/user/runner"',
|
||||
'RUNNER="${UBI_RUNNER:-./runner}"',
|
||||
'a well-known, self-hosted, run-to-completion job',
|
||||
];
|
||||
const s = scratch({ '.gstack/pregate.json': policy(SEALED) });
|
||||
commit(s, { 'runner/launch.sh': [...positives, ...negatives].join('\n') + '\n' });
|
||||
const r = hook(s);
|
||||
expect(r.code).toBe(1);
|
||||
const flagged = [...r.err.matchAll(/sealed\.local_path\s+runner\/launch\.sh:(\d+)/g)].map(m => Number(m[1]));
|
||||
expect(flagged).toEqual(positives.map((_, i) => i + 1));
|
||||
});
|
||||
|
||||
test('path rules ignore content: a binary file, an empty transcript, an add-then-delete and a rename into a sealed path all refuse', () => {
|
||||
const binary = scratch({ '.gstack/pregate.json': policy(SEALED) });
|
||||
commit(binary, { 'heldout/questions.bin': Buffer.from([0, 1, 2, 0, 255, 0]) });
|
||||
|
||||
Reference in new issue
Block a user