mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 08:23:59 +01:00
test(qa-callers): admit ship Step 9's review-plan helper and place its Step 11 voices (late-input 40664336141, plan-checks 40707142223)
Gate edit: the caller interface admits the gstack-review-plan forms Step 9 names at the exact installed path; the ship prompt says the plan's adversarial-native and outside-voice lines are Step 11's, outside the Steps 8-9 excerpt. Free replays of both 40707142223 captures and the real plan for all four ship cases. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
ebbdf33354
commit
8ff0f3f6ef
4 files changed
+247
-1
No files matched your search
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"source": "Paid screen 40707142223 (#3544 head) ship-exploratory-plan-checks: paid-slice-10-a1 and paid-rerun-1-a1 native-events.json, every Bash command in order (parent and child); late-input receipt from train 35 rebuild gate 40664336141 paid-slice-9-a1",
|
||||
"runs": {
|
||||
"40707142223-slice-10": {
|
||||
"root": "/home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE",
|
||||
"commands": [
|
||||
{
|
||||
"parent": false,
|
||||
"command": "date -u +%Y-%m-%dT%H:%M:%SZ"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-deadline start /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports/deadline.json 300 2026-10-28T14:53:05.952Z"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-evidence capture /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports 001 --public --deadline /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports/deadline.json -- bun scripts/probe.ts 4"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-deadline status /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports/deadline.json"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-evidence capture /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports 002 --public --deadline /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports/deadline.json --after 001 --hypothesis 'Success holds for 4; riskiest changed edge is just past the upper bound, so 10 must exit 2 with the exact stderr message.' -- bun scripts/probe.ts 10"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-evidence capture /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports 003 --public --timeout-ms 10000 --after 002 --hypothesis 'Rejection of 10 holds; PLAN.md requires the upper boundary check: 9 must exit 0 with stdout 18 and empty stderr.' -- bun scripts/probe.ts 9"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun run test"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-qa-evidence materialize /home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/product/reports annotations.json"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "if GATE_OUT=$(/home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-gate-diff main 2>&1); then\n printf '%s\\n' \"$GATE_OUT\"\nelse\n GATE_EXIT=$?; printf '%s\\n' \"$GATE_OUT\"\n case \"$GATE_EXIT\" in\n 2) echo \"Gate integrity: UNAVAILABLE \u2014 $(printf '%s\\n' \"$GATE_OUT\" | grep -m1 '^GATE_ERROR=')\" ;;\n *) echo \"Gate integrity: UNAVAILABLE \u2014 helper exit $GATE_EXIT (stale install? run /gstack-upgrade)\" ;;\n esac\nfi"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "date -u +%Y-%m-%dT%H:%M:%SZ"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "/home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-review-plan --base main"
|
||||
},
|
||||
{
|
||||
"parent": true,
|
||||
"command": "git diff origin/main"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "git status --short"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "/home/runner/.cache/gstack-paid-shard-T57Isu/tmp/qc-9kHKwE/host/runtime/bin/gstack-review-log '{\"skill\":\"review\",\"timestamp\":\"'\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"'\",\"status\":\"clean\",\"issues_found\":0,\"critical\":0,\"informational\":0,\"quality_score\":10.0,\"specialists\":{\"state-machines\":{\"dispatched\":true,\"findings\":0,\"critical\":0,\"informational\":0},\"red-team\":{\"dispatched\":false,\"reason\":\"scope\"}},\"findings\":[],\"commit\":\"'\"$(git rev-parse --short HEAD)\"'\",\"via\":\"ship\",\"completed\":true,\"converged\":true,\"cycles\":0,\"pass\":1,\"review_scope\":\"frozen\",\"range_base\":null}' --finish 5534d8f6-4d67-4b6f-b691-c6e83c659df2"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "date -u +%Y-%m-%dT%H:%M:%SZ"
|
||||
}
|
||||
]
|
||||
},
|
||||
"40707142223-rerun-1": {
|
||||
"root": "/home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP",
|
||||
"commands": [
|
||||
{
|
||||
"parent": false,
|
||||
"command": "date -u +%Y-%m-%dT%H:%M:%SZ"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-qa-deadline start /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports/deadline.json 300 2026-10-28T15:06:29.695Z"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-qa-evidence capture /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports 001 --public --deadline /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports/deadline.json -- bun scripts/probe.ts 9"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-qa-evidence capture /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports 002 --public --deadline /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports/deadline.json --after 001 --hypothesis 'Range rule: 10 breaks only the 0..9 bound; changed return path must not alter rejection (exit 2, exact stderr, empty stdout).' -- bun scripts/probe.ts 10"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun run test"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "if GATE_OUT=$(/home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-gate-diff main 2>&1); then\n printf '%s\\n' \"$GATE_OUT\"\nelse\n GATE_EXIT=$?; printf '%s\\n' \"$GATE_OUT\"\n case \"$GATE_EXIT\" in\n 2) echo \"Gate integrity: UNAVAILABLE \u2014 $(printf '%s\\n' \"$GATE_OUT\" | grep -m1 '^GATE_ERROR=')\" ;;\n *) echo \"Gate integrity: UNAVAILABLE \u2014 helper exit $GATE_EXIT (stale install? run /gstack-upgrade)\" ;;\n esac\nfi"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "bun /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-qa-evidence materialize /home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/product/reports annotations.json"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "git status --short"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "date -u +%Y-%m-%dT%H:%M:%SZ"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "/home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-review-plan --base main"
|
||||
},
|
||||
{
|
||||
"parent": true,
|
||||
"command": "git diff origin/main"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "/home/runner/.cache/gstack-paid-shard-pi2bIV/tmp/qc-kMsNBP/host/runtime/bin/gstack-review-log '{\"skill\":\"review\",\"timestamp\":\"'\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"'\",\"status\":\"clean\",\"issues_found\":0,\"critical\":0,\"informational\":0,\"quality_score\":10.0,\"specialists\":{\"state-machines\":{\"dispatched\":true,\"findings\":0,\"critical\":0,\"informational\":0}},\"findings\":[],\"commit\":\"'\"$(git rev-parse --short HEAD)\"'\",\"via\":\"ship\",\"completed\":true,\"converged\":true,\"cycles\":0,\"pass\":1,\"review_scope\":\"frozen\",\"range_base\":null}' --finish 94e80914-bf02-4c55-84a9-a9ea9e1adbac"
|
||||
},
|
||||
{
|
||||
"parent": false,
|
||||
"command": "git status --short"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"lateInputReceipt": {
|
||||
"status": "pass",
|
||||
"probes": [
|
||||
"probe-1cd02598-4151-4346-9556-b245a37e9a44",
|
||||
"probe-11857dac-c540-41de-8e13-ca6181ec88fc",
|
||||
"probe-a8572671-a2ec-4b2d-b5bb-aee043898de1"
|
||||
],
|
||||
"remaining": [
|
||||
"Step 11 native adversarial review (not dispatched)",
|
||||
"review record completed:false"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -179,6 +179,7 @@ export const FREE_FIXTURES: Readonly<Record<string, readonly string[]>> = {
|
||||
'test/fixtures/plan-format-kind-notes.json': ['test/plan-format-kind-note.test.ts'],
|
||||
'test/fixtures/qa-caller-handoff-order-public.json': ['test/qa-exploratory-callers.test.ts'],
|
||||
'test/fixtures/qa-caller-read-probe-mtb1007a.json': ['test/qa-exploratory-callers.test.ts'],
|
||||
'test/fixtures/qa-caller-review-plan-40707142223.json': ['test/qa-caller-review-plan.test.ts'],
|
||||
'test/fixtures/qa-caller-section-skip-ship-small-cli.json': ['test/qa-exploratory-callers.test.ts'],
|
||||
'test/fixtures/plans/autoplan-dashboard.md': ['test/autoplan-init.test.ts', 'test/autoplan-preconfigured-onboarding-ar.test.ts', 'test/autoplan-snapshot.test.ts'],
|
||||
'test/fixtures/plans/autoplan-focus-appearance-design.md': [],
|
||||
|
||||
@@ -217,9 +217,19 @@ function callerDeadlineCommand(command: string, context?: CallerDeadlineContext)
|
||||
return { action, stateFile };
|
||||
}
|
||||
|
||||
const reviewPlanFlags = '(?: --pass \\d+)?(?: --last (?:none|full|fix-check))?(?: --(?:fixed-blocking|fixed-below|blocking-open|touched-gate|critical-found|adversarial-ran))*(?: --reviewed-numbers [\\w:.-]+)?';
|
||||
const reviewPlanForms = new RegExp(`^(?:--base main${reviewPlanFlags}|--fix-check-prompt --fix-list ${literalCallerArgument} --hunks ${literalCallerArgument} --tests ${literalCallerArgument}(?: --callers ${literalCallerArgument})?)$`);
|
||||
|
||||
/** The review-plan helper forms ship Step 9 names, run by the fixture's exact installed path. */
|
||||
function reviewPlanCommandAllowed(text: string, runtime?: string): boolean {
|
||||
const helper = runtime && `${runtime}/bin/gstack-review-plan `;
|
||||
return !!helper && text.startsWith(helper) && reviewPlanForms.test(text.slice(helper.length));
|
||||
}
|
||||
|
||||
export function qaCallerCommandAllowed(command: string, workflowCommands: string[] = [], deadline?: CallerDeadlineContext): boolean {
|
||||
const text = command.trim();
|
||||
if (qaHelperUsageCommand(text)) return true;
|
||||
if (reviewPlanCommandAllowed(text, deadline?.runtime)) return true;
|
||||
if (callerEvidenceCommand(text, deadline)) return true;
|
||||
if (callerDeadlineCommand(text, deadline)) return true;
|
||||
if (/\bgstack-qa-(?:deadline|evidence)\b/.test(text) && !literalCallerCLI.test(text)
|
||||
@@ -699,7 +709,7 @@ export function callerReviewRecordTemplate(fixture: Pick<QaCallerFixture, 'calle
|
||||
|
||||
export function qaCallerSessionOptions(fixture: QaCallerFixture, runId: string): Parameters<typeof runSkillTest>[0] {
|
||||
return {
|
||||
prompt: `Load gstack's /${fixture.caller} supplied parent phase from caller-${fixture.caller}.md and resume it on the selected working-tree diff against origin/main. This excerpt comes from ${fixture.runtime}/${fixture.caller}/SKILL.md; resolve installed-relative references there, not from the excerpt file or product directory. That path identifies the asset base, not another entrypoint: do not read or invoke the full parent SKILL.md or rerun its preamble. Earlier preamble/branch/base setup is complete; use the existing local origin/main ref without fetch. Earlier-phase asset locators are ${fixture.runtime}/review/checklist.md and ${fixture.runtime}/qa/templates/functional-report-template.md. Read those files directly when referenced; recursive Glob does not follow the installed asset symlinks. Cross-project learnings are configured off in this owned fixture. ${fixture.reviewStart ? `The actual review-start helper already captured REVIEW_START=${fixture.reviewStart} for this unchanged core pass; retain that token. ` : ''} This fixture evaluates only the supplied parent phase, not later publication stages. The fixture owner recorded these read-only observations when this phase began; they are current until an input changes, so use them instead of re-running those commands, and recheck freshness before completion outputs:\n${fixture.startObservations}\n Read README.md for the project contract and commands. Use diagnostic-client commands such as \`bun scripts/probe.ts <literal>\` for exploratory discoveries and their checkpoint evidence. A required \`bun run test\` is separate suite verification: report it as verification, never as a diagnostic observation or checkpoint anchor/target. Use the production evidence helper to publish each diagnostic checkpoint as \`reports/exploration-NNN.json\`, not inside a nested directory; do not transcribe its observed payload. ${fixture.caseId === 'ship-exploratory-plan-checks' ? 'The previously discovered plan is PLAN.md.' : 'No plan file was found.'} There is no remote service and no release publication is authorized. There is no interactive approver; do not invent answers or permission. Keep normal parent decision gates. Handoff freshness check: Read HANDOFF.md and reports/HANDOFF.md if present for any concurrent collaborator update, await those results, and compare evidence with current inputs; rerun any probe whose input changed. Run the check before each of these, and dispatch each only in a later message than the check's Read results: the evidence helper's materialize, which runs once per report root and freezes the verdict; every gstack-review-log completed:true record, adversarial-review included, since a record is a completion, not preliminary bookkeeping; and the completion report. A later handoff read cannot validate an earlier materialize or completion. If a probe's snapshot differs from an earlier probe's, read reports/HANDOFF.md first; it names any collaborator change.\n\nQA fixture bindings: the deadline guard, capture, checkpoint and materialize command forms are in the installed qa/sections/exploratory.md this phase requires you to Read; use those forms verbatim with these bindings substituted literally. DEADLINE_TOOL = ${fixture.runtime}/bin/gstack-qa-deadline. EVIDENCE_TOOL = ${fixture.runtime}/bin/gstack-qa-evidence. PROBE_DIR = ${fixture.cwd}/reports. DEADLINE_FILE = ${fixture.cwd}/reports/deadline.json. SECONDS must be positive and at most 300. EARLIER_UTC is the optional caller absolute deadline: use the section clock's Hard deadline UTC, never its Runner entry UTC, reserve-start time or a clock-read time. The only native COMMAND is the existing diagnostic client, bun scripts/probe.ts, with zero or one literal argument. Resolve these exact helper and state paths; do not use variables, another helper, another state file, nested wrappers, scripts, operators or substitutions. Its diagnostic receipts are declared public/synthetic, so --public is approved. Only an explicit plan check this phase requires may use --timeout-ms 10000 in place of the deadline; every other capture, including a rerun or revalidation of an earlier probe, uses the deadline. This does not reset or bypass the smoke deadline. Only the deadline helper may create or change reports/deadline.json and its .qa-deadline- temporary files; never use Write/Edit/MultiEdit on those paths. Record the full outer command in checkpoints and evidence; keep the unchanged child JSON as observed, separate from prefixed guard diagnostics. A completed expired guard-run is not a probe or a pass: retain its unused checkpoint, report not-run coverage and do not restart the deadline. Keep the 12-probe smoke limit. Required suites and explicit plan checks are outside the bounded smoke budget, not permission to reset it. Quote arguments literally. Sources stay inside reports. Decide to execute the next probe before publishing its checkpoint, then await successful publication and dispatch that exact probe. I
Line truncated
|
||||
prompt: `Load gstack's /${fixture.caller} supplied parent phase from caller-${fixture.caller}.md and resume it on the selected working-tree diff against origin/main. This excerpt comes from ${fixture.runtime}/${fixture.caller}/SKILL.md; resolve installed-relative references there, not from the excerpt file or product directory. That path identifies the asset base, not another entrypoint: do not read or invoke the full parent SKILL.md or rerun its preamble. Earlier preamble/branch/base setup is complete; use the existing local origin/main ref without fetch. Earlier-phase asset locators are ${fixture.runtime}/review/checklist.md and ${fixture.runtime}/qa/templates/functional-report-template.md. Read those files directly when referenced; recursive Glob does not follow the installed asset symlinks. Cross-project learnings are configured off in this owned fixture. ${fixture.reviewStart ? `The actual review-start helper already captured REVIEW_START=${fixture.reviewStart} for this unchanged core pass; retain that token. ` : ''} This fixture evaluates only the supplied parent phase, not later publication stages. The fixture owner recorded these read-only observations when this phase began; they are current until an input changes, so use them instead of re-running those commands, and recheck freshness before completion outputs:\n${fixture.startObservations}\n Read README.md for the project contract and commands. Use diagnostic-client commands such as \`bun scripts/probe.ts <literal>\` for exploratory discoveries and their checkpoint evidence. A required \`bun run test\` is separate suite verification: report it as verification, never as a diagnostic observation or checkpoint anchor/target. Use the production evidence helper to publish each diagnostic checkpoint as \`reports/exploration-NNN.json\`, not inside a nested directory; do not transcribe its observed payload. ${fixture.caseId === 'ship-exploratory-plan-checks' ? 'The previously discovered plan is PLAN.md.' : 'No plan file was found.'} There is no remote service and no release publication is authorized. There is no interactive approver; do not invent answers or permission. Keep normal parent decision gates. Handoff freshness check: Read HANDOFF.md and reports/HANDOFF.md if present for any concurrent collaborator update, await those results, and compare evidence with current inputs; rerun any probe whose input changed. Run the check before each of these, and dispatch each only in a later message than the check's Read results: the evidence helper's materialize, which runs once per report root and freezes the verdict; every gstack-review-log completed:true record, adversarial-review included, since a record is a completion, not preliminary bookkeeping; and the completion report. A later handoff read cannot validate an earlier materialize or completion. If a probe's snapshot differs from an earlier probe's, read reports/HANDOFF.md first; it names any collaborator change.\n\nQA fixture bindings: the deadline guard, capture, checkpoint and materialize command forms are in the installed qa/sections/exploratory.md this phase requires you to Read; use those forms verbatim with these bindings substituted literally. DEADLINE_TOOL = ${fixture.runtime}/bin/gstack-qa-deadline. EVIDENCE_TOOL = ${fixture.runtime}/bin/gstack-qa-evidence. PROBE_DIR = ${fixture.cwd}/reports. DEADLINE_FILE = ${fixture.cwd}/reports/deadline.json. SECONDS must be positive and at most 300. EARLIER_UTC is the optional caller absolute deadline: use the section clock's Hard deadline UTC, never its Runner entry UTC, reserve-start time or a clock-read time. The only native COMMAND is the existing diagnostic client, bun scripts/probe.ts, with zero or one literal argument. Resolve these exact helper and state paths; do not use variables, another helper, another state file, nested wrappers, scripts, operators or substitutions. Its diagnostic receipts are declared public/synthetic, so --public is approved. Only an explicit plan check this phase requires may use --timeout-ms 10000 in place of the deadline; every other capture, including a rerun or revalidation of an earlier probe, uses the deadline. This does not reset or bypass the smoke deadline. Only the deadline helper may create or change reports/deadline.json and its .qa-deadline- temporary files; never use Write/Edit/MultiEdit on those paths. Record the full outer command in checkpoints and evidence; keep the unchanged child JSON as observed, separate from prefixed guard diagnostics. A completed expired guard-run is not a probe or a pass: retain its unused checkpoint, report not-run coverage and do not restart the deadline. Keep the 12-probe smoke limit. Required suites and explicit plan checks are outside the bounded smoke budget, not permission to reset it. Quote arguments literally. Sources stay inside reports. Decide to execute the next probe before publishing its checkpoint, then await successful publication and dispatch that exact probe. I
Line truncated
|
||||
appendSystemPrompt: `Caller execution scheduling (fixture contract):
|
||||
This session has at most 25 assistant turns, including required verification and final artifacts. The command boundary applies to each Bash call, not to the number of independent tool calls in an assistant turn.
|
||||
After required clock and approval prerequisites settle, issue independent source Reads and read-only discovery together as separate native tool calls once their paths and inputs are known. Read-only discovery is Read, Glob, Grep and the declared inventory, Git and review-read forms; a capture, a deadline guard start or run, or a diagnostic-client run is a probe, never discovery. For example, after the first clock read, one response can Read the caller excerpt, README.md, every product file and the referenced checklist and templates. Wait for their results before decisions that depend on them.
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* #3527 put Step 9's review plan into ship/sections/review-army.md as prose, so the qa-callers transport
|
||||
* neither admitted the helper nor said where the plan's Step 11 voices run.
|
||||
* - Paid screen 40707142223 (ship-exploratory-plan-checks, slice 10 and its rerun): the only refused call in
|
||||
* both trials was `<runtime>/bin/gstack-review-plan --base main`.
|
||||
* - Train 35 rebuild gate 40664336141 (ship-exploratory-late-input, slice 9): the actor never ran the plan,
|
||||
* read Step 11's native adversarial pass as owed by this Steps 8-9 excerpt, and reported pass with it remaining.
|
||||
*/
|
||||
import { afterEach, describe, expect, test } from 'bun:test';
|
||||
import * as fs from 'node:fs';
|
||||
import * as os from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { bunIsolationArgs } from '../lib/bun-isolation';
|
||||
import {
|
||||
createQaCallerFixture, qaCallerCommandAllowed, qaCallerSessionOptions, validateCallerEvidence,
|
||||
type QaCallerCase, type QaCallerFixture,
|
||||
} from './helpers/qa-callers-fixture';
|
||||
|
||||
const captured = JSON.parse(fs.readFileSync(path.join(import.meta.dir, 'fixtures/qa-caller-review-plan-40707142223.json'), 'utf8'));
|
||||
const SHIP_CASES: QaCallerCase[] = ['ship-exploratory-small-cli', 'ship-exploratory-unavailable', 'ship-exploratory-plan-checks', 'ship-exploratory-late-input'];
|
||||
const fixtures: QaCallerFixture[] = [];
|
||||
afterEach(async () => {
|
||||
for (const fixture of fixtures.splice(0)) { await fixture.close(); fs.rmSync(fixture.root, { recursive: true, force: true }); }
|
||||
});
|
||||
const fixtureFor = (caseId: QaCallerCase, installRuntime = false) => {
|
||||
const fixture = createQaCallerFixture(caseId, { installRuntime });
|
||||
fixtures.push(fixture);
|
||||
return fixture;
|
||||
};
|
||||
const context = (fixture: QaCallerFixture) => ({ runtime: fixture.runtime, fixtureRoot: fixture.cwd });
|
||||
|
||||
describe('ship Step 9 review plan through the qa-callers transport', () => {
|
||||
for (const [run, trial] of Object.entries(captured.runs) as [string, { root: string; commands: { command: string }[] }][]) {
|
||||
test(`captured ${run}: every Bash call the actor made is inside the declared interface`, () => {
|
||||
const fixture = fixtureFor('ship-exploratory-plan-checks', true);
|
||||
const commands = trial.commands.map(({ command }) => command.replaceAll(trial.root, fixture.root));
|
||||
expect(commands.filter(command => command.includes('/bin/gstack-review-plan '))).toEqual([`${fixture.runtime}/bin/gstack-review-plan --base main`]);
|
||||
expect(commands.filter(command => !qaCallerCommandAllowed(command, fixture.workflowCommands, context(fixture)))).toEqual([]);
|
||||
});
|
||||
}
|
||||
|
||||
test('the helper forms Step 9 names are admitted at the exact installed path, and nothing else is', () => {
|
||||
const fixture = fixtureFor('ship-exploratory-late-input');
|
||||
const helper = `${fixture.runtime}/bin/gstack-review-plan`;
|
||||
const allowed = (command: string) => qaCallerCommandAllowed(command, fixture.workflowCommands, context(fixture));
|
||||
for (const args of ['--base main', '--base main --pass 1 --last full', '--base main --pass 2 --last fix-check --fixed-below --adversarial-ran',
|
||||
'--base main --pass 1 --last full --blocking-open --touched-gate --critical-found --reviewed-numbers fp:0a1b',
|
||||
'--fix-check-prompt --fix-list reports/fix-list.md --hunks reports/hunks.diff --tests reports/tests.txt',
|
||||
"--fix-check-prompt --fix-list 'reports/fix list.md' --hunks reports/h.diff --tests reports/t.txt --callers reports/c.txt"]) {
|
||||
expect(allowed(`${helper} ${args}`), args).toBe(true);
|
||||
}
|
||||
for (const command of [`${helper} --base origin/main`, `${helper} --base main --json`, `${helper} --base main --force all`,
|
||||
`${helper} --base main --last full --pass 1`, helper, `${helper} --base main | tee reports/plan.txt`, `${helper} --base main; rm -rf reports`,
|
||||
`${helper} --base main && git reset --hard`, `${helper} --base "$(git rev-parse HEAD)"`, `${helper} --fix-check-prompt --fix-list $HOME/x --hunks a --tests b`,
|
||||
`bun ${helper} --base main`, `${helper}x --base main`, `${fixture.runtime}/bin/gstack-review-planner --base main`,
|
||||
'/tmp/elsewhere/bin/gstack-review-plan --base main', '~/.claude/skills/gstack/bin/gstack-review-plan --base main']) {
|
||||
expect(allowed(command), command).toBe(false);
|
||||
}
|
||||
expect(qaCallerCommandAllowed(`${helper} --base main`, fixture.workflowCommands)).toBe(false);
|
||||
});
|
||||
|
||||
test.each(SHIP_CASES)('%s: every reviewer the real plan dispatches has a declared route in the transport', caseId => {
|
||||
const fixture = fixtureFor(caseId, true);
|
||||
const options = qaCallerSessionOptions(fixture, 'free-review-plan');
|
||||
expect(qaCallerCommandAllowed(`${fixture.runtime}/bin/gstack-review-plan --base main`, fixture.workflowCommands, context(fixture))).toBe(true);
|
||||
const plan = spawnSync(process.execPath, [...bunIsolationArgs(), path.join(fixture.runtime, 'bin/gstack-review-plan'), '--base', 'main'],
|
||||
{ cwd: fixture.cwd, env: { ...process.env, ...options.env }, encoding: 'utf8', timeout: 60_000 });
|
||||
expect(plan.status, plan.stderr).toBe(0);
|
||||
const roles = [...plan.stdout.matchAll(/^DISPATCH: (\S+)/gm)].map(match => match[1]);
|
||||
expect(roles).toContain('adversarial-native');
|
||||
const prompt = options.prompt.toLowerCase();
|
||||
for (const role of roles) expect(prompt.includes(role) || prompt.includes(role.replace('-', ' ')), role).toBe(true);
|
||||
expect(options.prompt).toContain("The plan's adversarial-native and outside-voice lines are Step 11's voices, which Step 11 runs in a later stage outside this excerpt; they are not remaining work of this phase.");
|
||||
});
|
||||
|
||||
test('review keeps its own Step 4.8 transport and is not told about ship Step 11', () => {
|
||||
const prompt = qaCallerSessionOptions(fixtureFor('review-exploratory-small-cli'), 'free-review-plan').prompt;
|
||||
expect(prompt).toContain('the native adversarial reviewer (Step 4.8)');
|
||||
expect(prompt).not.toContain('gstack-review-plan');
|
||||
expect(prompt).not.toContain("Step 11's voices");
|
||||
});
|
||||
|
||||
test('captured 40664336141 late-input receipt: pass with remaining work is still a false green', () => {
|
||||
const receipt = captured.lateInputReceipt;
|
||||
expect(receipt.remaining).toContain('Step 11 native adversarial review (not dispatched)');
|
||||
const reportRoot = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'qc-late-'));
|
||||
const validate = (remaining: string[]) => validateCallerEvidence({ caller: 'ship', result: { exitReason: 'success', transcript: [] }, probes: [],
|
||||
receipt: { status: receipt.status, probes: [], remaining }, currentSnapshot: 'none', requiredCharters: [], mutations: [], observerComplete: true,
|
||||
reportRoot, checkpointFiles: {}, reportMarkdown: '' });
|
||||
try {
|
||||
expect(validate(receipt.remaining)).toContain('blocked, failing or incomplete coverage reported green');
|
||||
expect(validate([])).not.toContain('blocked, failing or incomplete coverage reported green');
|
||||
} finally { fs.rmSync(reportRoot, { recursive: true, force: true }); }
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user