v1.57.10.0 feat: Codex review default-on across review/ship/plan/docs (#1966)

* feat(config): make codex_reviews the master switch for all Codex review

Broaden the codex_reviews doc to describe it governing /review, /ship,
/document-release, plan reviews, and /autoplan. Reject invalid values on
set (preserving the existing value) so a typo can never silently flip
paid Codex calls on or off.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(review): Codex review default-on across review/ship/plan/docs

Add a shared codexPreflight() helper (constants.ts) that, in one bash
block, reads codex_reviews, sources gstack-codex-probe, checks install +
auth, and echoes a single canonical mode (ready/not_installed/not_authed/
disabled). All Codex resolvers route through it.

- generateCodexPlanReview: opt-in question removed; the outside voice now
  runs automatically (default-on), falling back to a Claude subagent when
  Codex is missing/unauthed. Cross-model tension still gates on user
  approval (sovereignty preserved).
- generateAdversarialStep: probe-based availability (install AND auth),
  distinct not-installed vs not-authed guidance; 200-line structured-review
  threshold unchanged.
- generateCodexDocReview (new, wired via CODEX_DOC_REVIEW): reviews the
  release's docs against the shipped diff range, informational + an explicit
  apply-fixes decision point, never auto-edits.
- autoplan Phase 0.5 now honors codex_reviews=disabled so the switch is
  truly global.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(docs): regenerate SKILL docs + refresh ship golden

Output of gen:skill-docs for the Codex-default-on resolver/template
changes. Refreshes the factory-ship golden fixture (codex-host output
unchanged — resolvers strip for the codex host).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(infra): widen size-budget guards for default-on Codex outside-voice

The codexPreflight() block + CODEX_MODE branch prose (replacing the
smaller opt-in question) grows plan-ceo/eng/devex-review and review by
5-7% over baseline. Each bump carries a comment justifying it as
intentional capability, not slop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: guard Codex default-on + config reject-on-set

skill-validation: assert plan reviews no longer carry the opt-in question
and render the default-on outside-voice, document-release carries the doc
review, and the codex host strips all of it.

gstack-config: codex_reviews defaults to enabled, accepts enabled/disabled,
and rejects an invalid value while preserving the existing one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(test): align gstack-config tests with defaults-fallback behavior

Three tests (last touched v0.13.7.0) asserted get/list print empty for
unset keys, but gstack-config falls back to the documented defaults table
(get returns the default, list shows the active-values block). Update the
assertions to the real behavior and split out an unknown-key case that does
still return empty. Pre-existing red, unrelated to codex review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* v1.57.10.0 feat: Codex review default-on across review/ship/plan/docs

Codex cross-model review now runs by default on /review, /ship, all four
plan reviews, /document-release, and /autoplan, governed by one master
switch (codex_reviews, default enabled). Plan-review outside voice is
default-on; /document-release gets a new Codex doc-vs-diff audit; every
call site detects install AND auth and falls back to a Claude subagent
with a clear reason. Disable everything with:
gstack-config set codex_reviews disabled

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-06-10 21:14:58 -07:00
committed by GitHub
parent 8241949357
commit a5833c413f
21 changed files with 766 additions and 196 deletions
+37 -5
View File
@@ -41,9 +41,16 @@ afterEach(() => {
describe('gstack-config', () => {
// ─── get ──────────────────────────────────────────────────
test('get on missing file returns empty, exit 0', () => {
test('get on missing file returns the default, exit 0', () => {
// auto_upgrade has a default of false; get falls back to the defaults table.
const { exitCode, stdout } = run(['get', 'auto_upgrade']);
expect(exitCode).toBe(0);
expect(stdout).toBe('false');
});
test('get unknown key on missing file returns empty, exit 0', () => {
const { exitCode, stdout } = run(['get', 'some_unknown_key']);
expect(exitCode).toBe(0);
expect(stdout).toBe('');
});
@@ -110,10 +117,12 @@ describe('gstack-config', () => {
expect(stdout).toContain('update_check: false');
});
test('list on missing file returns empty, exit 0', () => {
test('list on missing file shows defaults, exit 0', () => {
// list prints the active-values block with defaults for unset keys.
const { exitCode, stdout } = run(['list']);
expect(exitCode).toBe(0);
expect(stdout).toBe('');
expect(stdout).toContain('proactive:');
expect(stdout).toContain('(default)');
});
// ─── usage ────────────────────────────────────────────────
@@ -151,6 +160,29 @@ describe('gstack-config', () => {
expect(content).toContain('skip_eng_review:');
});
// ─── codex_reviews (paid-calls switch: reject-on-set, preserve existing) ──
test('codex_reviews defaults to enabled', () => {
const { exitCode, stdout } = run(['get', 'codex_reviews']);
expect(exitCode).toBe(0);
expect(stdout).toBe('enabled');
});
test('codex_reviews accepts enabled and disabled', () => {
expect(run(['set', 'codex_reviews', 'disabled']).exitCode).toBe(0);
expect(run(['get', 'codex_reviews']).stdout).toBe('disabled');
expect(run(['set', 'codex_reviews', 'enabled']).exitCode).toBe(0);
expect(run(['get', 'codex_reviews']).stdout).toBe('enabled');
});
test('codex_reviews rejects an invalid value and preserves the existing one', () => {
run(['set', 'codex_reviews', 'disabled']);
const { exitCode, stderr } = run(['set', 'codex_reviews', 'disabledd']);
expect(exitCode).not.toBe(0); // rejected, not warn-and-default
expect(stderr).toContain('not recognized');
// existing value must be untouched — a typo never silently flips paid Codex on/off
expect(run(['get', 'codex_reviews']).stdout).toBe('disabled');
});
test('header written only once, not duplicated on second set', () => {
run(['set', 'foo', 'bar']);
run(['set', 'baz', 'qux']);
@@ -176,9 +208,9 @@ describe('gstack-config', () => {
});
// ─── routing_declined ──────────────────────────────────────
test('routing_declined defaults to empty (not set)', () => {
test('routing_declined defaults to false (not set)', () => {
const { stdout } = run(['get', 'routing_declined']);
expect(stdout).toBe('');
expect(stdout).toBe('false');
});
test('routing_declined can be set and read', () => {