From 1e798cd986c2aeedaf4c9f35b92cbe002871ad44 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 18 Oct 2026 16:56:46 -0700 Subject: [PATCH 1/2] v1.91.140.0 fix(cso-eval): producer accepts dependency-closure names with the helper's 32-hex finding IDs (#3278) * fix(cso-eval): producer accepts dependency-closure names with the helper's 32-hex finding IDs * v1.91.140.0 fix(cso-eval): producer accepts dependency-closure names with the helper's 32-hex finding IDs --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- scripts/cso-eval-producer.ts | 2 +- test/cso-eval.test.ts | 4 ++++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f23ffbb26..dedc67352 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.91.140.0] - 2026-10-18 + +**/cso evaluation cells that run a repair no longer fail on helper dependency-closure names that use the helper's own 32-character finding IDs.** In the third paid runtime qualification, one comprehensive cell failed with REDACTION_FAILED again, on `dependency-closures/-after-.json`. 1.91.135.0 taught the producer this name shape with a 64-character finding ID. The helper actually names closures with its 32-character finding IDs, so real names still fell through to the secret redactor, which reads some of them as wallet addresses. + +### Fixed +- **The eval producer recognizes dependency-closure names with 32- or 64-character finding IDs.** Any other word in the phase position still goes through the redactor. The test now uses a real-length, redactor-flagged 32-character name and fails on the 1.91.135.0 pattern. + ## [1.91.139.0] - 2026-10-18 **The docs-sync fixture's declared Git interface now includes read-only `git describe`, so `ship-docsync-store` no longer goes red when the /document-release child checks for release tags.** PR #3272's gate run 39153452209 failed that case on one command, `git describe --tags --always`, which the observer did not list. A focused paid rerun of `ship-docsync-store` on this tree passed ($3.83); the child ran the same command twice and the observer accepted it. diff --git a/VERSION b/VERSION index 46ba4c6df..bd17523e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.139.0 +1.91.140.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 1c453e835..cabf876b8 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.139.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.140.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, diff --git a/package.json b/package.json index 6efc1a9fa..39b5c15e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.139", + "version": "1.91.140", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/scripts/cso-eval-producer.ts b/scripts/cso-eval-producer.ts index 375f3eb68..d06c841e8 100644 --- a/scripts/cso-eval-producer.ts +++ b/scripts/cso-eval-producer.ts @@ -180,7 +180,7 @@ function emptyArtifactInventory(): ProducerArtifactInventory { } /** A whole path component that is one of the helper's own identifiers: `-` run and replay IDs, retired runs, hex artifact IDs with an optional lowercase-word prefix (`gitleaks--.json`), and dependency-closure files (`-before|after-.json`). */ -const HELPER_ID_COMPONENT = /^(?:\d{13}-[a-f0-9]{16}|\.retired-\d{13}-[a-f0-9]{16}-[a-f0-9]{32}|(?:[a-z]+-)*[a-f0-9]{16,64}(?:-[a-f0-9]{16})*(?:\.[a-z]+)?|[a-f0-9]{64}-(?:before|after)-[a-f0-9]{16}\.json)$/; +const HELPER_ID_COMPONENT = /^(?:\d{13}-[a-f0-9]{16}|\.retired-\d{13}-[a-f0-9]{16}-[a-f0-9]{32}|(?:[a-z]+-)*[a-f0-9]{16,64}(?:-[a-f0-9]{16})*(?:\.[a-z]+)?|(?:[a-f0-9]{32}){1,2}-(?:before|after)-[a-f0-9]{16}\.json)$/; /** * Helper artifact paths are `//...` plus the helper's public-cache/ and legacy-imports/. Components that diff --git a/test/cso-eval.test.ts b/test/cso-eval.test.ts index b64390551..9e01b2501 100644 --- a/test/cso-eval.test.ts +++ b/test/cso-eval.test.ts @@ -1218,8 +1218,11 @@ describe('CSO matched producer orchestration', () => { const repo = 'e'.repeat(24); let closure = ''; while (!closure) { const name = `${randomHex(32)}-before-${randomHex(8)}.json`; if (redact(name) !== name) closure = name; } + let helperFindingClosure = ''; + while (!helperFindingClosure) { const name = `${randomHex(16)}-after-${randomHex(8)}.json`; if (redact(name) !== name) helperFindingClosure = name; } const accepted = [`${repo}/${runId}/report.json`, `${repo}/${runId}/reviews/${walletShaped}.json`, `${repo}/${runId}/scanner-outcomes/gitleaks-${randomHex(8)}-${randomHex(8)}.json`, `${repo}/${runId}/dependency-closures/${closure}`, `${repo}/${runId}/dependency-closures/${closure.replace('-before-', '-after-')}`, + `${repo}/${runId}/dependency-closures/${helperFindingClosure}`, `${repo}/${runId}/dependency-closures/${helperFindingClosure.replace('-after-', '-before-')}`, `${repo}/${runId}/snapshot/test/fixtures/cso-canary-token.txt`, 'public-cache/osv/index.json']; for (const path of accepted) expect(() => assertProducerArtifactPath(path)).not.toThrow(); for (const [path, message] of [ @@ -1228,6 +1231,7 @@ describe('CSO matched producer orchestration', () => { [`${repo}/${runId}/bad name.json`, 'INVALID_PRODUCER_ARTIFACTS: an artifact path has a component outside'], ] as const) expect(() => assertProducerArtifactPath(path)).toThrow(message); expect(() => assertProducerArtifactPath(`${repo}/${runId}/dependency-closures/${closure.replace('-before-', '-during-')}`)).toThrow('looks like a secret'); + expect(() => assertProducerArtifactPath(`${repo}/${runId}/dependency-closures/${helperFindingClosure.replace('-after-', '-during-')}`)).toThrow('looks like a secret'); const planted = `sk-ant-api03-${randomHex(24)}`; expect(redact(planted)).not.toBe(planted); let failure: unknown; From 8640ab4ff43accda6676105868935903232d8c93 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 18 Oct 2026 17:15:09 -0700 Subject: [PATCH 2/2] v1.91.141.0 fix(cso): daily reports omit candidates without demonstrated in-scope impact (#3283) * fix(cso): daily reports omit candidates without demonstrated in-scope impact * CHANGELOG: daily /cso supported-finding bar * v1.91.141.0 fix(cso): daily reports omit candidates without demonstrated in-scope impact --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- cso/SKILL.md | 2 +- cso/SKILL.md.tmpl | 2 +- package.json | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dedc67352..b247d0d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.91.141.0] - 2026-10-18 + +**Daily `/cso` reports now leave out candidates without demonstrated in-scope impact.** The daily rubric already required an attacker-controlled entrypoint, a security-boundary crossing, demonstrated impact, and challenged protective controls. It now says what to omit: candidates whose impact needs code outside the snapshot or a future change, or that expose nothing sensitive. Those stay coverage evidence instead of supported findings. Comprehensive reports are unchanged and keep unresolved candidates as labeled hypotheses. In the third paid runtime qualification, daily precision was 47/53, below the 0.95 bar, and four of its five false-positive classes were findings of this kind. In a preregistered 12-cell pilot, 5 of the 6 false positives disappeared, every seeded issue was kept, and no new false positive appeared. Daily reports also drop low and informational real issues: 4 of the 13 pilot controls were lost this way. Garry accepted that trade-off. Comprehensive mode still reports them. + +### Changed +- **`cso/SKILL.md.tmpl`: the daily supported-finding paragraph names what to omit.** The generated `cso/SKILL.md` is 18,097 bytes, under the 18,100 parity cap. This changes no gate, scorer, threshold, sample count, recall definition, baseline or answer key. + ## [1.91.140.0] - 2026-10-18 **/cso evaluation cells that run a repair no longer fail on helper dependency-closure names that use the helper's own 32-character finding IDs.** In the third paid runtime qualification, one comprehensive cell failed with REDACTION_FAILED again, on `dependency-closures/-after-.json`. 1.91.135.0 taught the producer this name shape with a 64-character finding ID. The helper actually names closures with its 32-character finding IDs, so real names still fell through to the secret redactor, which reads some of them as wallet addresses. diff --git a/VERSION b/VERSION index bd17523e6..639e36f47 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.140.0 +1.91.141.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index cabf876b8..b539c3953 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.140.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.141.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, diff --git a/cso/SKILL.md b/cso/SKILL.md index 47293f45f..1b8030423 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -135,7 +135,7 @@ This **CSO evidence rubric** governs CSO instead of shared review confidence ins - **Confidence:** how strongly available evidence supports that precise claim; explain unknowns and counterevidence. Do not turn a number into proof. - **Evidence:** candidate hypothesis, supported static evidence, or a helper-recorded reproduction. Code tracing can support a finding; it cannot establish that an application booted or a repair passed tests. -Daily reports contain **supported findings**: a concrete attacker-controlled entrypoint, a path across an intended security boundary, demonstrated impact, and a challenge of relevant protective controls. Comprehensive reports retain unresolved candidates separately as **labeled hypotheses**, never mixed into supported totals. Disproved candidates are retained as disposition/coverage evidence, not vulnerabilities. +Daily reports hold only **supported findings**: an attacker-controlled entrypoint, a security-boundary crossing, demonstrated in-scope impact, and challenged protective controls. Omit daily candidates whose impact needs out-of-snapshot code or a future change, or exposes nothing sensitive. Comprehensive reports keep unresolved candidates as separate **labeled hypotheses**; omitted or disproved ones are coverage. Do not apply blanket exclusions for development dependencies, availability/resource attacks, historical secrets, user-role prompt injection, or gstack-owned skills. Analyze attacker control and impact. UUIDs are not authorization; user-controlled URL paths can cross a sensitive boundary; environment variables may come from untrusted workflows; framework escape hatches can bypass safe defaults. Missing hardening alone needs a concrete failure scenario before becoming a finding. diff --git a/cso/SKILL.md.tmpl b/cso/SKILL.md.tmpl index 765027bc5..8030addaf 100644 --- a/cso/SKILL.md.tmpl +++ b/cso/SKILL.md.tmpl @@ -127,7 +127,7 @@ This **CSO evidence rubric** governs CSO instead of shared review confidence ins - **Confidence:** how strongly available evidence supports that precise claim; explain unknowns and counterevidence. Do not turn a number into proof. - **Evidence:** candidate hypothesis, supported static evidence, or a helper-recorded reproduction. Code tracing can support a finding; it cannot establish that an application booted or a repair passed tests. -Daily reports contain **supported findings**: a concrete attacker-controlled entrypoint, a path across an intended security boundary, demonstrated impact, and a challenge of relevant protective controls. Comprehensive reports retain unresolved candidates separately as **labeled hypotheses**, never mixed into supported totals. Disproved candidates are retained as disposition/coverage evidence, not vulnerabilities. +Daily reports hold only **supported findings**: an attacker-controlled entrypoint, a security-boundary crossing, demonstrated in-scope impact, and challenged protective controls. Omit daily candidates whose impact needs out-of-snapshot code or a future change, or exposes nothing sensitive. Comprehensive reports keep unresolved candidates as separate **labeled hypotheses**; omitted or disproved ones are coverage. Do not apply blanket exclusions for development dependencies, availability/resource attacks, historical secrets, user-role prompt injection, or gstack-owned skills. Analyze attacker control and impact. UUIDs are not authorization; user-controlled URL paths can cross a sensitive boundary; environment variables may come from untrusted workflows; framework escape hatches can bypass safe defaults. Missing hardening alone needs a concrete failure scenario before becoming a finding. diff --git a/package.json b/package.json index 39b5c15e7..a665af9bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.140", + "version": "1.91.141", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module",