Skip to content

fix+chore: 30+ fixes bundle F — deferred criticals + MCP+round5 bulk - #859

Merged
lusoris merged 10 commits into
masterfrom
chore/bundle-f-30-fixes-deferred-mcp-bulk-race
Jun 12, 2026
Merged

lusoris merged 10 commits into
masterfrom
chore/bundle-f-30-fixes-deferred-mcp-bulk-race

Conversation

@lusoris

@lusoris lusoris commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Mega-bundle of ~30 fixes across three rounds (deferred criticals, MCP test suite, round-5 bulk hunt):

Deferred criticals (rounds 4-5 skip-pile, 8 commits):

  • HIP WARP_SIZE replaced with runtime warpSize across 10 kernel files for gfx10+/wave32 correctness
  • vmaf_tiny_v2/v3/v4 double-scaling fix via onnx_has_scaler sidecar flag; C-side scaler skipped when ONNX has one baked in
  • gpu_picture_pool partial-alloc rollback: extracted alloc_pictures() helper with mutex + slot cleanup on failure
  • vmaf_use_feature_extractor / vmaf_use_features_from_model NULL-deref guard: *fex_ctx=NULL on all error exits + early-return in caller + destroy on state-setter failure (3 files)
  • Rust Context<'a> + PhantomData<&'a mut Model> prevents UAF when registered model is freed before context
  • Rust vmaf_read_pictures FFI: explicit vmaf_picture_unref on rc<0 early-error path to free plane buffers
  • Docker base image digest-pinning for nvidia/cuda:13.3.0 and golang:1.23-bookworm (4 Dockerfiles)
  • fr_regressor_v2_ensemble_v1.json SHA256 refresh — 5 stale digests updated to match on-disk ONNX files

MCP test fixes (1 commit, 5 fixes): round2_client env scope, async/sync wrapper, round3 patch scope, REPO path monkeypatch, tempdir cleanup assertion

Round-5 bulk (1 commit, 18 fixes): pdjson SIGABRT depth-overflow guard, thread_pool POSIX while→if spurious-wakeup fix, libvmaf + thread_pool NULL guards, motion_avx512 UBSan cast, opt.h const-correctness, SYCL reqd_sub_group_size, Go pkg/errors migration, Rust assertion fixes, build flags, dead-code removal

Race-fix commit (w7nry8u3o) not included — task output was empty (still in flight).

Test plan

  • meson test -C build --suite=fast: 87/87 PASS
  • cargo check -p vmafx: clean
  • No conflict markers (git grep '^<<<<<<<' clean)
  • No Netflix golden assertions touched
  • Pre-commit hooks passed; push hooks ran normally

Deep-dive deliverables (ADR-0108)

  • Research digest: no digest needed: trivial — root-causes documented per-commit from rounds 4-5 hunt findings
  • Decision matrix: no alternatives: only-one-way fix per finding (NULL-guard, unref, lifetime param)
  • AGENTS.md invariant note: no rebase-sensitive invariants introduced
  • Reproducer / smoke-test command: per-fix verifies in individual commits (meson test --suite=fast, cargo check, ONNX sha256sum cross-check)
  • changelog.d fragment: no changelog fragment needed: mega-bundle (closes ~20+ T- rows)
  • docs/rebase-notes.md: no rebase impact: additive fixes, no renamed symbols or moved API surfaces

state.md touch

  • Closes ~20+ T- rows across deferred criticals, MCP test suite, and round-5 bulk categories

🤖 Generated with Claude Code

lusoris and others added 10 commits June 12, 2026 19:21
…kernels

gfx10+ (RDNA2+) devices run in wave32 mode; all HIP kernels that hardcoded
WARP_SIZE=64 produced wrong results (incorrect warp-reduce strides, lane
detection off by factor 2, warp-partial shared arrays under-allocated on
wave32 hardware) because the reduction loops iterated 32 lanes when only
16 were live.

Fix pattern applied across 10 kernel files:
- Replace `#define *_WARP_SIZE 64` with `*_MIN_WARP_SIZE 32` (for shared-mem
  sizing — allocates enough slots for wave32 worst case).
- Replace `WARPS_PER_BLOCK = BX*BY / WARP_SIZE` denominator with MIN_WARP_SIZE
  so shared-mem arrays are large enough on wave32 (over-allocated on wave64,
  which is correct and safe — unused slots are never written).
