From f2d55aba7b0a004b1ab02344f2c2fe5e04020f6d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 10 Nov 2026 23:04:06 +0000 Subject: [PATCH] fix(limits): ignore allowlists and require tracked limits to be settings Discovery no longer treats comments or registration-list entries as producers. The three limits moving on their own PRs must join ANALYSIS_SETTINGS; the exception registry cannot classify them. --- scripts/verify/rea-numeric-limits.d.mts | 15 +++- scripts/verify/rea-numeric-limits.mjs | 89 +++++++++++++++++++++- tests/evaluation/numericLimitCheck.test.ts | 46 +++++++++++ 3 files changed, 145 insertions(+), 5 deletions(-) diff --git a/scripts/verify/rea-numeric-limits.d.mts b/scripts/verify/rea-numeric-limits.d.mts index aa8690eb8a..5baa3739ac 100644 --- a/scripts/verify/rea-numeric-limits.d.mts +++ b/scripts/verify/rea-numeric-limits.d.mts @@ -1,10 +1,23 @@ /** Relative path of the registry. Its text is a declaration, not a producer. */ export const NUMERIC_LIMIT_DECLARATION: "src/domain/numericLimitRegistry.ts"; +/** Limits that must become analysis settings and cannot be registry exceptions. */ +export const REQUIRED_RUNTIME_LIMITS: readonly [ + "REA_NTFS_MFT_MAX_FILE_BYTES", + "REA_REGF_HIVE_MAX_FILE_BYTES", + "REA_WEB_BUNDLE_ENDPOINT_LITERAL_CANDIDATES", +]; + /** True for a numeric `REA_` limit, including the documented endpoint-candidate count. */ export function isNumericLimit(name: string): boolean; -/** Producer paths for numeric limits. Registry declarations are omitted. */ +/** Producer paths for numeric limits. Registry text, comments, and allowlists are omitted. */ export function discoverNumericLimitUses( files: readonly { readonly path: string; readonly source: string }[], ): Map; + +/** Why a tracked limit is not an analysis setting, when it is present. */ +export function requiredRuntimeLimitFailure( + name: string, + presence: { readonly inRuntime: boolean; readonly inRegistry: boolean }, +): string | undefined; diff --git a/scripts/verify/rea-numeric-limits.mjs b/scripts/verify/rea-numeric-limits.mjs index eb7435f2db..68a2244991 100644 --- a/scripts/verify/rea-numeric-limits.mjs +++ b/scripts/verify/rea-numeric-limits.mjs @@ -40,6 +40,68 @@ const DOCUMENTED_COUNT_LIMITS = new Set([ /** Registry text is a declaration, not a producer that uses the limit. */ export const NUMERIC_LIMIT_DECLARATION = "src/domain/numericLimitRegistry.ts"; +/** + * These limits are moving onto runtime analysis settings on their own PRs. + * A producer or a registry entry cannot satisfy that requirement. + */ +export const REQUIRED_RUNTIME_LIMITS = [ + "REA_NTFS_MFT_MAX_FILE_BYTES", + "REA_REGF_HIVE_MAX_FILE_BYTES", + "REA_WEB_BUNDLE_ENDPOINT_LITERAL_CANDIDATES", +]; + +/** Drop comments without treating `//` inside a string as a comment. */ +export const sourceForLimitDiscovery = (source) => { + let out = ""; + let quote = ""; + for (let index = 0; index < source.length; index += 1) { + const current = source[index]; + const next = source[index + 1]; + if (quote !== "") { + out += current; + if (current === "\\" && quote !== "`") { + out += next ?? ""; + index += 1; + continue; + } + if (current === quote) quote = ""; + continue; + } + if (current === '"' || current === "'" || current === "`") { + quote = current; + out += current; + continue; + } + if (current === "/" && next === "/") { + while (index < source.length && source[index] !== "\n") index += 1; + out += "\n"; + continue; + } + if (current === "/" && next === "*") { + index += 2; + while ( + index < source.length && + !(source[index] === "*" && source[index + 1] === "/") + ) + index += 1; + index += 1; + out += " "; + continue; + } + out += current; + } + return out; +}; + +/** A quoted name in an array is an allowlist entry, not a limit producer. */ +const isArrayElementLiteral = (source, index) => { + if (source[index - 1] !== '"') return false; + let cursor = index - 2; + while (cursor >= 0 && /\s/u.test(source[cursor] ?? "")) cursor -= 1; + const previous = source[cursor]; + return previous === "[" || previous === ","; +}; + export const isNumericLimit = (name) => DOCUMENTED_COUNT_LIMITS.has(name) || /(?:_BYTES|_MS|_MIB|_SECONDS|_POLLS|_JOBS|_ELEMENTS|_COUNT|_SESSIONS|_COMMANDS)$/u.test( @@ -49,23 +111,33 @@ export const isNumericLimit = (name) => /_(?:TIMEOUT|DEADLINE|BUDGET)(?:_|$)/u.test(name) || /_HEAP(?:_|$)/u.test(name); -/** Names used by producers. Registry declarations are not usage. */ +/** Names used by producers. Registry declarations, comments, and allowlists are not usage. */ export const discoverNumericLimitUses = (files) => { const discovered = new Map(); for (const file of files) { const relativePath = file.path.split(sep).join("/"); if (relativePath === NUMERIC_LIMIT_DECLARATION) continue; - for (const match of file.source.matchAll( - /(? { + if (!REQUIRED_RUNTIME_LIMITS.includes(name)) return undefined; + if (inRuntime && !inRegistry) return undefined; + return `${name} must join ANALYSIS_SETTINGS; numericLimitRegistry cannot classify it`; +}; + const namesIn = (source, pattern) => new Set([...source.matchAll(pattern)].map((match) => match[1])); @@ -120,6 +192,15 @@ if (direct) { if (!discovered.has(name)) failures.push(`${name} is registered but no longer appears in src`); } + const present = new Set([...discovered.keys(), ...listed.keys(), ...runtime]); + for (const name of REQUIRED_RUNTIME_LIMITS) { + if (!present.has(name)) continue; + const failure = requiredRuntimeLimitFailure(name, { + inRuntime: runtime.has(name), + inRegistry: listed.has(name), + }); + if (failure !== undefined) failures.push(failure); + } if (failures.length > 0) { console.error(`Numeric REA_ limit check failed:\n${failures.join("\n")}`); diff --git a/tests/evaluation/numericLimitCheck.test.ts b/tests/evaluation/numericLimitCheck.test.ts index 37e563930e..21eeafb6f6 100644 --- a/tests/evaluation/numericLimitCheck.test.ts +++ b/tests/evaluation/numericLimitCheck.test.ts @@ -3,6 +3,7 @@ import { NUMERIC_LIMIT_DECLARATION, discoverNumericLimitUses, isNumericLimit, + requiredRuntimeLimitFailure, } from "../../scripts/verify/rea-numeric-limits.mjs"; const ENDPOINT_CANDIDATES = "REA_WEB_BUNDLE_ENDPOINT_LITERAL_CANDIDATES"; @@ -39,3 +40,48 @@ it("does not treat a registry declaration as a producer", () => { ]).has(name), ).toBe(false); }); + +it("does not treat a registration allowlist or a comment as a producer", () => { + const discovered = discoverNumericLimitUses([ + { + path: NUMERIC_LIMIT_DECLARATION, + source: `name: "${ENDPOINT_CANDIDATES}",`, + }, + { + path: "src/application/SetupRegistrationEnvironment.ts", + source: `const SELECTED_REGISTRATION_SETTINGS = ["${ENDPOINT_CANDIDATES}"] as const;`, + }, + { + path: "src/config/removedLimit.ts", + source: `// ${ENDPOINT_CANDIDATES} used to be read here\nconst unrelated = 1;\n`, + }, + ]); + expect(discovered.has(ENDPOINT_CANDIDATES)).toBe(false); +}); + +it("requires the tracked endpoint-candidate limit to be an analysis setting", () => { + expect( + requiredRuntimeLimitFailure(ENDPOINT_CANDIDATES, { + inRuntime: false, + inRegistry: true, + }), + ).toMatch(/ANALYSIS_SETTINGS/); + expect( + requiredRuntimeLimitFailure(ENDPOINT_CANDIDATES, { + inRuntime: true, + inRegistry: false, + }), + ).toBeUndefined(); + expect( + requiredRuntimeLimitFailure("REA_NTFS_MFT_MAX_FILE_BYTES", { + inRuntime: false, + inRegistry: false, + }), + ).toMatch(/ANALYSIS_SETTINGS/); + expect( + requiredRuntimeLimitFailure("REA_REGF_HIVE_MAX_FILE_BYTES", { + inRuntime: true, + inRegistry: true, + }), + ).toMatch(/numericLimitRegistry/); +});