Skip to content

Address CRAN review: \value tags, runnable examples, DESCRIPTION - #47

Merged
TroyHernandez merged 9 commits into
mainfrom
feat/flux-pinned-staging
Aug 3, 2026
Merged

Address CRAN review: \value tags, runnable examples, DESCRIPTION#47
TroyHernandez merged 9 commits into
mainfrom
feat/flux-pinned-staging

Conversation

@TroyHernandez

Copy link
Copy Markdown
Contributor

The 0.2.0 submission came back on four items, none of which R CMD check
implements: there is no missing-\value check anywhere in tools, no
\dontrun-vs-\donttest policy check, and nothing that inspects
DESCRIPTION quoting or whitespace. Every local check had been green, and
always would have been.

  • \value on all 50 exported .Rd files that had a \usage block and
    no return documentation, chiefly the nn_module generators for the FLUX,
    FLUX.2, Z-Image, LTX-2.3 and Gemma3 ports. Doc-only topic pages have no
    \usage and are correctly exempt.
  • Examples: 14 of the 23 \dontrun{} blocks now run during check, and
    were rewritten to be self-contained rather than referencing objects that
    were never defined. The 9 that remain need model weights on disk and are
    itemised in cran-comments.md.
  • DESCRIPTION: 'Python', 'Stable Diffusion' and 'Hugging Face'
    (with its URL) single-quoted; trailing whitespace removed. Every
    continuation line had ended in a space since the first commit, and DCF
    folding turned each one into a double space.

Two bugs surfaced from making the examples actually run:

ddim_scheduler_create() was uncallable at its documented defaults —
beta_schedule never went through match.arg(), so switch() errored on
the length-3 default, and device defaulted to a length-2 vector that
torch_tensor() rejects. ddim_scheduler_step() had the same missing
match.arg() on prediction_type. Every internal caller passes these
explicitly, which is why the documented defaults were never exercised.

save_video()'s mp4 example ate the check script. --as-cran runs examples
a second time feeding diffuseR-Ex.R to R on stdin; the encoder inherits
that stdin and consumes a byte, so every later example parsed one character
short and the run died on pos = "CheckExEv"CheckExEnv with one byte
gone. It reproduced at the same offset with the GPU hidden, so it was never
CUDA-related.

Also refreshes the safetensors messaging: mlverse/safetensors#11, #13 and #14
merged upstream on 2026-07-31 without a version bump, so CRAN's 0.2.1 and
upstream's share a version string and no version expression can tell them
apart. The advice now points upstream, and the comments record why the gates
are runtime probes.

R CMD check: 0 errors, 0 warnings, 2 NOTEs (New submission + the local
torch/lantern artifact already documented in cran-comments.md).

The staging mechanism (pin host copies once, onload by non-blocking DMA,
offload by pointer swap) is about to be shared by the FLUX-family image
loaders, so drop the ltx23 prefix: staging_ltx23.R -> staging.R, and
.ltx23_pin_host/.ltx23_pin_component/.ltx23_staged_onload/
.ltx23_staged_offload -> .pin_host/.pin_component/.staged_onload/
.staged_offload. Doc topic staging_ltx23 -> staging (alias kept). Pure
rename across the LTX pipeline, the Gemma3 encoder, and the fp8 loader;
no behavior change.
flux1/flux2/zimage phase-swap the transformer, VAE decoder, and text
encoder(s) CPU<->GPU every generation, through pageable host memory. Pin
them once at load (the LTX staging mechanism) so onload runs at full PCIe
rate and offload is a pointer swap. Payoff: flux1 T5 encode ~7-12 s ->
sub-second, flux2/zimage Qwen3 swap ~2-4 s -> ~0.4 s, plus faster
transformer/decoder moves.

- Shared pin gate: extract .pin_decision (host RAM >= 2x pinned set) from
  recommend() and add .resolve_pin (explicit pin= > option > decision).
  Loaders gain pin=NULL. "full" checkpoints map to the bf16 row.
- .flux_build_staging pins the listed components; the resident-fp8
  transformer (flux2/zimage) also pins its plain weight_fp8/weight_scale
  fields via .flux_fp8_collect (set_data keeps the field reference live).
  Generation skips .flux_fp8_to_device when staging covers the
  transformer, else the field reassignment would orphan the staged pairs.