- Replace all `for (off = WARP_SIZE/2; ...)` with `(int)warpSize / 2`.
- Replace all `lid % WARP_SIZE` / `lid / WARP_SIZE` with `% (unsigned)warpSize`
  / `/ (unsigned)warpSize`.
- Replace compile-time `WARPS_PER_BLOCK` loop bounds in the final accumulation
  loops with runtime `nwarps = blockDim.x * blockDim.y / warpSize` so wave64
  does not read uninitialised shared-mem slots 2-3 that wave32 would write.

Files changed (9 kernels + 2 host launchers):
  float_adm_score.hip, float_ssim/ssim_score.hip,
  integer_ciede/ciede_score.hip, integer_moment/moment_score.hip,
  integer_motion/motion_score.hip, integer_motion_v2/motion_v2_score.hip,
  integer_ms_ssim/ms_ssim_score.hip, integer_psnr/psnr_score.hip,
  integer_ssim/integer_ssim_score.hip.

speed/speed_score.hip: HIP_WARP_SIZE is a launch-time parameter (blockDim.x
must equal the device wavefront size). Updated speed_chroma_hip.c and
speed_temporal_hip.c to query hipDeviceProp_t.warpSize at init and store it
in state->solve_warp, replacing the hardcoded SC_SOLVE_WARP/ST_SOLVE_WARP
constant at hipModuleLaunchKernel call sites.

integer_vif/vif_statistics.hip was already fixed in PR #850 (ADR-0563
per-thread atomicAdd); float_motion, float_psnr, float_vif, float_moment
were already using warpSize at runtime.

Local verify: meson setup -Denable_hip=true + ninja 1087/1087 OK.
The 9 fast+gpu HIP parity failures are pre-existing on master (confirmed
by baseline run on origin/master before this change).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The vmaf_tiny_v2/v3/v4 ONNX graphs bake the StandardScaler as Constant
nodes (ADR-0244), so the runtime should feed raw feature values. However,
the sidecar JSON files echo input_mean/input_std for tooling, and
vmaf_dnn_sidecar_load sets has_feature_scaler=true whenever it finds
those arrays. The C runtime in vmaf_ctx_dnn_run_frame_feature_vector then
unconditionally applied (v - mean) / std before calling ORT — effectively
double-scaling every feature vector and corrupting vmaf_tiny_v{2,3,4}
scores.

Fix: add an onnx_has_scaler boolean field to VmafModelSidecar and the
sidecar JSON spec. When true, the C runtime skips its own scaler step
because the ONNX graph handles normalisation internally. The three
affected sidecars (vmaf_tiny_v2.json, v3.json, v4.json) are updated to
set "onnx_has_scaler": true. Older models without this flag (fr_regressor
v1/v2/v3 etc.) are unaffected — their ONNX graphs do NOT bake the scaler,
so the C runtime continues to apply it.

Two new unit tests are added to test_model_loader.c:
  - test_sidecar_onnx_has_scaler_flag: verifies parsing onnx_has_scaler
    while has_feature_scaler remains true for tooling.
  - test_sidecar_onnx_has_scaler_absent: verifies backward compatibility
    (flag defaults to false when key is absent from the sidecar).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… failure

vmaf_gpu_picture_pool_init accumulated errors with |= but never freed
pictures that were successfully allocated before the first failure,
leaking one GPU buffer per successfully-completed slot.

Extract alloc_pictures() static helper that breaks on first failure and
rolls back slots 0..alloc_cnt-1 via free_picture_callback before
returning the error.  Also call pthread_mutex_destroy on the
alloc-failure path so the mutex does not leak its internal state.

The helper also brings vmaf_gpu_picture_pool_init back under the 60-line
readability-function-size threshold (was 64 lines).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ate failure

vmaf_feature_extractor_context_create freed and returned *fex_ctx as a
dangling pointer on error (malloc failure or vmaf_fex_ctx_parse_options
failure), without zeroing the out-parameter. Two call sites in libvmaf.c
then used err |= set_fex_cuda_state(fex_ctx, ...) unconditionally,
dereferencing the freed pointer before the err-check.

Fix in three parts:
1. feature_extractor.c / .cpp: set *fex_ctx = NULL on all error exits so
   callers always receive NULL on failure, never a dangling pointer.
