From 25dbe34f4228fc3d920101472f29477bd5023c0e Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 18 Oct 2026 02:12:41 -0700 Subject: [PATCH] v1.91.135.0 fix(cso-eval): producer artifact inventory recognizes dependency-closure file names (#3265) * fix(cso-eval): producer artifact inventory recognizes dependency-closure file names * v1.91.135.0 stamp --- CHANGELOG.md | 7 +++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- scripts/cso-eval-producer.ts | 4 ++-- test/cso-eval.test.ts | 4 ++++ 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b82c2ac4a..f0d0e97d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.91.135.0] - 2026-10-18 + +**/cso evaluation cells that run a repair no longer fail on the helper's own file names.** In the second paid runtime qualification, one comprehensive Rails cell failed with REDACTION_FAILED. Once a repair ran, the helper retained dependency closures as `-before-.json`. The producer's artifact inventory checks each path component, and this name didn't match any known helper-ID shape. So the secret redactor read the 64-character hex finding ID as a credential and failed the whole cell. + +### Fixed +- **The eval producer recognizes dependency-closure file names.** `<64-hex finding id>-before|after-<16-hex>.json` is now a helper-ID shape, like run IDs and scanner-outcome names. Any other word in that position still goes through the redactor, and a test pins both cases. + ## [1.91.134.0] - 2026-10-18 **The paid PR gate now starts only after a PR head's free tests pass and the PR has been quiet for 10 minutes, and a head whose own diff already passed the gate reuses that verdict instead of paying again.** Re-measured over Oct 3 to 17 (505 runs, $21,449) with GSTA-47's scripts: the readiness wait alone would have saved $2,986 (about $1,380 a week), and verdict reuse up to $601 more (restamp-only $97, main moved $504). Together that is up to $3,587, about $1,660 a week; how much of the main-moved share survives the selection check is between $146 and $390 of the $601 by approximation. The same heads still get the same selection and verdict rules; only the start time moves. The PR receipt store, which never restored once, now does. diff --git a/VERSION b/VERSION index 04f57dc99..ec3b8f365 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.134.0 +1.91.135.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index b777d326f..cbb0c7cc4 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.134.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.135.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 176753427..36e793f2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.134", + "version": "1.91.135", "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 a2995473b..375f3eb68 100644 --- a/scripts/cso-eval-producer.ts +++ b/scripts/cso-eval-producer.ts @@ -179,8 +179,8 @@ function emptyArtifactInventory(): ProducerArtifactInventory { return { ...base, identityHash: producerArtifactInventoryHash(base) }; } -/** A whole path component that is one of the helper's own identifiers: `-` run and replay IDs, retired runs, and hex artifact IDs with an optional lowercase-word prefix (`gitleaks--.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 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)$/; /** * 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 d1892ba87..b398f7300 100644 --- a/test/cso-eval.test.ts +++ b/test/cso-eval.test.ts @@ -1156,7 +1156,10 @@ describe('CSO matched producer orchestration', () => { while (!walletShaped) { const id = randomHex(16); if (redact(id) !== id) walletShaped = id; } expect(redact(runId)).not.toBe(runId); const repo = 'e'.repeat(24); + let closure = ''; + while (!closure) { const name = `${randomHex(32)}-before-${randomHex(8)}.json`; if (redact(name) !== name) closure = 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}/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 [ @@ -1164,6 +1167,7 @@ describe('CSO matched producer orchestration', () => { [`${repo}/report.json`, 'INVALID_PRODUCER_ARTIFACTS: an artifact lies outside'], [`${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'); const planted = `sk-ant-api03-${randomHex(24)}`; expect(redact(planted)).not.toBe(planted); let failure: unknown;