mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
fix(javascript): name heap and semantic ceilings (#6022)
* fix(javascript): name heap and semantic ceilings Refs #5910. Heap exhaustion names max_heap_mb with its effective value, range, and next-analysis worker restart. Semantic ceiling coverage names the four max_semantic_* arguments. Wakaru and transfer ceilings say this release has no runtime override. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): distinguish adjustable ceilings from fixed limits The effective transfer file ceiling and the parent result budget follow the CLI/MCP process heap, so recovery names NODE_OPTIONS instead of denying an override. A provenance report over 8 MiB keeps the fixed allowance guidance, and the Wakaru deadline says an unchanged retry may hit it again. Refs #5910 Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): keep Bun OOM and checkpoint heap controls distinct Bun heap-exhaustion exits no longer claim the ignored max_heap_mb V8 old-space limit. Checkpoint decode names the parent heap and Node NODE_OPTIONS, the same control as the parent result budget. Refs #5910 Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): name semantic ceilings without claiming both were reached Truncated semantic retention names the total and per-file controls as effective ceilings. Callers only know that retention was truncated, so the limitation no longer says both ceilings were reached. Refs #5910 Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): name only the semantic ceiling that stopped retention Semantic ceiling limitations claimed both the application total and the per-file control whenever either one truncated the graph. Record which offered budget stopped node and unknown retention, and name only those controls. Coverage limits still list both effective values. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): require a value in the NODE_OPTIONS heap example A bare --max-old-space-size is an illegal V8 flag and prevents Node from starting. Parent-heap and transfer-ceiling recovery now share --max-old-space-size=<MiB>, and the Kuna heap remediation uses the same complete form. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(javascript): limit the old-space placeholder to NODE_OPTIONS recovery The review covers the CLI/MCP NODE_OPTIONS example and the transfer-ceiling copy. The Kuna heap-headroom sentence stays unchanged. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com>
This commit is contained in:
@@ -47,11 +47,21 @@ import {
|
||||
import {
|
||||
readJavaScriptAnalysisTransfer,
|
||||
JAVASCRIPT_ANALYSIS_TRANSFER_RECORD_BYTES,
|
||||
javaScriptForwardedTransferRemediation,
|
||||
javaScriptTransferRetentionBytes,
|
||||
} from "./JavaScriptAnalysisTransfer.js";
|
||||
import {
|
||||
JAVASCRIPT_PARENT_CHECKPOINT_HEAP_REMEDIATION,
|
||||
JAVASCRIPT_PARENT_RESULT_BUDGET_REMEDIATION,
|
||||
JAVASCRIPT_WORKER_HEAP_MIB_MAXIMUM,
|
||||
JAVASCRIPT_WORKER_HEAP_MIB_MINIMUM,
|
||||
javaScriptWorkerHeapExhaustionRecovery,
|
||||
javaScriptWorkerHeapRemediation,
|
||||
} from "../../domain/javascript/javascriptAnalysisResourceControls.js";
|
||||
import { javaScriptWorkerStaticAnalysisSchema } from "./JavaScriptAnalysisWorkerSchemas.js";
|
||||
import {
|
||||
JAVASCRIPT_ANALYSIS_WORKER_DEFAULTS as DEFAULTS,
|
||||
javaScriptCheckpointCeilingRemediation,
|
||||
javaScriptWorkerMessageSchema,
|
||||
javaScriptWorkerRequestSchema,
|
||||
javaScriptWorkerAdmissionSchema,
|
||||
@@ -159,8 +169,8 @@ export class JavaScriptAnalysisWorker {
|
||||
});
|
||||
if (
|
||||
!Number.isSafeInteger(limits.heapMb) ||
|
||||
limits.heapMb < 128 ||
|
||||
limits.heapMb > 16_384 ||
|
||||
limits.heapMb < JAVASCRIPT_WORKER_HEAP_MIB_MINIMUM ||
|
||||
limits.heapMb > JAVASCRIPT_WORKER_HEAP_MIB_MAXIMUM ||
|
||||
!Number.isSafeInteger(limits.timeoutMs) ||
|
||||
limits.timeoutMs <= 0 ||
|
||||
limits.timeoutMs > 2_147_483_647
|
||||
@@ -303,8 +313,11 @@ export class JavaScriptAnalysisWorker {
|
||||
throw new AnalysisResourceConstraintError(
|
||||
OPERATION,
|
||||
"transport",
|
||||
`Source identity for ${file.path} exceeds the worker request byte budget`,
|
||||
`Source identity for ${file.path} exceeds the ${String(DEFAULTS.protocolBytes)}-byte worker request ceiling. This release has no runtime override.`,
|
||||
{ worker_request_bytes: DEFAULTS.protocolBytes },
|
||||
{
|
||||
remediationAction: `This release has no runtime override for the ${String(DEFAULTS.protocolBytes)}-byte JavaScript worker request ceiling. Raising max_heap_mb does not raise it. Repeating the unchanged request fails the same way.`,
|
||||
},
|
||||
);
|
||||
const stdin = supervisor.launch.process.stdin;
|
||||
if (stdin === undefined || stdin === null)
|
||||
@@ -422,8 +435,7 @@ export class JavaScriptAnalysisWorker {
|
||||
module_retention_estimate_bytes: moduleEstimate,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Use the retained static facts or analyze fewer source files. This limit belongs to the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
remediationAction: `Use the retained static facts or analyze fewer source files. ${JAVASCRIPT_PARENT_RESULT_BUDGET_REMEDIATION}`,
|
||||
},
|
||||
),
|
||||
});
|
||||
@@ -462,8 +474,7 @@ export class JavaScriptAnalysisWorker {
|
||||
graph_records: descriptor.graph_records,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Use the retained static and module facts or analyze fewer source files. This limit belongs to the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
remediationAction: `Use the retained static and module facts or analyze fewer source files. ${JAVASCRIPT_PARENT_RESULT_BUDGET_REMEDIATION}`,
|
||||
},
|
||||
),
|
||||
});
|
||||
@@ -685,6 +696,9 @@ export class JavaScriptAnalysisWorker {
|
||||
"memory",
|
||||
"The parent's remaining heap cannot safely decode the completed JavaScript static checkpoint",
|
||||
{ ...this.#limits(), checkpoint_bytes: bytes },
|
||||
{
|
||||
remediationAction: JAVASCRIPT_PARENT_CHECKPOINT_HEAP_REMEDIATION,
|
||||
},
|
||||
);
|
||||
const text = await readFile(path, "utf8");
|
||||
if (
|
||||
@@ -720,8 +734,7 @@ export class JavaScriptAnalysisWorker {
|
||||
application_projection_required_bytes: expandedBytes,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Read the complete static facts on the file node or analyze fewer source files. Expanded application relationships exceed the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
remediationAction: `Read the complete static facts on the file node or analyze fewer source files. Expanded application relationships exceed the parent result budget. ${JAVASCRIPT_PARENT_RESULT_BUDGET_REMEDIATION}`,
|
||||
},
|
||||
);
|
||||
return facts;
|
||||
@@ -753,9 +766,12 @@ export class JavaScriptAnalysisWorker {
|
||||
return new AnalysisResourceConstraintError(
|
||||
OPERATION,
|
||||
"memory",
|
||||
`Owned JavaScript worker reached its ${this.#processMemoryLimitBytes === null ? "" : `${String(this.#processMemoryLimitBytes)}-byte `}process memory limit while analyzing ${path} during ${this.#phase}`,
|
||||
`Owned JavaScript worker reached its ${this.#processMemoryLimitBytes === null ? "" : `${String(this.#processMemoryLimitBytes)}-byte `}process memory limit while analyzing ${path} during ${this.#phase}. That limit is max_heap_mb ${String(this.limits.heapMb)} MiB plus a 512 MiB Bun runtime reserve`,
|
||||
this.#limits(),
|
||||
{ capturedOutput: this.#captured() },
|
||||
{
|
||||
capturedOutput: this.#captured(),
|
||||
remediationAction: javaScriptWorkerHeapRemediation(this.limits.heapMb),
|
||||
},
|
||||
);
|
||||
}
|
||||
#remainingResultBudget(): number {
|
||||
@@ -990,14 +1006,24 @@ export class JavaScriptAnalysisWorker {
|
||||
path: string,
|
||||
failure: Extract<WorkerPrimaryFailure, { kind: "exit" }>,
|
||||
): AnalysisError {
|
||||
if (failure.heapExhaustion)
|
||||
if (failure.heapExhaustion) {
|
||||
const recovery = javaScriptWorkerHeapExhaustionRecovery({
|
||||
heapFlagsEnforced: WORKER_HEAP_FLAGS_ENFORCED,
|
||||
heapMb: this.limits.heapMb,
|
||||
path,
|
||||
phase: this.#phase,
|
||||
});
|
||||
return new AnalysisResourceConstraintError(
|
||||
OPERATION,
|
||||
"memory",
|
||||
`Owned JavaScript worker exhausted its heap while analyzing ${path} during ${this.#phase}`,
|
||||
recovery.reason,
|
||||
this.#limits(),
|
||||
{ capturedOutput: this.#captured() },
|
||||
{
|
||||
capturedOutput: this.#captured(),
|
||||
remediationAction: recovery.remediationAction,
|
||||
},
|
||||
);
|
||||
}
|
||||
return new ProviderAdapterError(PROVIDER, OPERATION, {
|
||||
capturedOutput: this.#captured(),
|
||||
diagnostics: {
|
||||
@@ -1031,13 +1057,33 @@ export class JavaScriptAnalysisWorker {
|
||||
response: Extract<JavaScriptWorkerMessage, { kind: "failure" }>,
|
||||
phase: string,
|
||||
): AnalysisError {
|
||||
if (response.reason === "resource")
|
||||
if (response.reason === "resource") {
|
||||
const reported = response.limits;
|
||||
const limits = { ...this.#limits(), ...reported };
|
||||
const transferRemediation =
|
||||
javaScriptForwardedTransferRemediation(reported);
|
||||
const checkpointBytes = reported?.checkpoint_limit_bytes;
|
||||
const checkpointRemediation =
|
||||
typeof checkpointBytes === "number"
|
||||
? javaScriptCheckpointCeilingRemediation(checkpointBytes)
|
||||
: undefined;
|
||||
const parentBudget =
|
||||
reported?.semantic_result_budget_bytes !== undefined ||
|
||||
reported?.parent_result_budget_bytes !== undefined;
|
||||
const remediationAction =
|
||||
transferRemediation ??
|
||||
checkpointRemediation ??
|
||||
(parentBudget
|
||||
? JAVASCRIPT_PARENT_RESULT_BUDGET_REMEDIATION
|
||||
: undefined);
|
||||
return new AnalysisResourceConstraintError(
|
||||
OPERATION,
|
||||
response.resource ?? "memory",
|
||||
response.message,
|
||||
{ ...this.#limits(), ...response.limits },
|
||||
limits,
|
||||
remediationAction === undefined ? undefined : { remediationAction },
|
||||
);
|
||||
}
|
||||
return new AnalysisOutputError(
|
||||
OPERATION,
|
||||
`${path} during ${phase}: ${response.message}`,
|
||||
|
||||
Reference in New Issue
Block a user