e0e48d12c8d45e2c196bca0e7bfaa9fcdfe973ca
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
950b55df5f |
Add __version__, patch-time version+pred-type log, platform-agnostic issue template (#39)
## What
Groundwork folded ahead of the held v1.0.0 release (publish-neutral —
**`pyproject.toml` is untouched**, so this does not trigger the registry
auto-publish):
1. **`NRS.__version__`** — added `__version__ = "0.7.4"` (mirrors the
current `pyproject.toml` version) in `NRS/nodes_NRS.py`, re-exported
from a new `NRS/__init__.py` so `NRS.__version__` is importable.
Commented to bump both together at release.
2. **Patch-time log line** — `patch()` now emits, right after
prediction-type detection:
`logging.info(f"NRS v{__version__}: prediction type detected ->
{pred_type.name}")`
So a user's console shows which NRS version ran and which prediction
space it selected (the key diagnostic for the flow-family
reclassification).
3. **GitHub bug-report issue form** —
`.github/ISSUE_TEMPLATE/bug_report.yml` + `config.yml`. Captures the NRS
version + detected prediction type (from the new log line),
model/sampler family, skew/stretch/squash values, expected vs actual,
repro, and console log.
- **Platform-agnostic:** NRS ships for ComfyUI *and* the A1111 family,
so the form has a **Platform / UI** dropdown — `ComfyUI, AUTOMATIC1111,
Forge, reForge, Forge Neo, Stability Matrix, Other` — with a free-text
follow-up and a generic "Platform version" field (no ComfyUI-only
wording).
## Tests
`tests/test_version.py`: asserts `NRS.__version__` is a valid `X.Y.Z`
string, matches `pyproject.toml` (catches future drift), and (via
`caplog`) that `patch()` emits the exact version + pred-type log line.
## Notes
- Adding `NRS/__init__.py` turned `NRS` from an implicit namespace
package into a real package, which newly triggered ruff's `N999` on the
pre-existing mixed-case filename `nodes_NRS.py`. Since `pyproject.toml`
is off-limits here, it's suppressed with an in-file `# ruff: noqa: N999`
pragma (with an explanatory comment) — consistent with the existing
per-file `N802/N804` carve-out for that same file. Renaming the file is
out of scope (breaks imports).
## Validation
- `ruff check .` → clean.
- `pytest --cov=NRS --cov-branch` → **45 passed** (42 + 3 new).
- diff-cover branch gate (mirrors CI) → **100%** on changed code.
- `pyproject.toml` / `uv.lock` untouched; issue-form YAML validated with
`yaml.safe_load`.
|
||
|
|
c526ec9353 |
PR-3: FLOW operation space + flow-family reclassification (#37)
## What Adds `PredictionType.FLOW` — an **identity operation space** — and reclassifies the flow-matching family (`flux`, `chroma`, `flow`, `wan`, `const`) off the VP ε-prediction path onto it. Flow models (H3, Flux, Chroma, WAN) were resolving to `PredictionType.EPS`, so NRS ran the ε→v / v→ε σ-algebra on them using the wrong sigma convention. NRS's projection/rejection geometry and norm ratios are invariant to a flow model's per-sample velocity scale, so flow models are now operated **natively with no conversion** (identity in, identity out). ## Changes (`NRS/nodes_NRS.py`) - New enum member `PredictionType.FLOW`. - `_convert_to_v_space` / `_finalize_from_v_space`: the `V` identity branch is widened to `V | FLOW` (no ε↔v algebra, `x_div=None`, cond/uncond/x_final passed through). **EPS** (SDXL/SD1.5), `X0` (`NotImplementedError`), and the UNKNOWN fallback are untouched. - `_RAW_TO_ENUM`: `flux`/`chroma`/`flow`/`wan`/`const` → `FLOW` (comments updated). `eps`/`epsilon`/`v`/`v_prediction`/`x0`/`sample` unchanged. - `_get_pred_type` enhanced-detection fallback (the **second** detection site): the CONST sampling-class branch and the `model.model.model_type` flow/flux branch now return `FLOW` instead of `EPS` (log strings updated). The `v_prediction`→V and `eps`→EPS branches are unchanged. Changing only the dict would have silently left class-name / model_type-detected models (WAN, H3) on the VP path. ## H3 specifically MiniMax H3 needs **no special case**. It exposes `BaseModel.model_type` as the `ModelType.FLOW` **Enum**; `_canon`'s Enum branch reduces it to `"flow"`, an exact `_RAW_TO_ENUM` key → resolves to `FLOW` at the dict direct-hit site. There is no `"h3"` raw type. A regression test pins this exact Enum→canon→FLOW path. ## Tests (`tests/test_pred_type.py`) - Flipped the flow-family pins (`flow`/`const`/`flux`/`chroma`/`wan`) from EPS to **FLOW** — the PR-1 safety net doing its job. - Fallback-site coverage: stubs whose only flow signal is a CONST-like `model_sampling` class name, or a `model.model.model_type` string merely *containing* `"flow"`/`"flux"` (not an exact dict key) — so the enhanced-detection branch is genuinely exercised, not the dict. - H3-representative test: an actual `enum.Enum` member (`ModelType.FLOW`-shaped) resolves to FLOW via `_canon`'s Enum branch. - FLOW identity round-trip through both conversion helpers; V-path identity regression guard; EPS-path regression guard asserting the ε→v algebra still runs. - `uvx ruff check .` → All checks passed! - `uvx --with torch pytest -q` → **42 passed** (up from 33) ## Rollout Breaking for **all flow-family outputs** (Flux/Chroma/WAN/H3 produce different images/video — retune skew/stretch). Baseline preserved at tag `pre-flow`. This is the last breaking change before the **v1.0.0** release. |
||
|
|
d4ff852491 |
PR-2: pack-aware per-stream NRS routing + degeneracy tripwire (#36)
## What Fixes NRS on MiniMax H3 (and any sampler that packs multiple streams). ComfyUI hands the cfg hook a **flat packed latent** `[B,1,N]` whose `dim=1` is a singleton, so every NRS reduction runs over a size-1 axis and the projection geometry collapses — Skew becomes a silent no-op, Stretch degenerates to elementwise CFG, Squash to a Stretch-reverter (proven to float precision in Phase 0). This PR unpacks the flat pack into its real channels-first per-stream tensors, runs the **unchanged** NRS geometry per stream, then repacks. ## Changes (`NRS/nodes_NRS.py`) - Guarded `import comfy.utils as _comfy_utils` (module still imports with no ComfyUI present) + `import math`. - Module-level pure-Python `_unpack_latents`/`_pack_latents` fallbacks matching ComfyUI's pack contract (each stream reshaped to `(B,1,-1)` and concatenated on the last dim; unpack slices `prod(shape[1:])` per stream). - Extracted `_apply_guidance(...)` — the per-stream geometry pipeline (sigma reshape → `_convert_to_v_space` → dot/proj/stretch/skew/squash → `_finalize_from_v_space`), **byte-for-byte identical** to the prior inline math. - Rewired `nrs()`: read `args["model"].latent_shapes`; when present with `len>1`, unpack cond/uncond/input per stream (comfy-preferred, pure-Python fallback), map `_apply_guidance`, repack; otherwise the single-stream path is the **exact prior behavior** (regression no-op for SDXL etc.). - Permanent **degeneracy tripwire**: warns once per `patch()` if any routed stream still has a singleton reduction axis — the silent-failure class that cost the original Skew investigation days. ## Why this is safe - Single-stream models are a verified byte-for-byte no-op (two regression tests compare against a manually-computed `_apply_guidance`). - Not H3 fingerprinting: any multi-stream packed sampler (LTXV AV variants) benefits; older ComfyUI without the API falls through cleanly. - Verified against the real 18MB H3 capture (not committed): unpack→repack is bit-exact for cond/uncond/x_orig; streams recover as `[1,24,72,38,22]` (video) / `[1,32,2,405]` (audio); per-stream guidance produces large live deviations where the flat pack was near-degenerate — Skew is alive again. ## Tests New `tests/test_pack_split.py` (9 tests, real-torch via a module-scoped isolation harness that restores the mock afterward): round-trip pack/unpack, single- & multi-stream fallback regression, tripwire fires/doesn't-fire, per-stream reduced shapes, and non-degenerate-vs-degenerate rejection. - `uvx ruff check .` → All checks passed! - `uvx --with torch pytest -q` → **33 passed** (24 existing + 9 new) Breaking for H3 outputs only. Baseline preserved at tag `pre-flow`. |
||
|
|
2ca0df18bc |
Sort imports in test_pred_type to satisfy ruff I001 (#35)
## What Sorts the import block at `tests/test_pred_type.py:18` so `ruff` (rule I001) passes clean on `main`. ```diff -from NRS.nodes_NRS import PredictionType, _RAW_TO_ENUM, NRS +from NRS.nodes_NRS import _RAW_TO_ENUM, NRS, PredictionType ``` ## Why Gate-1 (pre-refactor checkpoint) requires `ruff` + `pytest` green on `main`. This was the only outstanding lint violation. ## Verification - `uvx ruff check .` → All checks passed! - `uvx --with torch pytest -q` → 24 passed Import-sort only; no behavior change. |
||
|
|
ffeb7fe4f3 |
PR-1: cleanup — remove mangled guard, amputate dead operation-space arms, add detection tests (#34)
## Summary Behavior-preserving cleanup ahead of the H3 flow-fix work (see `.claude/plans/nrs_h3_fix_plan.2.md`, fact 8 / Phase 3 / Sequencing PR-1). No output change — pure refactor plus a regression net. ### Changes to `NRS/nodes_NRS.py` - **Removed the broken name-mangling guard.** `hasattr(self, "__pred_type")` checked the literal name while assignment created `_NRS__pred_type`, so the guard never fired. `patch()` now computes `pred_type = self._get_pred_type(model)` unconditionally and passes it as a closure local / explicit parameter into `nrs()`, `_convert_to_v_space`, and `_finalize_from_v_space`. This preserves the (correct) always-redetect behavior and removes a latent cross-model aliasing bug. The `hasattr` string was **not** "repaired" — doing so would introduce a stale-cache bug since ComfyUI reuses node instances across queue runs. - **Amputated dead operation-space arms.** `self.__OPERATION_SPACE` was hardcoded to `PredictionType.V`, making both `match` blocks and the `_convert_to_eps_space`/`_finalize_from_eps_space` helpers unreachable. Removed them; the `nrs()` hook now calls the V-space conversion/finalization directly. The inner V-vs-EPS conversion math inside the V-space helpers is untouched — that is the real per-model algebra, not dead code. FLOW is added in a later PR. ### Tests - New `tests/test_pred_type.py`: parametrized coverage of all 11 `_RAW_TO_ENUM` entries plus `_get_pred_type` walks over stub models (direct-attribute path and enhanced-detection fallback). These pin **current** behavior (flow-family → EPS) as a regression net for the FLOW reclassification PR. ## Verification - `24/24` tests pass (21 new + 3 pre-existing smoke) from a clean checkout. - Greps for `self.__pred_type`, `_NRS__pred_type`, `self.__OPERATION_SPACE` all empty. - Diff: `NRS/nodes_NRS.py` +16/-87, `tests/test_pred_type.py` +111 — behavior-preserving, well under 500 LoC. |
||
|
|
ee6dc40393 |
Add git hooks and development infrastructure (#32)
## Summary Establishes a complete development infrastructure for the project with automated quality checks, testing, and contributor guidelines. - Add pre-commit hooks for automated linting and quality checks - Configure ruff for code linting and formatting (120 char line length, Python 3.10+) - Set up pytest with mocked torch/gradio dependencies for CI/CD compatibility - Create comprehensive CONTRIBUTING.md with setup instructions and workflow guidance - Add uv.lock for reproducible dependency resolution - Replace trivial tests with functional interface tests ## Key Components ### Git Hooks (.pre-commit-config.yaml) - Pre-commit: ruff linting/formatting, trailing whitespace, YAML validation, prevents direct commits to main - Pre-push: runs pytest test suite, prevents direct pushes to main ### Testing (tests/) - Functional tests for ComfyUI node and WebUI script interfaces - Mock torch, gradio, and WebUI modules via conftest.py (no heavy dependencies in dev env) - Tests verify API contracts without requiring full ComfyUI/WebUI runtime ### Documentation (CONTRIBUTING.md) - Development setup with uv package manager - Git workflow and branch protection guidelines - Linting, testing, and pre-commit hook usage - Code style guidelines and commit message conventions ## Test Plan - [x] Pre-commit hooks run on commit (linting, formatting, checks) - [x] Pre-push hooks run pytest successfully - [x] All tests pass in isolated venv - [x] CONTRIBUTING.md instructions verified - [x] No IDE diagnostics or issues |