mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-01 14:34:42 +01:00
size: fit the wave's wording under ship, review and qa parity caps
Measured after all lane merges: ship -79, review -210, qa -68 bytes over. Trimmed the added wording first (post-expiry rule, MISSING COVERAGE, plan-gate default, value-card JSON, stop line) and folded /review's redundant INFORMATIONAL sentence and findings bullet. ship 268,036 (room 8), review 130,118 (room 1). qa needed 11 more bytes: cap 1.11 -> 1.1102 with the measured 93,305 / 84,049 = 1.11013 and its reason beside it.
This commit is contained in:
1 parent
7bd137d636
commit
3bd625d3b8
9 files changed
+22
-22
No files matched your search
@@ -176,7 +176,7 @@ ${outsideVoiceInvocation(ctx, { timeoutMs: 540000, nativeAlreadyRequired: true,
|
|||||||
${outsideVoiceFor(ctx).id === 'codex' ? 'The Codex backend uses `codex review --base` without a positional prompt: those arguments are mutually exclusive. Never drop --base to resolve an argv error; prompt-only review changes the diff scope.' : 'The Claude Code backend receives the parent-captured base diff, including committed and working-tree changes, because review mode cannot execute git.'}
|
${outsideVoiceFor(ctx).id === 'codex' ? 'The Codex backend uses `codex review --base` without a positional prompt: those arguments are mutually exclusive. Never drop --base to resolve an argv error; prompt-only review changes the diff scope.' : 'The Claude Code backend receives the parent-captured base diff, including committed and working-tree changes, because review mode cannot execute git.'}
|
||||||
|
|
||||||
Present output under \`${outsideVoiceFor(ctx).label.toUpperCase()} SAYS (code review):\` inside a \`tool-output\` fence.
|
Present output under \`${outsideVoiceFor(ctx).label.toUpperCase()} SAYS (code review):\` inside a \`tool-output\` fence.
|
||||||
Only a completed response with severity tags or an explicit no-findings conclusion establishes the gate. P0/P1 findings (\`[P0]\`/\`[P1]\` or native \`P0:\`/\`P1:\` labels; \`VERDICT: findings\`) → GATE: FAIL. Completed without P0/P1 → GATE: PASS. Refusal, failure, missing markers or \`OUTSIDE_STATUS: unverified\` → GATE: MISSING COVERAGE: no fix question; say so and never report the review clean.
|
Only a completed response with severity tags or an explicit no-findings conclusion establishes the gate. P0/P1 findings (\`[P0]\`/\`[P1]\` or native \`P0:\`/\`P1:\` labels; \`VERDICT: findings\`) → GATE: FAIL. Completed without P0/P1 → GATE: PASS. Refusal, failure, missing markers or \`OUTSIDE_STATUS: unverified\` → GATE: MISSING COVERAGE; no fix question.
|
||||||
|
|
||||||
If GATE is FAIL, use AskUserQuestion:
|
If GATE is FAIL, use AskUserQuestion:
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|||||||
@@ -467,14 +467,13 @@ The plan completion results augment the existing Scope Drift Detection. If a pla
|
|||||||
|
|
||||||
- **NOT DONE items** become additional evidence for **MISSING REQUIREMENTS** in the scope drift report.
|
- **NOT DONE items** become additional evidence for **MISSING REQUIREMENTS** in the scope drift report.
|
||||||
- **Items in the diff that don't match any plan item** become evidence for **SCOPE CREEP** detection.
|
- **Items in the diff that don't match any plan item** become evidence for **SCOPE CREEP** detection.
|
||||||
- **HIGH-impact plan-file discrepancies** trigger AskUserQuestion:
|
- **HIGH-impact plan-file discrepancies** trigger AskUserQuestion showing the investigation findings:
|
||||||
- Show the investigation findings
|
|
||||||
- Options: A) Stop this review for implementation, B) Continue this review with P1 TODOs, C) Record the items as intentionally dropped
|
- Options: A) Stop this review for implementation, B) Continue this review with P1 TODOs, C) Record the items as intentionally dropped
|
||||||
- A ends this invocation before code review or implementation. List the missing work; after implementation, start a fresh /review.
|
- A ends this invocation before code review or implementation. List the missing work; after implementation, start a fresh /review.
|
||||||
- B queues the approved TODO changes for Step 5, not this read-only audit. B/C continue to the final Scope Check and Step 2. None of these choices authorizes shipping or waives required verification.
|
- B queues the approved TODO changes for Step 5, not this read-only audit. B/C continue to the final Scope Check and Step 2. None of these choices authorizes shipping or waives required verification.
|
||||||
- Spawned or non-interactive runs ask nothing: report REQUIREMENTS MISSING with the items and continue, writing no TODOs and dropping nothing.
|
- Spawned or non-interactive: report REQUIREMENTS MISSING, continue; record nothing.
|
||||||
|
|
||||||
This is **INFORMATIONAL** unless HIGH-impact plan-file discrepancies are found (then it gates via AskUserQuestion).
|
Otherwise the audit is **INFORMATIONAL**.
|
||||||
Discrepancies derived only from fallback sources (commit messages, TODOS.md, PR description) never trigger
|
Discrepancies derived only from fallback sources (commit messages, TODOS.md, PR description) never trigger
|
||||||
this question, whatever their IMPACT: report them in the Scope Check as lower-confidence missing requirements.
|
this question, whatever their IMPACT: report them in the Scope Check as lower-confidence missing requirements.
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Without a total time limit, do not create DEADLINE_FILE; announce finite command
|
|||||||
Stop when scoped contracts are tested or blocked.
|
Stop when scoped contracts are tested or blocked.
|
||||||
Clocks/checkpoints use REPORT_DIR; mixed standalone runs use REPORT_DIR/browser and REPORT_DIR/functional, with one final report at REPORT_DIR. Caller paths win.
|
Clocks/checkpoints use REPORT_DIR; mixed standalone runs use REPORT_DIR/browser and REPORT_DIR/functional, with one final report at REPORT_DIR. Caller paths win.
|
||||||
Names used below (quote every path):
|
Names used below (quote every path):
|
||||||
- PROBE_DIR: this surface's probe directory from the line above. DEADLINE_FILE: \`PROBE_DIR/deadline.json\`, which exists only for a bounded run.
|
- PROBE_DIR: this surface's probe directory per the line above. DEADLINE_FILE: \`PROBE_DIR/deadline.json\`, which exists only for a bounded run.
|
||||||
- SECONDS: the total probe budget set above. NNN: a fresh three-digit ID (001, 002, ...) for each capture or checkpoint; never reuse one.
|
- SECONDS: the total probe budget set above. NNN: a fresh three-digit ID (001, 002, ...) for each capture or checkpoint; never reuse one.
|
||||||
- DEADLINE_TOOL = \`${quoteSafePath(ctx.paths.binDir)}/gstack-qa-deadline\`, the deadline guard: \`start\` creates DEADLINE_FILE, \`status\` prints \`remainingMs\` and \`expired\`, and \`run\` executes one command, stopping it at the deadline.
|
- DEADLINE_TOOL = \`${quoteSafePath(ctx.paths.binDir)}/gstack-qa-deadline\`, the deadline guard: \`start\` creates DEADLINE_FILE, \`status\` prints \`remainingMs\` and \`expired\`, and \`run\` executes one command, stopping it at the deadline.
|
||||||
- EVIDENCE_TOOL = \`${quoteSafePath(ctx.paths.binDir)}/gstack-qa-evidence\`, the functional evidence recorder: \`capture\` runs one command, stores its exit code, stdout and stderr under \`PROBE_DIR/.qa-evidence/NNN/\`, and prints status \`complete\`, \`incomplete\` or \`sensitive\`.
|
- EVIDENCE_TOOL = \`${quoteSafePath(ctx.paths.binDir)}/gstack-qa-evidence\`, the functional evidence recorder: \`capture\` runs one command, stores its exit code, stdout and stderr under \`PROBE_DIR/.qa-evidence/NNN/\`, and prints status \`complete\`, \`incomplete\` or \`sensitive\`.
|
||||||
@@ -103,7 +103,7 @@ How one probe works: (1) if bounded, check the clock and choose the next command
|
|||||||
|
|
||||||
1. First demonstrate success: output AND durable effects. Guard if bounded; await completion.
|
1. First demonstrate success: output AND durable effects. Guard if bounded; await completion.
|
||||||
2. **Decide whether another probe is needed.** If bounded, run \`bun DEADLINE_TOOL status DEADLINE_FILE\`.
|
2. **Decide whether another probe is needed.** If bounded, run \`bun DEADLINE_TOOL status DEADLINE_FILE\`.
|
||||||
If expired or no safe next probe remains, STOP exploration; write the report, not a checkpoint: go to §4 (annotations, materialize, then Markdown).
|
If expired or no safe next probe remains, STOP exploration; write the report (§4), not a checkpoint.
|
||||||
${reportOnly ? ` **Classify the last result before copying it.** For public or synthetic observations,
|
${reportOnly ? ` **Classify the last result before copying it.** For public or synthetic observations,
|
||||||
retain the entire result unchanged, including owned fixture paths, IDs, hashes and
|
retain the entire result unchanged, including owned fixture paths, IDs, hashes and
|
||||||
existing credential placeholders. An absolute state path is not itself a secret.
|
existing credential placeholders. An absolute state path is not itself a secret.
|
||||||
@@ -263,7 +263,7 @@ Never install, import cookies or bootstrap tests. Functional-only skips browser
|
|||||||
|
|
||||||
**3. Run smoke and plan checks.**
|
**3. Run smoke and plan checks.**
|
||||||
Follow the shared Probe loop for smoke checks and replays until the smoke limit.
|
Follow the shared Probe loop for smoke checks and replays until the smoke limit.
|
||||||
Then run required plan checks and revalidation, even after smoke expires, using the same procedure but no smoke guard; never reset the clock. Their checkpoints sit beside DEADLINE_FILE; they skip \`DEADLINE_TOOL status DEADLINE_FILE\` and use \`--timeout-ms\`, not \`--deadline DEADLINE_FILE\`. After smoke expiry, step 4c reruns plan checks only; affected smoke checks are not-run.
|
Then run required plan checks and revalidation, even after smoke expires, using the same procedure but no smoke guard; never reset the clock. Their checkpoints sit beside DEADLINE_FILE; they skip \`DEADLINE_TOOL status DEADLINE_FILE\` and use \`--timeout-ms\`, not \`--deadline DEADLINE_FILE\`. Post-expiry smoke rechecks are not-run, even in 4c.
|
||||||
Use finite command timeouts, capped at the caller's remaining time if it has a deadline.${ship ? '' : ' /review sets none; only an invoker-supplied EARLIER_UTC counts.'}
|
Use finite command timeouts, capped at the caller's remaining time if it has a deadline.${ship ? '' : ' /review sets none; only an invoker-supplied EARLIER_UTC counts.'}
|
||||||
Await clock/guard results before acting. When the caller's deadline expires, mark unfinished checks not-run.
|
Await clock/guard results before acting. When the caller's deadline expires, mark unfinished checks not-run.
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ function cardRules(mode: TestValueBarMode, skillName: string): string {
|
|||||||
qa: skillName === 'qa-only' ? 'Put it under each proposed test.' : 'Put it in the 8e.5 record.',
|
qa: skillName === 'qa-only' ? 'Put it under each proposed test.' : 'Put it in the 8e.5 record.',
|
||||||
audit: 'Read cards from test header comments when present.',
|
audit: 'Read cards from test header comments when present.',
|
||||||
}[mode];
|
}[mode];
|
||||||
return `Value card: \`Value: protects=<...>; fails_when=<...>; why_new=<...>; seam=none\` (seam: \`none\` or its name); each field at most ${CARD_FIELD_MAX_BYTES} UTF-8 bytes here (clamp to 157 plus \`...\`; JSON records you write keep full values). ${where} A missing upstream card never blocks: derive it; ignore unknown fields.
|
return `Value card: \`Value: protects=<...>; fails_when=<...>; why_new=<...>; seam=none\` (seam: \`none\` or its name); each field at most ${CARD_FIELD_MAX_BYTES} UTF-8 bytes here (clamp to 157 plus \`...\`; written JSON keeps full values). ${where} A missing upstream card never blocks: derive it; ignore unknown fields.
|
||||||
|
|
||||||
Example: ${EXAMPLE_CARD}
|
Example: ${EXAMPLE_CARD}
|
||||||
${EXAMPLE_REJECTED}`;
|
${EXAMPLE_REJECTED}`;
|
||||||
|
|||||||
@@ -668,7 +668,7 @@ do not launch the downstream skill or open a browser.`,
|
|||||||
},
|
},
|
||||||
behavioral: 'prompt',
|
behavioral: 'prompt',
|
||||||
maxSkeletonBytes: 63_500, // + v2.0 {{ASIDE_SETUP}}/{{BROWSE_FALLBACK}} (replaces the browse setup block); measured 61_253
|
maxSkeletonBytes: 63_500, // + v2.0 {{ASIDE_SETUP}}/{{BROWSE_FALLBACK}} (replaces the browse setup block); measured 61_253
|
||||||
maxSizeRatio: 1.110, // + v1.81 Aside contract + gstack-browser fallback block (1.080 on v1.91.7.0) + the shared test value bar at 8a.5 ({{TEST_VALUE_BAR:qa}}); measured 1.094 + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.101 (2026-09-30) + v1.91.12.0 merge of #2999 (await scope/method Reads, capture --after checkpoints, browser-only empty evidence list) with #3002; measured 1.1028 (2026-10-01). + both untrusted-content marker formats in the browser fallback (W7f); measured 1.1035 (2026-10-02). Re-measured 1.1038 after the W8 probe-loop renames (2026-10-03); the cap already matches. + the annotate-every-capture and superseded rule before materialize (a ship-exploratory-late-input run published evidence that omitted older-snapshot captures); measured 1.1064 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 93,282 / 84,049 = 1.1099 (2026-10-04).
|
maxSizeRatio: 1.1102, // + v1.81 Aside contract + gstack-browser fallback block (1.080 on v1.91.7.0) + the shared test value bar at 8a.5 ({{TEST_VALUE_BAR:qa}}); measured 1.094 + W1 guarded state-root resolution (`eval gstack-paths; : "${GSTACK_STATE_ROOT:?…}"`) in the Context Recovery preamble, the eureka log and each state-writing bash block; measured 1.101 (2026-09-30) + v1.91.12.0 merge of #2999 (await scope/method Reads, capture --after checkpoints, browser-only empty evidence list) with #3002; measured 1.1028 (2026-10-01). + both untrusted-content marker formats in the browser fallback (W7f); measured 1.1035 (2026-10-02). Re-measured 1.1038 after the W8 probe-loop renames (2026-10-03); the cap already matches. + the annotate-every-capture and superseded rule before materialize (a ship-exploratory-late-input run published evidence that omitted older-snapshot captures); measured 1.1064 (2026-10-03). + v1.91.18.0 (#3023) merged into the v1.91.19.0 wave; measured 93,282 / 84,049 = 1.1099 (2026-10-04). + reliability follow-ups C2 (judge-named gaps after trimming the added wording: feasible 180 s Browser Quick, PROBE_DIR's source line, stop goes to the §4 report, written JSON keeps full card values; lane S's {user}/timing fields); measured 93,305 / 84,049 = 1.11013 (2026-10-04).
|
||||||
minUnionBytes: 69_500, // measured union 70,385
|
minUnionBytes: 69_500, // measured union 70,385
|
||||||
// 'aside repl' pins the Aside contract; '$B goto' pins the fallback block in the always-loaded skeleton.
|
// 'aside repl' pins the Aside contract; '$B goto' pins the fallback block in the always-loaded skeleton.
|
||||||
mustContain: ['bug', 'aside repl', '$B goto', 'fix', 'Health Score Rubric', 'regression'],
|
mustContain: ['bug', 'aside repl', '$B goto', 'fix', 'Health Score Rubric', 'regression'],
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ test('adversarial outside failures retain the required native pass without dupli
|
|||||||
expect(output).toContain('GATE: MISSING COVERAGE');
|
expect(output).toContain('GATE: MISSING COVERAGE');
|
||||||
// C2: the gate names what missing coverage does instead of an unnamed "existing user decision flow".
|
// C2: the gate names what missing coverage does instead of an unnamed "existing user decision flow".
|
||||||
if (output.includes('Only a completed response with severity tags')) {
|
if (output.includes('Only a completed response with severity tags')) {
|
||||||
expect(output).toContain('→ GATE: MISSING COVERAGE: no fix question; say so and never report the review clean.');
|
expect(output).toContain('→ GATE: MISSING COVERAGE; no fix question.');
|
||||||
|
expect(outsideVoiceInvocation(ctx)).toContain('missing coverage is never clean/PASS');
|
||||||
expect(output).not.toContain('preserve the existing user decision flow');
|
expect(output).not.toContain('preserve the existing user decision flow');
|
||||||
}
|
}
|
||||||
expect(outsideVoiceInvocation(ctx)).toContain("Use the caller's fallback; missing coverage is never clean/PASS.");
|
expect(outsideVoiceInvocation(ctx)).toContain("Use the caller's fallback; missing coverage is never clean/PASS.");
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ describe('QA probe entry and checkpoint gates', () => {
|
|||||||
const write = text.indexOf('**Publish before probing.**');
|
const write = text.indexOf('**Publish before probing.**');
|
||||||
expect(decision).toBeGreaterThan(-1);
|
expect(decision).toBeGreaterThan(-1);
|
||||||
expect(decision).toBeLessThan(write);
|
expect(decision).toBeLessThan(write);
|
||||||
expect(text.slice(decision, write)).toMatch(/write the report, not a checkpoint/i);
|
expect(text.slice(decision, write)).toMatch(/write the report\b[^.\n]*, not a checkpoint/i);
|
||||||
expect(text.slice(decision, write)).toMatch(/if expired/i);
|
expect(text.slice(decision, write)).toMatch(/if expired/i);
|
||||||
expect(text.slice(decision, write)).not.toContain('If done or blocked');
|
expect(text.slice(decision, write)).not.toContain('If done or blocked');
|
||||||
if (skillName === 'qa-only') {
|
if (skillName === 'qa-only') {
|
||||||
@@ -314,23 +314,23 @@ describe('judge-named QA workflow gaps (C2)', () => {
|
|||||||
for (const skillName of ['qa', 'qa-only']) {
|
for (const skillName of ['qa', 'qa-only']) {
|
||||||
const text = generateQAExploratory(ctx(skillName));
|
const text = generateQAExploratory(ctx(skillName));
|
||||||
const layout = text.indexOf('mixed standalone runs use REPORT_DIR/browser and REPORT_DIR/functional');
|
const layout = text.indexOf('mixed standalone runs use REPORT_DIR/browser and REPORT_DIR/functional');
|
||||||
const probeDir = text.indexOf("PROBE_DIR: this surface's probe directory from the line above.");
|
const probeDir = text.indexOf("PROBE_DIR: this surface's probe directory per the line above.");
|
||||||
expect(layout).toBeGreaterThan(-1);
|
expect(layout).toBeGreaterThan(-1);
|
||||||
expect(probeDir).toBeGreaterThan(layout);
|
expect(probeDir).toBeGreaterThan(layout);
|
||||||
expect(text.slice(layout, probeDir).split('\n')).toHaveLength(3);
|
expect(text.slice(layout, probeDir).split('\n')).toHaveLength(3);
|
||||||
expect(text).toContain('write the report, not a checkpoint: go to §4 (annotations, materialize, then Markdown)');
|
expect(text).toContain('write the report (§4), not a checkpoint.');
|
||||||
const final = text.indexOf('## 4. Final report');
|
const final = text.indexOf('## 4. Final report');
|
||||||
expect(final).toBeGreaterThan(-1);
|
expect(final).toBeGreaterThan(-1);
|
||||||
expect(text.indexOf('annotations.json', final)).toBeLessThan(text.indexOf('materialize PROBE_DIR', final));
|
expect(text.indexOf('annotations.json', final)).toBeLessThan(text.indexOf('materialize PROBE_DIR', final));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('/review and /ship: after smoke expiry only plan checks rerun in revalidation', () => {
|
test('/review and /ship: step 4c revalidation does not rerun smoke checks after smoke expiry', () => {
|
||||||
for (const skillName of ['review', 'ship']) {
|
for (const skillName of ['review', 'ship']) {
|
||||||
const text = generateQAReview(ctx(skillName));
|
const text = generateQAReview(ctx(skillName));
|
||||||
expect(text).toContain('After smoke expiry, step 4c reruns plan checks only; affected smoke checks are not-run.');
|
const rule = text.indexOf('Post-expiry smoke rechecks are not-run, even in 4c.');
|
||||||
expect(text).toContain('c. Re-review changed or uncertain coverage and repeat step 3 for affected checks.');
|
expect(rule).toBeGreaterThan(-1);
|
||||||
expect(text).not.toContain('Post-expiry smoke rechecks are not-run.');
|
expect(rule).toBeLessThan(text.indexOf('c. Re-review changed or uncertain coverage and repeat step 3 for affected checks.'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -318,8 +318,8 @@ test('review finalization ownership: the plan audit retains its high-impact gate
|
|||||||
expect(flatAudit).toContain('B/C continue to the final Scope Check and Step 2');
|
expect(flatAudit).toContain('B/C continue to the final Scope Check and Step 2');
|
||||||
expect(flatAudit).toMatch(/none of these choices authorizes shipping or waives required verification/i);
|
expect(flatAudit).toMatch(/none of these choices authorizes shipping or waives required verification/i);
|
||||||
// C2: a spawned or non-interactive review cannot answer the question; its default writes and drops nothing.
|
// C2: a spawned or non-interactive review cannot answer the question; its default writes and drops nothing.
|
||||||
expect(flatAudit).toContain('Spawned or non-interactive runs ask nothing: report REQUIREMENTS MISSING with the items and continue, writing no TODOs and dropping nothing.');
|
expect(flatAudit).toContain('Spawned or non-interactive: report REQUIREMENTS MISSING, continue; record nothing.');
|
||||||
expect(flatAudit.indexOf('Spawned or non-interactive runs ask nothing')).toBeLessThan(flatAudit.indexOf('When continuing after the audit'));
|
expect(flatAudit.indexOf('Spawned or non-interactive: report')).toBeLessThan(flatAudit.indexOf('When continuing after the audit'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('review scope notes remain provisional until the plan section emits the only final scope check', () => {
|
test('review scope notes remain provisional until the plan section emits the only final scope check', () => {
|
||||||
|
|||||||
@@ -83,9 +83,9 @@ describe('test value bar render contract', () => {
|
|||||||
expect(Buffer.byteLength(rendered, 'utf8')).toBeLessThanOrEqual(TEST_VALUE_BAR_MAX_BYTES[mode]);
|
expect(Buffer.byteLength(rendered, 'utf8')).toBeLessThanOrEqual(TEST_VALUE_BAR_MAX_BYTES[mode]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the card clamp applies to card lines only; JSON records keep full values (C2)', () => {
|
test('the card clamp applies to card lines only; written JSON keeps full values (C2)', () => {
|
||||||
for (const mode of TEST_VALUE_BAR_MODES) {
|
for (const mode of TEST_VALUE_BAR_MODES) {
|
||||||
expect(bar(mode)).toContain(`each field at most ${CARD_FIELD_MAX_BYTES} UTF-8 bytes here (clamp to 157 plus \`...\`; JSON records you write keep full values)`);
|
expect(bar(mode)).toContain(`each field at most ${CARD_FIELD_MAX_BYTES} UTF-8 bytes here (clamp to 157 plus \`...\`; written JSON keeps full values)`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user