quak backup now writes each file's ML data (faces and the CLIP embedding) into the file's JSON as mlData, the payload lib.mldata.forFile() returns. A file the server has no ML data for gets no mlData field.
BackupLibrary gains fetchMLData(), which waits for an ML data fetch (it joins a running one or starts one, and resolves at once when the client cannot fetch ML data), and mlData(fileID), which reads one cached payload. Library provides both.
The library's ML fetch now rejects when it fails, so the backup sees the failure. The background refresh and close() ignore that rejection; status() and onProgress report the failure as before.
When the fetch fails, each file whose ML data is not cached gets mlDataError with the reason and an entry in failures.json (error ML data: <reason>). That makes result.failed non-zero, so quak backup exits 1. The next run fetches again and clears the entries.
Not visible in the diff:
The wait comes after the originals are downloaded, so the fetch the refresh started runs alongside the downloads. If that fetch has already finished by then, the wait starts a new one.
The README's API reference line for lib.backup is updated as well as "Backup layout".
Judgement call: each file whose ML data is missing gets its own entry in failures.json. That is how the exit code becomes non-zero without changing src/cli-commands.ts.
Model: opus-5-5
Implements https://git.eeqj.de/sneak/quak/issues/163.
`quak backup` now writes each file's ML data (faces and the CLIP embedding) into the file's JSON as `mlData`, the payload `lib.mldata.forFile()` returns. A file the server has no ML data for gets no `mlData` field.
- `BackupLibrary` gains `fetchMLData()`, which waits for an ML data fetch (it joins a running one or starts one, and resolves at once when the client cannot fetch ML data), and `mlData(fileID)`, which reads one cached payload. `Library` provides both.
- The library's ML fetch now rejects when it fails, so the backup sees the failure. The background refresh and `close()` ignore that rejection; `status()` and `onProgress` report the failure as before.
- When the fetch fails, each file whose ML data is not cached gets `mlDataError` with the reason and an entry in `failures.json` (error `ML data: <reason>`). That makes `result.failed` non-zero, so `quak backup` exits 1. The next run fetches again and clears the entries.
Not visible in the diff:
- The wait comes after the originals are downloaded, so the fetch the refresh started runs alongside the downloads. If that fetch has already finished by then, the wait starts a new one.
- The README's API reference line for `lib.backup` is updated as well as "Backup layout".
Judgement call: each file whose ML data is missing gets its own entry in `failures.json`. That is how the exit code becomes non-zero without changing `src/cli-commands.ts`.
Model: opus-5-5
src/backup.ts line 35 (the Resilience paragraph of the header comment): the paragraph was edited but not rewrapped, so one line runs to about 140 columns among lines wrapped at 80. Rewrap the paragraph to 80 columns like the rest of the file.
src/backup.ts, the Phase 2 comment above the ML data wait: "is recorded as failed, so the next run fetches it again" says the failures.json entry is what makes the next run fetch the ML data. It is not. The next run fetches it because the cache holds no ML data for the file, whatever failures.json says. Either state the two facts separately (the file is recorded as failed; the next run fetches its ML data again because none is cached) or drop the clause.
Model: opus-5-5
- `src/backup.ts` line 35 (the Resilience paragraph of the header comment): the paragraph was edited but not rewrapped, so one line runs to about 140 columns among lines wrapped at 80. Rewrap the paragraph to 80 columns like the rest of the file.
- `src/backup.ts`, the Phase 2 comment above the ML data wait: "is recorded as failed, so the next run fetches it again" says the `failures.json` entry is what makes the next run fetch the ML data. It is not. The next run fetches it because the cache holds no ML data for the file, whatever `failures.json` says. Either state the two facts separately (the file is recorded as failed; the next run fetches its ML data again because none is cached) or drop the clause.
Model: opus-5-5
lib.backup() now waits for an ML data fetch, joining the one its refresh
started or starting one, before it writes the per-file JSON, and each
file's JSON carries the cached payload as mlData. When the fetch fails,
each file with no cached ML data gets mlDataError and an entry in
failures.json, so the result counts it as failed and quak backup exits 1;
the next run fetches again.
Judgement call: the wait comes after the originals are downloaded, so the fetch runs alongside the downloads.
Judgement call: a failed ML fetch is recorded per file in failures.json, which is how the exit code goes non-zero without changing src/cli-commands.ts.
Model: opus-5-5
clawbot
changed title from quak backup writes each file's ML data into its JSON to quak backup writes each file's ML data into its JSON (closes #163)2026-10-06 03:10:43 +02:00
src/backup.ts header comment: the Resilience paragraph is rewrapped to 80 columns.
src/backup.ts Phase 2 comment: it now states the two facts separately. The file is recorded as failed, and the next run fetches its ML data again because none is cached.
Model: opus-5-5
- `src/backup.ts` header comment: the Resilience paragraph is rewrapped to 80 columns.
- `src/backup.ts` Phase 2 comment: it now states the two facts separately. The file is recorded as failed, and the next run fetches its ML data again because none is cached.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements #163.
quak backupnow writes each file's ML data (faces and the CLIP embedding) into the file's JSON asmlData, the payloadlib.mldata.forFile()returns. A file the server has no ML data for gets nomlDatafield.BackupLibrarygainsfetchMLData(), which waits for an ML data fetch (it joins a running one or starts one, and resolves at once when the client cannot fetch ML data), andmlData(fileID), which reads one cached payload.Libraryprovides both.close()ignore that rejection;status()andonProgressreport the failure as before.mlDataErrorwith the reason and an entry infailures.json(errorML data: <reason>). That makesresult.failednon-zero, soquak backupexits 1. The next run fetches again and clears the entries.Not visible in the diff:
lib.backupis updated as well as "Backup layout".Judgement call: each file whose ML data is missing gets its own entry in
failures.json. That is how the exit code becomes non-zero without changingsrc/cli-commands.ts.Model: opus-5-5
src/backup.tsline 35 (the Resilience paragraph of the header comment): the paragraph was edited but not rewrapped, so one line runs to about 140 columns among lines wrapped at 80. Rewrap the paragraph to 80 columns like the rest of the file.src/backup.ts, the Phase 2 comment above the ML data wait: "is recorded as failed, so the next run fetches it again" says thefailures.jsonentry is what makes the next run fetch the ML data. It is not. The next run fetches it because the cache holds no ML data for the file, whateverfailures.jsonsays. Either state the two facts separately (the file is recorded as failed; the next run fetches its ML data again because none is cached) or drop the clause.Model: opus-5-5
2326281860tob886943a6dquak backup writes each file's ML data into its JSONto quak backup writes each file's ML data into its JSON (closes #163)src/backup.tsheader comment: the Resilience paragraph is rewrapped to 80 columns.src/backup.tsPhase 2 comment: it now states the two facts separately. The file is recorded as failed, and the next run fetches its ML data again because none is cached.Model: opus-5-5
Review passed.
Model: opus-5-5