docs(plan): scope step 7, the transcode dual-write
Investigated but deliberately not started — the remaining pieces span a service, its DI wiring and an unresolved design question, and a half-wired service is worse than none. ImageTranscodeService does not write the derived tier at all today, the same gap persist_rendered closed for thumbnails, and it must close before transcode_import can converge or the import chases a growing cache. Three pieces, and the first is smaller than it looks. get_transcoded takes file_id while the table is content-keyed, but the hash is already in scope one frame up — file_retrieval_service::try_transcode is called where dto.content_hash is live — so it is a parameter to thread, not a lookup to invent. Explicitly NOT by hashing original_content on the fly, which would be a BLAKE3 over the whole file per request. Second, the service has no BlobHandler field, so this touches the constructor and DI; ThumbnailService hit the same ordering problem and solved it with a per-call parameter, which is the cheaper precedent. Third, the .skip markers stay unresolved: a negative verdict has no bytes, so it does not fit a table whose row points at a blob. Either leave them local and recompute per instance, or model a sentinel. It is the only genuinely open design question left in step 10.
This commit is contained in:
@@ -1289,7 +1289,38 @@ hardcoded SQL). New sources bolt on independently.
|
|||||||
after, step 5 lands at scale; per-row HEADs do not survive a 4×
|
after, step 5 lands at scale; per-row HEADs do not survive a 4×
|
||||||
row count.
|
row count.
|
||||||
7. **`ImageTranscodeService`** — same shape, `kind = 'transcode'`,
|
7. **`ImageTranscodeService`** — same shape, `kind = 'transcode'`,
|
||||||
no new table.
|
no new table. **Scoped 2026-08-27, not started.** The service does
|
||||||
|
not currently write the derived tier at all, which is the same gap
|
||||||
|
`persist_rendered` closed for thumbnails, and it must be closed
|
||||||
|
before `transcode_import` can converge.
|
||||||
|
|
||||||
|
Three concrete pieces, in order:
|
||||||
|
|
||||||
|
* **Thread the source hash to the call site.** `get_transcoded` takes
|
||||||
|
`file_id` only, and the table is content-keyed. The hash IS
|
||||||
|
available one frame up — `file_retrieval_service::try_transcode`
|
||||||
|
is called from a scope holding `dto.content_hash` — so it is a
|
||||||
|
parameter to add, not a lookup to invent. Do **not** hash
|
||||||
|
`original_content` on the fly: that is a BLAKE3 over the whole
|
||||||
|
file on every request.
|
||||||
|
* **Give the service a `BlobHandler`.** It has no field for one
|
||||||
|
(`cache_dir`, `memory_cache`, `stats`), so this is a constructor
|
||||||
|
and DI change — mind the construction order, as
|
||||||
|
`ThumbnailService` hit the same thing and solved it with a
|
||||||
|
per-call parameter instead.
|
||||||
|
* **Decide the `.skip` markers.** `{file_id}.{ext}.skip` records a
|
||||||
|
negative verdict ("result was not smaller — serve the original")
|
||||||
|
and has no bytes, so it does not fit a table whose row points at a
|
||||||
|
blob. Options: leave them as a purely local cache and accept the
|
||||||
|
verdict being recomputed per instance, or model it with a sentinel
|
||||||
|
`blob_hash`. Unresolved; it is the only genuinely open design
|
||||||
|
question in step 10.
|
||||||
|
|
||||||
|
Note the cache is keyed `{file_id}:{ext}` in memory and
|
||||||
|
`.transcoded/{ext}/{file_id}.{ext}` on disk, so it also carries the
|
||||||
|
file-vs-content keying mismatch that `transcode_import` has to
|
||||||
|
re-key. Fixing the write path first means the import only has to
|
||||||
|
handle history, not a moving target.
|
||||||
8. **`storage.copy_file_satellites` consolidation** — collapse the two
|
8. **`storage.copy_file_satellites` consolidation** — collapse the two
|
||||||
copy paths onto one helper, with a manifest-aware reference bump.
|
copy paths onto one helper, with a manifest-aware reference bump.
|
||||||
**Blocks step 9**: adding a file-keyed table before this means
|
**Blocks step 9**: adding a file-keyed table before this means
|
||||||
|
|||||||
Reference in New Issue
Block a user