Files
gstack/scripts/resolvers/sideways.ts
T
garrytanandcapy-ai[bot] 79ac33c96e fix(flaky): repair the five paid gate detectors and the judged review/plan-review prose (GSTA-128)
Daily flaky pass over the 2026-10-27 Open ledger entries, paid cases first.

- ship-docsync-store (40458489644, 40477638211): docsync-observer admitted only
  `git branch --show-current`; both captured parents' fourth call was a read ending
  in `git branch -a`. Operand-free branch listings are now part of the read grammar.
- ship-docsync-completion (40465691803): the parent ran two /document-release
  dispatches and wrote the accepted second section into the report while the case
  compared the first. The contract now follows the last foreground dispatch.
- ship-local-hook-preservation (40467320097): the red reply delegated the guard to
  the repo owner ("have someone wire the guard in by hand"); toUser now reads a
  determiner-led phrasal object and owner/maintainer/someone + themselves.
- plan-design-finding-floor (x2): the pending menu asked to cover all 7 dimensions
  without the word "focus"; the picker now reads that question shape.
- Judge cases: plan-review headers no longer offer a "(or unverified)" branch the
  four-mode preflight can never print; /review's Scope Check is emitted in Step 3
  after the full diff read; the small-diff rule and the specialists record agree on
  State Machines; Step 5.8.2 names which post-fix rerun rule governs. Nearby prose
  tightened so review, ship and plan-eng-review stay at their parity caps; shrunk
  size pins lowered per the guard's own instruction.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
2026-10-27 14:11:17 +00:00

56 lines
3.8 KiB
TypeScript

/**
* Sideways review (multi-agent wave D2, shared with D3's flake recipe).
*
* A finding is a defect class, not a line: the same pattern usually sits at
* another ingress, command or call site, and the severity is the worst
* sibling's. These resolvers render that rule once:
*
* {{SIDEWAYS_SWEEP}} review Step 4: sweep + the forced-CRITICAL list
* {{SIDEWAYS_SWEEP:cso}} /cso Phase 12: the sibling sweep only (D2: nothing else)
* {{FLAKE_FIX_NUMBER:review}} a test-only flake fix needs P(fail | regression) before and after
* {{FLAKE_FIX_NUMBER:investigate}}
* the same number, as the flake recipe computes it
*
* `undeclaredBehaviorLines()` is the Scope Check addition the plan-completion
* resolver (scripts/resolvers/plan-gates.ts, review mode) renders: diff
* behavior the author's summary omits, and no approval without a recorded
* full-diff read. The forced-CRITICAL classes are data so the review checklist
* test and the rendered prose cannot drift (decision D8a: CRITICAL/INFORMATIONAL
* stay the vocabulary; the list is what no lane may downgrade).
*/
import type { TemplateContext } from './types';
export const FORCED_CRITICAL = ['data loss', 'trust-boundary bypass', 'uncapped spend'] as const;
export function forcedCriticalPhrase(): string {
return 'data loss, a trust-boundary bypass or uncapped spend';
}
export function generateSidewaysSweep(_ctx: TemplateContext, args?: string[]): string {
if (args?.[0] === 'cso') {
return 'After supporting a finding, grep its pattern at every other in-scope ingress, command and call site; severity follows the worst sibling.';
}
return `**Sideways sweep (every finding; reads code OUTSIDE the diff).** Grep the finding's pattern at every other ingress, command and call site, Read each match and rate severity on the worst sibling; a new enum value, status, tier or type constant is traced through every consumer the same way (checklist: Sideways sweep). ${forcedCriticalPhrase().replace(/^d/, 'D')} is forced CRITICAL: no lane, specialist, dedup or saved decision downgrades it. Keep findings anchored to changed code.`;
}
export function generateFlakeFixNumber(_ctx: TemplateContext, args?: string[]): string {
if (args?.[0] === 'investigate') {
return `**The flake-fix number.** A fix that touches only the test (a wider timeout, a retry,
a looser assertion, a skip) must state \`P(fail | regression)\`: the probability the test
still fails when the behavior it guards regresses, before and after the change. Derive
it from the forced probe (break the behavior on purpose, run the test N times, count
failures) and write both numbers in \`## Flake evidence\`. A number that drops is a gate
relaxation (review tag RH-15) and needs the owner's decision, not a merge.`;
}
return `A test-only flake fix (timeout, retry, looser assertion, skip) states \`P(fail | regression)\` before and after, from a forced probe; without both numbers it is RH-15.`;
}
/** The Scope Check lines the review-mode plan-completion audit adds (D2). */
export function undeclaredBehaviorLines(): { fields: string; rule: string } {
return {
fields: `Diff read: full (<n> files, <m> hunks) | partial (<unread paths>)
Undeclared behavior changes: <behavior the diff changes that the PR body, commit messages and plan do not state> | none`,
rule: `\`Diff read\` records Step 3's full-diff read; \`Scope Check: CLEAN\`, and options B and C above, count as approved only with \`Diff read: full\` recorded. A partial read is \`DRIFT DETECTED\` naming the unread paths. \`Undeclared behavior changes\` lists every behavior the diff changes (a default, an exit code, a stored value, a route, a side effect) that the author's own summary omits; each is a Scope Check item for the reviewer, never silently CLEAN.`,
};
}