fix(gate-diff): RH-15? only on CI/config floors after calibration

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-10 16:55:42 +00:00
1 parent 934e5b7ed6
commit eb9263538d
3 files changed
+15 -6

No files matched your search

+4 -3
View File
@@ -38,9 +38,10 @@ No artifact was written: calibration never touches the state root.
{ timeout: 30_000 })` in new or moved test code; this repository requires a
timeout on every synchronous spawn (`test/spawnsync-timeout-tripwire.test.ts`),
so nearly every test PR carries dozens. As specified ("unpaired values are
tagged RH-15? and read") the tag is noise here. Candidates for the human
decision the design reserves: demote `RH-15?` to inventory, or keep it only
for CI/config files and test-framework timeout options. The detector was
tagged RH-15? and read") the tag is noise here. **Decision (integrator, per
the design's demotion rule):** `RH-15?` now applies only to CI and
runner/lint-config files; in test files unpaired values are inventory and
only paired RH-15 is tagged. The table below predates that change. The detector was
tightened to key-value assignments (`key: N`, `key = N`, `key(N)`, `--key N`,
and a gate key opening a nested structure) and to numeric literals with `_`
separators; prose strings and `setTimeout` calls no longer fire.
+9 -3
View File
@@ -162,9 +162,10 @@ function valueLines(lines: string[]): ValueLine[] {
/**
* RH-15 inside one hunk: removed/added pairs with the same gate key and the
* same numeric shape whose numbers differ (direction shown in notes), an
* exact-count assertion relaxed to a bound, and RH-15? for unpaired values.
* exact-count assertion relaxed to a bound, and RH-15? for unpaired values
* when `opts.unpaired` is not false (callers disable it for test files).
*/
export function detectRelaxation(h: Hunk): { tags: string[]; notes: string[] } {
export function detectRelaxation(h: Hunk, opts: { unpaired?: boolean } = { unpaired: true }): { tags: string[]; notes: string[] } {
const dels = valueLines(removed(h));
const adds = valueLines(added(h));
const tags = new Set<string>();
@@ -188,6 +189,7 @@ export function detectRelaxation(h: Hunk): { tags: string[]; notes: string[] } {
tags.add('RH-15');
notes.push(`RH-15: exact-count assertion relaxed to a bound (${subject.trim()})`);
}
if (opts.unpaired === false) return { tags: [...tags], notes };
for (const v of [...dels, ...adds]) {
if (v.paired) continue;
tags.add('RH-15?');
@@ -245,8 +247,12 @@ export function tagHunk(h: Hunk, ctx: TagContext): TagResult {
if (nonTest && anyMatch(adds, ENV_SNIFF_IDIOMS)) tags.add('RH-12');
if (anyMatch(adds, SUPPRESSION_IDIOMS)) tags.add('RH-13');
if (anyMatch(adds, BYPASS_IDIOMS)) tags.add('RH-14');
// Calibration over gstack's last 50 PRs (docs/designs/gate-diff-calibration.md):
// unpaired values in test code are mandated `spawnSync` timeouts on 41 of
// 50 PRs, so RH-15? applies only to CI and runner/lint config; test files
// keep paired RH-15 and stay inventory otherwise.
if (ctx.floor === 'test' || ctx.floor === 'ci' || ctx.floor === 'config') {
const r = detectRelaxation(h);
const r = detectRelaxation(h, { unpaired: ctx.floor !== 'test' });
for (const t of r.tags) tags.add(t);
notes.push(...r.notes);
}
+2
View File
@@ -111,6 +111,8 @@ describe('gate-diff tags: one planted case per id', () => {
test('RH-15?: an unpaired gate value (new file or reordered lines) is read, not inferred', () => {
const d = detectRelaxation({ header: '@@', lines: [{ kind: 'add', text: 'export default { testTimeout: 60000 };' }] });
expect(d.tags).toEqual(['RH-15?']);
const inTest = detectRelaxation({ header: '@@', lines: [{ kind: 'add', text: " spawnSync('git', ['status'], { timeout: 30_000 });" }] }, { unpaired: false });
expect(inTest.tags).toEqual([]);
expect(gateKey('const minScore = 0.4;')).toEqual({ key: 'minScore', relaxes: 'down', value: 0.4 });
expect(gateKey("console.log('Test Coverage Audit: 5 new code paths');")).toBeNull();
expect(gateKey('setTimeout(done, 0);')).toBeNull();