|
16 | 16 | // precedents are check-type-source-resolution.mjs, check-test-source-alias.mjs, |
17 | 17 | // check-adr-links.mjs and check-driver-memory-census.mjs. |
18 | 18 | // |
| 19 | +// ── The ruled EXCEPTION: an authorised cross-file move (2026-09-03) ───────── |
| 20 | +// |
| 21 | +// The disjunction above asks WHO may take a registry-growing remedy, and on a |
| 22 | +// shrink-only ratchet the answer was always "a maintainer, per instance". One |
| 23 | +// class of act is now authorised generally instead of one PR at a time. |
| 24 | +// Maintainer ruling, 2026-09-03, adopting option A of item 5 in the skills |
| 25 | +// optimization programme's third decision batch (#14685, comment 5520452691) — |
| 26 | +// verbatim and untranslated: 「同意」; the text it adopts: |
| 27 | +// |
| 28 | +// the per-file line ratchet admits a cross-file move in one PR when the |
| 29 | +// destination's allowance rises by no more than the source's net decrease and |
| 30 | +// total lines do not increase, with the ruling cited in the ratchet comment; |
| 31 | +// `check:ratchet-remedy-authority`'s self-description gains this exception |
| 32 | +// |
| 33 | +// So: a cross-file MOVE in the per-file line ratchet is NOT a maintainer-only |
| 34 | +// remedy while all three conditions hold — the destination's raise is covered by |
| 35 | +// the named sources' net decrease, the map-wide total does not increase, and the |
| 36 | +// raised entry cites that ruling. The scope is exactly the act the ruling names, |
| 37 | +// in the gate the ruling names. A raise failing any condition is an ordinary |
| 38 | +// raise and belongs to a maintainer as before, and no other ratchet in this farm |
| 39 | +// gains anything: the reason a move is not a weakening is that the corpus SHRANK |
| 40 | +// on net, which is a property of the act, not of the author. |
| 41 | +// |
| 42 | +// ⚠️ TODAY THE EXCEPTION IS DOCUMENTARY, and recording that is half the point of |
| 43 | +// writing it here. The corpus walk is a NON-RECURSIVE readdir of `scripts/` (see |
| 44 | +// corpusFiles), and the gate the ruling amends lives one directory down, in |
| 45 | +// scripts/pm/ — it has never been in this sweep, so no verdict of this gate |
| 46 | +// moves. A self-test assertion pins that, so a wider walk reds HERE and makes |
| 47 | +// the class a decision someone takes rather than one that lands in silence. |
| 48 | +// |
| 49 | +// ⛔ NO NEW VERDICT CLASS. `marked` / `refused` / `unmarked` / `excluded` stay as |
| 50 | +// they are. A fifth class for "authorised by standing ruling" would have a |
| 51 | +// population of zero in this corpus, and an unreachable class is a claim of |
| 52 | +// enforcement nobody has — the same defect this file's control corpus exists to |
| 53 | +// prevent, one level up. If the walk ever reaches a gate offering this act, the |
| 54 | +// honest first move is to read that gate's own verdict and record it in CONTROL, |
| 55 | +// the way every instance in this file arrived. |
| 56 | +// |
| 57 | +// ⛔ THIS SECTION IS COMMENT, never a string literal — the header warning above, |
| 58 | +// applied to itself. It describes an act that grows a registry, so in |
| 59 | +// author-facing text it would make this gate an instance of the convention it |
| 60 | +// enforces and flip its own verdict off `excluded`. |
| 61 | +// |
19 | 62 | // WHY A SWEEP AND NOT A SHARED MODULE. #8519 proposed a shared helper module as |
20 | 63 | // the enforcement route. It is not one: a module is reachable only from gates |
21 | 64 | // that choose to import it, so it standardises the gates that already agreed and |
@@ -1265,6 +1308,29 @@ function selfTest() { |
1265 | 1308 | + 'nothing, and a dead declaration prints as the same silence as declaring nothing)', |
1266 | 1309 | !ROOT_DIR_WATCH_HINTS.some((h) => h.includes('{'))); |
1267 | 1310 |
|
| 1311 | + // ── (21) The ruled cross-file-move exception (2026-09-03) ─────────────── |
| 1312 | + // |
| 1313 | + // Two assertions, and both are about THIS FILE rather than about the ratchet |
| 1314 | + // the ruling amends: where the exception is written down, and whether it is |
| 1315 | + // doing anything yet. Neither can be held by the run — a header section runs |
| 1316 | + // green whatever it says, which is exactly how a documented exception drifts |
| 1317 | + // into a claimed one. |
| 1318 | + const selfSrc = readFileSync(join(SCRIPTS_DIR, SELF_FILE), 'utf8'); |
| 1319 | + // ⛔ The phrase is ASSEMBLED, never spelled, for the reason the ADD hoist above gives in |
| 1320 | + // its own case: a literal spelling would put the phrase into THIS file's author-facing text |
| 1321 | + // and falsify the assertion below by the act of making it. |
| 1322 | + const EXCEPTION_PHRASE = ['cross-file', 'MOVE'].join(' '); |
| 1323 | + expect('the ruled exception is recorded in COMMENT space only — written into author-facing text ' |
| 1324 | + + 'it would describe a registry-growing act, and this gate would then read as an instance of ' |
| 1325 | + + 'the convention it enforces, which is what assertion (17) catches', |
| 1326 | + selfSrc.includes(EXCEPTION_PHRASE) |
| 1327 | + && !authorFacingMessages(selfSrc).some((m) => m.includes(EXCEPTION_PHRASE))); |
| 1328 | + |
| 1329 | + expect('the ruled exception is documentary today: the amended line ratchet lives one directory ' |
| 1330 | + + 'down and this walk is non-recursive, so a wider walk reds HERE rather than admitting a new ' |
| 1331 | + + 'remedy class in silence', |
| 1332 | + !corpusFiles().includes('check-skill-line-ratchet.mjs')); |
| 1333 | + |
1268 | 1334 | if (failures.length > 0) { |
1269 | 1335 | for (const f of failures) console.error(` x self-test: ${f}`); |
1270 | 1336 | console.error(`\ncheck-ratchet-remedy-authority --self-test: ${failures.length} failure(s).\n`); |
|
0 commit comments