mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-14 17:05:28 +02:00
fix: make documentation release review and publication consistent
Review before commit, clarify changelog safeguards and unavailable reviewer modes, and preserve raw PR bodies across separate shell calls. Keep title sync in one shell and add regression coverage. Co-authored-by: OpenAI Codex <noreply@openai.com>
This commit is contained in:
co-authored by
OpenAI Codex
parent
9096d9f3f8
commit
24ed2030f4
@@ -63,8 +63,8 @@ describe('content-binding template drift', () => {
|
||||
|
||||
test('release-body write side carries the banner tripwire (and it actually fires)', () => {
|
||||
const body = rendered('document-release/sections/release-body.md');
|
||||
expect(body).toContain('grep -c "UNTRUSTED TRACKER CONTENT" /tmp/gstack-pr-body-$$.md');
|
||||
expect(body).toContain('grep -c "UNTRUSTED TRACKER CONTENT" /tmp/gstack-pr-body-orig-$$.md');
|
||||
expect(body).toContain('grep -c "UNTRUSTED TRACKER CONTENT" "<run-dir>/body.md"');
|
||||
expect(body).toContain('grep -c "UNTRUSTED TRACKER CONTENT" "<run-dir>/body-original.md"');
|
||||
// The fail-open shape: grep -c prints 0 AND exits 1 on no-match, so an
|
||||
// `|| echo 0` double-emits and breaks the -gt into the clean branch.
|
||||
expect(body).not.toContain('|| echo 0');
|
||||
@@ -94,8 +94,8 @@ describe('content-binding template drift', () => {
|
||||
fs.writeFileSync(path.join(dir, 'orig.md'), origContent);
|
||||
fs.writeFileSync(path.join(dir, 'new.md'), newContent);
|
||||
return block![0]
|
||||
.replaceAll('/tmp/gstack-pr-body-orig-$$.md', path.join(dir, 'orig.md'))
|
||||
.replaceAll('/tmp/gstack-pr-body-$$.md', path.join(dir, 'new.md'));
|
||||
.replaceAll('<run-dir>/body-original.md', path.join(dir, 'orig.md'))
|
||||
.replaceAll('<run-dir>/body.md', path.join(dir, 'new.md'));
|
||||
};
|
||||
|
||||
// Banner leaked into the outgoing body → the ABORT branch fires, loudly.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, "..");
|
||||
// document-release is carved (skeleton + sections/release-body.md). Step 9
|
||||
@@ -25,14 +26,29 @@ const GENERATE = fs.readFileSync(path.join(ROOT, "document-generate", "SKILL.md.
|
||||
|
||||
describe("/document-release redaction", () => {
|
||||
test("scans the PR-body temp file before gh pr edit", () => {
|
||||
const scanIdx = RELEASE.indexOf("gstack-redact --from-file /tmp/gstack-pr-body");
|
||||
const editIdx = RELEASE.indexOf("gh pr edit --body-file /tmp/gstack-pr-body");
|
||||
const scanIdx = RELEASE.indexOf('gstack-redact --from-file "<run-dir>/body.md"');
|
||||
const editIdx = RELEASE.indexOf('gh pr edit --body-file "<run-dir>/body.md"');
|
||||
expect(scanIdx).toBeGreaterThan(-1);
|
||||
expect(editIdx).toBeGreaterThan(scanIdx);
|
||||
});
|
||||
test("HIGH blocks the edit", () => {
|
||||
expect(RELEASE).toMatch(/exit 3 \(HIGH\).*do NOT edit/i);
|
||||
});
|
||||
test("separate shell calls share an explicit run directory and never re-read raw tracker text", () => {
|
||||
expect(RELEASE).toContain('mktemp -d /tmp/gstack-doc-release-XXXXXXXX');
|
||||
expect(RELEASE).not.toContain('/tmp/gstack-pr-body-$$');
|
||||
expect(RELEASE).not.toContain('<paste the file contents here>');
|
||||
expect(RELEASE).toContain('pathlib.Path(sys.argv[1]).read_text()');
|
||||
});
|
||||
test("title synchronization keeps every variable in one valid shell block", () => {
|
||||
const section = RELEASE.slice(RELEASE.indexOf('**PR/MR title sync'));
|
||||
const script = section.match(/```bash\n([\s\S]*?)\n```/)![1];
|
||||
for (const command of ['V=$(cat VERSION', 'CURRENT_TITLE=$(gh pr view', 'NEW_TITLE=$(', 'gh pr edit --title "$NEW_TITLE"', 'glab mr update -t "$NEW_TITLE"']) {
|
||||
expect(script).toContain(command);
|
||||
}
|
||||
const result = spawnSync('bash', ['-n'], { input: script, encoding: 'utf8', timeout: 5000 });
|
||||
expect(result.status, result.stderr).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("/document-generate redaction", () => {
|
||||
|
||||
@@ -65,6 +65,18 @@ describe('workflow judge excerpts', () => {
|
||||
expect(text).toContain('## Step 9:');
|
||||
});
|
||||
|
||||
test('documentation review precedes publication and keeps changelog protection', () => {
|
||||
const text = readWorkflowExcerpt('document-release/SKILL.md', '# Document Release:', '## Important Rules');
|
||||
expect(text).toContain('DOC_DIFF_BASE=$(git merge-base origin/<base> HEAD 2>/dev/null || git merge-base <base> HEAD) || exit 1');
|
||||
expect(text.indexOf('## Codex Documentation Review')).toBeLessThan(text.indexOf('## Step 9:'));
|
||||
expect(text).toContain('no in-host substitute is defined here');
|
||||
expect(text).toContain('all Claude fallback modes');
|
||||
expect(text).toContain('Step 9 then commits and pushes those edits');
|
||||
expect(text).toContain('Entries scoring <2 need attention, not replacement');
|
||||
expect(text).not.toContain('Flag and rewrite');
|
||||
expect(text).toContain('if VERSION is absent, use the completion date only');
|
||||
});
|
||||
|
||||
test('plan review evidence and design approval rules precede their use', () => {
|
||||
const eng = readWorkflowExcerpt('plan-eng-review/SKILL.md', '## Review Sections', '## CRITICAL RULE');
|
||||
expect(eng.indexOf('## Confidence Calibration')).toBeLessThan(eng.indexOf('### 1. Architecture review'));
|
||||
|
||||
Reference in New Issue
Block a user