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 <noreply@anthropic.com>
This commit is contained in:
Kaoru0822andClaude Opus 5.5 committed 2026-10-25 10:17:19 +00:00
1 parent 87d3d6022c
commit 0600c7d11a
4 files changed
+30 -32

No files matched your search

+3 -2
View File
@@ -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 setup` copies it into client registrations. An invalid launch value is refused
by matching only, and a runtime value repairs it. A refusal carries by matching only, and a runtime value repairs it. A refusal carries
`details.limit` with the effective value, its source and bounds. Raising the `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 allowance lets matching retain more in the REA process. The 1 GiB maximum is
the complete Evidence's canonical serialization within one Node string. 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 Summary delivery happens after complete matching Evidence is constructed and
retained. It reduces the initial reply, but does not avoid that construction or retained. It reduces the initial reply, but does not avoid that construction or
raise the allowance. Repeated provenance remains raise the allowance. Repeated provenance remains
@@ -1,34 +1,13 @@
import { setImmediate } from "node:timers/promises"; import { setImmediate } from "node:timers/promises";
import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js"; import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js";
import { analysisSettingLimit } from "../../domain/analysisSettingDefinitions.js"; import { analysisSettingLimit } from "../../domain/analysisSettingDefinitions.js";
import {
DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES,
MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES,
} from "../../domain/analysisResourceLimits.js";
import { import {
DEFAULT_NATIVE_MATCHING_ALLOWANCE, DEFAULT_NATIVE_MATCHING_ALLOWANCE,
NATIVE_MATCHING_ALLOWANCE_SETTING, nativeMatchingAllowanceRecovery,
nativeMatchingByteAllowance,
type NativeMatchingAllowance, type NativeMatchingAllowance,
} from "../../config/nativeMatchingAllowance.js"; } 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. */ /** Budget the actual selected observations, before cloning or index allocation. */
export class NativeMatchingAdmission { export class NativeMatchingAdmission {
readonly #maximum: number; readonly #maximum: number;
@@ -53,7 +32,7 @@ export class NativeMatchingAdmission {
throw new AnalysisResourceConstraintError( throw new AnalysisResourceConstraintError(
this.operation, this.operation,
"capacity", "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 }, { maximum_bytes: this.#maximum },
{ {
retryable: false, retryable: false,
+20
View File
@@ -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(" ");
+4 -6
View File
@@ -18,12 +18,10 @@ export const MAXIMUM_ASAR_MAX_HEADER_BYTES = 256 * 1024 * 1024;
export const DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES = 96 * 1024 * 1024; export const DEFAULT_NATIVE_MATCHING_REPRESENTATION_BYTES = 96 * 1024 * 1024;
/** /**
* Largest configurable matching admission. Complete matching Evidence is * Largest configurable matching admission. This is an REA policy ceiling, not
* serialized into one canonical string for its digest, about 670 bytes per * a claim about host capacity: the allowance approximates the heap
* emitted member with short names. Each member is charged at least about * representation matching retains, and peak heap during a request can exceed
* 1.9 KiB, so 1 GiB keeps that text well below Node's single-string ceiling * it. A lower value only refuses more requests, so the setting has no floor.
* of about 512 Mi code units. A lower value only refuses more requests, so the
* setting has no floor.
*/ */
export const MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES = 1024 * 1024 * 1024; export const MAXIMUM_NATIVE_MATCHING_REPRESENTATION_BYTES = 1024 * 1024 * 1024;