fix(autofix): close the escape hatches the review found in the weakening gate

- count-test-surface: see through type-only wrappers (`as`, `<T>x`,
  `satisfies`, `!`) in constant folding, options objects and call
  chains; fold comparison/equality/logical operators of two constants;
  treat template-literal returns as non-thenable
- count-test-surface: an `if (true)` wrapper or a catch whose try holds
  an assertion no longer shelters a body skip; a registration callback
  handed by name resolves to its module-scope binding; a collector
  factory binding (it.skipIf / it.each / test.extend) registers nothing
- af-155: charge a regression only when the run's window IS the live
  re-arm key, and never stamp pre=green when the push carries a merge
  past the head prepare classified
- tests: exercise all five own-lane names in the charge classifier, and
  gate the verbatim staging witness on the host having sha256sum

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
qwen-code-dev-bot 2026-09-09 11:50:17 +00:00
parent d089bd867b
commit a211bc0851
5 changed files with 597 additions and 154 deletions

View file

@ -619,6 +619,11 @@ if [[ "${OUTCOME}" == "fixed" ]]; then
PUSH_PRE="${CHECK_STATE:-none}"
[[ "${PUSH_RACE_MERGED}" == 'true' ]] && PUSH_PRE='none'
[[ "${CONFLICT:-false}" == 'true' ]] && PUSH_PRE='none'
# A merge commit between the head prepare classified and the head this
# round pushes -- a clean in-round merge of main trips neither arm above
# -- means the pushed head carries content prepare never classified: the
# premise is unknown, and an unknown premise is never green.
[[ -n "$(git rev-list --merges "${REPORT_HEAD}..${PUSHED_HEAD}" 2>/dev/null)" ]] && PUSH_PRE='none'
{
echo "🤖 Addressed the latest review feedback (round ${NEXT_ROUND}/${MAX_ROUNDS}). What changed, and what I pushed back on: · 已处理最新评审反馈(第 ${NEXT_ROUND}/${MAX_ROUNDS} 轮)。改动内容与我反驳保留之处如下:"
echo

View file

@ -47,23 +47,33 @@
// `fails` is a truthy constant (vitest truthy-checks them, so a reason
// string disables), a body-level `skip()`/`ctx.skip()` whose first
// argument is absent or any constant other than `false` (the runner's
// own rule) and that is not itself under a condition, and every
// registration nested inside a disabled `describe`. A body skip at file
// own rule) and that is not itself under a REAL condition — an
// `if (true)` wrapper never withholds its branch, and a `catch`
// whose `try` holds an assertion fires exactly when that assertion
// fails, so neither shelters a skip — and every registration
// nested inside a disabled `describe`. A body skip at file
// scope — a statement of the module, or inside a `beforeEach`/
// `beforeAll`/`afterEach`/`afterAll` callback the file registers —
// disables the whole file, which is what the runner does with it. A
// constant is a literal of any kind (object, array, regex and bigint
// included), `undefined`/`void 0`/`NaN`/`Infinity`, a unary
// `!`/`-`/`+`/`~` of a constant, or `+` of two constants.
// registration callback handed by NAME resolves to the single
// module-scope function declaration or function-valued variable
// initializer of that name — the runner receives that very
// function — while an absent, redeclared or nested binding stays
// opaque. A constant is a literal of any kind (object, array,
// regex and bigint included), `undefined`/`void 0`/`NaN`/`Infinity`,
// a unary `!`/`-`/`+`/`~` of a constant, `+` of two string/number
// constants, a comparison or equality of two primitive constants,
// a logical `&&`/`||`/`??` of two constants, and any of those
// behind a type-only wrapper (`as`, `<T>x`, `satisfies`, `!`).
// Deliberately NOT measured, because they are runtime facts the runner is the
// authority for, not declarations: whether an assertion is REACHABLE (dead
// code, a condition that is false in CI, a helper never called), a
// condition-valued guard (`it.skipIf(process.platform === 'win32')`,
// `skip(cond, reason)`, `if (cond) ctx.skip()`, a skip in a `catch` —
// this repository's environment-guard idiom; the assertions an honest
// guard shelters are measured, its condition is not), and options or
// collector names carried by a binding (`test('x', opts, fn)`,
// `it[S]('x')`).
// `skip(cond, reason)`, `if (cond) ctx.skip()`, a skip in a `catch`
// whose `try` asserts nothing — this repository's environment-guard
// idiom; the assertions an honest guard shelters are measured, its
// condition is not), and options or collector names carried by a
// binding (`test('x', opts, fn)`, `it[S]('x')`).
//
// `measure` takes {"path", "tip", "pre", "events":
// [{"before", "after", "landed", "mainHolds"}]} — blob files (null =
@ -145,15 +155,36 @@ function isStringLike(n) {
return ts.isStringLiteral(n) || ts.isNoSubstitutionTemplateLiteral(n);
}
// Type-only wrappers carry no value of their own — `as T`, `<T>x`,
// `x satisfies T`, `x!` and parentheses all evaluate to their operand —
// so every fold in constant() and the options-object test see through
// them. `await` and `void` are NOT transparent (one unwraps a thenable,
// the other discards the value) and keep their own handling instead.
function unwrap(node) {
let n = node;
while (
ts.isParenthesizedExpression(n) ||
ts.isNonNullExpression(n) ||
ts.isAsExpression(n) ||
ts.isTypeAssertionExpression(n) ||
(ts.isSatisfiesExpression && ts.isSatisfiesExpression(n))
) {
n = n.expression;
}
return n;
}
// The constant value of an expression the parser can decide without a
// binding: literals of every kind (including object, array, regex and
// bigint), `undefined`/`void 0`/`NaN`/`Infinity`, a unary `!`/`-`/`+`/`~`
// of a constant, `+` of two constants, parentheses. `{ known: false }`
// for anything else — so one operator away from a shape this folds is
// never one operator away from escaping a signal.
// of a constant, `+` of two string/number constants, a comparison or
// equality of two primitive constants, a logical `&&`/`||`/`??` of two
// constants, and any of those behind a type-only wrapper. `{ known:
// false }` for anything else — so one operator away from a shape this
// folds is never one operator away from escaping a signal.
function constant(node) {
if (!node) return { known: false };
if (ts.isParenthesizedExpression(node)) return constant(node.expression);
node = unwrap(node);
if (node.kind === ts.SyntaxKind.TrueKeyword)
return { known: true, value: true };
if (node.kind === ts.SyntaxKind.FalseKeyword)
@ -198,20 +229,76 @@ function constant(node) {
return { known: false };
}
}
if (
ts.isBinaryExpression(node) &&
node.operatorToken.kind === ts.SyntaxKind.PlusToken
) {
if (ts.isBinaryExpression(node)) {
const l = constant(node.left);
const r = constant(node.right);
if (
l.known &&
r.known &&
(typeof l.value === 'string' || typeof l.value === 'number') &&
(typeof r.value === 'string' || typeof r.value === 'number')
) {
return { known: true, value: l.value + r.value };
if (!l.known || !r.known) return { known: false };
const op = node.operatorToken.kind;
// The logical operators select an operand by truthiness alone, which
// the object/array/regex placeholder (`true`) answers faithfully.
if (op === ts.SyntaxKind.AmpersandAmpersandToken) {
return { known: true, value: l.value ? r.value : l.value };
}
if (op === ts.SyntaxKind.BarBarToken) {
return { known: true, value: l.value ? l.value : r.value };
}
if (op === ts.SyntaxKind.QuestionQuestionToken) {
return {
known: true,
value: l.value === null || l.value === undefined ? r.value : l.value,
};
}
if (op === ts.SyntaxKind.PlusToken) {
if (
(typeof l.value === 'string' || typeof l.value === 'number') &&
(typeof r.value === 'string' || typeof r.value === 'number')
) {
return { known: true, value: l.value + r.value };
}
return { known: false };
}
// Comparison and equality evaluate natively — JS semantics ARE the
// runner's — but only on primitives: the object/array/regex fold is a
// truthiness placeholder, not a value (`{} === {}` must never fold
// true), and a bigint literal folds to a Number for arithmetic, which
// `1n === 1` would mis-fold.
const opaque = (n) => {
const u = unwrap(n);
return (
ts.isObjectLiteralExpression(u) ||
ts.isArrayLiteralExpression(u) ||
ts.isRegularExpressionLiteral(u) ||
ts.isBigIntLiteral(u)
);
};
if (opaque(node.left) || opaque(node.right)) return { known: false };
const a = l.value;
const b = r.value;
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken) {
return { known: true, value: a === b };
}
if (op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
return { known: true, value: a !== b };
}
if (op === ts.SyntaxKind.EqualsEqualsToken) {
return { known: true, value: a == b };
}
if (op === ts.SyntaxKind.ExclamationEqualsToken) {
return { known: true, value: a != b };
}
if (op === ts.SyntaxKind.LessThanToken) {
return { known: true, value: a < b };
}
if (op === ts.SyntaxKind.LessThanEqualsToken) {
return { known: true, value: a <= b };
}
if (op === ts.SyntaxKind.GreaterThanToken) {
return { known: true, value: a > b };
}
if (op === ts.SyntaxKind.GreaterThanEqualsToken) {
return { known: true, value: a >= b };
}
return { known: false };
}
return { known: false };
}
@ -255,7 +342,15 @@ function chainOf(call) {
) {
segments.push({ member: memberName(n) });
n = n.expression;
} else if (ts.isNonNullExpression(n) || ts.isParenthesizedExpression(n)) {
} else if (
ts.isNonNullExpression(n) ||
ts.isParenthesizedExpression(n) ||
ts.isAsExpression(n) ||
ts.isTypeAssertionExpression(n) ||
(ts.isSatisfiesExpression && ts.isSatisfiesExpression(n))
) {
// Type-only wrappers are chain-transparent: `(it as any).skip(...)`
// IS a skip of `it`.
n = n.expression;
} else {
break;
@ -340,16 +435,18 @@ function propertyName(name) {
}
function optionsDisable(call) {
return (call.arguments ?? []).some(
(o) =>
return (call.arguments ?? []).some((arg) => {
const o = unwrap(arg);
return (
ts.isObjectLiteralExpression(o) &&
o.properties.some(
(p) =>
ts.isPropertyAssignment(p) &&
DISABLING_OPTIONS.has(propertyName(p.name)) &&
truthyConstant(p.initializer),
),
);
)
);
});
}
function titleOf(call, sf) {
@ -387,15 +484,34 @@ function isBodySkip({ root, members, calls }) {
return c.known && c.value !== false;
}
// True when `node` sits under a condition inside the nearest enclosing
// function: an if/switch/loop, a ternary, or a short-circuit operand.
function underCondition(node) {
// True when `node` sits under a REAL condition inside the nearest
// enclosing function: an if/switch/loop, a ternary, or a short-circuit
// operand. Two wrappers only look conditional and are walked through: an
// `if` whose test constant-folds TRUE never withholds its branch, and a
// `catch` whose try block holds a counted assertion fires exactly when
// that assertion fails — a skip in either is the runner's unconditional
// outcome, not an environment guard. `assertionPositions` must be complete
// when this runs: callers collect their skips during the visit and resolve
// them after it.
function underCondition(node, assertionPositions) {
for (let p = node.parent; p && !ts.isFunctionLike(p); p = p.parent) {
if (ts.isIfStatement(p)) {
if (truthyConstant(p.expression)) continue;
return true;
}
if (ts.isCatchClause(p)) {
const tryBlock = ts.isTryStatement(p.parent) ? p.parent.tryBlock : null;
if (
tryBlock &&
assertionPositions.some((a) => a > tryBlock.pos && a < tryBlock.end)
) {
continue;
}
return true;
}
if (
ts.isIfStatement(p) ||
ts.isConditionalExpression(p) ||
ts.isSwitchStatement(p) ||
ts.isCatchClause(p) ||
ts.isIterationStatement(p, false) ||
(ts.isBinaryExpression(p) &&
(p.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
@ -416,6 +532,10 @@ function underCondition(node) {
// ordinary control flow the runner awaits.
function returnsNothing(ret) {
if (!ret.expression) return true;
// A template's value is a string however its substitutions evaluate —
// never a thenable — so the runner ignores it exactly like the literal
// spellings constant() folds.
if (ts.isTemplateExpression(unwrap(ret.expression))) return true;
return constant(ret.expression).known;
}
@ -474,6 +594,37 @@ export function count(text, path) {
const registrations = [];
const bodySkips = [];
const hookBodies = [];
// A callback handed by NAME resolves to the single module-scope function
// declaration or function-valued variable initializer of that name — the
// runner receives that very function, so the registration measures
// through its body. An absent, redeclared or nested binding stays
// opaque.
const topFns = new Map();
const ambiguousFns = new Set();
const bindTopFn = (name, fnNode) => {
if (ambiguousFns.has(name) || topFns.has(name)) {
ambiguousFns.add(name);
topFns.delete(name);
} else {
topFns.set(name, fnNode);
}
};
for (const st of sf.statements) {
if (ts.isFunctionDeclaration(st) && st.name && st.body) {
bindTopFn(st.name.text, st);
} else if (ts.isVariableStatement(st)) {
for (const d of st.declarationList.declarations) {
if (
ts.isIdentifier(d.name) &&
d.initializer &&
(ts.isArrowFunction(d.initializer) ||
ts.isFunctionExpression(d.initializer))
) {
bindTopFn(d.name.text, d.initializer);
}
}
}
}
const visit = (node) => {
if (ts.isCallExpression(node) && !extendsChain(node)) {
const chain = chainOf(node);
@ -483,16 +634,41 @@ export function count(text, path) {
chain.calls.length > 0
) {
const last = chain.calls[chain.calls.length - 1].call;
const fns = (last.arguments ?? []).filter(
(a) => ts.isArrowFunction(a) || ts.isFunctionExpression(a),
);
registrations.push({
kind: ROOTS.get(chain.root) ?? XROOTS.get(chain.root),
title: titleOf(last, sf),
disabled: registrationDisabled(chain),
pos: node.getStart(sf),
fn: fns.length ? fns[fns.length - 1] : null,
});
const lastArgs = last.arguments ?? [];
// A chain that never reaches a registration call registers
// nothing: `it.skipIf(cond)`, `it.each(cases)` and
// `test.extend({})` are collector FACTORIES, and binding one to a
// variable is not a test. The terminal call carries the title or
// the callback.
const terminates =
lastArgs.length > 0 &&
(isStringLike(lastArgs[0]) ||
ts.isTemplateExpression(lastArgs[0]) ||
lastArgs.some(
(a) => ts.isArrowFunction(a) || ts.isFunctionExpression(a),
) ||
(lastArgs.length > 1 &&
ts.isIdentifier(lastArgs[lastArgs.length - 1]) &&
topFns.has(lastArgs[lastArgs.length - 1].text)));
if (terminates) {
const fns = lastArgs.filter(
(a) => ts.isArrowFunction(a) || ts.isFunctionExpression(a),
);
let fn = fns.length ? fns[fns.length - 1] : null;
if (!fn) {
const lastArg = lastArgs[lastArgs.length - 1];
if (ts.isIdentifier(lastArg)) {
fn = topFns.get(lastArg.text) ?? null;
}
}
registrations.push({
kind: ROOTS.get(chain.root) ?? XROOTS.get(chain.root),
title: titleOf(last, sf),
disabled: registrationDisabled(chain),
pos: node.getStart(sf),
fn,
});
}
} else if (
chain.root !== null &&
HOOKS.has(chain.root) &&
@ -504,7 +680,10 @@ export function count(text, path) {
if (fns.length) hookBodies.push(fns[fns.length - 1]);
} else if (isStatementLevel(node) && isAssertion(chain)) {
assertionPositions.push(node.getStart(sf));
} else if (isBodySkip(chain) && !underCondition(node)) {
} else if (isBodySkip(chain)) {
// Conditional-or-not is decided after the visit: a catch clause is
// a condition only when its try holds no assertion, which needs
// the complete assertionPositions.
bodySkips.push(node);
}
}
@ -513,6 +692,7 @@ export function count(text, path) {
visit(sf);
let fileDisabled = false;
for (const skip of bodySkips) {
if (underCondition(skip, assertionPositions)) continue;
const target = skipTarget(skip, registrations);
if (!target.applies) continue;
if (target.scope) target.scope.disabled = true;
@ -575,7 +755,14 @@ export function count(text, path) {
r.disabled = true;
}
}
const silenced = registrations.filter((r) => r.disabled && r.fn);
// A body shared between a disabled and an enabled registration stays
// live: the enabled one executes it, so its assertions are surface.
const liveFns = new Set(
registrations.filter((r) => !r.disabled && r.fn).map((r) => r.fn),
);
const silenced = registrations.filter(
(r) => r.disabled && r.fn && !liveFns.has(r.fn),
);
const executes = (p) => !silenced.some((r) => p > r.fn.pos && p < r.fn.end);
const key = (r) => `${r.kind}:${r.title}`;
const declaredAssertions = fileDisabled

View file

@ -4270,7 +4270,12 @@ the marker's head to the checked-out head, and the check
rollup to the commit it describes (`headRefOid` is read in
the same call as the rollup; a rollup for any other commit
classifies `none`, unknown, never chargeable). A re-arm
changes the window key and drops the whole set with it. A
changes the window key and drops the whole set with it —
and the charge itself fires only when the run's matrix
window IS the live re-arm key: a supersede-exempt conflict
round can still run under a stale window, and a charge
keyed to that dead window is one the brake's live-window
headline walk would never read, so it is not charged. A
head classified from a base-conflict merge or a salvage merge
stamps `pre=none`: the pushed head did not start from the
head prepare classified. A cancelled check is neither red

View file

@ -4785,8 +4785,11 @@ jobs:
| "\(.r // "") \(.h // "") \(.p // "") \(.k // "")"' \
"${WORKDIR}/ic.json" 2> /dev/null || echo '')"
read -r LP_ROUND LP_HEAD LP_PRE LP_KEY <<< "${LAST_PUSH}" || true
# Charged only in the live window: a supersede-exempt round's
# stale matrix WINDOW must not key a charge the brake never walks.
if [[ -n "${LP_ROUND:-}" && "${LP_HEAD:-}" == "${CHECKED_OUT_HEAD}" \
&& "${LP_PRE:-}" == 'green' && "${LP_KEY:-}" == "${WINDOW:-none}" \
&& "${WINDOW:-none}" == "${LIVE_REARM_KEY}" \
&& "${CHECK_STATE}" == 'red' ]]; then
REGRESSED_ROUND="${LP_ROUND}"
echo "🩸 #${PR}: round ${LP_ROUND} pushed ${CHECKED_OUT_HEAD:0:9} onto a green head and it is red now — charging that round as a regression"

View file

@ -254,6 +254,16 @@ const hasBashMapfile =
spawnSync('bash', ['-c', 'mapfile -d "" -t x <<< y'], { stdio: 'ignore' })
.status === 0;
// sha256sum is GNU coreutils: a macOS host without the GNU toolchain
// (Homebrew ships it as gsha256sum) cannot run the staging step's digest
// lines — the step is written for the runner, where coreutils is always
// present. Probe the host like hasBashMapfile does; the pin gates only the
// verbatim phase of the staging witness, never its text pins.
const hasSha256sum =
spawnSync('bash', ['-c', 'command -v sha256sum > /dev/null 2>&1'], {
stdio: 'ignore',
}).status === 0;
// GitHub Actions expressions return operand VALUES from &&/||, not
// booleans: && yields the first falsy operand (else the last operand), ||
// the first truthy (else the last), '' is falsy, and && binds tighter
@ -26923,6 +26933,23 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
],
}),
},
// The same shape with the callback handed by NAME: the instrument
// resolves the module-scope binding, so the skipped body's assertions
// still measure as removed.
'skip-with-standin-named': {
files: { 'pkg/a.test.ts': WT_BASE },
round: roundWrites({
'pkg/a.test.ts': [
WT_IMPORT,
'function body() {',
' expect(one()).toBe(1);',
' expect(two()).toBe(2);',
'}',
"it.skip('a', body);",
"it('a', () => {});",
],
}),
},
'delete-behind-guard': {
files: {
'pkg/a.test.ts': [
@ -27621,6 +27648,9 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
// Skip the body and plant an empty same-titled stand-in: the title
// count balances, the executed assertions do not.
rejectsWeakening('skip-with-standin', 'net 2 assertion(s) removed');
// ...and the same silencing with the callback handed by name: the
// binding resolves, so the skipped body still measures as removed.
rejectsWeakening('skip-with-standin-named', 'net 2 assertion(s) removed');
});
it('charges a weakening by the tip, whichever commit sequence produced it', () => {
@ -28347,61 +28377,72 @@ describe('review verification gate: baseline A/B on deterministic rejection', ()
// ...and the branch that runs in PRODUCTION once this lands: the
// counter present, the parser where npm ci puts it. Text pins cannot
// see ordering or a newly-failing command inside that `if`, and this
// step is unconditional, so a break there kills every round. Run it.
writeFileSync(
join(surfaceProbeDir, '.github', 'scripts', 'count-test-surface.mjs'),
readFileSync('.github/scripts/count-test-surface.mjs'),
);
mkdirSync(join(surfaceProbeDir, 'node_modules', 'typescript', 'lib'), {
recursive: true,
});
const plantedParser = '// planted typescript build\nmodule.exports={};\n';
writeFileSync(
join(
surfaceProbeDir,
'node_modules',
'typescript',
'lib',
'typescript.js',
),
plantedParser,
);
rmSync(join(surfaceRunnerTemp, 'count-test-surface.mjs'), {
recursive: true,
force: true,
});
rmSync(join(surfaceRunnerTemp, 'weaken-parser'), {
recursive: true,
force: true,
});
writeFileSync(surfaceOutput, '');
const staged = runStage();
expect(staged.stderr).toBe('');
expect(staged.status).toBe(0);
expect(
readFileSync(join(surfaceRunnerTemp, 'count-test-surface.mjs'), 'utf8'),
).toBe(readFileSync('.github/scripts/count-test-surface.mjs', 'utf8'));
expect(
readFileSync(
join(surfaceRunnerTemp, 'weaken-parser', 'typescript.cjs'),
'utf8',
),
).toBe(plantedParser);
// The digests the gate verifies against are of the bytes that were
// actually staged, and BOTH reach expression context.
const digestOf = (file) =>
createHash('sha256').update(readFileSync(file)).digest('hex');
const emitted = readFileSync(surfaceOutput, 'utf8');
expect(emitted).toContain(
`weaken_counter_sha256=${digestOf(
join(surfaceRunnerTemp, 'count-test-surface.mjs'),
)}\n`,
);
expect(emitted).toContain(
`weaken_parser_sha256=${digestOf(
join(surfaceRunnerTemp, 'weaken-parser', 'typescript.cjs'),
)}\n`,
);
// step is unconditional, so a break there kills every round. Run it —
// on hosts with the GNU coreutils the step's digest lines assume:
// they call sha256sum bare, and a macOS host without it (Homebrew
// ships gsha256sum) would fail the spawn for a reason the runner can
// never hit. The witness is the string pins PLUS the redacted-arm
// probes above on such a host.
if (hasSha256sum) {
writeFileSync(
join(surfaceProbeDir, '.github', 'scripts', 'count-test-surface.mjs'),
readFileSync('.github/scripts/count-test-surface.mjs'),
);
mkdirSync(join(surfaceProbeDir, 'node_modules', 'typescript', 'lib'), {
recursive: true,
});
const plantedParser =
'// planted typescript build\nmodule.exports={};\n';
writeFileSync(
join(
surfaceProbeDir,
'node_modules',
'typescript',
'lib',
'typescript.js',
),
plantedParser,
);
rmSync(join(surfaceRunnerTemp, 'count-test-surface.mjs'), {
recursive: true,
force: true,
});
rmSync(join(surfaceRunnerTemp, 'weaken-parser'), {
recursive: true,
force: true,
});
writeFileSync(surfaceOutput, '');
const staged = runStage();
expect(staged.stderr).toBe('');
expect(staged.status).toBe(0);
expect(
readFileSync(
join(surfaceRunnerTemp, 'count-test-surface.mjs'),
'utf8',
),
).toBe(readFileSync('.github/scripts/count-test-surface.mjs', 'utf8'));
expect(
readFileSync(
join(surfaceRunnerTemp, 'weaken-parser', 'typescript.cjs'),
'utf8',
),
).toBe(plantedParser);
// The digests the gate verifies against are of the bytes that were
// actually staged, and BOTH reach expression context.
const digestOf = (file) =>
createHash('sha256').update(readFileSync(file)).digest('hex');
const emitted = readFileSync(surfaceOutput, 'utf8');
expect(emitted).toContain(
`weaken_counter_sha256=${digestOf(
join(surfaceRunnerTemp, 'count-test-surface.mjs'),
)}\n`,
);
expect(emitted).toContain(
`weaken_parser_sha256=${digestOf(
join(surfaceRunnerTemp, 'weaken-parser', 'typescript.cjs'),
)}\n`,
);
}
} finally {
rmSync(surfaceProbeDir, { recursive: true, force: true });
rmSync(surfaceRunnerTemp, { recursive: true, force: true });
@ -28686,6 +28727,62 @@ describe('count-test-surface: the declared test surface of a test file', () => {
],
{ a: 0, e: 2, d: ['test:a', 'test:b', 'test:c', 'test:d'] },
],
[
'reads a constant through a type-only wrapper',
[
"it.skipIf(true as boolean)('a', fn);",
"it.runIf(false as boolean)('b', fn);",
"it('c', { skip: true } as const, fn);",
"it('d', { skip: (true as boolean) }, fn);",
"it.skipIf(<boolean>true)('e', fn);",
"it.skipIf(true!)('f', fn);",
"it.skipIf(true satisfies boolean)('g', fn);",
// A wrapper around a runtime value stays a condition.
"it.skipIf(process.env.CI as boolean)('h', fn);",
],
{
a: 0,
e: 1,
d: [
'test:a',
'test:b',
'test:c',
'test:d',
'test:e',
'test:f',
'test:g',
],
},
],
[
'folds a comparison, equality or logical operator of two constants',
[
"it.skipIf(1 === 1)('a', fn);",
"describe.skipIf(2 > 1)('b', fn);",
"it.skipIf('x' !== '')('c', fn);",
"it.skipIf(1 && true)('d', fn);",
"it.runIf(1 > 2)('e', fn);",
"it('f', { skip: 1 === 1 }, fn);",
// Placeholder folds and bigint arithmetic stay opaque to
// comparison: `{} === {}` is false at runtime, `1n === 1` too.
"it.skipIf({} === {})('g', fn);",
"it.skipIf(1n === 1)('h', fn);",
"it['' || 'skip']('i', fn);",
],
{
a: 0,
e: 2,
d: [
'test:a',
'describe:b',
'test:c',
'test:d',
'test:e',
'test:f',
'test:i',
],
},
],
[
"applies the runner's own rule to body skips: only `false` keeps the test",
[
@ -28790,6 +28887,18 @@ describe('count-test-surface: the declared test surface of a test file', () => {
],
{ a: 1, e: 6, d: ['test:g', 'test:h', 'test:i'] },
],
[
'reads a constant return through wrappers and templates alike',
[
"it('a', () => { if (!r) return undefined as void; expect(x).toBe(1); });",
"it('b', () => { if (!r) return `full suite only: ${process.env.QWEN_FULL}`; expect(x).toBe(1); });",
"it('c', () => { if (!r) return `reason`; expect(x).toBe(1); });",
// A possibly-thenable return stays ordinary control flow.
"it('d', () => { if (!r) return go(); expect(x).toBe(1); });",
"it('e', () => { return expect(p).resolves.toBe(1); });",
],
{ a: 2, e: 5, d: [] },
],
[
'silences the assertions a describe body or a hook shelters',
[
@ -28846,6 +28955,78 @@ describe('count-test-surface: the declared test surface of a test file', () => {
],
{ a: 2, e: 2, d: [] },
],
[
'reads a skip that cannot be escaped as a disable, however wrapped',
[
// The catch fires exactly when the assertion fails: the test can
// never report a failure, so the registration is disabled — the
// setup-failure guard this is one token away from.
"it('a', (ctx) => { try { expect(x).toBe(1); } catch { ctx.skip(); } });",
"it('b', (ctx) => { if (true) ctx.skip(); expect(x).toBe(1); });",
"it('c', (ctx) => { if (1 === 1) { ctx.skip(); } expect(x).toBe(1); });",
],
{ a: 0, e: 0, d: ['test:a', 'test:b', 'test:c'] },
],
[
'measures a registration through a callback handed by name',
[
'function body(ctx) {',
' ctx.skip();',
' expect(1).toBe(1);',
'}',
"it('a', body);",
"it('b', fn);",
],
{ a: 0, e: 1, d: ['test:a'] },
],
[
'measures the named-body shapes exactly like their inline spellings',
[
'function body() {',
' expect(1).toBe(1);',
'}',
"it.skip('a', body);",
"it('a', () => {});",
'function suite() {',
" it('b', () => { expect(2).toBe(2); });",
'}',
"describe.skip('c', suite);",
],
{ a: 0, e: 1, d: ['test:a', 'test:b', 'describe:c'] },
],
[
'keeps a body shared with an enabled registration live',
[
'function body() {',
' expect(1).toBe(1);',
'}',
"it('a', body);",
"it.skip('b', body);",
],
{ a: 1, e: 1, d: ['test:b'] },
],
[
'reads a collector factory binding as no registration at all',
[
"const posixOnly = it.skipIf(process.platform !== 'linux');",
'const rows = it.each(getCases());',
'const myTest = test.extend({});',
"it('a', fn);",
],
{ a: 0, e: 1, d: [] },
],
[
'sees a chain through a type-only wrapper',
[
"(it as any).skip('a', () => { expect(1).toBe(1); });",
"(it.skip as any)('b', () => { expect(1).toBe(1); });",
"it('c', (ctx) => { (ctx as any).skip(); expect(1).toBe(1); });",
"it('d', () => { (expect(1) as any).toBe(1); });",
"(describe as any).skip('e', () => { it('f', () => { expect(1).toBe(1); }); });",
],
// test:d stays enabled — its body only ASSERTS through a wrapper.
{ a: 1, e: 1, d: ['test:a', 'test:b', 'test:c', 'describe:e', 'test:f'] },
],
[
'counts assertions only where the runner would execute them',
[
@ -28873,6 +29054,59 @@ describe('count-test-surface: the declared test surface of a test file', () => {
expect(surface(source, path)).toEqual(expected);
});
it('resolves a registration callback bound by name, exactly like the inline spelling', () => {
// The runner receives the SAME function whether the registration
// hands it over inline or by name, so the two spellings must measure
// alike: the body's skip reaches the registration, its assertions
// leave the surface, and a disabled describe's body propagates.
expect(
countTestSurface(
[
'function body(ctx) {',
' ctx.skip();',
' expect(1).toBe(1);',
'}',
"it('x', body);",
].join('\n'),
'a.test.ts',
),
).toMatchObject({
assertions: 0,
enabled: 0,
disabled: ['test:x'],
enabledTitles: [],
});
expect(
countTestSurface(
[
'function suite() {',
" it('a', () => { expect(1).toBe(1); });",
'}',
"describe.skip('d', suite);",
].join('\n'),
'a.test.ts',
),
).toMatchObject({ enabledTitles: [], enabled: 0, assertions: 0 });
// The inline spellings these must agree with.
expect(
countTestSurface(
"it('x', (ctx) => { ctx.skip(); expect(1).toBe(1); });",
'a.test.ts',
),
).toMatchObject({
assertions: 0,
enabled: 0,
disabled: ['test:x'],
enabledTitles: [],
});
expect(
countTestSurface(
"describe.skip('d', () => { it('a', () => { expect(1).toBe(1); }); });",
'a.test.ts',
),
).toMatchObject({ enabledTitles: [], enabled: 0, assertions: 0 });
});
it('measures every dialect the gate selects, not only .ts', () => {
// The pathspec selects `*.test.*` and `*.spec.*` whatever the
// extension, and the repository tracks hundreds of `*.test.js` files.
@ -29206,6 +29440,10 @@ describe('review-address: regression accounting (af-155)', () => {
// The commit the rollup describes (headRefOid read with the rollup).
checksHead = HEAD,
window = 'w1',
// The live re-arm key prepare computed: defaults to the run's window
// (the ordinary case); a supersede-exempt conflict round can still run
// under a stale matrix window.
liveKey = window,
}) => {
const dir = mkdtempSync(join(tmpdir(), 'af148-'));
try {
@ -29217,7 +29455,7 @@ describe('review-address: regression accounting (af-155)', () => {
'bash',
[
'-c',
`set -euo pipefail\nWORKDIR=${JSON.stringify(dir)}\nAUTOFIX_BOT=qwen-code-dev-bot\nDISPATCH_STATUS_CONTEXT='qwen-autofix/dispatch-pending'\nCHECKED_OUT_HEAD='${checkedOutHead}'\nROLLUP_HEAD='${checksHead}'\nWINDOW='${window}'\nPR=1\nGITHUB_OUTPUT=${JSON.stringify(outFile)}\n${script}`,
`set -euo pipefail\nWORKDIR=${JSON.stringify(dir)}\nAUTOFIX_BOT=qwen-code-dev-bot\nDISPATCH_STATUS_CONTEXT='qwen-autofix/dispatch-pending'\nCHECKED_OUT_HEAD='${checkedOutHead}'\nROLLUP_HEAD='${checksHead}'\nWINDOW='${window}'\nLIVE_REARM_KEY='${liveKey}'\nPR=1\nGITHUB_OUTPUT=${JSON.stringify(outFile)}\n${script}`,
],
{ encoding: 'utf8' },
);
@ -29380,56 +29618,43 @@ describe('review-address: regression accounting (af-155)', () => {
// pushed code introduced, and an in-flight own check is observer
// noise on the triggers whose suite attaches to the PR head. The
// carve-out survives at the FEEDBACK sites (N_FAILED_CHECKS /
// N_RED_NOW).
expect(
run({
checks: [
{
name: 'review-scan',
conclusion: 'FAILURE',
workflowName: 'Qwen Autofix',
},
...GREEN,
],
}).state,
).toBe('green');
expect(
run({
checks: [
{
name: 'review-address (1)',
conclusion: 'FAILURE',
workflowName: 'Qwen Autofix',
},
...GREEN,
],
}).state,
).toBe('green');
expect(
run({
checks: [
{
name: 'review-address (1)',
conclusion: 'FAILURE',
workflowName: 'Qwen Autofix',
},
],
}).state,
).toBe('none');
// A red AUXILIARY lane of the fleet is the loop's own business too.
expect(
run({
checks: [
{
name: 'review-pr',
status: 'COMPLETED',
conclusion: 'FAILURE',
workflowName: '🧐 Qwen Pull Request Review',
},
...GREEN,
],
}).state,
).toBe('green');
// N_RED_NOW). All FIVE own-lane workflow names are exercised — a name
// dropped from the jq filter would read as a PR-side regression here.
for (const loopWorkflow of [
'Qwen Autofix',
'🧐 Qwen Pull Request Review',
'Qwen CI Failure Patrol',
'Qwen Autofix Fork Bridge',
'Qwen Autofix Fork Signal',
]) {
expect(
run({
checks: [
{
name: 'build',
status: 'COMPLETED',
conclusion: 'FAILURE',
workflowName: loopWorkflow,
},
...GREEN,
],
}).state,
).toBe('green');
// An own lane ALONE is no signal at all: excluded by the filter, it
// leaves an empty set — unknown, never the red a charge needs.
expect(
run({
checks: [
{
name: 'build',
status: 'COMPLETED',
conclusion: 'FAILURE',
workflowName: loopWorkflow,
},
],
}).state,
).toBe('none');
}
// The round's own in-flight check must not hold the verdict pending.
expect(
run({
@ -29474,6 +29699,18 @@ describe('review-address: regression accounting (af-155)', () => {
expect(
run({ checks: RED, comments: pushMarker({ key: 'w0' }) }).regressed,
).toBe('');
// ...and when this run's own matrix window is the stale one (a
// supersede-exempt conflict round after a re-arm), the charge stays
// with the live window: the brake walks headlines under the live key,
// so a charge keyed to the dead window would never land there.
expect(
run({
checks: RED,
comments: pushMarker({ key: 'w0' }),
window: 'w0',
liveKey: 'w1',
}).regressed,
).toBe('');
// Head is green now — nothing to charge.
expect(run({ checks: GREEN, comments: pushMarker({}) }).regressed).toBe('');
// A failed own address run beside a green suite is feedback, not a
@ -29556,6 +29793,12 @@ describe('review-address: regression accounting (af-155)', () => {
expect(pushAndReportScript).toContain(
"[[ \"${CONFLICT:-false}\" == 'true' ]] && PUSH_PRE='none'",
);
// ...and so does any merge commit the push carries past the head
// prepare classified (a clean in-round merge of main trips neither arm
// above): the pushed head then holds content prepare never classified.
expect(pushAndReportScript).toContain(
'[[ -n "$(git rev-list --merges "${REPORT_HEAD}..${PUSHED_HEAD}" 2>/dev/null)" ]] && PUSH_PRE=\'none\'',
);
// When the push landed but the report post failed, a marker-only
// comment still carries the push record — the only record a later
// round can charge a regression against.