### Parameter sets kept loaded between decodes

- **The store.** A decode through the integer operator set lowers its parameter set and
  loads each graph, the bounds pass included; for the pretrained conditional-codec set
  that costs more than the decode. `int_set_cache::LoadedSets` now keeps a set once it
  has loaded, and the next decode through the same bytes takes it from there
  ([integer-operators](extensions/integer-operators.md) §8.6, informative note).
  `int_payload::decode_int` and `int_payload::declared_cost` use it for `WIH1`, a
  `WIV1`'s keyframe, `WIA1`, `WIS1` and `wai.neural.int_synth`, and so the neural sink
  and `wai-web`'s `decodeWiv1`, `decodeWih1`, `decodeWia1`, `decodeWis1` and
  `decodeIntSynth` do too; `decodeIntSynth` now decodes through `decode_int`, and a
  refusal's message starts with its code. `int_synth::decode_from_spec`, which the
  byte-equality crate shares, is now three steps (`check_payload`, `load_spec`,
  `decode_loaded`) and loads its set every time. The entry points that read the tools'
  JSON forms do not use the store.
- **The key** is the capability, the lowering, the profile the graphs were loaded under,
  and the SHA-256 of the listing of the members the decode reads, each by its own
  SHA-256 (`pin::listing_from`): the digest a pin over exactly those members names.
  Never a name: two sets whose members share their names and differ in one byte have
  two entries. Parameters `int_payload::resolve` built carry the listing digest it
  already formed for check 5, so such a decode does not hash its set a second time;
  the digest is used only for a capability that reads exactly the members it was formed
  over, and any other key hashes the bytes.
- **What does not change.** An entry is made only from what a load returned, after it
  returned, so a refused set is never kept: it is lowered, loaded and refused again on
  its next decode, with the same refusal. Every check before the load runs as before,
  in integer-payloads §7's order. Every output, refusal and declared cost is unchanged,
  and no golden moved.
- **Memory.** A kept set is the set's, outside every decode's declared working bytes
  ([integer-payloads](extensions/integer-payloads.md) §7, informative note). The store
  keeps its entries within a byte budget, 256 MiB to start with, evicts the least
  recently used first, and keeps no set larger than the whole budget; a budget of 0
  turns it off, and the set is then not hashed. `LoadedSets::set_budget` sets it, and
  `wai-web` exports `setLoadedSetBudget` and `loadedSetStats` for a page. An entry is
  counted as the shared allocation that holds the set, its graphs' heap bytes
  (`wai_ops::Graph::heap_bytes`, new) and a fixed share of the store's indexes, never
  less than it holds (`tests/int_payload_cost.rs`).
- **Tests.** `tests/int_set_cache.rs`: a second decode through each committed set is a
  hit, by the store's count, with the bytes of a decode with the store off; sets one
  byte apart never share an entry; a set the load refuses (an `int_synth` set the bounds
  pass refuses; a conditional-codec set whose lowering admits no input range) stays
  refused while a set one byte away is held; every refusal fixture keeps its code and
  detail with its set held; the least recently used set goes first; threads decoding
  one set keep one entry. The browser crate's check (`demo/verify_int_payload_wasm.mjs`) decodes `tiny`
  twice and counts the hit.

