diff --git a/changelog.d/capy-gst-1088-lane-c.md b/changelog.d/capy-gst-1088-lane-c.md index 74dc7fff4..75aed8173 100644 --- a/changelog.d/capy-gst-1088-lane-c.md +++ b/changelog.d/capy-gst-1088-lane-c.md @@ -1,7 +1,7 @@ -**/investigate loads about 3.4 KB less and /review about 3.3 KB less, and a /review blocker now needs proof (GST-1088 lane C, the candidate).** Opus 5.5 read these skills in full and still skipped their required steps (Run D, gstack-evals#140). The forced full /review caught 67.2% of blocking bugs but raised 2.71 false blockers per PR per pass (gstack-evals#120). This change cuts pieces of the two skills that nothing showed were doing work, and it makes every blocking /review finding prove itself. It merges only after the GST-1089 no-loss replay passes. +**/investigate loads about 3.4 KB less and /review about 3.2 KB less, and a /review blocker now needs proof (GST-1088 lane C, the candidate).** Opus 5.5 read these skills in full and still skipped their required steps (Run D, gstack-evals#140). The forced full /review caught 67.2% of blocking bugs but raised 2.71 false blockers per PR per pass (gstack-evals#120). This change cuts pieces of the two skills that nothing showed were doing work, and it makes every blocking /review finding prove itself. It merges only after the GST-1089 no-loss replay passes. ### Changed -- **Cuts, every loadout and every host**: /investigate drops its learnings search, Capture Learnings and the investigation-typed learnings log. /review drops its learnings search, Capture Learnings, the repo-ownership preamble section and the Step 3.4 VERSION queue line. Always-loaded bytes: /investigate 20,243 to 16,839, /review 58,815 to 55,517 (Claude SKILL.md, frontmatter included). Telemetry (`gstack-skill-end`) stays, because it writes the timeline's `completed` event with the real outcome. No other skill changes on any host. +- **Cuts, every loadout and every host**: /investigate drops its learnings search, Capture Learnings and the investigation-typed learnings log. /review drops its learnings search, Capture Learnings, the repo-ownership preamble section and the Step 3.4 VERSION queue line. Always-loaded bytes: /investigate 21,242 to 17,838, /review 60,014 to 56,716 (Claude SKILL.md, frontmatter included, against v1.94.24.0). Telemetry (`gstack-skill-end`) stays, because it writes the timeline's `completed` event with the real outcome. No other skill changes on any host. - **/review blocker proof**: a CRITICAL finding names its floor reason (fails a test, breaks production, loses data or secrets, or one of the forced-CRITICAL classes) and carries a repro, a failing test, or a cited line with its consequence. /review checks a forwarded finding and adds both itself. A CRITICAL nobody proves is INFORMATIONAL. This applies in the critical pass and in the pre-emit verification gate. - **/review markers**: specialist selection always prints one `Dispatching N specialists:` line, small diffs included (`Dispatching 0 specialists: (small diff)`), and the native adversarial pass prints `Dispatching adversarial pass: native` before its Agent call. /ship's text is unchanged. diff --git a/modules/cuts.json b/modules/cuts.json index 9536e2241..84455dab3 100644 --- a/modules/cuts.json +++ b/modules/cuts.json @@ -70,6 +70,6 @@ ], "pins": { "investigate": 17838, - "review": 56769 + "review": 56716 } } diff --git a/review/SKILL.md b/review/SKILL.md index 21b090c4a..fe47608c4 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -29,7 +29,6 @@ contract: - id: adversarial-pass kind: agent_dispatch match: Think like an attacker and a chaos engineer - marker: "Dispatching adversarial pass: native" - id: review-report kind: report_labels heading: Pre-Landing Review diff --git a/review/SKILL.md.tmpl b/review/SKILL.md.tmpl index 118c4a28d..d41739d10 100644 --- a/review/SKILL.md.tmpl +++ b/review/SKILL.md.tmpl @@ -35,7 +35,6 @@ contract: - id: adversarial-pass kind: agent_dispatch match: Think like an attacker and a chaos engineer - marker: "Dispatching adversarial pass: native" - id: review-report kind: report_labels heading: Pre-Landing Review diff --git a/scripts/resolvers/contract-done-means.ts b/scripts/resolvers/contract-done-means.ts index 39a1e7416..ef98c9b0d 100644 --- a/scripts/resolvers/contract-done-means.ts +++ b/scripts/resolvers/contract-done-means.ts @@ -18,7 +18,7 @@ export type ContractItem = | { id: string; kind: 'report_labels'; heading: string; labels: string[] } | { id: string; kind: 'check_after_last_edit' } | { id: string; kind: 'selected_specialists_dispatched'; marker: string } - | { id: string; kind: 'agent_dispatch'; match: string; marker?: string }; + | { id: string; kind: 'agent_dispatch'; match: string }; export interface SkillContract { version: 1; @@ -32,11 +32,6 @@ const KIND_FIELDS: Record = { agent_dispatch: ['match'], }; -// Fields a kind may carry; when present each must be non-empty text. bin/gstack-skill-contract checks agent_dispatch's marker before its match. -const OPTIONAL_FIELDS: Partial> = { - agent_dispatch: ['marker'], -}; - // The resolver and section that render the step each kind checks today. A host that suppresses the resolver, or a loadout that excludes the section, never shows that step, so its items are left out of the list there. const BACKED_BY: Partial> = { selected_specialists_dispatched: { resolver: 'REVIEW_ARMY', section: 'review-army' }, @@ -74,14 +69,11 @@ export function parseSkillContract(value: unknown, where: string): SkillContract if (seen.has(raw.id)) fail(where, at + ' duplicate id "' + raw.id + '"'); seen.add(raw.id); for (const key of Object.keys(raw)) { - if (key !== 'id' && key !== 'kind' && !KIND_FIELDS[kind].includes(key) && !OPTIONAL_FIELDS[kind]?.includes(key)) fail(where, at + ' (' + kind + ') has unknown key "' + key + '"'); + if (key !== 'id' && key !== 'kind' && !KIND_FIELDS[kind].includes(key)) fail(where, at + ' (' + kind + ') has unknown key "' + key + '"'); } for (const field of KIND_FIELDS[kind]) { if (field !== 'labels' && !isText(raw[field])) fail(where, at + ' ' + field + ' must be a non-empty string'); } - for (const field of OPTIONAL_FIELDS[kind] ?? []) { - if (field in raw && !isText(raw[field])) fail(where, at + ' ' + field + ' must be a non-empty string'); - } if (kind === 'report_labels') { if (!Array.isArray(raw.labels) || raw.labels.length === 0) fail(where, at + ' labels must be a non-empty list'); for (const label of raw.labels as unknown[]) { diff --git a/test/cut-ledger.test.ts b/test/cut-ledger.test.ts index 02312ae68..9bd6b69d6 100644 --- a/test/cut-ledger.test.ts +++ b/test/cut-ledger.test.ts @@ -142,6 +142,17 @@ describe('cut ledger against every host render', () => { if (violations.length) throw new Error(`${violations.length} cut ledger violation(s):\n ${violations.join('\n ')}`); }); + test('a preamble cut never comes back through the shared preamble file, on any host', () => { + const leaks: string[] = []; + for (const host of ALL_HOST_CONFIGS) for (const cut of ledger.cuts.filter(c => c.preamble_piece)) { + const file = host.name === 'claude' + ? path.join(ROOT, cut.skill, 'sections', SHARED_PREAMBLE_FILE) + : path.join(outDir, host.hostSubdir, 'skills', `gstack-${cut.skill}`, 'sections', SHARED_PREAMBLE_FILE); + if (fs.existsSync(file) && fs.readFileSync(file, 'utf-8').includes(cut.match)) leaks.push(`${host.name}: ${cut.id} "${cut.match}" in ${path.relative(outDir, file)}`); + } + expect(leaks).toEqual([]); + }); + test('review-only GST-1088 text renders in /review alone, on every host', () => { const leaks = Object.entries(renders).filter(([key]) => !key.endsWith('/review')) .flatMap(([key, text]) => REVIEW_ONLY.filter(s => text.includes(s)).map(s => `${key}: "${s}"`)); diff --git a/test/helpers/carve-guards.ts b/test/helpers/carve-guards.ts index 93aff1be0..858b2190e 100644 --- a/test/helpers/carve-guards.ts +++ b/test/helpers/carve-guards.ts @@ -490,10 +490,10 @@ do not launch the downstream skill or open a browser.`, gateAfterStop: undefined, // operational multi-STOP skill, like ship }, behavioral: 'plan', - maxSkeletonBytes: 56_769, // GST-1088 lane C diet (R56 cut ledger modules/cuts.json: learnings search and capture, repo ownership, queue status; plus the blocker-proof rule, the two dispatch markers and the adversarial-pass contract marker): lowered from 60,014 to measured, no headroom; measured 56,769 with #3909 merged (2026-11-03). Before: GST-1088 lane B (#3909, raised from 59,774 to measured, no headroom; owner ruling via GStack Minder 2026-11-03): CONTRACT_CHECKER_SHIPPED=true now that bin/gstack-skill-contract ships (#3912) renders the gstack-skill-contract check/waive sentence under the Done means list (renders/GSTA-256/plan-v3.md line 74, r2-d6 "Done-means list"), +240 bytes; measured 60,014. Before: GST-1088 lane B (raised from 59,073 to measured, no headroom): the contract: frontmatter block and the F1 "Done means" list rendered from it at the top of the body, plus widened triggers; GST-1088 gate rev 2 (Garry, 2026-11-03, "do it") raised them for the Done-means list, and this lane's diet brings them back to 56,769; measured 59,774. Before: GSTA-96 hoist (2026-10-26): lowered from 80_900 by the shared preamble that moved to sections/preamble.md, keeping the pre-hoist headroom of 319 bytes; measured 58,754. Before: Shared-code identity/skip/action rules + critical-severity validation; measured 74,493 (2026-09-17). + v1.91.12.0 merge of #2999 (review clarity repairs: await reads, research alongside dispatch, /review deadline and setup authority, findings sources) with #3002 (guarded state-root lines, plan-check checkpoints); each fit alone; measured 74,881 (2026-10-01). + Oct 8 wave: shared voice directive bans "load-bearing" and adds the reply-language rule, offset by tightening the bounded closer (net +17 bytes per tier-2+ skill); measured 74,884 (2026-10-08). + gate integrity (HONEST_WORK_GATE_INTEGRITY W2): Step 3.5 Diff scans with the shared GATE_SCAN_BLOCK, the Step 4 carry, the four-option `review-gate-disposition` question in 5c, gate record fields in 5.8 and the Gate edits report line; measured 80,054 (2026-10-10). + Oct 10 multi-agent wave PR D2 (sideways review): Step 4's enum-only paragraph becomes the sideways sweep with the forced-CRITICAL list, plus the flake-fix number sentence in the Gate Integrity paragraph; measured skeleton 80,812 (2026-10-10). + maxSkeletonBytes: 56_716, // GST-1088 lane C diet (R56 cut ledger modules/cuts.json: learnings search and capture, repo ownership, queue status; plus the blocker-proof rule, and the two dispatch markers): lowered from 60,014 to measured, no headroom; measured 56,716 with #3909 merged (2026-11-03). Before: GST-1088 lane B (#3909, raised from 59,774 to measured, no headroom; owner ruling via GStack Minder 2026-11-03): CONTRACT_CHECKER_SHIPPED=true now that bin/gstack-skill-contract ships (#3912) renders the gstack-skill-contract check/waive sentence under the Done means list (renders/GSTA-256/plan-v3.md line 74, r2-d6 "Done-means list"), +240 bytes; measured 60,014. Before: GST-1088 lane B (raised from 59,073 to measured, no headroom): the contract: frontmatter block and the F1 "Done means" list rendered from it at the top of the body, plus widened triggers; GST-1088 gate rev 2 (Garry, 2026-11-03, "do it") raised them for the Done-means list, and this lane's diet brings them back to 56,716; measured 59,774. Before: GSTA-96 hoist (2026-10-26): lowered from 80_900 by the shared preamble that moved to sections/preamble.md, keeping the pre-hoist headroom of 319 bytes; measured 58,754. Before: Shared-code identity/skip/action rules + critical-severity validation; measured 74,493 (2026-09-17). + v1.91.12.0 merge of #2999 (review clarity repairs: await reads, research alongside dispatch, /review deadline and setup authority, findings sources) with #3002 (guarded state-root lines, plan-check checkpoints); each fit alone; measured 74,881 (2026-10-01). + Oct 8 wave: shared voice directive bans "load-bearing" and adds the reply-language rule, offset by tightening the bounded closer (net +17 bytes per tier-2+ skill); measured 74,884 (2026-10-08). + gate integrity (HONEST_WORK_GATE_INTEGRITY W2): Step 3.5 Diff scans with the shared GATE_SCAN_BLOCK, the Step 4 carry, the four-option `review-gate-disposition` question in 5c, gate record fields in 5.8 and the Gate edits report line; measured 80,054 (2026-10-10). + Oct 10 multi-agent wave PR D2 (sideways review): Step 4's enum-only paragraph becomes the sideways sweep with the forced-CRITICAL list, plus the flake-fix number sentence in the Gate Integrity paragraph; measured skeleton 80,812 (2026-10-10). minUnionBytes: 89_000, // Phase 4 wave 1; measured union 93,357 mustContain: ['confidence', 'P1', 'P2', 'Review Army', 'adversarial'], - maxSizeRatio: 1.2984, // GST-1088 lane C diet (same cuts and additions as maxSkeletonBytes): lowered from 1.3283 to measured, rounded up; measured 140,902 / 108,523 = 1.29836 with #3909 merged (2026-11-03). Before: + GST-1088 lane B (#3909, raised from 1.3261 to measured, no headroom; owner ruling via GStack Minder 2026-11-03): the gstack-skill-contract check/waive sentence that CONTRACT_CHECKER_SHIPPED=true renders (renders/GSTA-256/plan-v3.md line 74, r2-d6 "Done-means list"), +240 bytes; measured 144,147 / 108,523 = 1.32826, rounded up. Before: + GST-1088 lane B (raised from 1.3180 to measured, no headroom): the contract: frontmatter block and the F1 "Done means" list; GST-1088 gate rev 2 (Garry, 2026-11-03, "do it") raised them for the Done-means list, and this lane's diet brings them back to 1.2984; measured 143,907 / 108,523 = 1.3261. Before: + GSTA-167 variant G part 1 (plan approved by Garry 2026-10-30, autoplan-20261030161754 "Do it", which names about +0.3k prompt tokens per voice): the native adversarial and outside-voice prompts carry the blocking floor and the Severity and Blocks lines, +537 bytes; measured 1.3180 (2026-10-30). Before: 1.3136. GSTA-96 hoist merged with GSTA-92 phase 2 (2026-10-26): both owner-approved raises together, measured 142,550 / 108,523 = 1.3135. Before: Shared-code feature + critical-severity validation: 128,042 union bytes / 108,523 baseline = 1.1799; preserves content floors. + v1.91.12.0 merge of #2999 (above, plus plan-completion fallback intent and specialist checklist-by-path) with #3002; measured 1.1843 (2026-10-01). + v1.91.19.0 wave: verdict-form Codex callers with sandbox preflight (INV-1/B1), P0/P1 structured gate (B1b), bound-plan discovery and data-not-instructions guard (F1/D3), visible LEARNINGS failures (B5); measured 129,941 / 108,523 = 1.1974 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 130,025 / 108,523 = 1.1981 (2026-10-04). + Oct 6 fix wave: quota_exhausted preflight branch (#3051); measured 130,359 / 108,523 = 1.2012 (2026-10-06). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 131,314 / 108,523 = 1.2100 (2026-10-06). Combined Oct 6 wave head (A and B): measured 131,966 / 108,523 = 1.2160 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 132,199 / 108,523 = 1.2182 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 132,258 / 108,523 = 1.2187 (2026-10-07). + Oct 7 wave guard (CEO-20): conditional `run_in_background` request plus the background-run recovery at each foreground dispatch site; measured 132,233 / 108,523 = 1.2185 (2026-10-07). Merged with the guard area: measured 132,522 / 108,523 = 1.2211 (2026-10-07). + Oct 8 wave: the defensive-security framing and fixture summary mode reach the security specialist and the Red Team (stated once in the dispatch, referenced by the Red Team); measured 133,902 / 108,523 = 1.2339 (2026-10-08). + gate integrity W2 (above); measured 1.282 (2026-10-10). + Oct 10 multi-agent wave PR D2 (sideways review): sideways sweep and flake-fix number in Step 4; `Diff read` and `Undeclared behavior changes` in the review-mode Scope Check (plan-completion section); measured 140,497 / 108,523 = 1.2946 (2026-10-10). + harness lane E (2026-10-26): the lead-judgment stage in the finding merge and the `cause` anchor in the specialist prompts, shared with /ship through scripts/resolvers/review-army.ts; measured 141,949 / 108,523 = 1.3080. + maxSizeRatio: 1.2979, // GST-1088 lane C diet (same cuts and additions as maxSkeletonBytes): lowered from 1.3283 to measured, rounded up; measured 140,849 / 108,523 = 1.29788 with #3909 merged (2026-11-03). Before: + GST-1088 lane B (#3909, raised from 1.3261 to measured, no headroom; owner ruling via GStack Minder 2026-11-03): the gstack-skill-contract check/waive sentence that CONTRACT_CHECKER_SHIPPED=true renders (renders/GSTA-256/plan-v3.md line 74, r2-d6 "Done-means list"), +240 bytes; measured 144,147 / 108,523 = 1.32826, rounded up. Before: + GST-1088 lane B (raised from 1.3180 to measured, no headroom): the contract: frontmatter block and the F1 "Done means" list; GST-1088 gate rev 2 (Garry, 2026-11-03, "do it") raised them for the Done-means list, and this lane's diet brings them back to 1.2979; measured 143,907 / 108,523 = 1.3261. Before: + GSTA-167 variant G part 1 (plan approved by Garry 2026-10-30, autoplan-20261030161754 "Do it", which names about +0.3k prompt tokens per voice): the native adversarial and outside-voice prompts carry the blocking floor and the Severity and Blocks lines, +537 bytes; measured 1.3180 (2026-10-30). Before: 1.3136. GSTA-96 hoist merged with GSTA-92 phase 2 (2026-10-26): both owner-approved raises together, measured 142,550 / 108,523 = 1.3135. Before: Shared-code feature + critical-severity validation: 128,042 union bytes / 108,523 baseline = 1.1799; preserves content floors. + v1.91.12.0 merge of #2999 (above, plus plan-completion fallback intent and specialist checklist-by-path) with #3002; measured 1.1843 (2026-10-01). + v1.91.19.0 wave: verdict-form Codex callers with sandbox preflight (INV-1/B1), P0/P1 structured gate (B1b), bound-plan discovery and data-not-instructions guard (F1/D3), visible LEARNINGS failures (B5); measured 129,941 / 108,523 = 1.1974 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 130,025 / 108,523 = 1.1981 (2026-10-04). + Oct 6 fix wave: quota_exhausted preflight branch (#3051); measured 130,359 / 108,523 = 1.2012 (2026-10-06). + Oct 6 fix wave A3/CEO-12: free text reaches commands only through agent-written mktemp files (mktemp block, write rule, path rebuild and refusal at each posting, prompt and brief site); measured 131,314 / 108,523 = 1.2100 (2026-10-06). Combined Oct 6 wave head (A and B): measured 131,966 / 108,523 = 1.2160 (2026-10-06). + Oct 7 wave B3: the Codex probe runs as a command (select-model capture lines, check-sandbox/probe-model/run-with-timeout subcommands) instead of being sourced; measured 132,199 / 108,523 = 1.2182 (2026-10-07). + Oct 7 wave CEO-28/DX-11: review prompts ask for a severity per finding and design proposals use the proposal gate; measured 132,258 / 108,523 = 1.2187 (2026-10-07). + Oct 7 wave guard (CEO-20): conditional `run_in_background` request plus the background-run recovery at each foreground dispatch site; measured 132,233 / 108,523 = 1.2185 (2026-10-07). Merged with the guard area: measured 132,522 / 108,523 = 1.2211 (2026-10-07). + Oct 8 wave: the defensive-security framing and fixture summary mode reach the security specialist and the Red Team (stated once in the dispatch, referenced by the Red Team); measured 133,902 / 108,523 = 1.2339 (2026-10-08). + gate integrity W2 (above); measured 1.282 (2026-10-10). + Oct 10 multi-agent wave PR D2 (sideways review): sideways sweep and flake-fix number in Step 4; `Diff read` and `Undeclared behavior changes` in the review-mode Scope Check (plan-completion section); measured 140,497 / 108,523 = 1.2946 (2026-10-10). + harness lane E (2026-10-26): the lead-judgment stage in the finding merge and the `cause` anchor in the specialist prompts, shared with /ship through scripts/resolvers/review-army.ts; measured 141,949 / 108,523 = 1.3080. }, codex: { skill: 'codex', diff --git a/test/skill-descriptions.test.ts b/test/skill-descriptions.test.ts index 28ab27716..d6eff7b43 100644 --- a/test/skill-descriptions.test.ts +++ b/test/skill-descriptions.test.ts @@ -184,8 +184,6 @@ describe('contract-done-means renderer', () => { ['heading missing', one({ id: 'a', kind: 'report_labels', labels: ['Symptom'] }), /heading must be a non-empty string/], ['marker missing', one({ id: 'a', kind: 'selected_specialists_dispatched' }), /marker must be a non-empty string/], ['match missing', one({ id: 'a', kind: 'agent_dispatch' }), /match must be a non-empty string/], - ['empty agent_dispatch marker', one({ id: 'a', kind: 'agent_dispatch', match: 'x', marker: ' ' }), /marker must be a non-empty string/], - ['marker on a kind without one', one({ id: 'a', kind: 'report_labels', heading: 'R', labels: ['L'], marker: 'x' }), /unknown key "marker"/], ['field from another kind', one({ id: 'a', kind: 'check_after_last_edit', match: 'x' }), /unknown key "match"/], ]; for (const [name, value, want] of MALFORMED) {