diff --git a/server/src/maintenance/native-harness-prestage-runtime.test.ts b/server/src/maintenance/native-harness-prestage-runtime.test.ts index dd5873411e0..0712f162eca 100644 --- a/server/src/maintenance/native-harness-prestage-runtime.test.ts +++ b/server/src/maintenance/native-harness-prestage-runtime.test.ts @@ -20,7 +20,6 @@ it("writes backups with the configured app key even after its file disappears", await initializeNativeHarnessPrestageKey(keyFile); await fs.unlink(keyFile); const prepared = createLocalEncryptedCipher("write").encrypt("saved harness key"); - // A later app process uses its own original key, not a newly generated file. vi.stubEnv("PAPERCLIP_SECRETS_MASTER_KEY", ""); await fs.writeFile(keyFile, key, { mode: 0o600 }); expect(createLocalEncryptedCipher("read").decrypt(prepared)).toBe("saved harness key"); @@ -69,7 +68,6 @@ describe.skipIf(!support.supported)("prestage database waits", () => { await expect(db.transaction(tx => tx.execute(sql`select pg_advisory_xact_lock(939193)`))) .rejects.toMatchObject({ cause: { code: "55P03" } }); expect(Date.now() - started).toBeLessThan(10_000); - // Abort cleanup must also interrupt a query whose statement deadline is later. const waiting = db.execute(sql`select pg_sleep(20)`); const rejected = expect(waiting).rejects.toBeTruthy(); await new Promise(resolve => setTimeout(resolve, 100)); diff --git a/server/src/maintenance/native-harness-prestage-runtime.ts b/server/src/maintenance/native-harness-prestage-runtime.ts index 2924b89e9fc..9aae4ad1b60 100644 --- a/server/src/maintenance/native-harness-prestage-runtime.ts +++ b/server/src/maintenance/native-harness-prestage-runtime.ts @@ -1,8 +1,6 @@ import fs from "node:fs/promises"; import { isValidLocalEncryptedMasterKey } from "../secrets/local-encrypted-provider.js"; -/** Use the same existing vault key as the app for the whole preparation. A - * missing or replaced file must never cause a new key during publication. */ export async function initializeNativeHarnessPrestageKey(keyFilePath: string, env: NodeJS.ProcessEnv = process.env) { const path = env.PAPERCLIP_SECRETS_MASTER_KEY_FILE?.trim() || keyFilePath; const key = env.PAPERCLIP_SECRETS_MASTER_KEY?.trim() || await fs.readFile(path, "utf8"); @@ -11,8 +9,6 @@ export async function initializeNativeHarnessPrestageKey(keyFilePath: string, en env.PAPERCLIP_SECRETS_MASTER_KEY = key; } -/** These settings apply to every connection, including later transactions. - * Existing URL options stay intact; the finite command owns its wait bounds. */ export function nativeHarnessPrestageDatabaseUrl(source: string) { const url = new URL(source); url.searchParams.set("lock_timeout", "5000"); diff --git a/server/src/maintenance/native-harness-prestage.test.ts b/server/src/maintenance/native-harness-prestage.test.ts index f065e078296..f114f60b822 100644 --- a/server/src/maintenance/native-harness-prestage.test.ts +++ b/server/src/maintenance/native-harness-prestage.test.ts @@ -37,8 +37,6 @@ it.each([true, false])("checks unfulfilled database obligations for an empty sou expect(JSON.parse(failure.mock.calls[0][0])).toEqual({ schema: "paperclip.native-harness-prestage.v1", state: "blocked", failure: "native_harness_prestage_source_missing", enrollmentReady: false }); } else { - // Fresh databases and databases whose retained sources are already durable - // both have no unfulfilled local obligations, so an empty scan is valid. expect(process.exitCode ?? 0).toBe(0); expect(failure).not.toHaveBeenCalled(); expect(success).toHaveBeenCalledWith(JSON.stringify({ schema: "paperclip.native-harness-prestage.v1", counts, enrollmentReady: false })); @@ -61,8 +59,6 @@ it("reports a failed deadline with real timers when the dependency holds no even const bundled = await build({ entryPoints: [fileURLToPath(new URL("./native-harness-prestage.ts", import.meta.url))], bundle: true, platform: "node", format: "esm", write: false, - // Shorten only the command's deadlines. These remain real Node timers in - // a separate process, so an unreferenced fallback cannot be advanced by us. banner: { js: "const realTimeout = globalThis.setTimeout; globalThis.setTimeout = (fn, ms, ...args) => realTimeout(fn, ms === 5400000 ? 10 : ms === 10000 ? 50 : ms, ...args);" }, plugins: [{ name: "prestage-dependencies", setup(builder) { builder.onResolve({ filter: /.*/ }, args => args.importer ? { path: "dependencies", namespace: "fixture" } : undefined); diff --git a/server/src/maintenance/native-harness-prestage.ts b/server/src/maintenance/native-harness-prestage.ts index f65d4be3bd5..fba4095a408 100644 --- a/server/src/maintenance/native-harness-prestage.ts +++ b/server/src/maintenance/native-harness-prestage.ts @@ -7,8 +7,6 @@ import { getStorageService } from "../storage/index.js"; import { hasLocalNativeHarnessObligations, prestageNativeHarnessBackups } from "../services/native-runtime/native-harness-backup-migration.js"; import { initializeNativeHarnessPrestageKey, nativeHarnessPrestageDatabaseUrl } from "./native-harness-prestage-runtime.js"; -// Operator-only finite preparation. No task drain, scheduler, app routes, -// enrollment export, or assertion that other executions have stopped. if (process.env.PAPERCLIP_NATIVE_HARNESS_PRESTAGE !== "true") throw new Error("Explicit harness pre-copy mode is required"); const sourceUrl = process.env.DATABASE_URL; if (!sourceUrl) throw new Error("Harness pre-copy requires an explicit database"); @@ -26,11 +24,8 @@ const reportBlocked = (error: unknown) => { }; const abort = (reason: string) => { if (cancellation.signal.aborted) return; - // Report failure before awaiting cleanup: a dependency may never settle. reportBlocked(new Error(reason)); cancellation.abort(new Error(reason)); - // Closing this command's clients interrupts blocked queries. A bounded - // fallback also covers an unresponsive storage or filesystem dependency. shutdown = setTimeout(() => process.exit(1), 10_000); void closeRegisteredClients(url, { scope: "database" }); }; diff --git a/server/src/services/native-runtime/native-harness-backup-migration.ts b/server/src/services/native-runtime/native-harness-backup-migration.ts index a3f9f84fbba..12d55d49757 100644 --- a/server/src/services/native-runtime/native-harness-backup-migration.ts +++ b/server/src/services/native-runtime/native-harness-backup-migration.ts @@ -153,11 +153,7 @@ export async function migrateNativeHarnessBackups(db: Db, input: { return counts.reduce((total, count) => total + count, 0); } -/** Copy settled successful history using its released runtime owner. This is - * preparatory work, never an offline-writer assertion or enrollment receipt. */ export async function prestageNativeHarnessBackups(db: Db, input: { storage: StorageService; signal: AbortSignal }) { - // Keep preparatory work below offline throughput so the serving process can - // continue handling real work. This finite operation has no idle schedule. const deferSource = (scopeDigest: string, reason: string, outcome: string) => { console.warn(JSON.stringify({ schema: "paperclip.native-harness-prestage-source.v1", scopeDigest, reason })); return outcome; @@ -166,7 +162,6 @@ export async function prestageNativeHarnessBackups(db: Db, input: { storage: Sto if (error instanceof NativeHarnessBackupSourceError || error instanceof Error && error.message === "native_harness_migration_source_unsettled") { return deferSource(scopeDigest, error.message, "source_unavailable"); } - // This callback only receives preparation filesystem failures, never DB errors. if (["ENOENT", "ENOTDIR", "EISDIR", "ELOOP", "EACCES", "EPERM"].includes((error as NodeJS.ErrnoException)?.code ?? "")) { return deferSource(scopeDigest, "native_harness_migration_source_unavailable", "source_unavailable"); } diff --git a/server/src/services/native-runtime/native-harness-backup-source.ts b/server/src/services/native-runtime/native-harness-backup-source.ts index 26c559e3e49..5a8500bf921 100644 --- a/server/src/services/native-runtime/native-harness-backup-source.ts +++ b/server/src/services/native-runtime/native-harness-backup-source.ts @@ -1,12 +1,8 @@ import { lstat, readFile } from "node:fs/promises"; import { join } from "node:path"; -/** Only filesystem inspection can produce this error. Database failures must - * retain their identity, even if their class or code resembles a source error. */ export class NativeHarnessBackupSourceError extends Error {} -/** Wrap input reads individually, so archive output and database errors never - * become deferrable just because they share a filesystem error code. */ export async function readNativeHarnessBackupSourceInput(read: () => Promise): Promise { try { return await read(); } catch (error) { diff --git a/server/src/services/native-runtime/native-harness-backup-storage.ts b/server/src/services/native-runtime/native-harness-backup-storage.ts index 5c5fb935836..ae7ee97d9af 100644 --- a/server/src/services/native-runtime/native-harness-backup-storage.ts +++ b/server/src/services/native-runtime/native-harness-backup-storage.ts @@ -164,8 +164,6 @@ async function fence(tx: Parameters[0]>[0], owner: || stamp.normalizedSessionId !== inactiveSource.normalizedSessionId || stamp.runnerInstanceId !== inactiveSource.runnerInstanceId) { fail("prestage_source_changed"); } - // The task share lock serializes publication with execution checkout. A - // turn that ran during upload also changes the immutable backup manifest. const source = await readNativeHarnessBackupSource(inactiveSource.root); if (!source) fail("prestage_source_changed"); const { manifestBytes: manifest, manifest: identity, state } = source;