diff --git a/.gitignore b/.gitignore
index b45dbdf..eb6f8b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -233,3 +233,7 @@ time_cost.json
costtime.json
batch_eval.txt
*.log
+
+# README comparison assets intentionally included in the PR
+!assets/wan21_comparison/
+!assets/wan21_comparison/*.mp4
diff --git a/NaviCache4HunyuanVideo/README.md b/NaviCache4HunyuanVideo/README.md
index 87b2b43..c31a09b 100644
--- a/NaviCache4HunyuanVideo/README.md
+++ b/NaviCache4HunyuanVideo/README.md
@@ -1,10 +1,10 @@
# NaviCache for HunyuanVideo
-NaviCache is a training-free test-time self-calibration caching method for accelerating video generation. This directory provides the NaviCache sampling script for [HunyuanVideo](https://github.com/Tencent-Hunyuan/HunyuanVideo).
+NaviCache is a training-free, test-time self-calibration caching method for accelerating [HunyuanVideo](https://github.com/Tencent-Hunyuan/HunyuanVideo) generation.
## Usage
-Follow [HunyuanVideo](https://github.com/Tencent-Hunyuan/HunyuanVideo) to clone the repo, finish the installation, and download the required model weights. Then copy `navicache_sample_video.py` in this repo to the HunyuanVideo repo.
+Install HunyuanVideo following the official repository, then copy the NaviCache sampling script into it:
```bash
git clone https://github.com/Tencent-Hunyuan/HunyuanVideo.git
@@ -14,7 +14,7 @@ cp NaviCache/NaviCache4HunyuanVideo/navicache_sample_video.py HunyuanVideo/
cd HunyuanVideo
```
-For 544 x 960 generation, set `--video-size` to `544 960`:
+Run the paper configuration at 129 frames, 960x544, and 50 sampling steps:
```bash
python3 navicache_sample_video.py \
@@ -23,27 +23,32 @@ python3 navicache_sample_video.py \
--infer-steps 50 \
--prompt "A cat walks on the grass, realistic style." \
--use-cpu-offload \
- --navicache_thresh 0.025 \
+ --navicache_thresh 0.040 \
--navicache_align_steps 5 \
--save-path ./navicache_results
```
-For 720 x 1280 generation, set `--video-size` to `720 1280`:
+## Results
-```bash
-python3 navicache_sample_video.py \
- --video-size 720 1280 \
- --video-length 129 \
- --infer-steps 50 \
- --prompt "A cat walks on the grass, realistic style." \
- --use-cpu-offload \
- --navicache_thresh 0.025 \
- --navicache_align_steps 5 \
- --save-path ./navicache_results
-```
+### Visual Quality Comparison
+
+#### HunyuanVideo, 129 frames, 960x544, 50 steps
+
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| HunyuanVideo | 2363.83 s | 1.00x | NVIDIA H20 |
+| TeaCache | 1070.14 s | 2.21x | NVIDIA H20 |
+| **NaviCache** (`threshold=0.040`, `align_steps=5`) | **928.45 s** | **2.55x** | NVIDIA H20 |
+
+
+
+
+

+
-The generated video and `time_cost.json` are saved under `--save-path`.
+**Prompt:** `a book`
+**Analysis:** TeaCache drifts to an unrelated subject, while NaviCache stays close to the Native result.
## Acknowledgements
-We would like to thank the contributors to [HunyuanVideo](https://github.com/Tencent-Hunyuan/HunyuanVideo).
+We would like to thank the contributors to [HunyuanVideo](https://github.com/Tencent-Hunyuan/HunyuanVideo) and [TeaCache](https://github.com/ali-vilab/TeaCache).
diff --git a/NaviCache4OpenSora/README.md b/NaviCache4OpenSora/README.md
index 57bdbe5..fba587c 100644
--- a/NaviCache4OpenSora/README.md
+++ b/NaviCache4OpenSora/README.md
@@ -1,73 +1,27 @@
-# NaviCache for Open-Sora
+# NaviCache for Open-Sora 1.2
-This directory provides the Open-Sora NaviCache evaluation code. It contains:
+NaviCache is a training-free, test-time self-calibration caching method for accelerating [Open-Sora 1.2](https://github.com/hpcaitech/Open-Sora) text-to-video generation.
-- `videosys/`: the VideoSys-based Open-Sora inference framework used by the evaluation script.
-- `eval/`: generation, VBench, PSNR, LPIPS, and SSIM evaluation utilities.
+## Usage
-## Installation
+Clone NaviCache, install its dependencies, and download the Open-Sora 1.2 checkpoints:
-Prerequisites:
-
-- Python >= 3.10
-- PyTorch >= 2.0
-- CUDA >= 11.6
-
-We recommend using Anaconda to create a clean environment:
-
-```shell
-conda create -n navicache python=3.10 -y
-conda activate navicache
-```
-
-Install NaviCache from the repository root:
-
-```shell
-git clone https://github.com/HelloZicky/NaviCache
+```bash
+git clone https://github.com/HelloZicky/NaviCache.git
cd NaviCache
pip install -r requirements.txt
-```
-
-## Open-Sora Weights
-
-The Open-Sora evaluation script uses the following Hugging Face model ids by default:
-
-```text
-hpcai-tech/OpenSora-STDiT-v3
-hpcai-tech/OpenSora-VAE-v1.2
-DeepFloyd/t5-v1_1-xxl
-```
-
-For offline or more reproducible evaluation, download the weights before running:
-
-```shell
-mkdir -p checkpoints/opensora
huggingface-cli download hpcai-tech/OpenSora-STDiT-v3 \
--local-dir checkpoints/opensora/OpenSora-STDiT-v3
-
huggingface-cli download hpcai-tech/OpenSora-VAE-v1.2 \
--local-dir checkpoints/opensora/OpenSora-VAE-v1.2
-
huggingface-cli download DeepFloyd/t5-v1_1-xxl \
--local-dir checkpoints/opensora/t5-v1_1-xxl
```
-If Hugging Face access is slow in your region, set a mirror endpoint before running the same commands:
+Run the paper configuration at 51 frames, 848x480, and 30 sampling steps:
-```shell
-export HF_ENDPOINT=https://hf-mirror.com
-```
-
-## Evaluation
-
-The evaluation workflow first generates videos from VBench prompts, then computes VBench, PSNR, LPIPS, and SSIM scores.
-
-### Generate Videos
-
-Run from the repository root:
-
-```shell
+```bash
python NaviCache4OpenSora/eval/navicache/experiments/opensora.py \
--transformer_path checkpoints/opensora/OpenSora-STDiT-v3 \
--vae_path checkpoints/opensora/OpenSora-VAE-v1.2 \
@@ -77,49 +31,31 @@ python NaviCache4OpenSora/eval/navicache/experiments/opensora.py \
--navicache_align_steps 5
```
-By default, `opensora.py` uses `--loop 5` and generates five random videos for each prompt, following the VBench evaluation protocol.
+The integration defaults select Open-Sora 1.2, 51 frames, 480p at a 9:16 aspect ratio (848x480), and 30 sampling steps.
-The script reads prompts from:
+## Results
-```text
-NaviCache4OpenSora/eval/navicache/vbench/VBench_full_info.json
-```
+### Visual Quality Comparison
-and saves videos to:
+#### Open-Sora 1.2, 51 frames, 848x480, 30 steps
-```text
-NaviCache4OpenSora/eval/navicache/samples/opensora_base
-NaviCache4OpenSora/eval/navicache/samples/opensora_navicache
-```
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| Open-Sora 1.2 | 56.48 s | 1.00x | RTX 4090 |
+| TeaCache | 41.38 s | 1.36x | RTX 4090 |
+| **NaviCache** (`threshold=0.35`, `align_steps=5`) | **35.29 s** | **1.60x** | RTX 4090 |
-To run only one generation branch:
+
+
+
-```shell
-python NaviCache4OpenSora/eval/navicache/experiments/opensora.py --mode base
-python NaviCache4OpenSora/eval/navicache/experiments/opensora.py --mode navicache
-```
+
+
+
-NaviCache hyperparameters can be changed directly from the command line.
-
-### Calculate VBench
-
-```shell
-python NaviCache4OpenSora/eval/navicache/vbench/run_vbench.py \
- --video_path NaviCache4OpenSora/eval/navicache/samples/opensora_navicache \
- --save_path NaviCache4OpenSora/eval/navicache/vbench_results/navicache
-
-python NaviCache4OpenSora/eval/navicache/vbench/cal_vbench.py \
- --score_dir NaviCache4OpenSora/eval/navicache/vbench_results/navicache
-```
-
-### Calculate PSNR, LPIPS, and SSIM
-
-```shell
-python NaviCache4OpenSora/eval/navicache/common_metrics/eval.py \
- --gt_video_dir NaviCache4OpenSora/eval/navicache/samples/opensora_base \
- --generated_video_dir NaviCache4OpenSora/eval/navicache/samples/opensora_navicache
-```
+**Prompt:** `a train accelerating to gain speed`
+**Analysis:** TeaCache turns the tall green train into a low blue-and-red streak with a mismatched car body, whereas NaviCache retains the Native train, track-side composition, and left-to-right trajectory.
## Acknowledgements
-We would like to thank the contributors to [Open-Sora](https://github.com/hpcaitech/Open-Sora) and [VideoSys](https://github.com/NUS-HPC-AI-Lab/VideoSys).
+We would like to thank the contributors to [Open-Sora](https://github.com/hpcaitech/Open-Sora), [VideoSys](https://github.com/NUS-HPC-AI-Lab/VideoSys), and [TeaCache](https://github.com/ali-vilab/TeaCache).
diff --git a/NaviCache4Wan2.1/README.md b/NaviCache4Wan2.1/README.md
index abd1ef8..bc1d4e9 100644
--- a/NaviCache4Wan2.1/README.md
+++ b/NaviCache4Wan2.1/README.md
@@ -1,10 +1,10 @@
# NaviCache for Wan2.1
-NaviCache is a training-free test-time self-calibration caching method for accelerating video diffusion models. This directory provides the NaviCache generation script for [Wan2.1](https://github.com/Wan-Video/Wan2.1).
+NaviCache is a training-free, test-time self-calibration caching method for accelerating [Wan2.1](https://github.com/Wan-Video/Wan2.1) text-to-video and image-to-video generation.
## Usage
-Follow [Wan2.1](https://github.com/Wan-Video/Wan2.1) to clone the repo, finish the installation, and download the required model weights. Then copy `navicache_generate.py` in this repo to the Wan2.1 repo.
+Install Wan2.1 following the [official repository](https://github.com/Wan-Video/Wan2.1), then copy the NaviCache integration script into the Wan2.1 repository:
```bash
git clone https://github.com/Wan-Video/Wan2.1.git
@@ -14,11 +14,7 @@ cp NaviCache/NaviCache4Wan2.1/navicache_generate.py Wan2.1/
cd Wan2.1
```
-Please make sure that `--ckpt_dir` points to the matching Wan2.1 checkpoint directory. The T2V-14B and T2V-1.3B models use different weights. The I2V 480P and I2V 720P models also use different weights.
-
-## Text-to-Video
-
-For T2V with the 1.3B model:
+### T2V 1.3B, 832x480
```bash
python navicache_generate.py \
@@ -27,12 +23,13 @@ python navicache_generate.py \
--ckpt_dir ./Wan2.1-T2V-1.3B \
--offload_model True \
--t5_cpu \
+ --base_seed 42 \
--navicache_thresh 0.05 \
--navicache_align_steps 10 \
- --prompt "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."
+ --prompt "A boat sailing leisurely along the Seine River with the Eiffel Tower in background, zoom out"
```
-For T2V with the 14B model:
+### T2V 14B, 1280x720
```bash
python navicache_generate.py \
@@ -41,14 +38,13 @@ python navicache_generate.py \
--ckpt_dir ./Wan2.1-T2V-14B \
--offload_model True \
--t5_cpu \
+ --base_seed 42 \
--navicache_thresh 0.05 \
--navicache_align_steps 10 \
- --prompt "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage."
+ --prompt "A person is skateboarding"
```
-## Image-to-Video
-
-For I2V with the 480P model:
+### I2V 14B, 832x480
```bash
python navicache_generate.py \
@@ -58,12 +54,13 @@ python navicache_generate.py \
--image examples/i2v_input.JPG \
--offload_model True \
--t5_cpu \
+ --base_seed 42 \
--navicache_thresh 0.05 \
--navicache_align_steps 10 \
- --prompt "Summer beach vacation style, a white cat wearing sunglasses sits on a surfboard. The fluffy-furred feline gazes directly at the camera with a relaxed expression. Blurred beach scenery forms the background featuring crystal-clear waters, distant green hills, and a blue sky dotted with white clouds."
+ --prompt "A beautiful coastal beach in spring, waves lapping on sand by Hokusai, in the style of Ukiyo"
```
-For I2V with the 720P model:
+### I2V 14B, 1280x720
```bash
python navicache_generate.py \
@@ -71,15 +68,95 @@ python navicache_generate.py \
--size 1280*720 \
--ckpt_dir ./Wan2.1-I2V-14B-720P \
--image examples/i2v_input.JPG \
+ --frame_num 61 \
--offload_model True \
--t5_cpu \
+ --base_seed 42 \
--navicache_thresh 0.05 \
--navicache_align_steps 10 \
- --prompt "Summer beach vacation style, a white cat wearing sunglasses sits on a surfboard. The fluffy-furred feline gazes directly at the camera with a relaxed expression. Blurred beach scenery forms the background featuring crystal-clear waters, distant green hills, and a blue sky dotted with white clouds."
+ --prompt "an orange cat"
```
-The I2V commands use the sample image included in Wan2.1 at `examples/i2v_input.JPG`; replace it with your own input image as needed.Generated files are written to `outputs/` unless `--save_file` is specified. Generation timing records are appended to `output/time_cost.json` by default. Use `--out_dir` to choose another timing-output directory.
+## Results
+
+### Visual Quality Comparison
+
+#### T2V 1.3B, 832x480
+
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| Wan2.1 | 214.93 s | 1.00x | RTX 4090 |
+| TeaCache | 121.57 s | 1.77x | RTX 4090 |
+| **NaviCache** (`threshold=0.05`, `align_steps=10`) | **106.97 s** | **2.01x** | RTX 4090 |
+
+
+
+
+

+
+
+
+Prompt: A boat sailing leisurely along the Seine River with the Eiffel Tower in background, zoom out
+
+A boat sailing leisurely along the Seine River with the Eiffel Tower in background, zoom out
+
+#### T2V 14B, 1280x720
+
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| Wan2.1 | 3483.95 s | 1.00x | NVIDIA A100-SXM4-80GB |
+| TeaCache (`threshold=0.20`) | 1736.61 s | 2.01x | NVIDIA A100-SXM4-80GB |
+| **NaviCache** (`threshold=0.05`, `align_steps=10`) | **1286.33 s** | **2.71x** | NVIDIA A100-SXM4-80GB |
+
+
+
+
+

+
+
+
+Prompt: A person is skateboarding
+
+A person is skateboarding
+
+#### I2V 14B, 832x480
+
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| Wan2.1 | 744.00 s | 1.00x | NVIDIA A100-SXM4-80GB |
+| TeaCache (`threshold=0.10`) | 532.27 s | 1.40x | NVIDIA A100-SXM4-80GB |
+| **NaviCache** (`threshold=0.05`, `align_steps=10`) | **386.70 s** | **1.92x** | NVIDIA A100-SXM4-80GB |
+
+
+
+
+

+
+
+
+Prompt
+
+The ribbon dancer spins rapidly across the courtyard, both red silk ribbons tracing wide fluid arcs as her layered costume billows; the camera tracks sideways with strong natural background parallax.
+
+#### I2V 14B, 1280x720
+
+| Method | Latency | Speedup | Hardware |
+|:-------|--------:|--------:|:---------|
+| Wan2.1 | 1817.79 s | 1.00x | NVIDIA A100-SXM4-80GB |
+| TeaCache (`threshold=0.15`) | 1213.66 s | 1.50x | NVIDIA A100-SXM4-80GB |
+| **NaviCache** (`threshold=0.05`, `align_steps=10`) | **937.67 s** | **1.94x** | NVIDIA A100-SXM4-80GB |
+
+
+
+
+

+
+
+
+Prompt
+
+The clockwork hummingbird beats both articulated wings rapidly and flies from one red flower to the next; tiny gears turn visibly while the camera arcs around it through the greenhouse with deep parallax.
## Acknowledgements
-We would like to thank the contributors to [Wan2.1](https://github.com/Wan-Video/Wan2.1).
+We would like to thank the contributors to [Wan2.1](https://github.com/Wan-Video/Wan2.1), [TeaCache](https://github.com/ali-vilab/TeaCache), [EasyCache](https://github.com/H-EmbodVis/EasyCache), and [MagCache](https://github.com/Zehong-Ma/MagCache).
diff --git a/NaviCache4Wan2.2/README.md b/NaviCache4Wan2.2/README.md
new file mode 100644
index 0000000..9d0e369
--- /dev/null
+++ b/NaviCache4Wan2.2/README.md
@@ -0,0 +1,66 @@
+# NaviCache for Wan2.2
+
+NaviCache is a training-free test-time self-calibration caching method for accelerating video diffusion models. This directory provides the NaviCache generation script for [Wan2.2](https://github.com/Wan-Video/Wan2.2).
+
+## Usage
+
+Follow the official [Wan2.2](https://github.com/Wan-Video/Wan2.2) instructions to clone the repository, install the required environment, and download the Wan2.2-TI2V-5B model weights. NaviCache requires no training or offline calibration. From the directory containing the cloned `Wan2.2` repository, copy `navicache_generate.py` to its root:
+
+```bash
+git clone https://github.com/HelloZicky/NaviCache.git
+
+cp NaviCache/NaviCache4Wan2.2/navicache_generate.py Wan2.2/
+cd Wan2.2
+mkdir -p outputs
+```
+
+Make sure that `--ckpt_dir` points to the downloaded Wan2.2-TI2V-5B checkpoint directory. Once the official environment and weights are ready, run either of the following commands to generate videos with NaviCache.
+
+## Text-to-Video
+
+Run Wan2.2-TI2V-5B without an input image:
+
+```bash
+python navicache_generate.py \
+ --task ti2v-5B \
+ --size 1280*704 \
+ --frame_num 121 \
+ --ckpt_dir ./Wan2.2-TI2V-5B \
+ --offload_model True \
+ --convert_model_dtype \
+ --t5_cpu \
+ --navicache_thresh 0.05 \
+ --navicache_align_steps 10 \
+ --navicache_process_noise 0.05 \
+ --navicache_measurement_noise 0.05 \
+ --prompt "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage." \
+ --save_file ./outputs/wan22_t2v_navicache.mp4
+```
+
+## Image-to-Video
+
+Pass an input image to the same TI2V checkpoint with `--image`:
+
+```bash
+python navicache_generate.py \
+ --task ti2v-5B \
+ --size 1280*704 \
+ --frame_num 121 \
+ --ckpt_dir ./Wan2.2-TI2V-5B \
+ --image examples/i2v_input.JPG \
+ --offload_model True \
+ --convert_model_dtype \
+ --t5_cpu \
+ --navicache_thresh 0.05 \
+ --navicache_align_steps 10 \
+ --navicache_process_noise 0.05 \
+ --navicache_measurement_noise 0.05 \
+ --prompt "Summer beach vacation style, a white cat wearing sunglasses sits on a surfboard at a sunny beach." \
+ --save_file ./outputs/wan22_i2v_navicache.mp4
+```
+
+The command uses the sample image included in Wan2.2 at `examples/i2v_input.JPG`; replace it with your own input image as needed. Generated videos are written to the path provided by `--save_file`.
+
+## Acknowledgements
+
+We would like to thank the contributors to [Wan2.2](https://github.com/Wan-Video/Wan2.2).
diff --git a/NaviCache4Wan2.2/navicache_generate.py b/NaviCache4Wan2.2/navicache_generate.py
new file mode 100644
index 0000000..e0d2b9d
--- /dev/null
+++ b/NaviCache4Wan2.2/navicache_generate.py
@@ -0,0 +1,402 @@
+# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.
+# Copyright 2026 The NaviCache Authors. All rights reserved.
+#
+# The CLI and generation flow are adapted from Wan2.2 generate.py at commit
+# 42bf4cfaa384bc21833865abc2f9e6c0e67233dc (Apache License 2.0). NaviCache
+# adds only the model-forward cache hook and its command-line options.
+
+"""Generate Wan2.2-TI2V-5B videos with NaviCache.
+
+Place this file in the root of an official Wan2.2 checkout, or invoke it by
+absolute path while the current directory is the Wan2.2 repository root.
+"""
+
+from __future__ import annotations
+
+import argparse
+import logging
+import os
+import random
+import sys
+import types
+from datetime import datetime
+
+import torch
+import torch.distributed as dist
+
+
+DEFAULT_PROMPT = (
+ "Two anthropomorphic cats in comfy boxing gear and bright gloves fight "
+ "intensely on a spotlighted stage."
+)
+
+
+class NaviCacheConfig:
+ """Prompt-local NaviCache parameters shared by the public hook and tests."""
+
+ def __init__(
+ self,
+ *,
+ threshold: float = 0.05,
+ ret_steps: int = 10,
+ kalman_q: float = 0.05,
+ kalman_r: float = 0.05,
+ sample_steps: int = 50,
+ ) -> None:
+ if threshold < 0:
+ raise ValueError("navicache threshold must be non-negative")
+ if ret_steps < 0:
+ raise ValueError("navicache ret_steps must be non-negative")
+ if sample_steps <= 0:
+ raise ValueError("sample_steps must be positive")
+ if ret_steps > sample_steps:
+ raise ValueError("navicache ret_steps cannot exceed sample_steps")
+ if kalman_q < 0 or kalman_r < 0:
+ raise ValueError("Kalman Q and R must be non-negative")
+ self.threshold = float(threshold)
+ self.ret_steps = int(ret_steps)
+ self.kalman_q = float(kalman_q)
+ self.kalman_r = float(kalman_r)
+ self.sample_steps = int(sample_steps)
+
+
+def _mean_abs_cat(tensors):
+ """Mean absolute value over a list of tensors, matching the formal runner."""
+ return torch.cat([tensor.flatten() for tensor in tensors]).abs().mean()
+
+
+def reset_navicache_state(model) -> None:
+ """Reset every prompt-dependent NaviCache state value on ``model``."""
+ model._nc_forward_count = 0
+ model._nc_compute_count = 0
+ model._nc_skip_count = 0
+ model._nc_accumulated_error = 0.0
+ model._nc_should_compute = True
+ model._nc_k = None
+ model._nc_kalman_k = 0.0
+ model._nc_kalman_p = 1.0
+ model._nc_prev_input_even = None
+ model._nc_prev_prev_input_even = None
+ model._nc_prev_output_even = None
+ model._nc_prev_output_odd = None
+ model._nc_cache_even = None
+ model._nc_cache_odd = None
+
+
+def _navicache_forward(
+ self,
+ x,
+ t,
+ context,
+ seq_len,
+ clip_fea=None,
+ y=None,
+):
+ """Wan2.2 forward hook with prompt-local residual reuse.
+
+ Wan2.2's formal TI2V interface uses ``y`` and has no ``clip_fea``
+ parameter. ``clip_fea`` remains accepted by this wrapper only so accidental
+ calls fail at the native boundary rather than being forwarded incorrectly.
+ """
+ config = self._navicache_config
+ raw_input = [tensor.clone() for tensor in x]
+ is_cond_forward = self._nc_forward_count % 2 == 0
+
+ # The conditional/even call makes one decision for the entire CFG pair.
+ if is_cond_forward:
+ first_alignment_forwards = config.ret_steps * 2
+ final_pair_start = config.sample_steps * 2 - 2
+ if (
+ self._nc_forward_count < first_alignment_forwards
+ or self._nc_forward_count >= final_pair_start
+ ):
+ self._nc_should_compute = True
+ self._nc_accumulated_error = 0.0
+ elif (
+ self._nc_prev_input_even is not None
+ and self._nc_prev_output_even is not None
+ and self._nc_k is not None
+ ):
+ input_change = _mean_abs_cat(
+ [
+ current - previous
+ for current, previous in zip(raw_input, self._nc_prev_input_even)
+ ]
+ )
+ output_norm = _mean_abs_cat(self._nc_prev_output_even)
+ self._nc_accumulated_error += (
+ self._nc_k * input_change / (output_norm + 1e-8)
+ )
+ self._nc_should_compute = bool(
+ self._nc_accumulated_error >= config.threshold
+ )
+ if self._nc_should_compute:
+ self._nc_accumulated_error = 0.0
+ else:
+ self._nc_should_compute = True
+
+ self._nc_prev_input_even = [tensor.clone() for tensor in raw_input]
+
+ residual_cache = self._nc_cache_even if is_cond_forward else self._nc_cache_odd
+ if not self._nc_should_compute and residual_cache is not None:
+ self._nc_skip_count += 1
+ self._nc_forward_count += 1
+ return [
+ (tensor + residual).float()
+ for tensor, residual in zip(raw_input, residual_cache)
+ ]
+
+ # The official Wan2.2 model interface is (..., seq_len, y=None). In
+ # particular, do not forward Wan2.1's incompatible clip_fea argument.
+ output = self._navicache_native_forward(x, t, context, seq_len, y=y)
+ self._nc_compute_count += 1
+
+ if is_cond_forward:
+ if (
+ self._nc_prev_output_even is not None
+ and self._nc_prev_prev_input_even is not None
+ ):
+ output_change = _mean_abs_cat(
+ [
+ current - previous
+ for current, previous in zip(output, self._nc_prev_output_even)
+ ]
+ )
+ input_change = _mean_abs_cat(
+ [
+ current - previous
+ for current, previous in zip(
+ self._nc_prev_input_even,
+ self._nc_prev_prev_input_even,
+ )
+ ]
+ )
+ observation = output_change / (input_change + 1e-8)
+ if self._nc_kalman_k is None:
+ self._nc_kalman_k = observation
+ self._nc_kalman_p = 1.0
+ else:
+ self._nc_kalman_p += config.kalman_q
+ gain = self._nc_kalman_p / (
+ self._nc_kalman_p + config.kalman_r + 1e-8
+ )
+ self._nc_kalman_k = self._nc_kalman_k + gain * (
+ observation - self._nc_kalman_k
+ )
+ self._nc_kalman_p = (1.0 - gain) * self._nc_kalman_p
+ self._nc_k = self._nc_kalman_k
+
+ self._nc_prev_prev_input_even = [
+ tensor.clone() for tensor in self._nc_prev_input_even
+ ]
+ self._nc_prev_output_even = [tensor.clone() for tensor in output]
+ self._nc_cache_even = [
+ current - raw
+ for current, raw in zip(output, raw_input)
+ ]
+ else:
+ self._nc_prev_output_odd = [tensor.clone() for tensor in output]
+ self._nc_cache_odd = [
+ current - raw
+ for current, raw in zip(output, raw_input)
+ ]
+
+ self._nc_forward_count += 1
+ return output
+
+
+def install_navicache(model, config: NaviCacheConfig) -> None:
+ """Install an instance-local NaviCache hook on an official Wan2.2 model."""
+ if not hasattr(model, "_navicache_native_forward"):
+ model._navicache_native_forward = model.forward
+ model.forward = types.MethodType(_navicache_forward, model)
+ model._navicache_config = config
+ reset_navicache_state(model)
+
+
+def navicache_stats(model) -> dict[str, object]:
+ """Return lightweight generation statistics without writing trace files."""
+ return {
+ "compute_forwards": model._nc_compute_count,
+ "skip_forwards": model._nc_skip_count,
+ "kalman_k_final": (
+ float(model._nc_k.detach().cpu())
+ if torch.is_tensor(model._nc_k)
+ else model._nc_k
+ ),
+ }
+
+
+def _str2bool(value):
+ if isinstance(value, bool):
+ return value
+ normalized = value.lower()
+ if normalized in {"true", "1", "yes", "y"}:
+ return True
+ if normalized in {"false", "0", "no", "n"}:
+ return False
+ raise argparse.ArgumentTypeError(f"invalid boolean value: {value}")
+
+
+def build_parser() -> argparse.ArgumentParser:
+ parser = argparse.ArgumentParser(
+ description="Generate a video with NaviCache for Wan2.2-TI2V-5B."
+ )
+ parser.add_argument("--task", default="ti2v-5B", choices=["ti2v-5B"])
+ parser.add_argument("--size", default="1280*704", choices=["1280*704", "704*1280"])
+ parser.add_argument("--frame_num", type=int, default=121)
+ parser.add_argument("--ckpt_dir", required=True)
+ parser.add_argument("--offload_model", type=_str2bool, default=None)
+ parser.add_argument("--t5_cpu", action="store_true", default=False)
+ parser.add_argument("--save_file", default=None)
+ parser.add_argument("--prompt", default=DEFAULT_PROMPT)
+ parser.add_argument("--image", default=None)
+ parser.add_argument("--sample_solver", default="unipc", choices=["unipc", "dpm++"])
+ parser.add_argument("--sample_steps", type=int, default=50)
+ parser.add_argument("--sample_shift", type=float, default=5.0)
+ parser.add_argument("--sample_guide_scale", type=float, default=5.0)
+ parser.add_argument("--base_seed", type=int, default=42)
+ parser.add_argument("--convert_model_dtype", action="store_true", default=False)
+ parser.add_argument(
+ "--navicache_thresh",
+ type=float,
+ default=0.05,
+ help="Accumulated normalized predicted-error threshold.",
+ )
+ parser.add_argument(
+ "--navicache_align_steps",
+ type=int,
+ default=10,
+ help="Number of initial diffusion steps computed for alignment.",
+ )
+ parser.add_argument(
+ "--navicache_process_noise",
+ type=float,
+ default=0.05,
+ help="Process-noise covariance used by NaviCache state estimation.",
+ )
+ parser.add_argument(
+ "--navicache_measurement_noise",
+ type=float,
+ default=0.05,
+ help="Measurement-noise covariance used by NaviCache state estimation.",
+ )
+ return parser
+
+
+def _validate_args(args) -> None:
+ if args.frame_num <= 0 or (args.frame_num - 1) % 4 != 0:
+ raise ValueError("frame_num must be 4n+1")
+ if args.sample_steps <= 0:
+ raise ValueError("sample_steps must be positive")
+ if args.base_seed < 0:
+ args.base_seed = random.randint(0, sys.maxsize)
+ if args.offload_model is None:
+ args.offload_model = False if int(os.getenv("WORLD_SIZE", "1")) > 1 else True
+
+
+def generate(args) -> None:
+ """Run the official WanTI2V pipeline with the NaviCache model hook."""
+ _validate_args(args)
+ world_size = int(os.getenv("WORLD_SIZE", "1"))
+ if world_size != 1:
+ raise NotImplementedError(
+ "This public Wan2.2 NaviCache entry is validated for single-GPU inference only."
+ )
+
+ # Delayed imports keep module import and --help usable before Wan2.2 is
+ # installed. Generation itself must run from an official Wan2.2 checkout.
+ try:
+ import wan
+ from PIL import Image
+ from wan.configs import MAX_AREA_CONFIGS, SIZE_CONFIGS, WAN_CONFIGS
+ from wan.utils.utils import save_video
+ except ImportError as exc:
+ raise RuntimeError(
+ "Official Wan2.2 is not importable. Run this script from the root "
+ "of an installed Wan2.2 checkout."
+ ) from exc
+
+ logging.basicConfig(
+ level=logging.INFO,
+ format="[%(asctime)s] %(levelname)s: %(message)s",
+ handlers=[logging.StreamHandler(stream=sys.stdout)],
+ )
+ cfg = WAN_CONFIGS[args.task]
+ image = Image.open(args.image).convert("RGB") if args.image else None
+ logging.info("Generation job args: %s", args)
+ logging.info("Creating WanTI2V pipeline.")
+ pipeline = wan.WanTI2V(
+ config=cfg,
+ checkpoint_dir=args.ckpt_dir,
+ device_id=0,
+ rank=0,
+ t5_fsdp=False,
+ dit_fsdp=False,
+ use_sp=False,
+ t5_cpu=args.t5_cpu,
+ convert_model_dtype=args.convert_model_dtype,
+ )
+ install_navicache(
+ pipeline.model,
+ NaviCacheConfig(
+ threshold=args.navicache_thresh,
+ ret_steps=args.navicache_align_steps,
+ kalman_q=args.navicache_process_noise,
+ kalman_r=args.navicache_measurement_noise,
+ sample_steps=args.sample_steps,
+ ),
+ )
+
+ logging.info("Generating video with NaviCache.")
+ video = pipeline.generate(
+ args.prompt,
+ img=image,
+ size=SIZE_CONFIGS[args.size],
+ max_area=MAX_AREA_CONFIGS[args.size],
+ frame_num=args.frame_num,
+ shift=args.sample_shift,
+ sample_solver=args.sample_solver,
+ sampling_steps=args.sample_steps,
+ guide_scale=args.sample_guide_scale,
+ seed=args.base_seed,
+ offload_model=args.offload_model,
+ )
+ expected_forwards = args.sample_steps * 2
+ if pipeline.model._nc_forward_count != expected_forwards:
+ raise RuntimeError(
+ f"unexpected CFG forward count: {pipeline.model._nc_forward_count} "
+ f"(expected {expected_forwards})"
+ )
+
+ if args.save_file is None:
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ safe_prompt = args.prompt.replace(" ", "_").replace("/", "_")[:50]
+ args.save_file = (
+ f"{args.task}_{args.size}_{safe_prompt}_navicache_{timestamp}.mp4"
+ )
+ logging.info("Saving generated video to %s", args.save_file)
+ save_video(
+ tensor=video[None],
+ save_file=args.save_file,
+ fps=cfg.sample_fps,
+ nrow=1,
+ normalize=True,
+ value_range=(-1, 1),
+ )
+ logging.info("NaviCache stats: %s", navicache_stats(pipeline.model))
+ del video
+ torch.cuda.synchronize()
+ if dist.is_initialized():
+ dist.barrier()
+ dist.destroy_process_group()
+ logging.info("Finished.")
+
+
+def main() -> None:
+ args = build_parser().parse_args()
+ generate(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/README.md b/README.md
index d0b332d..8fbc476 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ This is the official repository for **NaviCache: Test-Time Self-Calibration Cach
- **No offline calibration**: no calibration datasets, pre-processing, or per-model fitting.
- **Test-time self-calibration**: the cache updates its feature-change estimator during inference.
-- **Plug-and-play acceleration**: lightweight integration for Wan2.1, HunyuanVideo, and Open-Sora.
+- **Plug-and-play acceleration**: lightweight integration for Wan2.1, Wan2.2, HunyuanVideo, and Open-Sora.
- **Adaptive computation allocation**: skip/update decisions are controlled by an uncertainty-aware gate.
- **Strong speed-quality trade-off**: multiple presets are provided for fast, mid, and slow modes.
@@ -106,6 +106,7 @@ For easier preview and quick visual comparison, we also provide clickable GIF pr
| Model | Task | NaviCache entry point | Example scripts |
|---|---|---|---|
| Wan2.1 | Text-to-Video / Image-to-Video | `NaviCache4Wan2.1/navicache_generate.py` | `scripts/wan/` |
+| Wan2.2-TI2V-5B | Text-to-Video / Image-conditioned Video | [`NaviCache4Wan2.2/navicache_generate.py`](NaviCache4Wan2.2/navicache_generate.py) | [`README`](NaviCache4Wan2.2/README.md) |
| HunyuanVideo | Text-to-Video | `NaviCache4HunyuanVideo/navicache_sample_video.py` | `scripts/hunyuan/` |
| Open-Sora 1.2 | Text-to-Video / Evaluation | `NaviCache4OpenSora/eval/navicache/experiments/opensora.py` | `scripts/opensora/` |
@@ -160,6 +161,18 @@ bash ../NaviCache/scripts/wan/run_wan_t2v_1.3b.sh
bash ../NaviCache/scripts/wan/run_wan_i2v_480p.sh
```
+### Wan2.2-TI2V-5B
+
+The Wan2.2 integration is a standalone entry point for the official TI2V-5B pipeline. Copy it into an official Wan2.2 checkout and run the documented single-GPU command:
+
+```bash
+cd Wan2.2
+cp ../NaviCache/NaviCache4Wan2.2/navicache_generate.py .
+python navicache_generate.py --help
+```
+
+See [`NaviCache4Wan2.2/README.md`](NaviCache4Wan2.2/README.md) for the full command, validated configuration, latency boundary, and quality results.
+
### HunyuanVideo
Run from the official HunyuanVideo repository directory:
@@ -254,6 +267,7 @@ NaviCache/
├── NaviCache4HunyuanVideo/ # NaviCache script for HunyuanVideo
├── NaviCache4OpenSora/ # Open-Sora NaviCache evaluation and VideoSys modules
├── NaviCache4Wan2.1/ # NaviCache script for Wan2.1
+├── NaviCache4Wan2.2/ # Single-GPU NaviCache entry for Wan2.2-TI2V-5B
├── assets/ # Paper figure PDFs
├── scripts/ # Runnable helper scripts
├── requirements.txt
@@ -277,7 +291,7 @@ If you find NaviCache useful, please consider citing:
## 🙏 Acknowledgements
-We thank the contributors of Wan2.1, HunyuanVideo, Open-Sora, VideoSys, TeaCache, EasyCache, MagCache, and PAB for their excellent open-source work and inspiring research.
+We thank the contributors of Wan2.1, Wan2.2, HunyuanVideo, Open-Sora, VideoSys, TeaCache, EasyCache, MagCache, and PAB for their excellent open-source work and inspiring research.
## 📄 License
diff --git a/assets/hunyuanvideo_comparison/hunyuan_book_comparison.mp4 b/assets/hunyuanvideo_comparison/hunyuan_book_comparison.mp4
new file mode 100644
index 0000000..35e06a6
Binary files /dev/null and b/assets/hunyuanvideo_comparison/hunyuan_book_comparison.mp4 differ
diff --git a/assets/hunyuanvideo_comparison/speedup/hunyuanvideo_speedup.png b/assets/hunyuanvideo_comparison/speedup/hunyuanvideo_speedup.png
new file mode 100644
index 0000000..10529de
Binary files /dev/null and b/assets/hunyuanvideo_comparison/speedup/hunyuanvideo_speedup.png differ
diff --git a/assets/opensora_comparison/opensora_train_accelerating_comparison.mp4 b/assets/opensora_comparison/opensora_train_accelerating_comparison.mp4
new file mode 100644
index 0000000..3649770
Binary files /dev/null and b/assets/opensora_comparison/opensora_train_accelerating_comparison.mp4 differ
diff --git a/assets/opensora_comparison/sources/opensora_train_accelerating_navicache_seed885440.mp4 b/assets/opensora_comparison/sources/opensora_train_accelerating_navicache_seed885440.mp4
new file mode 100644
index 0000000..0f97b4b
Binary files /dev/null and b/assets/opensora_comparison/sources/opensora_train_accelerating_navicache_seed885440.mp4 differ
diff --git a/assets/opensora_comparison/speedup/opensora12_speedup.png b/assets/opensora_comparison/speedup/opensora12_speedup.png
new file mode 100644
index 0000000..e4dd178
Binary files /dev/null and b/assets/opensora_comparison/speedup/opensora12_speedup.png differ
diff --git a/assets/wan21_comparison/i2v14b480_ribbon_dancer_comparison.mp4 b/assets/wan21_comparison/i2v14b480_ribbon_dancer_comparison.mp4
new file mode 100644
index 0000000..05ec434
Binary files /dev/null and b/assets/wan21_comparison/i2v14b480_ribbon_dancer_comparison.mp4 differ
diff --git a/assets/wan21_comparison/i2v14b720_clockwork_hummingbird_comparison.mp4 b/assets/wan21_comparison/i2v14b720_clockwork_hummingbird_comparison.mp4
new file mode 100644
index 0000000..0a13430
Binary files /dev/null and b/assets/wan21_comparison/i2v14b720_clockwork_hummingbird_comparison.mp4 differ
diff --git a/assets/wan21_comparison/speedup/i2v14b480_speedup.png b/assets/wan21_comparison/speedup/i2v14b480_speedup.png
new file mode 100644
index 0000000..5153bd9
Binary files /dev/null and b/assets/wan21_comparison/speedup/i2v14b480_speedup.png differ
diff --git a/assets/wan21_comparison/speedup/i2v14b720_speedup.png b/assets/wan21_comparison/speedup/i2v14b720_speedup.png
new file mode 100644
index 0000000..2d7d349
Binary files /dev/null and b/assets/wan21_comparison/speedup/i2v14b720_speedup.png differ
diff --git a/assets/wan21_comparison/speedup/t2v13b480_speedup.png b/assets/wan21_comparison/speedup/t2v13b480_speedup.png
new file mode 100644
index 0000000..04329f7
Binary files /dev/null and b/assets/wan21_comparison/speedup/t2v13b480_speedup.png differ
diff --git a/assets/wan21_comparison/speedup/t2v14b720_speedup.png b/assets/wan21_comparison/speedup/t2v14b720_speedup.png
new file mode 100644
index 0000000..28f8a20
Binary files /dev/null and b/assets/wan21_comparison/speedup/t2v14b720_speedup.png differ
diff --git a/assets/wan21_comparison/t2v13b480_boat_comparison.mp4 b/assets/wan21_comparison/t2v13b480_boat_comparison.mp4
new file mode 100644
index 0000000..0ce712a
Binary files /dev/null and b/assets/wan21_comparison/t2v13b480_boat_comparison.mp4 differ
diff --git a/assets/wan21_comparison/t2v14b720_skateboarding_comparison.mp4 b/assets/wan21_comparison/t2v14b720_skateboarding_comparison.mp4
new file mode 100644
index 0000000..157c5f2
Binary files /dev/null and b/assets/wan21_comparison/t2v14b720_skateboarding_comparison.mp4 differ
diff --git a/docs/superpowers/plans/2026-08-10-wan22-readme-cli-alignment.md b/docs/superpowers/plans/2026-08-10-wan22-readme-cli-alignment.md
new file mode 100644
index 0000000..38ef182
--- /dev/null
+++ b/docs/superpowers/plans/2026-08-10-wan22-readme-cli-alignment.md
@@ -0,0 +1,354 @@
+# Wan2.2 README and CLI Alignment Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Make the Wan2.2 model README match the concise GitHub model-README style and make its public NaviCache CLI names exactly match the repository's established names.
+
+**Architecture:** Change only the argparse public surface and its mapping into the existing `NaviCacheConfig`; the cache algorithm and internal configuration fields remain unchanged. Rewrite the model README as a compact usage document, and enforce the public naming contract with parser tests that require the standard names and reject the removed Wan2.2-only names.
+
+**Tech Stack:** Python 3.11, argparse, pytest, Markdown, Git, PowerShell.
+
+## Global Constraints
+
+- Implementation changes are limited to `NaviCache4Wan2.2/navicache_generate.py`, `tests/test_wan22_navicache.py`, and `NaviCache4Wan2.2/README.md`.
+- The public CLI must expose `--navicache_thresh`, `--navicache_align_steps`, `--navicache_process_noise`, and `--navicache_measurement_noise`.
+- The public CLI must reject `--navicache_ret_steps`, `--navicache_kalman_q`, and `--navicache_kalman_r`; do not add aliases.
+- Keep defaults exactly `0.05`, `10`, `0.05`, and `0.05`, respectively.
+- Do not change `NaviCacheConfig`, cache decisions, Kalman equations, Wan2.2 native-forward arguments, or generation behavior.
+- The model README must use the concise GitHub style and must not contain Results, parameter tables, Limitations, internal provenance, or benchmark-infrastructure language.
+- Do not modify, stage, or commit the existing `NaviCache4Wan2.1/README.md` user change.
+- Do not modify the repository root README or move external benchmark/smoke evidence into the release repository.
+
+## File Responsibilities
+
+- `NaviCache4Wan2.2/navicache_generate.py`: owns the public argparse names and maps them into the existing algorithm configuration.
+- `tests/test_wan22_navicache.py`: owns the parser naming/default/mapping/rejection contract and existing algorithm regression coverage.
+- `NaviCache4Wan2.2/README.md`: owns concise installation and direct T2V/I2V commands using only public option names.
+
+---
+
+### Task 1: Hard-rename the Wan2.2 public CLI with TDD
+
+**Files:**
+- Modify: `tests/test_wan22_navicache.py:213-239`
+- Modify: `NaviCache4Wan2.2/navicache_generate.py:260-284`
+- Modify: `NaviCache4Wan2.2/navicache_generate.py:340-348`
+
+**Interfaces:**
+- Consumes: `build_parser() -> argparse.ArgumentParser` and `NaviCacheConfig(threshold, ret_steps, kalman_q, kalman_r, sample_steps)`.
+- Produces: parsed attributes `navicache_thresh: float`, `navicache_align_steps: int`, `navicache_process_noise: float`, and `navicache_measurement_noise: float`; the existing internal config still receives `ret_steps`, `kalman_q`, and `kalman_r`.
+
+- [ ] **Step 1: Write failing public-name tests**
+
+Replace the four old assertions in `test_public_cli_defaults_match_verified_configuration` and append explicit mapping and rejection tests:
+
+```python
+def test_public_cli_defaults_match_verified_configuration():
+ module = load_public_module()
+ parser = module.build_parser()
+ args = parser.parse_args(["--ckpt_dir", "weights"])
+
+ assert args.task == "ti2v-5B"
+ assert args.size == "1280*704"
+ assert args.frame_num == 121
+ assert args.sample_steps == 50
+ assert args.sample_shift == 5.0
+ assert args.sample_guide_scale == 5.0
+ assert args.base_seed == 42
+ assert args.navicache_thresh == 0.05
+ assert args.navicache_align_steps == 10
+ assert args.navicache_process_noise == 0.05
+ assert args.navicache_measurement_noise == 0.05
+
+
+def test_public_cli_maps_repository_standard_navicache_names():
+ module = load_public_module()
+ args = module.build_parser().parse_args(
+ [
+ "--ckpt_dir",
+ "weights",
+ "--navicache_thresh",
+ "0.07",
+ "--navicache_align_steps",
+ "8",
+ "--navicache_process_noise",
+ "0.03",
+ "--navicache_measurement_noise",
+ "0.04",
+ ]
+ )
+
+ assert args.navicache_thresh == 0.07
+ assert args.navicache_align_steps == 8
+ assert args.navicache_process_noise == 0.03
+ assert args.navicache_measurement_noise == 0.04
+
+
+@pytest.mark.parametrize(
+ "removed_name",
+ [
+ "--navicache_ret_steps",
+ "--navicache_kalman_q",
+ "--navicache_kalman_r",
+ ],
+)
+def test_public_cli_rejects_removed_wan22_only_names(removed_name):
+ module = load_public_module()
+ parser = module.build_parser()
+
+ with pytest.raises(SystemExit):
+ parser.parse_args(["--ckpt_dir", "weights", removed_name, "1"])
+```
+
+- [ ] **Step 2: Run the parser tests and verify RED**
+
+Run:
+
+```powershell
+python -m pytest tests/test_wan22_navicache.py -q
+```
+
+Expected: the new default and explicit mapping tests fail because `navicache_align_steps`, `navicache_process_noise`, and `navicache_measurement_noise` do not yet exist; existing algorithm tests remain green.
+
+- [ ] **Step 3: Implement the minimal public hard rename**
+
+Replace the three Wan2.2-only parser arguments with:
+
+```python
+ parser.add_argument(
+ "--navicache_align_steps",
+ type=int,
+ default=10,
+ help="Number of initial diffusion steps computed for alignment.",
+ )
+ parser.add_argument(
+ "--navicache_process_noise",
+ type=float,
+ default=0.05,
+ help="Process-noise covariance used by NaviCache state estimation.",
+ )
+ parser.add_argument(
+ "--navicache_measurement_noise",
+ type=float,
+ default=0.05,
+ help="Measurement-noise covariance used by NaviCache state estimation.",
+ )
+```
+
+Map the public names into the unchanged internal configuration:
+
+```python
+ NaviCacheConfig(
+ threshold=args.navicache_thresh,
+ ret_steps=args.navicache_align_steps,
+ kalman_q=args.navicache_process_noise,
+ kalman_r=args.navicache_measurement_noise,
+ sample_steps=args.sample_steps,
+ ),
+```
+
+- [ ] **Step 4: Run tests and verify GREEN**
+
+Run:
+
+```powershell
+python -m pytest tests/test_wan22_navicache.py -q
+```
+
+Expected: 14 tests pass, including three parameterized rejection cases.
+
+- [ ] **Step 5: Verify the public help surface**
+
+Run:
+
+```powershell
+$help = python NaviCache4Wan2.2/navicache_generate.py --help 2>&1 | Out-String
+$required = @('--navicache_thresh','--navicache_align_steps','--navicache_process_noise','--navicache_measurement_noise')
+$removed = @('--navicache_ret_steps','--navicache_kalman_q','--navicache_kalman_r')
+foreach ($name in $required) { if (-not $help.Contains($name)) { throw "Missing CLI name: $name" } }
+foreach ($name in $removed) { if ($help.Contains($name)) { throw "Removed CLI name remains: $name" } }
+```
+
+Expected: command exits successfully without throwing.
+
+- [ ] **Step 6: Commit the tested CLI contract**
+
+```powershell
+git add -- NaviCache4Wan2.2/navicache_generate.py tests/test_wan22_navicache.py
+git diff --cached --check
+git commit -m "fix: align Wan2.2 NaviCache CLI names"
+```
+
+Expected: the commit contains exactly the public entry point and its tests; `NaviCache4Wan2.1/README.md` remains unstaged.
+
+---
+
+### Task 2: Rewrite the Wan2.2 README in the GitHub model style
+
+**Files:**
+- Modify: `NaviCache4Wan2.2/README.md:1-84`
+
+**Interfaces:**
+- Consumes: the standard public CLI names produced by Task 1.
+- Produces: one concise model README with directly runnable T2V and image-conditioned commands.
+
+- [ ] **Step 1: Replace the README with the approved compact content**
+
+Use this complete content:
+
+````markdown
+# NaviCache for Wan2.2
+
+NaviCache is a training-free test-time self-calibration caching method for accelerating video diffusion models. This directory provides the NaviCache generation script for [Wan2.2](https://github.com/Wan-Video/Wan2.2).
+
+## Usage
+
+Follow [Wan2.2](https://github.com/Wan-Video/Wan2.2) to clone the repository, finish the installation, and download the Wan2.2-TI2V-5B model weights. Then copy `navicache_generate.py` from this repository to the Wan2.2 repository.
+
+```bash
+git clone https://github.com/Wan-Video/Wan2.2.git
+git clone https://github.com/HelloZicky/NaviCache.git
+
+cp NaviCache/NaviCache4Wan2.2/navicache_generate.py Wan2.2/
+cd Wan2.2
+mkdir -p outputs
+```
+
+Make sure that `--ckpt_dir` points to the downloaded Wan2.2-TI2V-5B checkpoint directory.
+
+## Text-to-Video
+
+Run Wan2.2-TI2V-5B without an input image:
+
+```bash
+python navicache_generate.py \
+ --task ti2v-5B \
+ --size 1280*704 \
+ --frame_num 121 \
+ --ckpt_dir ./Wan2.2-TI2V-5B \
+ --offload_model False \
+ --convert_model_dtype \
+ --navicache_thresh 0.05 \
+ --navicache_align_steps 10 \
+ --navicache_process_noise 0.05 \
+ --navicache_measurement_noise 0.05 \
+ --prompt "Two anthropomorphic cats in comfy boxing gear and bright gloves fight intensely on a spotlighted stage." \
+ --save_file ./outputs/wan22_t2v_navicache.mp4
+```
+
+## Image-to-Video
+
+Pass an input image to the same TI2V checkpoint with `--image`:
+
+```bash
+python navicache_generate.py \
+ --task ti2v-5B \
+ --size 1280*704 \
+ --frame_num 121 \
+ --ckpt_dir ./Wan2.2-TI2V-5B \
+ --image examples/i2v_input.JPG \
+ --offload_model False \
+ --convert_model_dtype \
+ --navicache_thresh 0.05 \
+ --navicache_align_steps 10 \
+ --navicache_process_noise 0.05 \
+ --navicache_measurement_noise 0.05 \
+ --prompt "A small wooden sailboat glides across a calm lake at sunrise, cinematic and detailed." \
+ --save_file ./outputs/wan22_i2v_navicache.mp4
+```
+
+The command uses the sample image included in Wan2.2 at `examples/i2v_input.JPG`; replace it with your own input image as needed. Generated videos are written to the path provided by `--save_file`.
+
+## Acknowledgements
+
+We would like to thank the contributors to [Wan2.2](https://github.com/Wan-Video/Wan2.2).
+````
+
+- [ ] **Step 2: Verify structure and removed content**
+
+Run:
+
+```powershell
+$readme = Get-Content -Raw NaviCache4Wan2.2/README.md
+$expectedHeadings = @('# NaviCache for Wan2.2','## Usage','## Text-to-Video','## Image-to-Video','## Acknowledgements')
+foreach ($heading in $expectedHeadings) { if (-not $readme.Contains($heading)) { throw "Missing heading: $heading" } }
+$removedSections = @('## Results','Inference Latency Comparison','Visual Quality Comparison','## Limitations','--navicache_ret_steps','--navicache_kalman_q','--navicache_kalman_r')
+foreach ($text in $removedSections) { if ($readme.Contains($text)) { throw "Removed README content remains: $text" } }
+```
+
+Expected: command exits successfully without throwing.
+
+- [ ] **Step 3: Verify every documented flag exists in argparse**
+
+Run:
+
+```powershell
+$readme = Get-Content -Raw NaviCache4Wan2.2/README.md
+$help = python NaviCache4Wan2.2/navicache_generate.py --help 2>&1 | Out-String
+$documented = [regex]::Matches($readme, '--[a-zA-Z0-9_]+') | ForEach-Object Value | Sort-Object -Unique
+foreach ($flag in $documented) { if (-not $help.Contains($flag)) { throw "README flag absent from CLI: $flag" } }
+```
+
+Expected: every documented flag is present in help output.
+
+- [ ] **Step 4: Scan release text and commit the README**
+
+```powershell
+$bad = Select-String -Path NaviCache4Wan2.2/README.md -Pattern 'TBD|TODO|/data/zhuzhibo|/var/tmp/zhuzhibo|js1.blockelite|driver_launch|prompt_stats_shard' -CaseSensitive:$false
+if ($bad) { $bad; exit 2 }
+git diff --check -- NaviCache4Wan2.2/README.md
+git add -- NaviCache4Wan2.2/README.md
+git diff --cached --check
+git commit -m "docs: align Wan2.2 model README style"
+```
+
+Expected: the commit contains only `NaviCache4Wan2.2/README.md`; the Wan2.1 user modification remains unstaged.
+
+---
+
+### Task 3: Final regression, scope, and push verification
+
+**Files:**
+- Verify: `NaviCache4Wan2.2/navicache_generate.py`
+- Verify: `tests/test_wan22_navicache.py`
+- Verify: `NaviCache4Wan2.2/README.md`
+
+**Interfaces:**
+- Consumes: the committed CLI contract and compact README from Tasks 1 and 2.
+- Produces: a pushed branch whose public docs and parser agree and whose only remaining worktree modification is the protected Wan2.1 file.
+
+- [ ] **Step 1: Run complete local verification**
+
+```powershell
+python -m pytest -q
+python -m py_compile NaviCache4Wan2.2/navicache_generate.py
+python NaviCache4Wan2.2/navicache_generate.py --help | Select-Object -First 20
+git diff --check
+```
+
+Expected: all tests pass, syntax compilation succeeds, help prints the standard names, and diff checking reports no task-file errors.
+
+- [ ] **Step 2: Verify naming and protected scope**
+
+```powershell
+$publicFiles = @('NaviCache4Wan2.2/navicache_generate.py','NaviCache4Wan2.2/README.md')
+$old = Select-String -Path $publicFiles -Pattern '--navicache_ret_steps|--navicache_kalman_q|--navicache_kalman_r'
+if ($old) { $old; exit 2 }
+$status = @(git status --short)
+if ($status.Count -ne 1 -or $status[0] -notmatch 'NaviCache4Wan2\.1/README\.md') { $status; throw 'Unexpected final worktree status' }
+```
+
+Expected: no removed public flag remains, and only `NaviCache4Wan2.1/README.md` is modified in the worktree.
+
+- [ ] **Step 3: Verify remote relation and push**
+
+```powershell
+git fetch origin codex/tidy-release-directory-names
+$relation = @(git rev-list --left-right --count HEAD...origin/codex/tidy-release-directory-names)
+if (($relation -join ' ') -notmatch '^\d+\s+0$') { throw "Remote branch moved or relation is unsafe: $relation" }
+git push origin codex/tidy-release-directory-names
+git fetch origin codex/tidy-release-directory-names
+if ((git rev-parse HEAD) -ne (git rev-parse origin/codex/tidy-release-directory-names)) { throw 'HEAD and origin differ after push' }
+```
+
+Expected: push succeeds and local HEAD equals the origin branch SHA.
diff --git a/docs/superpowers/plans/2026-08-16-navicache-readme-latency-policy-implementation.md b/docs/superpowers/plans/2026-08-16-navicache-readme-latency-policy-implementation.md
new file mode 100644
index 0000000..948b400
--- /dev/null
+++ b/docs/superpowers/plans/2026-08-16-navicache-readme-latency-policy-implementation.md
@@ -0,0 +1,97 @@
+# NaviCache README Latency Policy Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Update the shared NaviCache README release standard and provide a new-session goal prompt that applies the approved paper-first latency policy across every model integration without changing existing videos.
+
+**Architecture:** Keep policy in the workspace-root `AGENTS.md`, where all model integrations inherit it. Treat exact paper configurations and locally benchmarked subset8 configurations as two provenance paths that converge on the same `model_forward_latency_sec` table format, with hardware and source shown per row.
+
+**Tech Stack:** Markdown, Git, PowerShell validation commands
+
+## Global Constraints
+
+- Paper `Inference Latency` is `model_forward_latency_sec`.
+- Reuse paper values only for an exact configuration match.
+- Label paper values `RTX 4090, reported in paper`.
+- Run uncovered configurations on subset8 and label the actual GPU.
+- Keep existing showcase video files unchanged.
+- Showcase selection is dataset-agnostic and prioritizes samples where the competitor is visibly worse while NaviCache remains close to Native.
+- Preserve unrelated user changes in all integration READMEs, including the existing change in `NaviCache4Wan2.1/README.md`.
+
+---
+
+### Task 1: Update Shared Release Policy
+
+**Files:**
+- Modify: `../AGENTS.md`
+
+**Interfaces:**
+- Consumes: Approved design in `docs/superpowers/specs/2026-08-16-navicache-readme-latency-source-policy-design.md`.
+- Produces: A single shared Markdown policy used by future NaviCache model README tasks.
+
+- [x] **Step 1: Replace the latency provenance restriction**
+
+Allow either an exact matching NaviCache paper table or completed local `summary.json`, `summary.csv`, or `per_prompt_latency.jsonl`. Require paper table number, exact configuration, method mode, hardware, and values in the local provenance record.
+
+- [x] **Step 2: Add exact-match fields**
+
+Require model family/version, parameter scale, T2V/I2V task, resolution, frame count, sampling steps, acceleration method, and method configuration to match before reusing paper values.
+
+- [x] **Step 3: Replace the old benchmark-size rule**
+
+Use paper values for exact matches. Use subset8 for all uncovered or parameter-mismatched configurations. Require Native, competitor, and NaviCache to share the same eight prompts and generation settings.
+
+- [x] **Step 4: Add hardware/source presentation rules**
+
+Require a `Hardware / Source` field or equivalent explicit annotation for every latency row. Mark paper rows `RTX 4090, reported in paper`; mark subset8 rows with the actual GPU.
+
+- [x] **Step 5: Update visual showcase policy**
+
+State that existing video files remain unchanged unless replacement is explicitly requested, no fixed dataset is required, and samples should expose clear competitor degradation while NaviCache remains close to Native.
+
+- [x] **Step 6: Validate the standard**
+
+Run:
+
+```powershell
+rg -n "model_forward_latency_sec|RTX 4090|subset8|Hardware / Source|dataset|视频文件" ..\AGENTS.md
+rg -n "超过 5 分钟|subset92|每一个 latency 都必须来自真实跑完" ..\AGENTS.md
+```
+
+Expected: the first command finds every new policy concept; the second command finds no superseded benchmark-size or provenance rule.
+
+### Task 2: Verify Scope and Prepare New-Session Goal
+
+**Files:**
+- Verify only: `../AGENTS.md`
+- Verify only: `NaviCache4Wan2.1/README.md`
+- Verify only: `NaviCache4HunyuanVideo/README.md`
+- Verify only: `NaviCache4OpenSora/README.md`
+- Verify only: `docs/superpowers/specs/2026-08-16-navicache-readme-latency-source-policy-design.md`
+
+**Interfaces:**
+- Consumes: Updated shared policy from Task 1.
+- Produces: A self-contained Chinese goal prompt for a new Codex session.
+
+- [x] **Step 1: Check repository scope**
+
+Run:
+
+```powershell
+git status --short
+git diff -- NaviCache4Wan2.1/README.md NaviCache4HunyuanVideo/README.md NaviCache4OpenSora/README.md
+```
+
+Expected: no video file is modified; pre-existing README changes remain preserved and distinguishable from this policy work.
+
+- [x] **Step 2: Check policy consistency**
+
+Confirm the new policy does not simultaneously require paper-derived latency to have local JSONL, does not retain the old five-minute subset rule, and does not require a fixed showcase dataset.
+
+- [x] **Step 3: Write the handoff goal**
+
+The goal prompt must tell the new session to read `AGENTS.md`, the approved design, the paper, the Wan2.1, HunyuanVideo, and Open-Sora integration READMEs, and current git status before editing. It must audit only those three current model integrations; reuse exact Table 1 values for matching Wan2.1-1.3B, HunyuanVideo, and Open-Sora 1.2 configurations; use validated subset8 results for every uncovered or mismatched configuration only after confirming actual GPU and raw provenance; add hardware/source labeling; keep videos unchanged; synchronize mini-tables; and run fresh verification.
+
+- [x] **Step 4: Commit only the plan document if requested**
+
+Do not include the user's existing README modification in a policy or plan commit.
diff --git a/docs/superpowers/specs/2026-08-10-wan22-readme-alignment-design.md b/docs/superpowers/specs/2026-08-10-wan22-readme-alignment-design.md
new file mode 100644
index 0000000..1c712b0
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-10-wan22-readme-alignment-design.md
@@ -0,0 +1,55 @@
+# Wan2.2 Model README and CLI Alignment Design
+
+## Objective
+
+Rewrite `NaviCache4Wan2.2/README.md` so it follows the concise model-integration README style currently used by `NaviCache4Wan2.1/README.md` and `NaviCache4HunyuanVideo/README.md` on GitHub `main`. Make the Wan2.2 NaviCache command-line option names exactly match the established public names used by the other integrations.
+
+## Scope
+
+Implementation changes are limited to `NaviCache4Wan2.2/README.md`, `NaviCache4Wan2.2/navicache_generate.py`, and `tests/test_wan22_navicache.py`. The repository root README, algorithm behavior, benchmark evidence, and the existing unstaged `NaviCache4Wan2.1/README.md` user modification will remain unchanged.
+
+## Document Structure
+
+The rewritten README will use this order:
+
+1. `# NaviCache for Wan2.2`
+2. A two-sentence introduction describing NaviCache and linking to official Wan2.2.
+3. `## Usage`, with clone, installation, checkpoint-download, script-copy, and working-directory instructions.
+4. `## Text-to-Video`, with one directly runnable Wan2.2-TI2V-5B command using the validated balanced NaviCache configuration.
+5. `## Image-to-Video`, with one directly runnable command that adds an example input image path.
+6. A short output-path note.
+7. `## Acknowledgements`, thanking and linking to official Wan2.2.
+
+## Command-Line Naming
+
+The Wan2.2 public CLI will expose only the established repository names:
+
+| Meaning | Required public name | Removed Wan2.2-only name |
+|---|---|---|
+| Accumulated error threshold | `--navicache_thresh` | None; already consistent |
+| Initial alignment steps | `--navicache_align_steps` | `--navicache_ret_steps` |
+| Kalman process-noise covariance | `--navicache_process_noise` | `--navicache_kalman_q` |
+| Kalman measurement-noise covariance | `--navicache_measurement_noise` | `--navicache_kalman_r` |
+
+The removed names will not be retained as aliases. The parser will reject them. The renamed arguments will map to the same internal configuration values, so defaults and caching behavior remain unchanged.
+
+## Content Rules
+
+- Match the tone and compactness of the existing GitHub model READMEs.
+- Keep commands consistent with the actual public CLI and its validated defaults.
+- Use `./Wan2.2-TI2V-5B` as the checkpoint example and the official `examples/i2v_input.JPG` sample image.
+- Retain the balanced NaviCache values: threshold `0.05`, alignment steps `10`, process noise `0.05`, and measurement noise `0.05`.
+- State that users should replace the example image with their own file.
+- Remove the parameter table, benchmark Results section, latency explanation, quality metrics, Limitations section, internal runner/provenance language, and detailed implementation commentary.
+- Do not move benchmark or smoke evidence into the release repository; existing external audit records remain the source of verification.
+- Do not document or expose the removed Wan2.2-only command-line names.
+
+## Verification
+
+- Update tests before implementation so they require the established public names, verify their default and explicit-value mapping, and verify that the removed names are rejected.
+- Run the complete Wan2.2 unit-test suite after implementation.
+- Run Python syntax compilation and the public CLI `--help` command.
+- Confirm every documented option appears in CLI help and that the three removed names do not appear.
+- Scan the rewritten README for placeholders, internal server paths, benchmark infrastructure terms, and contradictory output descriptions.
+- Confirm the implementation diff contains only the Wan2.2 README, public entry point, and tests, apart from the already committed design document.
+- Explicitly stage only those three implementation files and preserve the unstaged Wan2.1 user modification.
diff --git a/docs/superpowers/specs/2026-08-16-navicache-readme-latency-source-policy-design.md b/docs/superpowers/specs/2026-08-16-navicache-readme-latency-source-policy-design.md
new file mode 100644
index 0000000..397dcd8
--- /dev/null
+++ b/docs/superpowers/specs/2026-08-16-navicache-readme-latency-source-policy-design.md
@@ -0,0 +1,107 @@
+# NaviCache README Latency Source Policy Design
+
+## Goal
+
+Define a reusable release policy for NaviCache model-integration READMEs that reuses latency values from the NaviCache paper when the evaluated configuration matches exactly, while limiting new measurements for uncovered configurations to subset8. Preserve the existing showcase videos and relax dataset restrictions for visual sample selection.
+
+## Source Precedence
+
+1. Use the NaviCache paper's latency values when the README configuration exactly matches a configuration evaluated in the paper.
+2. For configurations not exactly covered by the paper, run a real subset8 benchmark.
+3. Never infer, interpolate, scale, or manually alter latency values.
+
+The paper's `Inference Latency` is treated as `model_forward_latency_sec`. Paper-derived and locally measured values may therefore appear in the same latency table, provided every row identifies its hardware and source.
+
+## Exact-Match Rule
+
+A paper result is reusable only when all relevant fields match:
+
+- model family and version;
+- parameter scale;
+- generation task, including T2V versus I2V;
+- spatial resolution;
+- frame count;
+- sampling-step count;
+- acceleration method and the method configuration represented by the published mode.
+
+If any field differs, the configuration is treated as uncovered and requires subset8 measurement.
+
+## Paper-Covered Configurations
+
+The paper reports these primary latency configurations:
+
+| Model | Configuration |
+|---|---|
+| Wan2.1-1.3B | 81 frames, 832x480, 50 steps |
+| HunyuanVideo | 129 frames, 960x544, 50 steps |
+| Open-Sora 1.2 | 51 frames, 848x480, 30 steps |
+
+Paper-derived rows must be labeled `RTX 4090, reported in paper`. The local provenance record must retain the paper table number, complete configuration, selected mode, and copied values.
+
+The policy applies to every model integration README, including the current Wan2.1, HunyuanVideo, and Open-Sora release scope. For exact matches, the reusable Table 1 values are:
+
+| Model/configuration | Method | Latency | Speedup |
+|---|---|---:|---:|
+| Wan2.1-1.3B, 81f, 832x480, 50 steps | Native | 214.93 s | 1.00x |
+| Wan2.1-1.3B, 81f, 832x480, 50 steps | TeaCache | 121.57 s | 1.77x |
+| Wan2.1-1.3B, 81f, 832x480, 50 steps | NaviCache fast/mid/slow | 96.40 / 106.97 / 115.86 s | 2.23x / 2.01x / 1.86x |
+| HunyuanVideo, 129f, 960x544, 50 steps | Native | 2363.83 s | 1.00x |
+| HunyuanVideo, 129f, 960x544, 50 steps | TeaCache / MagCache / EasyCache | 1070.14 / 882.76 / 1100.30 s | 2.21x / 2.68x / 2.15x |
+| HunyuanVideo, 129f, 960x544, 50 steps | NaviCache fast/mid/slow | 928.45 / 1089.43 / 1150.87 s | 2.55x / 2.17x / 2.05x |
+| Open-Sora 1.2, 51f, 848x480, 30 steps | Native | 56.48 s | 1.00x |
+| Open-Sora 1.2, 51f, 848x480, 30 steps | TeaCache / MagCache / EasyCache | 41.38 / 26.07 / 34.55 s | 1.36x / 2.17x / 1.63x |
+| Open-Sora 1.2, 51f, 848x480, 30 steps | NaviCache fast/mid/slow | 31.80 / 35.29 / 40.98 s | 1.78x / 1.60x / 1.38x |
+
+Published NaviCache mode parameters are: Wan2.1 `Nalign=10`, thresholds fast/mid/slow `0.07/0.05/0.04`; HunyuanVideo `Nalign=5`, thresholds `0.040/0.035/0.025`; Open-Sora 1.2 `Nalign=5`, thresholds `0.55/0.35/0.15`. A README may use a published value only when its command selects the corresponding mode.
+
+## Subset8 Rule
+
+Every configuration not exactly covered by the paper uses subset8, regardless of model family. Within one configuration:
+
+- Native, competitor, and NaviCache use the same eight prompts;
+- all methods use `model_forward_latency_sec`;
+- seed, sampling steps, resolution, frame count, and other generation settings match;
+- method parameters are recorded;
+- success count, missing prompts, duplicate rows, and prompt IDs are validated before aggregation;
+- the README records the actual GPU model used for that result.
+
+Each summary must remain reproducible from its raw JSONL. Speedup is always `native_latency / method_latency`.
+
+## README Presentation
+
+The main latency table adds a `Hardware / Source` column. Paper rows and subset8 rows may share the table because their timing field is the same, but their different hardware must be visible. The visual-quality mini-table reuses the corresponding latency row and does not introduce separate runtime measurements.
+
+Current integration routing includes:
+
+| Configuration | Source |
+|---|---|
+| T2V 1.3B, 81 frames, 832x480, 50 steps | Paper, RTX 4090 |
+| T2V 14B, 1280x720 | subset8, actual GPU labeled |
+| I2V 14B 480P | subset8, actual GPU labeled |
+| I2V 14B 720P | subset8, actual GPU labeled |
+| HunyuanVideo, 129 frames, 960x544, 50 steps | Paper, RTX 4090 |
+| Open-Sora 1.2, 51 frames, 848x480, 30 steps | Paper, RTX 4090 |
+
+## Visual Showcase Policy
+
+- Keep existing video files unchanged unless the user separately requests replacement.
+- Do not require VBench or any other fixed dataset for showcase selection.
+- Select samples where the competitor is visibly worse and NaviCache remains closer to Native.
+- Preserve the method order `Native | Competitor | NaviCache`.
+- Preserve MP4 format, correct panel geometry, and the existing README layout rules.
+
+## Validation
+
+Before release:
+
+- verify every paper-derived value against the cited paper table and exact configuration;
+- verify every subset8 value against raw JSONL and its actual hardware;
+- recompute displayed speedups from displayed rounded latencies;
+- ensure every latency row identifies hardware and source;
+- ensure mini-tables match the main table;
+- ensure showcase video paths still resolve and no video file was modified;
+- scan the README for stale sample-count claims, superseded latency values, placeholders, and contradictory hardware statements.
+
+## Scope
+
+Implementation changes are limited to the shared release standard and the affected model README latency text or tables. Existing videos and unrelated repository files remain untouched.
diff --git a/tests/test_wan22_navicache.py b/tests/test_wan22_navicache.py
new file mode 100644
index 0000000..254553b
--- /dev/null
+++ b/tests/test_wan22_navicache.py
@@ -0,0 +1,278 @@
+from __future__ import annotations
+
+import importlib.util
+from pathlib import Path
+
+import pytest
+import torch
+
+
+ROOT = Path(__file__).resolve().parents[1]
+MODULE_PATH = ROOT / "NaviCache4Wan2.2" / "navicache_generate.py"
+
+
+def load_public_module():
+ spec = importlib.util.spec_from_file_location("navicache_wan22_public", MODULE_PATH)
+ if spec is None or spec.loader is None:
+ raise RuntimeError(f"cannot load {MODULE_PATH}")
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+ return module
+
+
+class FakeModel:
+ def __init__(self):
+ self.native_calls = []
+ self.forward = self.native_forward
+
+ def native_forward(self, x, t, context, seq_len, y=None):
+ branch_offset = 10.0 if context == "cond" else 20.0
+ self.native_calls.append({"context": context, "y": y})
+ return [item + branch_offset for item in x]
+
+
+def config(module, **overrides):
+ values = {
+ "threshold": 0.05,
+ "ret_steps": 0,
+ "kalman_q": 0.05,
+ "kalman_r": 0.05,
+ "sample_steps": 4,
+ }
+ values.update(overrides)
+ return module.NaviCacheConfig(**values)
+
+
+def call_pair(model, value, y=None):
+ raw = [torch.tensor([float(value)])]
+ cond = model.forward(raw, None, "cond", 1, y=y)[0]
+ uncond = model.forward(raw, None, "uncond", 1, y=y)[0]
+ return cond, uncond
+
+
+def test_reset_restores_every_prompt_local_state():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module))
+ module.reset_navicache_state(model)
+
+ model._nc_forward_count = 7
+ model._nc_accumulated_error = 3.0
+ model._nc_k = torch.tensor(2.0)
+ model._nc_kalman_k = torch.tensor(4.0)
+ model._nc_kalman_p = torch.tensor(5.0)
+ model._nc_cache_even = [torch.tensor([1.0])]
+ model._nc_cache_odd = [torch.tensor([2.0])]
+ model._nc_prev_input_even = [torch.tensor([3.0])]
+ model._nc_prev_prev_input_even = [torch.tensor([4.0])]
+ model._nc_prev_output_even = [torch.tensor([5.0])]
+ model._nc_prev_output_odd = [torch.tensor([6.0])]
+
+ module.reset_navicache_state(model)
+
+ assert model._nc_forward_count == 0
+ assert model._nc_compute_count == 0
+ assert model._nc_skip_count == 0
+ assert model._nc_accumulated_error == 0.0
+ assert model._nc_should_compute is True
+ assert model._nc_k is None
+ assert model._nc_kalman_k == 0.0
+ assert model._nc_kalman_p == 1.0
+ assert model._nc_cache_even is None and model._nc_cache_odd is None
+ assert model._nc_prev_input_even is None
+ assert model._nc_prev_prev_input_even is None
+ assert model._nc_prev_output_even is None
+ assert model._nc_prev_output_odd is None
+
+
+def test_ret_steps_force_both_cfg_forwards_to_compute():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, ret_steps=2, threshold=100.0))
+ module.reset_navicache_state(model)
+
+ call_pair(model, 1.0)
+ call_pair(model, 2.0)
+
+ assert len(model.native_calls) == 4
+ assert model._nc_compute_count == 4
+ assert model._nc_skip_count == 0
+
+
+def test_final_cfg_pair_is_forced_to_compute():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=100.0))
+ module.reset_navicache_state(model)
+ model._nc_forward_count = 6
+ model._nc_should_compute = False
+ model._nc_cache_even = [torch.tensor([10.0])]
+ model._nc_cache_odd = [torch.tensor([20.0])]
+
+ call_pair(model, 4.0)
+
+ assert len(model.native_calls) == 2
+ assert model._nc_compute_count == 2
+ assert model._nc_skip_count == 0
+
+
+def test_conditional_decision_controls_pair_and_branch_caches_stay_separate():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=100.0))
+ module.reset_navicache_state(model)
+
+ call_pair(model, 1.0)
+ call_pair(model, 2.0)
+ cond, uncond = call_pair(model, 3.0)
+
+ assert len(model.native_calls) == 4
+ assert model._nc_compute_count == 4
+ assert model._nc_skip_count == 2
+ assert torch.equal(cond, torch.tensor([13.0]))
+ assert torch.equal(uncond, torch.tensor([23.0]))
+
+
+def test_accumulated_error_uses_normalized_predicted_change():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=0.9))
+ module.reset_navicache_state(model)
+ model._nc_forward_count = 2
+ model._nc_accumulated_error = torch.tensor(0.1)
+ model._nc_k = torch.tensor(2.0)
+ model._nc_prev_input_even = [torch.tensor([1.0])]
+ model._nc_prev_output_even = [torch.tensor([4.0])]
+ model._nc_cache_even = [torch.tensor([10.0])]
+ model._nc_cache_odd = [torch.tensor([20.0])]
+
+ call_pair(model, 2.0)
+
+ assert model._nc_accumulated_error.item() == pytest.approx(0.6)
+ assert model._nc_skip_count == 2
+ assert len(model.native_calls) == 0
+
+
+def test_exact_compute_corrects_kalman_from_k_zero_and_p_one():
+ module = load_public_module()
+ model = FakeModel()
+ options = config(module, threshold=0.0)
+ module.install_navicache(model, options)
+ module.reset_navicache_state(model)
+
+ call_pair(model, 1.0)
+ call_pair(model, 2.0)
+
+ expected_gain = 1.05 / (1.05 + 0.05 + 1e-8)
+ assert float(model._nc_kalman_k) == pytest.approx(expected_gain)
+ assert float(model._nc_kalman_p) == pytest.approx((1.0 - expected_gain) * 1.05)
+ assert float(model._nc_k) == pytest.approx(expected_gain)
+
+
+def test_threshold_zero_matches_native_and_never_skips():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=0.0))
+ module.reset_navicache_state(model)
+
+ outputs = [call_pair(model, step + 1.0) for step in range(4)]
+
+ expected = [
+ (torch.tensor([step + 10.0]), torch.tensor([step + 20.0]))
+ for step in range(1, 5)
+ ]
+ assert all(
+ torch.equal(actual_cond, expected_cond)
+ and torch.equal(actual_uncond, expected_uncond)
+ for (actual_cond, actual_uncond), (expected_cond, expected_uncond) in zip(outputs, expected)
+ )
+ assert len(model.native_calls) == 8
+ assert model._nc_skip_count == 0
+
+
+def test_consecutive_prompts_do_not_inherit_cache_or_kalman_state():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=100.0))
+ module.reset_navicache_state(model)
+ call_pair(model, 1.0)
+ call_pair(model, 2.0)
+ call_pair(model, 3.0)
+ assert model._nc_skip_count == 2
+
+ module.reset_navicache_state(model)
+ call_pair(model, 100.0)
+
+ assert model._nc_forward_count == 2
+ assert model._nc_compute_count == 2
+ assert model._nc_skip_count == 0
+ assert model._nc_cache_even is not None and model._nc_cache_odd is not None
+
+
+def test_native_forward_receives_y_keyword_and_not_clip_fea():
+ module = load_public_module()
+ model = FakeModel()
+ module.install_navicache(model, config(module, threshold=0.0))
+ module.reset_navicache_state(model)
+ y = [torch.tensor([9.0])]
+
+ call_pair(model, 1.0, y=y)
+
+ assert [call["y"] for call in model.native_calls] == [y, y]
+
+
+def test_public_cli_defaults_match_verified_configuration():
+ module = load_public_module()
+ parser = module.build_parser()
+ args = parser.parse_args(["--ckpt_dir", "weights"])
+
+ assert args.task == "ti2v-5B"
+ assert args.size == "1280*704"
+ assert args.frame_num == 121
+ assert args.sample_steps == 50
+ assert args.sample_shift == 5.0
+ assert args.sample_guide_scale == 5.0
+ assert args.base_seed == 42
+ assert args.navicache_thresh == 0.05
+ assert args.navicache_align_steps == 10
+ assert args.navicache_process_noise == 0.05
+ assert args.navicache_measurement_noise == 0.05
+
+
+def test_public_cli_maps_repository_standard_navicache_names():
+ module = load_public_module()
+ args = module.build_parser().parse_args(
+ [
+ "--ckpt_dir",
+ "weights",
+ "--navicache_thresh",
+ "0.07",
+ "--navicache_align_steps",
+ "8",
+ "--navicache_process_noise",
+ "0.03",
+ "--navicache_measurement_noise",
+ "0.04",
+ ]
+ )
+
+ assert args.navicache_thresh == 0.07
+ assert args.navicache_align_steps == 8
+ assert args.navicache_process_noise == 0.03
+ assert args.navicache_measurement_noise == 0.04
+
+
+@pytest.mark.parametrize(
+ "removed_name",
+ [
+ "--navicache_ret_steps",
+ "--navicache_kalman_q",
+ "--navicache_kalman_r",
+ ],
+)
+def test_public_cli_rejects_removed_wan22_only_names(removed_name):
+ module = load_public_module()
+ parser = module.build_parser()
+
+ with pytest.raises(SystemExit):
+ parser.parse_args(["--ckpt_dir", "weights", removed_name, "1"])