From 0600c7d11a907b9d62f9e0ff6f19ae33b70d7795 Mon Sep 17 00:00:00 2001 From: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Date: Sun, 25 Oct 2026 10:17:19 +0000 Subject: [PATCH] refactor(native): keep matching allowance recovery with its parser Recovery text and display formatting move beside the launch parser under src/config, so the admission only enforces the budget. The 1 GiB maximum is restated as an REA policy: the canonical digest streams, so it was not bounded by a single serialized string. Co-Authored-By: Claude Opus 5.5 --- docs/native-function-matching.md | 5 ++-- .../native/NativeMatchingAdmission.ts | 27 +++---------------- src/config/nativeMatchingAllowance.ts | 20 ++++++++++++++ src/domain/analysisResourceLimits.ts | 10 +++---- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/docs/native-function-matching.md b/docs/native-function-matching.md index 75a306c11b..24f74e8418 100644 --- a/docs/native-function-matching.md +++ b/docs/native-function-matching.md @@ -128,8 +128,9 @@ operation without restarting REA. For CLI or future REA processes, set setup` copies it into client registrations. An invalid launch value is refused by matching only, and a runtime value repairs it. A refusal carries `details.limit` with the effective value, its source and bounds. Raising the -allowance lets matching retain more in the REA process; the upper bound keeps -the complete Evidence's canonical serialization within one Node string. +allowance lets matching retain more in the REA process. The 1 GiB maximum is +an REA policy, not a host-capacity claim, and peak heap during a request can +exceed the allowance. Summary delivery happens after complete matching Evidence is constructed and retained. It reduces the initial reply, but does not avoid that construction or raise the allowance. Repeated provenance remains diff --git a/src/application/native/NativeMatchingAdmission.ts b/src/application/native/NativeMatchingAdmission.ts index e0b779b234..2ecbf1e591 100644 --- a/src/application/native/NativeMatchingAdmission.ts +++ b/src/application/native/NativeMatchingAdmission.ts @@ -1,34 +1,13 @@ import { setImmediate } from "node:timers/promises"; import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js"; import { analysisSettingLimit } from "../../domain/analysisSettingDefinitions.js"; -import { - DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES, - MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES, -} from "../../domain/analysisResourceLimits.js"; import { DEFAULT_NATIVE_MATCHING_ALLOWANCE, - NATIVE_MATCHING_ALLOWANCE_SETTING, + nativeMatchingAllowanceRecovery, + nativeMatchingByteAllowance, type NativeMatchingAllowance, } from "../../config/nativeMatchingAllowance.js"; -const MEBIBYTE = 1024 * 1024; -const byteAllowance = (bytes: number): string => - Number.isInteger(bytes / MEBIBYTE) - ? `${String(bytes / MEBIBYTE)} MiB / ${String(bytes)} bytes` - : `${String(bytes)} bytes`; - -/** User-visible recovery for the effective matching representation allowance. */ -const nativeMatchingAllowanceRecovery = ( - allowance: NativeMatchingAllowance, -): string => - [ - `Native function matching is limited to ${byteAllowance(allowance.maximumBytes)} of representation${allowance.source === "setting" ? ` by ${NATIVE_MATCHING_ALLOWANCE_SETTING}` : ""}.`, - `On MCP, call update_analysis_settings with setting native.matching_representation_bytes, action set, and a value in bytes up to ${byteAllowance(MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES)} (default ${byteAllowance(DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES)}), then retry the original request. It applies to the next operation without restarting REA. For CLI or future REA processes, set ${NATIVE_MATCHING_ALLOWANCE_SETTING} in the launch environment.`, - "This budget is not a bound on total process RSS; raising it lets matching retain more representation in the REA process.", - "Splitting inventories into separate matches changes global name and body uniqueness, so it is not an equivalent workaround.", - "Repeating the unchanged request fails the same way.", - ].join(" "); - /** Budget the actual selected observations, before cloning or index allocation. */ export class NativeMatchingAdmission { readonly #maximum: number; @@ -53,7 +32,7 @@ export class NativeMatchingAdmission { throw new AnalysisResourceConstraintError( this.operation, "capacity", - `Native function matching exceeds its ${byteAllowance(this.#maximum)} representation allowance (native.matching_representation_bytes).`, + `Native function matching exceeds its ${nativeMatchingByteAllowance(this.#maximum)} representation allowance (native.matching_representation_bytes).`, { maximum_bytes: this.#maximum }, { retryable: false, diff --git a/src/config/nativeMatchingAllowance.ts b/src/config/nativeMatchingAllowance.ts index c834d066b9..55b5ea91e8 100644 --- a/src/config/nativeMatchingAllowance.ts +++ b/src/config/nativeMatchingAllowance.ts @@ -56,3 +56,23 @@ export const parseNativeMatchingAllowance = ( }), ); }; + +const MEBIBYTE = 1024 * 1024; + +/** Display one allowance in MiB and bytes, or bytes alone when not whole MiB. */ +export const nativeMatchingByteAllowance = (bytes: number): string => + Number.isInteger(bytes / MEBIBYTE) + ? `${String(bytes / MEBIBYTE)} MiB / ${String(bytes)} bytes` + : `${String(bytes)} bytes`; + +/** User-visible recovery for the effective matching representation allowance. */ +export const nativeMatchingAllowanceRecovery = ( + allowance: NativeMatchingAllowance, +): string => + [ + `Native function matching is limited to ${nativeMatchingByteAllowance(allowance.maximumBytes)} of representation${allowance.source === "setting" ? ` by ${NATIVE_MATCHING_ALLOWANCE_SETTING}` : ""}.`, + `On MCP, call update_analysis_settings with setting native.matching_representation_bytes, action set, and a value in bytes up to ${nativeMatchingByteAllowance(MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES)} (default ${nativeMatchingByteAllowance(DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES)}), then retry the original request. It applies to the next operation without restarting REA. For CLI or future REA processes, set ${NATIVE_MATCHING_ALLOWANCE_SETTING} in the launch environment.`, + "This budget is not a bound on total process RSS; raising it lets matching retain more representation in the REA process.", + "Splitting inventories into separate matches changes global name and body uniqueness, so it is not an equivalent workaround.", + "Repeating the unchanged request fails the same way.", + ].join(" "); diff --git a/src/domain/analysisResourceLimits.ts b/src/domain/analysisResourceLimits.ts index 93e68c94a1..83d6dba0f7 100644 --- a/src/domain/analysisResourceLimits.ts +++ b/src/domain/analysisResourceLimits.ts @@ -18,12 +18,10 @@ export const MAXIMUM_ASAR_MAX_HEADER_BYTES = 256 * 1024 * 1024; export const DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES = 96 * 1024 * 1024; /** - * Largest configurable matching admission. Complete matching Evidence is - * serialized into one canonical string for its digest, about 670 bytes per - * emitted member with short names. Each member is charged at least about - * 1.9 KiB, so 1 GiB keeps that text well below Node's single-string ceiling - * of about 512 Mi code units. A lower value only refuses more requests, so the - * setting has no floor. + * Largest configurable matching admission. This is an REA policy ceiling, not + * a claim about host capacity: the allowance approximates the heap + * representation matching retains, and peak heap during a request can exceed + * it. A lower value only refuses more requests, so the setting has no floor. */ export const MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES = 1024 * 1024 * 1024;