Skip to content

v0.34.0 - X-Trans colour, hardened budgets, typed scopes

Choose a tag to compare

@skymanbp skymanbp released this 20 Aug 12:39
· 114 commits to main since this release

Autoshop v0.34.0 — the R28 round: X-Trans colour, hardened budgets, typed scopes

Five batches, all landed 2026-08-20. No recipe-schema changes: a v0.33.0
binary reads a v0.34.0 recipe and vice versa
— the first feature release
since v0.30 with no forward break.

The headline: Fujifilm X-Trans renders correct colour

Through v0.33.0, X-Trans RAFs developed visibly green and dark. The root cause
was starker than a detail approximation: the Bayer demosaic's chroma pass
assumes the right/down neighbours of a green photosite carry the two chroma
colours, and inside X-Trans's four 2×2 all-green blocks per tile that
assumption fails 16 times per 36 pixels — R was never written (left at zero)
at 8 of every 36 photosites, B at another 8.
No white balance can repair a
per-channel hole.

v0.34.0 demosaics non-Bayer RGB arrays in-tree over the array's own geometry:
every channel is interpolated only from photosites that actually measured it,
with per-phase plane-fit weights (convex, no ringing). Measured on the release
binary against the CC0 X-S10 zoo sample: whole-frame G/R 1.5503 → 0.9473
(the camera's own preview reads 0.95), per-phase channel spread R 157.8 % →
0.34 %. All eight Bayer-format zoo renders hash byte-identical before and
after. Fine detail remains softer than a dedicated X-Trans converter and the
render's disclosure line says so — the old line's "colour, tone and framing
are unaffected" clause was measured false and is gone.

Behaviour changes (all deliberate, all disclosed)

  • Negative Texture is band-limited. texture = −100 used to degenerate to
    a full Gaussian blur (the transfer's endpoint was literally the blurred
    frame). It is now a mid-band smoothing: at −100 a 4 px pattern keeps 96 % of
    its contrast while a 16 px pattern still loses 71 %. The positive branch is
    untouched (it was measured against Lightroom in R27). The negative curve is
    ours and stated as unmeasured — there is no LR ground truth for it in the
    tree, and the sidecar still carries the raw slider value.
  • A RAW too big to develop is refused by name. The RAW door gains the same
    4 GiB per-file peak ceiling the baked door has had for months, charged on a
    header read before any sensor row is decompressed. At the measured
    31 bytes/pixel that is ~138.5 MP and up (a 150 MP back is caught; a 102 MP
    GFX is well clear). The message names the estimate, its basis, and says
    outright that --jobs 1 will not help. Such files used to be attempted and
    would page the machine.
  • AI-mask alphas re-derive once. The segmentation cache key now records
    the frame (quarter turns) it was computed in — closing a bug where a mask
    clicked exactly at the frame centre kept serving its pre-rotation alpha
    sideways. Every alpha cached by v0.33.0 re-runs the local segmenter on its
    first develop (seconds of GPU per mask), reported as a normal re-derivation.
  • AI masks on a saved retouch master now render. The resolver takes the
    photo for identity and the render source for pixels; a baked master used to
    fail the RAW-only staging decoder and the mask was carried inert.
  • The eval hue rows changed meaning. The four color_grade.*_hue rows
    count a photo only when BOTH sides put saturation on that wheel — a hue at
    zero saturation renders nothing, and the old rule manufactured a 141°
    "disagreement" between two colourless wheels. The report discloses that
    these rows are not comparable with pre-v0.34.0 runs.
  • The style-embedding sidecar loads in half precision by default and is
    single-flighted (one resident model regardless of worker count):
    4 × 1.50 GB of fp32 SigLIP weights becomes 1 × 0.75 GB.
    AUTOSHOP_EMBED_FP32=1 restores the old arithmetic exactly.
  • Batch transcripts are attributable. Worker-reachable warnings carry
    their photo's stem, and batch renders the proposer's note channel into
    each photo's own output block the way eval always did.

Hardening (defect classes closed, each with a gate that keeps it closed)

  • Every store-file read goes through the capped readers (four bypasses closed;
    a source-scanning test now fails on any new bare read).
  • Brush-dab truncation cuts on token boundaries and is disclosed on every
    surface; one dab token is bounded at 256 bytes; the import-side clamp
    summary is no longer discarded.
  • XMP read scope is a type (Tag vs Scope): a per-element read can no
    longer silently become a subtree search. Four adversarial scope fixtures pin
    the difference; the 16 real-Lightroom sidecars byte-round-trip unchanged,
    which is the proof the redesign moved no real-LR behaviour.
  • The docs gate lexers handle block comments, cross-check literal counts
    against [&str; N], and mask quoted spans in the TOML census.
  • The --jobs planner consults per-file peaks where headers are free (a
    native-resolution 16-bit TIFF from LR's "Edit in…" can exceed the corpus
    constant on its own, and now says so); the 1,800 MB constant was re-measured
    with the full-resolution render included (peak 1,771 MB — the render tail
    does not raise it) and the probe harness is now in-tree and re-runnable.

Gates at release (both build configurations)

clippy clean ×2 · 727 library (9 #[ignore]d forensic probes) / 11
CLI
/ 131 GUI / 2+2 contract · RAW zoo 9/9 (full test name) · 16/16 real
Lightroom radial sidecars byte-round-tripped · M-B forensic corpus 42/42 masks
· i18n audit 0 · doc-drift gate 11/11 with the release battery transcript.

The format-strip .raf tile in the README was re-rendered with this release.

Also in this release

Cross-platform compilation is CI-verified on ubuntu-latest and
macos-latest in both feature configurations on every push to main (compile
only — no tests run in CI, and no binary has been executed on either
platform). Prebuilt binaries remain Windows-only.