|
| 1 | +# Catalog-backed H3 adapter partition check (#870) |
| 2 | + |
| 3 | +Written by model `claude-opus-5-5` via provider `anthropic` (close-out, |
| 4 | +2026-10-14). Plan v2 approved by Don as "build smaller" on 2026-10-14; |
| 5 | +one stage, #888 (A), verified on lem. |
| 6 | + |
| 7 | +## The report |
| 8 | + |
| 9 | +On the H3 quality matrix (lem, workspace `h3-quality`), the fal Realism |
| 10 | +People LoRA (`fal/MiniMax-H3-Realism-People-LoRA`, |
| 11 | +`h3-realism-people-t2v-i2v-r2v.safetensors`) was put on a Ref2VA |
| 12 | +(`transformer_ref`) step to fix faces. It was inert and cost a full render |
| 13 | +to find out. `dw/adapter_compatibility.py` decided from the filename tokens |
| 14 | +`ref2v` / `fl2v`; this name has neither (its `r2v` even suggests reference |
| 15 | +support), so validate only warned "names neither". The file's safetensors |
| 16 | +`__metadata__` says `base_model: minimax-h3-fl2va`. On FL2VA/I2VA it works |
| 17 | +(R3: 4/5 faces). |
| 18 | + |
| 19 | +The ask was to read that header during validation and prefer `base_model` |
| 20 | +over the filename. |
| 21 | + |
| 22 | +## Decisions |
| 23 | + |
| 24 | +- **Plan v1: build smaller.** The catalog already said it: |
| 25 | + `loras/minimax-h3/realism-people.json` had `"workflow": "t2va"`, |
| 26 | + `"status": "proven"`. The check just never asked the catalog. Wire the |
| 27 | + catalog in; cut the header read, because: |
| 28 | + 1. it is I/O on the hottest validation path (every validate, admit, |
| 29 | + `for_each` member and composed child), which is free and offline today; |
| 30 | + 2. a local-path read during validate is a directory-existence oracle |
| 31 | + (`plan.py` refuses exactly that); |
| 32 | + 3. a ranged Hub GET breaks "`lora_hub.py` is the only place dw searches |
| 33 | + the Hub"; |
| 34 | + 4. `__metadata__` is uploader-written: it shouldn't turn a warning into a |
| 35 | + refusal; |
| 36 | + 5. only one vendor key (`base_model`) was evidence. |
| 37 | +- **Q1:** a catalog entry that disagrees with the filename token warns, |
| 38 | + never refuses. **Q2:** the revision is ignored. **Q3:** not needed (if a |
| 39 | + `save_lora` pre-fill comes back, trust `base_model` only). |
| 40 | +- **Build stop on v1 (#888, 2026-10-14):** v1 assumed the catalog was |
| 41 | + layered per workspace. It isn't: `server_lora_library(state)` is one |
| 42 | + library shared by every workspace, so one agent-written trial entry would |
| 43 | + refuse a file server-wide. |
| 44 | +- **Don's ruling (a) → plan v2:** keep the one shared catalog, add no |
| 45 | + layering. **Only a `proven` entry can refuse**; a `trial` or `rejected` |
| 46 | + entry that conflicts with the step's partition warns, naming the entry |
| 47 | + and its status. No new evidence requirement on `proven`. Scope narrower |
| 48 | + than v1. |
| 49 | +- **Non-goals held:** no header reads, no Hub request from validation, no |
| 50 | + non-H3 base-model checks, no change to the filename rule, no per-workspace |
| 51 | + catalogs, no MCP/REST/syntax change. |
| 52 | + |
| 53 | +## What was built |
| 54 | + |
| 55 | +**Stage A, #888** (server + data + docs), `feat/870-A-catalog-adapter-check` |
| 56 | +(27674293, 687e288a), merged to `develop` as `9a210585`: |
| 57 | + |
| 58 | +- **`adapter_compatibility.catalog_index(entries)`**: `(model_name, |
| 59 | + weight_name) -> (entry, workflows, status)`, revision ignored. With no |
| 60 | + index the result is the old rule. |
| 61 | +- **Partition, not workflow** (`_catalog_partition`): all of |
| 62 | + `{t2va, fl2va}` is `transformer`, `ref2va` is `transformer_ref`, a mix |
| 63 | + decides nothing. |
| 64 | +- **Status order:** a `proven` conflict is an error naming the entry |
| 65 | + ("catalog entry 'minimax-h3/realism-people' (proven) lists it for 't2va, |
| 66 | + fl2va', which denoises against 'transformer'…"); a `trial`/`rejected` |
| 67 | + conflict is a warning naming the entry and status; an agreeing entry |
| 68 | + clears "names neither" but a `trial` one never lifts a filename-token |
| 69 | + error; a `proven` entry that disagrees with a token is a warning naming |
| 70 | + both. |
| 71 | +- **Callers:** `deps.lora_index(state)` is built from the shared |
| 72 | + `catalog_entries(state)` (moved from `routes/loras.py` to `deps.py`, so |
| 73 | + `list_loras` and validation read one function), cached on |
| 74 | + `state.lora_indexes` keyed on the listing's (name, path, mtime). Passed by |
| 75 | + `admit_for` (`/api/validate`, submit, rerun, enhance-admit) and the save |
| 76 | + path in `routes/library.py`. The CLI `dw.validate`, the worker and |
| 77 | + `warn_adapters` pass none: the server is stricter than the worker, never |
| 78 | + looser. |
| 79 | +- **Data:** `realism-people.json` `workflow` is `["t2va","fl2va"]`, |
| 80 | + `use_when` says "not reference-to-video", new `evidence` note (#870); it |
| 81 | + stays `proven`. |
| 82 | +- **Docs:** the module docstring, `docs/ARCHITECTURE.md`, `docs/SERVER.md`, |
| 83 | + `docs/LORAS.md` (a `proven` entry's `workflow` is enforced on the server; |
| 84 | + a `trial` one only warns; promoting is what makes it refuse), and the |
| 85 | + `minimax-h3` skill's `checkpoints-and-loras.md` ("validate refuses it on |
| 86 | + `ref2va`"). |
| 87 | +- **Tests:** `tests/test_h3_adapters.py` (`test_a_proven_*`, |
| 88 | + `test_a_weaker_*`, `test_no_index_is_todays_rule`, null/mixed fallback, |
| 89 | + `arguments.<name>` path, `test_one_build_per_listing_for_every_member`, |
| 90 | + `test_a_trial_entry_warns_and_promoting_it_refuses`); the |
| 91 | + `workflows/**/*.json` sweep also runs with the packaged catalog. |
| 92 | + |
| 93 | +**Deviations from the plan**, both accepted at verify: |
| 94 | +- Two entries covering the same file: the index keeps the stronger status |
| 95 | + (proven > trial > rejected). |
| 96 | +- A `trial` conflict on a no-token file gives the entry's warning *in place |
| 97 | + of* "names neither", not both. |
| 98 | + |
| 99 | +## Bounces per stage |
| 100 | + |
| 101 | +| Stage | Bounces | Cause | |
| 102 | +|---|---|---| |
| 103 | +| A, #888 | 0 (1 build stop) | The build stopped on v1's per-workspace catalog assumption; re-planned as v2 (Don's ruling (a)), re-decomposed and re-specced. Verified first time on v2. | |
| 104 | + |
| 105 | +No stage comment names `usage:` figures, so per-stage cost is not recorded. |
| 106 | +The plan estimated ~$3-5. |
| 107 | + |
| 108 | +## Verification notes |
| 109 | + |
| 110 | +- Verified over MCP on lem `develop` @ f73088a5: M-F142-M-F145, M-F147, |
| 111 | + M-F152 and M-F153 pass. M-F142(c): `run_workflow` with Realism on |
| 112 | + `reference-to-video` is refused at `arguments.lora_weight_name` with no |
| 113 | + job queued. |
| 114 | +- M-F144(b): the `ref2v` turbo on `fl2va` is refused by the proven catalog |
| 115 | + message (`minimax-h3/turbo-reference (proven)`), not the filename message; |
| 116 | + v2 lets a proven entry decide. |
| 117 | +- M-F146 (v1 workspace layering) contradicts v2 and was not run; retiring it |
| 118 | + is dkackman/harnest#122. |
| 119 | +- mini-ai (MPS) was not checked, and its restart is Don's. |
| 120 | + |
| 121 | +## Deferred |
| 122 | + |
| 123 | +- **Reading safetensors headers**, reopened only by a second render lost to |
| 124 | + a LoRA the catalog doesn't cover, or a run of uncatalogued H3 trials that |
| 125 | + keep saying "names neither". It would go into `save_lora` / |
| 126 | + `recommend_loras` (which already read Hub headers via `lora_hub.py`) to |
| 127 | + *pre-fill* an entry's `workflow`, trusting `base_model` only; the |
| 128 | + validator stays free. |
| 129 | +- **Edges with no shipped entry** (a `proven` entry against its own token, a |
| 130 | + mixed list, a `rejected` entry with a `workflow`): unit-tested only, since |
| 131 | + probing them over MCP needs a `save_lora` write to the shared catalog. |
| 132 | +- **CLI `dw.validate` stays on the filename rule** (documented; the safe |
| 133 | + direction). |
0 commit comments