- flux1 now GPU-encodes T5 (bf16, pinned) on 14 GB+ cards where its
  ~9.8 GB encode phase fits; nf4 tiers keep the CPU-fp32 encode.
  text_device default "cpu" -> NULL (profile-resolved); gc footprint
  sized to the T5 phase. An explicit text_device="cpu" still encodes in
  place (also fixes a latent flux2/zimage OOM on that path).
- VAE decoder cast to compute dtype once at load so staged onload is
  device-only. onload/offload closures route by component name.
- .pinned_set_gb flux1 row 43/31/26 -> 34/22/17 (T5 host copy now bf16).
- Tests: test_flux_staging (gate logic, .flux_fp8_collect, pin round
  trip) and a zimage end-to-end smoke test.
The 0.2.0 submission was returned for four items, none of which
R CMD check implements (there is no missing-\value check anywhere in
tools, no \dontrun policy check, and no DESCRIPTION quoting or
whitespace check), so every local check had been green.

* \value on all 50 exported .Rd files that had a \usage block and no
  return documentation, chiefly the nn_module generators for the FLUX,
  FLUX.2, Z-Image, LTX-2.3 and Gemma3 ports. Doc-only topic pages have
  no \usage and are correctly exempt.
* Examples: 14 of the 23 \dontrun{} blocks now run during check, and
  were rewritten to be self-contained rather than referencing objects
  that were never defined. The 9 that remain need model weights on
  disk; cran-comments.md itemises them.
* DESCRIPTION: 'Python', 'Stable Diffusion' and 'Hugging Face' (with
  its URL) single-quoted; trailing whitespace removed. Every
  continuation line had ended in a space since the first commit, and
  DCF folding turned each one into a double space.

Making the examples run surfaced two dead defaults. ddim_scheduler_create()
never passed beta_schedule through match.arg(), so switch() errored on the
length-3 default, and its device default was a length-2 vector that
torch_tensor() rejects; ddim_scheduler_step() had the same missing
match.arg() on prediction_type. Every internal caller passes these
explicitly, which is why the documented defaults were never exercised.
device now defaults to torch_device("cpu").

Also refreshes the safetensors messaging: mlverse/safetensors#11, #13
and #14 merged upstream on 2026-07-31 without a version bump, so the
advice now points at upstream rather than the fork, and the comments
record why the gates are runtime probes (the version number cannot
distinguish the two 0.2.1 builds). The install.packages()/
install_github() literals in hint text are reworded, since CRAN's
scanner flags the token regardless of context.
R CMD check --as-cran runs the examples a second time with \donttest{}
enabled, feeding diffuseR-Ex.R to R on stdin. The mp4 branch of
save_video() hands off to an ffmpeg process that inherits that stdin and
consumes a byte of the script, so every later example parsed one
character short: the run died on

  base::assign(".ptime", proc.time(), pos = "CheckExEv")
  Error in as.environment(pos) :
    no item called "CheckExEv" on the search list

with the generated file plainly containing "CheckExEnv" (81 occurrences,
none of them mangled) and R evaluating a string one byte shorter. It
reproduced at the same offset with the GPU hidden, so it was never
CUDA-related.

The frames backend already exercises save_video() live and needs no
external encoder, so the encoder call is now a commented example with
the reason recorded next to it.
@TroyHernandez
TroyHernandez merged commit 1ea9636 into main Aug 3, 2026
0 of 2 checks passed
@TroyHernandez
TroyHernandez deleted the feat/flux-pinned-staging branch August 3, 2026 04:23
TroyHernandez added a commit that referenced this pull request Aug 3, 2026
CI has been red on every run since PR #47, on both ubuntu-latest and
macos-latest:

  FAILED[xcpt]: test_resident.R<117>
   call| expect_error(diffuseR:::.resident_check_fits(huge), pattern = "needs")
   diff| No error

The function is right and the test was wrong. .resident_check_fits()
refuses a bulk activation only when it can prove the set does not fit;
with no GPU the measurement is 0, which means "cannot tell", so it
declines to block. The test asserted the refusal unconditionally, so it
passed on the GPU box and failed everywhere else.

free_gb is now an argument, NULL measuring as before. The test states a
budget rather than depending on the machine having a card, and also
covers the cases it never did: a set that fits is allowed, and an
undetectable 0 or NA does not block.

Same class as the win-builder lantern failure and the Windows st_caps
failure: an assertion that read the environment instead of stating it.
Verified against all three environments this package has to survive --
58 assertions with a GPU, 43 with CUDA_VISIBLE_DEVICES="" (CI), 33 with
an empty TORCH_HOME (win-builder). Full suite CI-style: 1070 pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant