mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
2947a77507
* fix(engines): keep format ceilings fixed and recover the EVMole deadline Promote the owned EVMole worker wall clock to timeout_ms and name it in recovery. Fixed CPU, byte, and address-space refusals in this theme say the adjustable deadline does not raise them. Refs #5910 Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(engines): recover the allowance that refused the request Model capacity recovery follows a structured limit instead of message text, and the shared header ceiling no longer names Safetensors. Firmware signal errors keep captured tool output, oversized reports do not suggest an intermittent rerun, and NativeAOT hydration budget exhaustion explains the fixed parser allowance on the partial report. 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>
547 lines
18 KiB
TypeScript
547 lines
18 KiB
TypeScript
import {
|
|
createAnalysisExecution,
|
|
type AnalysisExecution,
|
|
type ExecutionOptions,
|
|
} from "../application/AnalysisProvider.js";
|
|
import type { SqliteDatabasePort } from "../application/sqlite/SqliteDatabasePort.js";
|
|
import { ArtifactResourceScope } from "../artifacts/ArtifactResourceScope.js";
|
|
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
|
import { bindArtifactFileCleanup } from "../artifacts/ArtifactFileOperation.js";
|
|
import type {
|
|
AnalysisCapturedOutput,
|
|
AnalysisError,
|
|
} from "../domain/analysisErrorBase.js";
|
|
import {
|
|
AnalysisCancelledError,
|
|
AnalysisInputError,
|
|
AnalysisOutputError,
|
|
AnalysisResourceConstraintError,
|
|
} from "../domain/analysisErrorCore.js";
|
|
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
|
import type { JsonValue } from "../domain/jsonValue.js";
|
|
import { createEvidence } from "../domain/evidence.js";
|
|
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
|
|
import { err, ok, type Result } from "../domain/result.js";
|
|
import {
|
|
inspectSqliteDatabaseInputSchema,
|
|
sqliteDatabaseSchema,
|
|
type InspectSqliteDatabaseInput,
|
|
SQLITE_PROVIDER_IDENTITY,
|
|
DEFAULT_SQLITE_WORKER_TIMEOUT_MS,
|
|
sqliteInspectionParameters,
|
|
} from "../domain/sqlite/sqliteDatabase.js";
|
|
import { isAbsolute } from "node:path";
|
|
import { PrivateRuntimeRoot } from "../process/PrivateRuntimeRoot.js";
|
|
import {
|
|
OwnedCommandFailure,
|
|
ownedCommandResources,
|
|
} from "../process/OwnedCommand.js";
|
|
import type {
|
|
ProviderProcessStopResult,
|
|
ProviderProcessSupervisor,
|
|
} from "../process/ProviderProcess.js";
|
|
import {
|
|
createSqliteCleanupError,
|
|
sqliteDatabaseFailure,
|
|
} from "./SqliteDatabaseFailures.js";
|
|
import { captureSqliteDatabaseSnapshot } from "./SqliteDatabaseSnapshot.js";
|
|
import { SQLITE_DATABASE_LIMITS } from "./SqliteDatabaseLimits.js";
|
|
|
|
import {
|
|
executeSqliteDatabaseWorker,
|
|
type SqliteWorkerLauncher,
|
|
} from "./SqliteDatabaseWorkerExecution.js";
|
|
|
|
const operation = "inspect_sqlite_database";
|
|
type SqliteOutcome = Result<AnalysisExecution, AnalysisError>;
|
|
type SqliteRuntimeRoot = Pick<PrivateRuntimeRoot, "path" | "close">;
|
|
interface PendingSnapshotCleanup {
|
|
readonly input: InspectSqliteDatabaseInput;
|
|
readonly result: SqliteOutcome;
|
|
readonly output: AnalysisCapturedOutput | undefined;
|
|
readonly rootFailure: AnalysisError;
|
|
readonly processFailure: AnalysisError | undefined;
|
|
process: ProviderProcessSupervisor | undefined;
|
|
}
|
|
/** Inspect a provider-owned copy through a cancellable SQLite child, without source writes. */
|
|
export class SqliteDatabaseProvider implements SqliteDatabasePort {
|
|
readonly #active = new Set<Promise<SqliteOutcome>>();
|
|
readonly #artifactResources = new ArtifactResourceScope();
|
|
readonly #pendingCleanup = new Map<
|
|
SqliteRuntimeRoot,
|
|
PendingSnapshotCleanup
|
|
>();
|
|
#closed = false;
|
|
#closePromise: Promise<void> | undefined;
|
|
#retryPromise: Promise<Result<null, AnalysisError>> | undefined;
|
|
constructor(
|
|
readonly environment: Readonly<NodeJS.ProcessEnv> = process.env,
|
|
readonly launcher?: SqliteWorkerLauncher,
|
|
readonly createRuntime: () => Promise<
|
|
Pick<PrivateRuntimeRoot, "path" | "close">
|
|
> = () => PrivateRuntimeRoot.create({ prefix: "rea-sqlite-database-" }),
|
|
) {}
|
|
|
|
/** Return exact original DB/WAL identities and current schema/selected committed rows. */
|
|
async inspect(
|
|
input: InspectSqliteDatabaseInput,
|
|
options?: ExecutionOptions,
|
|
): Promise<SqliteOutcome> {
|
|
if (options?.signal?.aborted)
|
|
return err(
|
|
new AnalysisCancelledError(operation, {
|
|
cause: options.signal.reason,
|
|
}),
|
|
);
|
|
if (this.#closed) return err(new AnalysisCancelledError(operation));
|
|
if (this.#active.size >= SQLITE_DATABASE_LIMITS.concurrentInspections)
|
|
return err(
|
|
new AnalysisResourceConstraintError(
|
|
operation,
|
|
"capacity",
|
|
"SQLite inspection capacity is occupied. Retry after an active inspection completes.",
|
|
{
|
|
active_inspections: this.#active.size,
|
|
max_concurrent_inspections:
|
|
SQLITE_DATABASE_LIMITS.concurrentInspections,
|
|
input_bytes_per_inspection: SQLITE_DATABASE_LIMITS.inputBytes,
|
|
},
|
|
{
|
|
remediationAction: `The concurrent SQLite inspection allowance is ${String(SQLITE_DATABASE_LIMITS.concurrentInspections)}. This release has no runtime override. Waiting for an active inspection to finish can free a slot. worker_timeout_ms does not raise it. Retry after an active SQLite inspection completes.`,
|
|
},
|
|
),
|
|
);
|
|
const inspection = this.#artifactResources
|
|
.run(() => this.#inspect(input, options))
|
|
.catch((cause: unknown) =>
|
|
err(
|
|
sqliteDatabaseFailure(
|
|
cause,
|
|
input.path,
|
|
"artifact-read",
|
|
options?.signal,
|
|
),
|
|
),
|
|
);
|
|
this.#active.add(inspection);
|
|
try {
|
|
return await inspection;
|
|
} finally {
|
|
this.#active.delete(inspection);
|
|
}
|
|
}
|
|
|
|
/** Await inspections and retry retained descriptors, workers, and snapshot roots. */
|
|
close(): Promise<void> {
|
|
this.#closed = true;
|
|
this.#closePromise ??= Promise.allSettled(this.#active)
|
|
.then(async () => {
|
|
let descriptorFailure: AnalysisError | undefined;
|
|
try {
|
|
await this.#artifactResources.close();
|
|
} catch (cause: unknown) {
|
|
const cleanup = ArtifactReaderFailure.cleanupObservation(
|
|
cause,
|
|
"SQLite artifact descriptors",
|
|
);
|
|
descriptorFailure = new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
cleanup.resources,
|
|
{ reason: cleanup.reason },
|
|
{ operation, cause },
|
|
);
|
|
bindArtifactFileCleanup(cause, descriptorFailure);
|
|
}
|
|
const cleaned = await this.#retryCleanup();
|
|
if (descriptorFailure !== undefined && !cleaned.ok) {
|
|
const failure = new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
[
|
|
...descriptorFailure.cleanupResources,
|
|
...cleaned.error.cleanupResources,
|
|
],
|
|
{
|
|
failures: [
|
|
projectAnalysisError(descriptorFailure),
|
|
projectAnalysisError(cleaned.error),
|
|
],
|
|
},
|
|
{ operation },
|
|
);
|
|
failure.bindCleanupDependencies([descriptorFailure, cleaned.error]);
|
|
throw failure;
|
|
}
|
|
if (descriptorFailure !== undefined) throw descriptorFailure;
|
|
if (!cleaned.ok) throw cleaned.error;
|
|
})
|
|
.catch((cause: unknown) => {
|
|
this.#closePromise = undefined;
|
|
throw cause;
|
|
});
|
|
return this.#closePromise;
|
|
}
|
|
|
|
#retryCleanup(): Promise<Result<null, AnalysisError>> {
|
|
this.#retryPromise ??= this.#cleanupPending().finally(() => {
|
|
this.#retryPromise = undefined;
|
|
});
|
|
return this.#retryPromise;
|
|
}
|
|
|
|
async #cleanupPending(): Promise<Result<null, AnalysisError>> {
|
|
const failures: AnalysisError[] = [];
|
|
for (const [root, pending] of [...this.#pendingCleanup]) {
|
|
if (pending.process !== undefined) {
|
|
const stopped = await pending.process.stop();
|
|
if (stopped.status === "incomplete" || stopped.status === "not-owned") {
|
|
const reason =
|
|
stopped.status === "incomplete"
|
|
? stopped.reason
|
|
: "SQLite worker ownership remains unresolved.";
|
|
const failure = sqliteCleanupFailure(
|
|
[
|
|
pending.process.launch.ownership?.runId ?? "owned-sqlite-worker",
|
|
root.path,
|
|
],
|
|
reason,
|
|
pending.result,
|
|
pending.input,
|
|
pending.output,
|
|
);
|
|
failure.bindCleanupDependencies(
|
|
[pending.processFailure, pending.rootFailure].filter(
|
|
(dependency): dependency is AnalysisError =>
|
|
dependency !== undefined,
|
|
),
|
|
);
|
|
failures.push(failure);
|
|
continue;
|
|
}
|
|
pending.process = undefined;
|
|
pending.processFailure?.resolveCleanup();
|
|
}
|
|
const cleaned = await cleanupSqliteRoot(
|
|
root,
|
|
pending.result,
|
|
pending.input,
|
|
pending.output,
|
|
);
|
|
if (cleaned.ok) {
|
|
pending.rootFailure.resolveCleanup();
|
|
this.#pendingCleanup.delete(root);
|
|
} else {
|
|
cleaned.error.bindCleanupDependencies([pending.rootFailure]);
|
|
failures.push(cleaned.error);
|
|
}
|
|
}
|
|
if (failures.length === 1 && failures[0] !== undefined)
|
|
return err(failures[0]);
|
|
return failures.length === 0
|
|
? ok(null)
|
|
: err(
|
|
new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
failures.flatMap((failure) => failure.cleanupResources),
|
|
{ failures: failures.map(projectAnalysisError) },
|
|
{ operation },
|
|
).bindCleanupDependencies(failures),
|
|
);
|
|
}
|
|
|
|
async #inspect(
|
|
input: InspectSqliteDatabaseInput,
|
|
options?: ExecutionOptions,
|
|
): Promise<SqliteOutcome> {
|
|
let root: Pick<PrivateRuntimeRoot, "path" | "close"> | undefined;
|
|
let processOwner: ProviderProcessSupervisor | undefined;
|
|
let processCleanup:
|
|
| Extract<ProviderProcessStopResult, { status: "incomplete" }>
|
|
| undefined;
|
|
let retainedOutput: AnalysisCapturedOutput | undefined;
|
|
let phase = "configuration";
|
|
let result: Result<AnalysisExecution, AnalysisError>;
|
|
const workerTimeoutMs =
|
|
input.worker_timeout_ms ?? DEFAULT_SQLITE_WORKER_TIMEOUT_MS;
|
|
try {
|
|
if (options?.signal?.aborted)
|
|
throw new AnalysisCancelledError(operation, {
|
|
cause: options.signal.reason,
|
|
});
|
|
validateSqliteInput(input);
|
|
const retired = await this.#retryCleanup();
|
|
if (!retired.ok) return retired;
|
|
if (options?.signal?.aborted)
|
|
throw new AnalysisCancelledError(operation, {
|
|
cause: options.signal.reason,
|
|
});
|
|
if (this.#closed) throw new AnalysisCancelledError(operation);
|
|
root = await this.createRuntime();
|
|
phase = "artifact-read";
|
|
const snapshot = await captureSqliteDatabaseSnapshot(
|
|
input.path,
|
|
root.path,
|
|
this.#artifactResources,
|
|
options?.signal,
|
|
);
|
|
phase = "worker";
|
|
const inspection = await executeSqliteDatabaseWorker({
|
|
input,
|
|
root: root.path,
|
|
snapshotPath: snapshot.snapshotPath,
|
|
timeoutMs: workerTimeoutMs,
|
|
environment: this.environment,
|
|
resourceScope: this.#artifactResources,
|
|
...(this.launcher === undefined ? {} : { launcher: this.launcher }),
|
|
...(options?.signal === undefined ? {} : { signal: options.signal }),
|
|
captured: (output) => {
|
|
retainedOutput = output;
|
|
},
|
|
retainCleanup: (owner, result) => {
|
|
processOwner = owner;
|
|
processCleanup = result;
|
|
},
|
|
});
|
|
const validated = sqliteDatabaseSchema.safeParse({
|
|
artifact: snapshot.artifact,
|
|
wal: snapshot.wal,
|
|
...inspection,
|
|
worker_timeout_ms: workerTimeoutMs,
|
|
});
|
|
if (!validated.success)
|
|
throw new AnalysisOutputError(
|
|
operation,
|
|
"SQLite worker report dimensions or identity fields are invalid",
|
|
retainedOutput === undefined
|
|
? undefined
|
|
: { capturedOutput: retainedOutput },
|
|
);
|
|
result = ok(createSqliteObservation(validated.data, input.path));
|
|
} catch (cause: unknown) {
|
|
// A failure rethrown after retainCleanup carries no owner of its own;
|
|
// keep the retained worker instead of discarding it.
|
|
if (
|
|
cause instanceof OwnedCommandFailure &&
|
|
cause.cleanupOwner !== undefined
|
|
)
|
|
processOwner = cause.cleanupOwner;
|
|
const failure = sqliteDatabaseFailure(
|
|
cause,
|
|
input.path,
|
|
phase,
|
|
options?.signal,
|
|
workerTimeoutMs,
|
|
);
|
|
retainedOutput ??= failure.capturedOutput;
|
|
result = err(failure);
|
|
}
|
|
if (root !== undefined) {
|
|
if (processOwner !== undefined) {
|
|
const ownership = processOwner.launch.ownership;
|
|
const rootFailure = new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
[root.path],
|
|
{ reason: "SQLite runtime root cleanup remains unresolved." },
|
|
{ operation },
|
|
);
|
|
const processReason =
|
|
processCleanup?.reason ?? "SQLite worker cleanup remains unresolved.";
|
|
const processFailure = new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
ownership === undefined
|
|
? ["owned-sqlite-worker"]
|
|
: ownedCommandResources(ownership),
|
|
{ reason: processReason },
|
|
{ operation },
|
|
);
|
|
this.#pendingCleanup.set(root, {
|
|
input,
|
|
result,
|
|
output: retainedOutput,
|
|
rootFailure,
|
|
processFailure,
|
|
process: processOwner,
|
|
});
|
|
if (processCleanup !== undefined) {
|
|
const failure = sqliteCleanupFailure(
|
|
ownership === undefined
|
|
? ["owned-sqlite-worker", root.path]
|
|
: ownedCommandResources(ownership, root.path),
|
|
processCleanup.reason,
|
|
result,
|
|
input,
|
|
retainedOutput,
|
|
processCleanup.cleanupResult === undefined
|
|
? undefined
|
|
: {
|
|
...(processCleanup.cleanupResult.failures === undefined
|
|
? {}
|
|
: {
|
|
failures: processCleanup.cleanupResult.failures.map(
|
|
(failure) => ({ ...failure }),
|
|
),
|
|
}),
|
|
...(processCleanup.cleanupResult.unverified === undefined
|
|
? {}
|
|
: {
|
|
unverified: processCleanup.cleanupResult.unverified.map(
|
|
(process) => ({ ...process }),
|
|
),
|
|
}),
|
|
},
|
|
);
|
|
failure.bindCleanupDependencies([processFailure, rootFailure]);
|
|
return err(failure);
|
|
}
|
|
if (!result.ok) {
|
|
result.error.bindCleanupDependencies([processFailure, rootFailure]);
|
|
return result;
|
|
}
|
|
const failure = sqliteCleanupFailure(
|
|
[
|
|
...(ownership === undefined
|
|
? ["owned-sqlite-worker"]
|
|
: ownedCommandResources(ownership)),
|
|
root.path,
|
|
],
|
|
processReason,
|
|
result,
|
|
input,
|
|
retainedOutput,
|
|
);
|
|
failure.bindCleanupDependencies([processFailure, rootFailure]);
|
|
return err(failure);
|
|
}
|
|
const cleaned = await cleanupSqliteRoot(
|
|
root,
|
|
result,
|
|
input,
|
|
retainedOutput,
|
|
);
|
|
if (!cleaned.ok) {
|
|
const rootFailure = new ProviderCleanupError(
|
|
SQLITE_PROVIDER_IDENTITY.id,
|
|
[root.path],
|
|
{ reason: "SQLite runtime root cleanup remains unresolved." },
|
|
{ operation },
|
|
);
|
|
cleaned.error.bindCleanupDependencies([rootFailure]);
|
|
this.#pendingCleanup.set(root, {
|
|
input,
|
|
result,
|
|
output: retainedOutput,
|
|
rootFailure,
|
|
processFailure: undefined,
|
|
process: undefined,
|
|
});
|
|
return cleaned;
|
|
}
|
|
}
|
|
if (result.ok && options?.signal?.aborted)
|
|
return err(
|
|
new AnalysisCancelledError(operation, {
|
|
cause: options.signal.reason,
|
|
partialObservation: completedSqliteEvidence(input, result.value),
|
|
}),
|
|
);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
const createSqliteObservation = (
|
|
report: ReturnType<typeof sqliteDatabaseSchema.parse>,
|
|
path: string,
|
|
): AnalysisExecution => {
|
|
const locations: AnalysisExecution["locations"][number][] = [
|
|
{ kind: "artifact-path", path },
|
|
];
|
|
if (report.wal !== null)
|
|
locations.push({ kind: "artifact-path", path: report.wal.path });
|
|
return createAnalysisExecution(
|
|
report,
|
|
{ ...SQLITE_PROVIDER_IDENTITY, version: `SQLite ${report.engine.version}` },
|
|
{
|
|
rawResult: null,
|
|
subject: { path, format: "file", sha256: report.artifact.sha256 },
|
|
locations,
|
|
limitations: report.limitations,
|
|
},
|
|
);
|
|
};
|
|
const cleanupSqliteRoot = async (
|
|
root: Pick<PrivateRuntimeRoot, "path" | "close">,
|
|
result: Result<AnalysisExecution, AnalysisError>,
|
|
input: InspectSqliteDatabaseInput,
|
|
output?: AnalysisCapturedOutput,
|
|
): Promise<Result<null, AnalysisError>> => {
|
|
try {
|
|
await root.close();
|
|
return ok(null);
|
|
} catch (cause: unknown) {
|
|
return err(
|
|
sqliteCleanupFailure(
|
|
[root.path],
|
|
cause instanceof Error ? cause.message : String(cause),
|
|
result,
|
|
input,
|
|
output,
|
|
undefined,
|
|
cause,
|
|
),
|
|
);
|
|
}
|
|
};
|
|
|
|
const sqliteCleanupFailure = (
|
|
resources: readonly string[],
|
|
reason: string,
|
|
result: SqliteOutcome,
|
|
input: InspectSqliteDatabaseInput,
|
|
output?: AnalysisCapturedOutput,
|
|
details?: Readonly<Record<string, JsonValue>>,
|
|
cause?: unknown,
|
|
): ProviderCleanupError => {
|
|
const partialObservation = result.ok
|
|
? completedSqliteEvidence(input, result.value)
|
|
: result.error.partialObservation;
|
|
return createSqliteCleanupError(
|
|
resources,
|
|
{
|
|
...details,
|
|
reason,
|
|
},
|
|
{
|
|
...(output === undefined ? {} : { capturedOutput: output }),
|
|
...(result.ok ? {} : { cleanupPrimary: result.error }),
|
|
...(cause === undefined ? {} : { cause }),
|
|
...(partialObservation === undefined ? {} : { partialObservation }),
|
|
},
|
|
);
|
|
};
|
|
|
|
const completedSqliteEvidence = (
|
|
input: InspectSqliteDatabaseInput,
|
|
execution: AnalysisExecution,
|
|
) =>
|
|
createEvidence(execution.subject ?? undefined, execution.provider, {
|
|
operation,
|
|
parameters: sqliteInspectionParameters(input),
|
|
result: execution.result,
|
|
confidence: "observed",
|
|
locations: execution.locations,
|
|
limitations: execution.limitations,
|
|
});
|
|
|
|
const validateSqliteInput = (input: InspectSqliteDatabaseInput): void => {
|
|
const parsed = inspectSqliteDatabaseInputSchema.safeParse(input);
|
|
if (!parsed.success || !isAbsolute(input.path))
|
|
throw new AnalysisInputError(operation, undefined, [
|
|
{
|
|
path: ["path"],
|
|
reason: "invalid_format",
|
|
message: parsed.success
|
|
? "path must be an absolute local filesystem path"
|
|
: parsed.error.message,
|
|
},
|
|
]);
|
|
};
|