writeAtomic, everywhere a file lands

the .part-then-rename rule was applied at two upload routes yesterday and
by this morning the platform had a dozen other writes putting files in the
same folders — an OCR result beside its image, a TTS clip, a download
landing, a save from the editor — every one straight to the final name. a
guarantee that holds for two of fourteen paths is not a guarantee, and the
next person adding a fifteenth had nothing to copy.

so it is a function now, and every durable write goes through it: the file
browser, sendoff, task definitions, skill and tool files, bug reports,
scraped attachments, the chat provider config.

the failure it prevents is silent rather than loud. a truncated m4a decodes
fine, it is simply short — a commander transcribing recordings as they land
would produce a clean transcript of the first few seconds of a two-minute
memo and report success.

two things learned writing it. Bun.write creates the parent chain itself,
so the mkdir option i added was dead weight and several callers were doing
it twice. and Parameters<typeof Bun.write>[1] resolves to the first
overload only — BunFile — which rejects the string and Buffer every caller
actually passes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
2026-08-25 05:26:40 +00:00
co-authored by Claude Opus 5
parent 20b270ef07
commit e87323f71a
9 changed files with 164 additions and 42 deletions
@@ -4,6 +4,7 @@ import { AGENT_CONFIG_DIR } from '../../data-path';
import { invalidateModelCache } from '../chat/list-models';
import { logger } from '../chat/logger';
import { readConfigValue, writeConfigValue } from 'officerdb';
import { writeAtomic } from '@@/write-atomic';
export const chatProvidersRouter = createRouter();
@@ -69,7 +70,7 @@ async function readModelsConfig(): Promise<ModelConfig> {
}
async function writeModelsConfig(config: ModelConfig): Promise<void> {
await Bun.write(MODELS_FILE, JSON.stringify(config, null, 2));
await writeAtomic(MODELS_FILE, JSON.stringify(config, null, 2));
}
/**
@@ -342,7 +343,7 @@ async function readAuthJson(): Promise<AuthJson> {
}
async function writeAuthJson(auth: AuthJson): Promise<void> {
await Bun.write(AUTH_FILE, JSON.stringify(auth, null, 2));
await writeAtomic(AUTH_FILE, JSON.stringify(auth, null, 2));
}
/**