test: cover the Codex default-prompt render, the openai.yaml ownership proof and the unattended grant

Adds the /ship coverage audit's tests: test/host-renders-openai-yaml-proof.test.ts
drives bin/gstack-host-renders.sh's weakened proof against a rendered yaml, a
hand-written one and a generic-prompt one; test/unattended-grant.test.ts pins the
docs/unattended.md grant section and the handoff pointer; test/gen-skill-docs.test.ts
adds modernize to the skills whose codex_default_prompt must reach openai.yaml.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 22:41:02 +00:00
1 parent 6b14d7da4b
commit d4793fa9be
3 files changed
+99 -1

No files matched your search

+2 -1
View File
@@ -2933,7 +2933,8 @@ describe('Codex generation (--host codex)', () => {
// A template's codex_default_prompt: key is the sentence Codex's picker
// inserts for the skill; without the key the generic fallback keeps every
// entry valid. The key is generator input only: no host render carries it.
const CODEX_PROMPT_SKILLS = ['ship', 'review', 'qa', 'autoplan', 'office-hours', 'land-and-deploy'];
// Value: protects=the new /modernize skill's picker prompt reaches its Codex render; fails_when=modernize's key is dropped, misquoted or unrendered; why_new=modernize-skill.test reads the template only; seam=none; no_claim=prompt wording quality
const CODEX_PROMPT_SKILLS = ['ship', 'review', 'qa', 'autoplan', 'office-hours', 'land-and-deploy', 'modernize'];
test('codex_default_prompt: in a template becomes that skill\'s default_prompt', () => {
for (const dir of CODEX_PROMPT_SKILLS) {
const tmpl = fs.readFileSync(path.join(ROOT, dir, 'SKILL.md.tmpl'), 'utf-8');
@@ -0,0 +1,53 @@
/**
* bin/gstack-host-renders.sh: the WEAK proof that an agents/openai.yaml is the
* generator's own render, now that a template's codex_default_prompt: makes
* the default_prompt line vary per skill (it used to be one fixed sentence).
*
* Value: protects=_gstack_hr_generated accepts the generator's openai.yaml for any default_prompt and still rejects a foreign or edited one; fails_when=the shape check reverts to the generic-prompt literal, or drops display_name/policy/6-line limits; why_new=host-renders-prune asserts one backed-up line; no test exercises the rejected shapes; seam=none; no_claim=what the prune does after the proof
*/
import { describe, expect, test } from 'bun:test';
import { spawnSync } from 'node:child_process';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { generateOpenAIYaml } from '../scripts/gen-skill-docs';
const ROOT = path.resolve(import.meta.dir, '..');
const HELPER = path.join(ROOT, 'bin/gstack-host-renders.sh');
describe.skipIf(process.platform === 'win32')('_gstack_hr_generated proves an openai.yaml by shape, not by its prompt sentence', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-openai-yaml-proof-'));
const tree = path.join(dir, '.agents');
const real = path.join(dir, 'checkout');
fs.mkdirSync(real, { recursive: true });
function proven(rel: string, content: string): boolean {
const file = path.join(tree, rel);
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.writeFileSync(file, content);
const r = spawnSync('bash', ['-c', `. "${HELPER}"\n_gstack_hr_generated "${file}" "${tree}" "${real}" && echo proven || echo kept`], {
encoding: 'utf8', timeout: 30_000, env: { PATH: process.env.PATH ?? '/usr/bin:/bin', HOME: os.tmpdir() },
});
expect(r.status, r.stderr).toBe(0);
return r.stdout.trim() === 'proven';
}
const custom = generateOpenAIYaml('gstack-ship', 'short', 'Use $gstack-ship to take this branch to a pull request: "quoted", colons: too.');
const generic = generateOpenAIYaml('gstack-careful', 'short');
test('the generator\'s render is proven whether the prompt is the skill\'s own sentence or the fallback', () => {
expect(custom).not.toContain('Use gstack-ship for this task.');
expect(proven('skills/gstack-ship/agents/openai.yaml', custom)).toBe(true);
expect(generic).toContain('default_prompt: "Use gstack-careful for this task."');
expect(proven('skills/gstack-careful/agents/openai.yaml', generic)).toBe(true);
});
test('a file that is not the generator\'s shape for that skill directory is kept, not backed up', () => {
expect(proven('skills/gstack-qa/agents/openai.yaml', custom), 'display_name names another skill').toBe(false);
expect(proven('skills/gstack-ship/agents/openai.yaml', custom.replace('policy:\n', 'rules:\n')), 'no policy: block').toBe(false);
expect(proven('skills/gstack-ship/agents/openai.yaml', custom.replace(' default_prompt: "', ' default_prompt: \'')), 'prompt not double-quoted').toBe(false);
expect(proven('skills/gstack-ship/agents/openai.yaml', custom + ' my_note: hand-written\n'), 'a seventh line').toBe(false);
expect(proven('skills/gstack-ship/agents/openai.yaml', 'notes:\n' + custom.slice('interface:\n'.length)), 'first line is not interface:').toBe(false);
expect(proven('skills/gstack-ship/openai.yaml', custom), 'not under agents/').toBe(false);
});
});
+44
View File
@@ -0,0 +1,44 @@
/**
* docs/unattended.md#what-an-unattended-session-may-do: the grant a parent
* gives an unattended run, and the pointer /ship's handoff section carries so a
* lane reads it where it reports done.
*
* Value: protects=the handoff pointer resolves to the grant section, and the grant states merge-never, the pinned-lease push form and the /modernize disposition; fails_when=the heading is renamed or moved, the pointer is dropped from the template or its render, or the grant loses a rule; why_new=no test reads the new section or the handoff pointer; seam=none; no_claim=that a run obeys the grant (eval-side)
*/
import { describe, expect, test } from 'bun:test';
import * as fs from 'node:fs';
import * as path from 'node:path';
const ROOT = path.resolve(import.meta.dir, '..');
const read = (rel: string) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
const POINTER = 'docs/unattended.md#what-an-unattended-session-may-do';
const slug = (heading: string) => heading.toLowerCase().replace(/[^a-z0-9 -]/g, '').trim().replace(/ /g, '-');
describe('the unattended grant and the /ship handoff pointer to it', () => {
const docs = read('docs/unattended.md');
const grantStart = docs.indexOf('\n## What an unattended session may do\n');
const grant = docs.slice(grantStart + 1, (i => i === -1 ? docs.length : i)(docs.indexOf('\n## ', grantStart + 1)));
test('the handoff section points at a heading that exists, in the template and its render', () => {
expect(grantStart).toBeGreaterThan(0);
const heading = grant.slice(3, grant.indexOf('\n'));
expect(`docs/unattended.md#${slug(heading)}`).toBe(POINTER);
expect(read('ship/sections/handoff.md.tmpl')).toContain(`What an\nunattended run may do is ${POINTER}.`);
expect(read('ship/sections/handoff.md')).toContain(POINTER);
expect(grant).toContain('`/ship`\'s handoff section (`ship/sections/handoff.md`) points here');
});
test('the grant names each rule once: merge never, a pinned-lease force-push on its own branch, named test methods, own-eyes proof', () => {
const flat = grant.replace(/\s+/g, ' ');
expect(flat).toContain('- **Merge: never.**');
expect(flat).toContain('- **Force-push: its own branch only, after a rebase the plan named, with a pinned lease.**');
expect(flat).toContain('- **Tests: the methods the repository\'s instructions name, without asking first.**');
expect(flat).toContain('- **Proof is what the run saw itself.**');
expect(flat).toContain('`git push --force-with-lease=<branch>:<sha observed before the rebase> origin <branch>`');
expect(flat).toContain('a plain `--force` is never allowed');
expect(flat).toContain('`git range-diff <old base>..<old head> <new base>..<new head>` runs before the push');
expect(flat).toContain('a `/modernize` disposition names before it happens');
expect(flat).toContain('enabling auto-merge, adding the PR to a merge queue, or `gh pr ready` on a PR the run did not open');
expect(flat).toContain('appended to `decisions.jsonl` with `kind: "approval"` and `status: "pending"`');
});
});