2. libvmaf.c (vmaf_use_feature_extractor): early-return on create failure
   before any set_fex_*() call; also destroy fex_ctx on state-setter failure.
3. libvmaf.c (vmaf_use_features_from_model): same pattern.

The pool slot allocator (ctx_pool_claim_slot) and predict.c already handled
the error correctly; no change needed there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
vmaf_use_features_from_model stores the raw VmafModel* inside the
context's feature-collector linked list (vmaf_feature_collector_mount_model
in core/src/feature/feature_collector.c, line 272: m->model = model).
Libvmaf dereferences that pointer during score computation, so if the
Rust Model wrapper was dropped while the Context was still alive, every
subsequent vmaf_score_pooled / vmaf_score_at_index call would be a
use-after-free.

Add lifetime parameter 'a to Context<'a> with PhantomData<&'a mut Model>
(invariant over 'a to prevent coercion to a longer lifetime), and bind
use_features_from_model to model: &'a mut Model. A freshly-constructed
Context<'static> carries no borrow; the borrow checker narrows the
context's apparent lifetime to the shortest-lived registered model as
soon as use_features_from_model is called, preventing the context from
outliving any registered model.

ContextBuilder::build() explicitly returns Result<Context<'static>>.

Local-verify: cargo check + cargo clippy -D warnings, both clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When `vmaf_read_pictures` returns an error, it has not taken ownership
of the plane buffers.  The Rust-side `Picture` wrappers already had
their `owned` flag cleared by `into_raw_owned()`, so their `Drop`
became a no-op.  The resulting raw `VmafPicture` structs then fell out
of scope without being freed — a silent memory leak on every rejected
frame.

Fix: check `rc < 0` immediately after the FFI call and explicitly call
`vmaf_picture_unref` on both raw pictures before returning the error.
Added a unit test (`into_raw_owned_clears_owned_flag_and_caller_frees`)
in `picture.rs` that exercises the same manual-unref path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ase images

Four Dockerfiles referenced golang:1.23-bookworm (controller, node,
operator) and nvidia/cuda:13.3.0-devel-ubuntu24.04 (root Dockerfile)
without @sha256 digest anchors, leaving supply-chain provenance
unverifiable and builds non-reproducible across rebuilds.

Pin each with the current manifest digest so BuildKit verifies the
layer before pulling. Also removes the stale TODO comment in Dockerfile
that deferred the nvidia/cuda pin until the digest "stabilises".

- Dockerfile: nvidia/cuda:13.3.0-devel-ubuntu24.04@sha256:ef220...
- docker/Dockerfile.controller: golang:1.23-bookworm@sha256:16705...
- docker/Dockerfile.node: golang:1.23-bookworm@sha256:16705...
- docker/Dockerfile.operator: golang:1.23-bookworm@sha256:16705...

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… manifest

The five per-member sha256 fields in the ensemble manifest were out of sync
with the actual ONNX files on disk. The per-seed sidecar JSONs already carry
the correct hashes (verified); only the parent manifest was stale.

Updated fields (old → new):
  seed0: fa89df1b... → 08ab1aed...
  seed1: 48b0b9f3... → 42d86249...
  seed2: 927a23fe... → 0f1d8a81...
  seed3: 1be056b0... → ed5e9260...
  seed4: 584ad69b... → 036c6224...

Verification: sha256sum of each .onnx file matches the updated manifest entry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. round2_client fixture: extend VMAFX_MCP_HTTP_NO_AUTH patch to cover
   the full test duration (yield inside with-block) so the security
   middleware sees the bypass at request-dispatch time, not just at
   app-creation time.
2. test_vmaf_version_handles_version_timeout: drive async _vmaf_version()
   via asyncio.run() instead of calling it synchronously (ADR-1023 made
   the function async).
3. test_coverage_round3.py HTTP tests: extend patch.dict scope to wrap
   client.post() + assertions in all three tests; the with-block was
   exiting before the request was made.
4. test_describe_model_onnx_no_metadata: replace hardcoded REPO constant
   with monkeypatch.setattr(srv, '_repo_root', lambda: tmp_path) to
   decouple from the physical install layout.
5. test_describe_worst_frames_uses_unique_tempdir_per_call: update
   assertion to match TemporaryDirectory semantics (files cleaned up on
   context exit — assert NOT exists, not exists).

All 8 previously-failing tests now pass (0.44 s).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Rust/warnings bulk

18 files, 19 distinct fixes across 11 of the 12 round-5 hunt cells
(race-conditions cell handled separately):

memory-leaks-strict (cell 2):
- core/src/libvmaf.c: set *vmaf=NULL after free(v) in free_v: path to
  prevent dangling pointer after vmaf_init sub-init failure
- core/src/thread_pool.c: set *pool=NULL after free(p) on workers-malloc
  failure; change if→while for pthread_cond_wait to guard spurious wakeups
- core/src/feature/feature_extractor.c: set *pool=NULL after free(p) at
  free_p: label; add comment documenting intentional mutex-init ordering

tiny-ai-model-runtime-audit (cell 9):
- core/src/pdjson.c: fix UBSan SIGABRT — change stack_top=-1 to
  (size_t)-1 at both init sites, matching the (size_t)-1 sentinel used
  at the two comparison sites (lines 720/746)

cross-extractor-numeric-comparison (cell 5):
- core/src/feature/x86/motion_avx512.c: fix signed integer overflow in
  three 16-bit scalar-tail paths (y_conv_8, y_conv_16, x_conv_16) — cast
  uint16_t filter[k] and src pixels to uint32_t before multiply so
  products stay in unsigned arithmetic (UBSan SIGABRT fix)

hidden-config-options (cell 6):
- core/meson_options.txt: fix inverted enable_nvcc description (was "Use
  clang…"; corrected to "Use nvcc…; when false, clang is used")
- docs/development/build-flags.md: remove false claim that enable_vulkan
  remains as a failing stub; the option() was fully deleted per ADR-0726
- core/src/meson.build: remove dead -DOC_NEW_STYLE_INCLUDES legacy define
  (no C consumer in tree since upstream libogg era)
- core/src/feature/adm.c: collapse ADM_OPT_SINGLE_PRECISION #ifdef branch
  (symbol never defined anywhere; 1e-2 threshold was permanently dead code)

unused-code-dead-code (cell 7):
- core/src/picture.h: remove dead VMAF_PICTURE_BUFFER_TYPE_VULKAN_DEVICE
  enum value (Vulkan removed per ADR-0726; no reference sites remain)

meson-build-warnings-grind (cell 12):
- core/src/opt.h: char*→const char* for default_val.s to prevent
  write-to-string-literal UB (icpx -Wwritable-strings)
- core/src/opt.c + opt.cpp: propagate const through set_option_string
  signature; opt.cpp uses const_cast per ADR-0721 ABI-stability comment
- core/src/feature/sycl/sycl_compat.h: update VMAF_SYCL_REQD_SG_SIZE macro
  from deprecated [[intel::reqd_sub_group_size(N)]] to SYCL 2020 standard
  [[sycl::reqd_sub_group_size(N)]] (oneAPI 2026.0 deprecation warning)

go-pkg-error-handling-audit (cell 10):
- pkg/libvmaf/libvmaf.go: check tmpOut.Close() error; use logged deferred
  remove instead of bare defer os.Remove
- cmd/vmafx-controller/queue/queue.go: surface json.Marshal error in
  ReportResult instead of silently falling back to "{}"; fix ListAll
  defer rows.Close() to log close errors (matching reload() pattern)
- cmd/vmafx-mcp/impl.go: intArg/floatArg return def (not 0) on
  json.Number conversion failure

rust-bindings-safety (cell 11):
- bindings/rust/vmafx-sys/tests/integration_test.rs: add debug_assert for
  non-negative strides before as-usize cast; add allow(cast_sign_loss)
  with justification comment

Build verified: ninja -C /tmp/vmaf-round5-build (CPU-only) 894/894 OK,
meson test --suite=fast 87/87 OK (including test_motion_avx512_parity
which previously aborted under UBSan). go build clean. cargo check clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lusoris
lusoris marked this pull request as ready for review June 12, 2026 17:38
@lusoris
lusoris force-pushed the chore/bundle-f-30-fixes-deferred-mcp-bulk-race branch from 2040251 to b3d34cc Compare June 12, 2026 17:38
@lusoris
lusoris merged commit 0a9dba8 into master Jun 12, 2026
@lusoris
lusoris deleted the chore/bundle-f-30-fixes-deferred-mcp-bulk-race branch June 12, 2026 17:38
lusoris added a commit that referenced this pull request Jun 12, 2026
…RF, AI scripts, MCP conformance) (#865)

* fix(hip,sycl): stale wave32 comment + Kahan IIR blur for ssimulacra2 (iter6-cross-backend-parity)

Three iter6 cross-backend-parity findings:

1. [critical — partial] float_adm_score.hip: wave32 code was already fixed
   in #859 (0a9dba8); correct the lingering stale comment that still read
   "FADM_WARPS_PER_BLOCK = 4 (64-lane warps)" — FADM_WARPS_PER_BLOCK is now
   256/32 = 8 slots (sized for the wave32 worst case).  No functional change.

2. [high — already fixed] float_ssim/ssim_score.hip + integer_psnr/psnr_score.hip:
   wave32 runtime-warpSize fixes landed in #859 alongside float_adm; nothing
   further to do here.

3. [high] ssimulacra2_sycl.cpp: add Kahan (compensated-summation) state
   tracking to the 3-pole recursive IIR blur kernel (launch_blur<PASS>).
   The IIR state (prev1_k) accumulated O(eps) rounding error per step;
   over 4K-tall frames this exceeded the 5e-5 cross-backend parity
   contract vs the CPU reference.  Each pole now carries a float comp_k
   compensation term; the standard Kahan pattern (y = candidate - comp;
   new_state = old_state + y; comp = (new_state - old_state) - y) bounds
   per-iteration error to O(eps^2) without fp64 (ADR-0220 compliant).

No Netflix golden-data assertions modified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ubsan): replace 0xFFFFFFFFFFFFFFFF hex literals with -1LL in adm_avx512.c

_mm512_set_epi64 takes long long (signed 64-bit) arguments. The literal
0xFFFFFFFFFFFFFFFF exceeds LLONG_MAX and is undefined behaviour under
strict UBSan. Replace with -1LL which has identical bit pattern and
correct type at both call sites (ADM_CM_THRESH_S_I_END macro lines 406
and 698).

Finding: iter6-ubsan-strict high [adm_avx512: 0xFFFF... overflows long long].
Note: motion_avx512.c and adm_avx2.c analogous fixes were already
present on master (PR #858 / PR #859 bundles).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(thread-safety): eliminate 2 TSAN races in threaded batch path (iter6-tsan-race-deep)

Finding #1 (high): Remove the racy write `fex->framesync = vmaf->framesync` in
`threaded_enqueue_one`.  `fex` is the *shared* registered VmafFeatureExtractor —
worker threads from previous frames may concurrently read its fields.  The write
is redundant: framesync is already propagated to every pool-slot copy by
`set_fex_framesync()` at registration time and by `ctx_pool_ensure_slot_ctx()`.

Finding #2 (high): Move the `vmaf->prev_ref` advance to BEFORE the enqueue call
in `threaded_read_pictures_batch`.  In the old order the main thread unreffed and
replaced `vmaf->prev_ref` after enqueue while the just-submitted worker still held
a live reference to the same underlying VmafRef*, creating a concurrent unref/write
on the same object without synchronisation.  Workers use `data.prev_ref` (an
independently refcounted snapshot) exclusively and never re-read `vmaf->prev_ref`
after enqueue, so moving the advance before enqueue is both safe and race-free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(vmaf-tune): fix --no-bisect TypeError and recommend CRF selection strategy

Two bugs in the compare/recommend paths:

1. _encode_and_score() in bisect.py had encode_runner and score_runner as
   required keyword-only args (no defaults). The CRF-sweep caller in cli.py
   did not pass them, causing an unconditional TypeError on any
   compare --no-bisect --crf-sweep invocation. Fixed by giving both
   parameters a default of None, consistent with the existing decode_runner
   parameter and the run_encode/run_score runner=None semantics.

2. _smallest_passing_crf() in cli.py used `crf > cur[0]` to select the
   largest (most efficient) passing CRF, contradicting both the function
   name and the CLI help string ("find the smallest CRF whose VMAF >=
   --target-vmaf"). The correct strategy is the smallest (highest-quality)
   passing CRF. Fixed comparison to `crf < cur[0]` and updated the docstring
   to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ai-scripts): 3 iter6 runtime bugs — vulkan-device AttributeError, saliency parity always-fail, ensemble ONNX codec-dim mismatch

- collect_gpu_calibration_data.py: remove dead args.vulkan_device
  reference from devices dict (Vulkan removed per ADR-0726; no
  --vulkan-device argparse registration existed, causing AttributeError
  at runtime)
- validate_saliency_student.py: replace broken PT-reconstruction parity
  check with ORT-only sanity check when no PT state provided.
  do_constant_folding=True folds BN stats into conv weights at export
  so ONNX initializer names diverge from PT state_dict keys; the old
  code silently left 60 of 65 weights at random defaults and always
  failed. When pt_state is provided (trainer path) full PT<->ORT diff
  is still performed.
- model/tiny/fr_regressor_v2_ensemble_v1_seed{0..4}.onnx: regenerate
  with codec_onehot=[batch,6] matching current CODEC_VOCAB (was [batch,14]
  from a 12-entry encoder_vocab + 2 norm dims; CODEC_VOCAB was later
  trimmed to 6). Regenerated via train_fr_regressor_v2_ensemble.py
  --smoke in vmaf-dev-mcp container. eval_probabilistic_proxy.py --smoke
  now passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(mcp): JSON-RPC parse-error conformance + deep-nesting guard

Two iter6 fuzz conformance findings fixed:

1. [high] Parse-error notification instead of error response (id=null):
   Add `_ParseErrorFilteredStdin` — a lazy async stdin wrapper that
   pre-validates each incoming line with
   `JSONRPCMessage.model_validate_json`. On failure it calls
   `_emit_parse_error` which writes
   `{"jsonrpc":"2.0","id":<recovered_or_null>,"error":{"code":-32700,
   "message":"Parse error"}}` to stdout synchronously, then drops the
   line so the mcp library never sees a bare Exception on the stream
   (the notification path is bypassed entirely).  `_run()` now passes
   `stdin=_ParseErrorFilteredStdin()` to `stdio_server`.

2. [high] 500-level deep nesting triggers recursion-limit exception:
   Add `_check_depth(obj, max_depth=50)` helper and call it at the top
   of `_call_tool_dispatch` before the tool dispatch.  Payloads exceeding
   50 nesting levels raise `ValueError`, which the mcp library converts
   to an isError=True tool result before the pydantic parser recurses.

Existing tests updated: the two `stdio_server`-patching tests in
`test_coverage_round2.py` now accept `**kwargs` so they tolerate the
new `stdin=` keyword argument forwarded by `_run()`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Lusoris <lusoris@pm.me>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@lusoris lusoris added this to the 1.0.0 — First release milestone Sep 4, 2026
lusoris added a commit that referenced this pull request Sep 4, 2026
bindings/rust/vmafx has existed since ADR-0929 (PR #859); the page still
said a higher-level crate was planned for a future PR. Found by the
2026-09-04 gap triage (#1270), verdict STALE, verified against master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 5, 2026
bindings/rust/vmafx has existed since ADR-0929 (PR #859); the page still
said a higher-level crate was planned for a future PR. Found by the
2026-09-04 gap triage (#1270), verdict STALE, verified against master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request Sep 5, 2026
…1282)

* docs(dev): replace the impossible venv recipe with the verified one

Replace the impossible repo-root pip install -e ".[dev]" in
docs/development/languages.md with the verified per-package editable
install recipe. The repository root pyproject.toml contains only tool
configuration for vmaf-fork-tooling and lacks build-system and root project
dependencies, causing flat-layout discovery failure.

Per-package editable installs are the model across independent
distributions, with dev/Containerfile:1037-1047 as the authoritative
reference. Pin meson==1.12.0 to prevent breaking ninja regeneration.
Add recovery instructions for virtualenvs broken by legacy tracked
.venv symlink loops (PR #1280).

docs/state.md: no bug row needed (docs-only).
docs/rebase-notes.md: no rebase impact: docs/development/ is fork-added.

* docs(dev): rust.md no longer calls the shipped vmafx crate 'planned'

bindings/rust/vmafx has existed since ADR-0929 (PR #859); the page still
said a higher-level crate was planned for a future PR. Found by the
2026-09-04 gap triage (#1270), verdict STALE, verified against master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs(changelog): rename the venv-recipe fragment so the tracked-venv gate stops matching it

scripts/ci/check-no-tracked-venv.sh matches any basename starting with 'venv'
(the dot is optional in its pattern); the fragment name venv-recipe-docs.md tripped
the required Pre-Commit check on #1282. The gate itself is tightened in a separate PR.

---------

Co-authored-by: Lusoris <lusoris@pm.me>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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