Files
club-3090/docs/PULL_EMIT_DERIVED.md
T
noonghunna b327f0311a refactor(gemma): rename dual slugs + ladder gemma-bf16-mtp to 131K (#286)
Rename vllm/gemma-int8→gemma-int8-mtp + vllm/gemma-mtp→gemma-bf16-mtp (both carry MTP n=4; only KV format differs); kv-calc alias fix. Ladder gemma-bf16-mtp default 32K→131K (measured BF16 KV pool 196,527 tok @ 0.95; verify-stress 8/8, NIAH→120K, bench 118.8/154.3, zero TPS regression). Codify the dual-card max-context-priority rule in DUAL_CARD.md. Suite 41/41.
2026-06-01 01:20:46 +05:00

389 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Pull-Emit-Derived — the `[E]` stage of `scripts/pull.sh` (v0.8.0, #147)
Contributor/maintainer guide for the v0.8.0 Pull-Emit-Derived stage. The
Pull-Gate ([`docs/PULL_GATE.md`](PULL_GATE.md)) evaluates *any* safetensors
HF repo and pull-and-emits **curated** (Tier-1) models only. `[E]` is the
deferred extension that makes a **download-eligible derived (non-curated)**
model real: it emits a patchless default-vLLM compose, downloads the weights,
boots them, smokes the endpoint, and writes the §6 capture artifacts the
later Loop phase consumes.
`[E]` is **post-Pull-Gate, not a new gate**: it runs as a stage *inside*
`run_pull()`, strictly after a `[C1]` terminal, and never alters the locked
6-stratum taxonomy, the `[C1]` table, or curated Path-A behaviour. Those are
*consumed*, never modified.
> ### The authoritative spec is the test, not this doc
> Per the locked v0.8.0 stop-condition, the executable specs are
> authoritative. For `[E]` those are
> **`scripts/tests/test-generate-from-profile.sh`** (CONTRACT-2/5: the
> derived template + the eligibility gate),
> **`scripts/tests/test-pullgate-download.sh`** (CONTRACT-3: the download
> stage), **`scripts/tests/test-pullemit-capture.sh`** (CONTRACT-4: the §6
> capture emitters + manifest), and the `[E]` continuations / trigger matrix
> in **`scripts/tests/test-pull.sh`** (g16–g22). Where this prose and any of
> those tests ever disagree, **the test is correct**; fix the doc. This
> document is the explanatory companion.
For the curated `[D]` substrate `[E]` reuses for the engine-pin resolver and
the structured-refusal style, see
[`docs/COMPOSE_GENERATOR.md`](COMPOSE_GENERATOR.md); for the patch/arch/
profile data model, [`docs/PATCH_ATTRIBUTION.md`](PATCH_ATTRIBUTION.md) and
[`docs/PATCH_POLICY.md`](PATCH_POLICY.md).
> **On-rig status:** the mocked suites listed above are green and are the
> shipped E1–E4 contract. The real small-non-curated end-to-end run
> (`pull <slug> --profile-like <vLLM key>` → derive → gates → `[C1]` →
> emit → download → boot → smoke → teardown) is **pending on-rig validation
> (E5)** and is driven separately. Nothing below describes the on-rig run as
> validated; it describes the shipped, unit-verified E1–E4 behaviour.
---
## 1. What `[E]` adds on top of Pull-Gate
| Class of model | Pull-Gate behaviour | With `[E]` |
|---|---|---|
| **curated (Tier-1)**, Path A | full gate → stratum-6 `[D]` dry-run → real `[D]` emit of the validated registry key; **no download stage** (curated weights are local) | **unchanged** — curated Path-A is `[D]`-emit only, byte-for-byte. `[E]` never runs for a curated slug. |
| **derived (non-curated)**, Path B | full gate → print the §7-caveated verdict → **STOP** (structurally incapable of emit/download) | a download-eligible derived verdict now **continues into `[E]`**: CONTRACT-5 eligibility gate → `generate_from_profile` → `download_model` → `boot_derived` → `smoke_derived` → `emit_capture` (+ pt5 on override) |
`[E]` is wired into `run_pull()` (`scripts/lib/profiles/pull.py`) from
**exactly two** post-`[C1]` return points, and only when
`not is_curated and not dry_run`:
1. the satisfied `proceed` / `confirm→proceed` Path-B verdict, and
2. the `override-accepted` terminal that `--force-download` satisfied.
The `[E]` stage mutates **only** the additive `PullResult` fields
(`download_ok`, `boot_ok`, `smoke`, `capture_paths`) plus
`notices`/`diagnostics`. `ok` / `terminal` / `raw_verdict` / `emitted` /
`stratum` / `abort_reason` are left exactly as the `[C1]` decision set them,
so every pre-`[E]` `test-pull.sh` assertion is byte-unaffected. Every stage
function is injectable; all stage exceptions are caught and recorded
structurally — the `[E]` stage **never** raises out of `run_pull()`.
---
## 2. Trigger semantics (exactly as shipped)
This is the new user-facing contract. It *supersedes* the pre-`[E]`
"Path B never emits/downloads" / "`--force-download` is a NO-OP" rules —
but **only** for the non-curated derived download-eligible no-`--dry-run`
case. (`scripts/tests/test-pull.sh` g16–g22 is the truth table.)
| Run shape | Enters `[E]`? | Behaviour |
|---|---|---|
| non-curated + download-eligible `[C1]` terminal (`proceed` / satisfied `confirm→proceed`) + **no** `--dry-run` | **yes** | CONTRACT-5 gate → emit → download → boot → smoke → capture (pt1–4 + manifest). `is_override_accepted=False` (no pt5). |
| non-curated + `override-accepted` (the terminal `--force-download` satisfied) + **no** `--dry-run` | **yes** | same chain, **plus** pt5 override force-capture (`is_override_accepted=True`). `--force-download` activates `[E]` **only** for this terminal (it was a no-op pre-`[E]`). |
| `--dry-run` (any slug) | **no** | verdict-only, unchanged. `--dry-run` *never* enters `[E]`. A curated slug only reaches Path B via `--dry-run`, which this guard excludes. |
| curated slug (Path A) | **no** | curated Path-A `[D]`-emit, unchanged. Curated weights are local — there is no download stage. |
| non-curated, `confirm→proceed` **without** `--yes`; or low-confidence `wont-fit` **without** `--force-download` | **no** | honest non-pass (`[C1]` not satisfied); `[E]` is gated behind a *satisfied* download-eligible terminal. |
`override-accepted` is **not** a fit. The §5.3 rule is preserved verbatim in
the notices: a forced low-confidence download is a *calibration signal*,
never recorded as fit-validated. On the `override-accepted` `[E]` path the
pt5 force-capture (§4 below) carries the literal
`calibration_signal_not_validated:true`.
If the run is download-eligible non-curated but the local GPU topology
cannot be determined (no `nvidia-smi`, no `--hardware-gpus` override),
`[E]` does **not** run — it refuses honestly (`gpu-topology-undetermined`
notice) rather than fabricate a topology; the Pull-Gate verdict stands.
---
## 3. CONTRACT-5 — the derived-emittable eligibility gate
`generate_compose.derived_emittable(einput) -> (bool, reason|None)` is a
**pure** pre-`[E]` precondition run *before* any emit/download. It is **not**
a new gate state — it is a structured-refuse precondition, printed like
Pull-Gate's honest non-answer terminals. On refuse: a
`derived-runtime-unsupported:<reason>` notice + diagnostics, **no download,
no boot**.
The derived template is deliberately **patchless** (no Genesis / curated
overlays). Many curated profiles only work *because of* those overlays, so
inheriting an arbitrary `--profile-like` runtime shape into a patchless
compose would be a guaranteed-broken boot. CONTRACT-5 rejects, by
construction, anything that would need a patch/overlay/Genesis or that the
local hardware cannot run. A model is derived-emittable iff **all** hold
(checked in this short-circuit order; first failing clause names the
reason):
| Clause | Refuse reason token | Property checked |
|---|---|---|
| engine clean + Docker-image install | `derived-runtime-unsupported:engine-install-method` | the resolved engine YAML must have `required_genesis == false` **and** `vendored_overlays == []` **and** `install.method == "docker_image"`. Property-driven (not a hard engine list) so it is future-proof; an unresolvable engine YAML also fails here. (`vllm-stable`/`vllm-stable-next` are clean but `install.method: pip` — this clause keeps them out so the gate never emits an invalid `image: vllm==...`.) |
| no overlay features | `derived-runtime-unsupported:overlay-feature` | the `--profile-like` **COMPOSE_REGISTRY runtime entry** has `required_engine_features == []` (the registry runtime entry, *not* the engine YAML). |
| KV in the explicit safe set | `derived-runtime-unsupported:kv` | `kv_format ∈ {bf16, fp16, fp8_e5m2, fp8_e4m3}` (the literal `DERIVED_SAFE_KV` set). This is **not** "`kv_arg()` returns a defined result" — `kv_arg()` is *also* defined for `int8_per_token_head` / `turboquant_3bit_nc`, the values that must be rejected, so that predicate is self-contradictory. `kv_arg()` is emission-only (see §4 / §5). |
| no drafter | `derived-runtime-unsupported:drafter` | `runtime["drafter"] is None` — no DFlash / MTP / speculative / drafter (those need patches `[E]` does not include). |
| local GPUs can run this `tp` | `derived-runtime-unsupported:gpu-count` | `visible_gpu_count >= runtime["tp"]` **and** `len(selected_gpu_indices) == tp`. A clean no-drafter TP=2 shape on a 1-GPU rig is rejected here, *before* a multi-GB download. |
| quant resolvable | `derived-runtime-unsupported:unsupported-quant-for-derived[:autoround\|:missing-torch-dtype]` | `weight_format` must be resolvable by the CONTRACT-2 dispatch table (§4). `autoround` is an explicit reject (`:autoround`); a quantized repo with no usable compute dtype is `:missing-torch-dtype`. |
`derived_emittable()` is called twice on the success path — once by
`run_pull()` as the pre-`[E]` precondition, and once again as the first
thing `generate_from_profile()` does (it raises `Refuse(reason)`, mirroring
`[D]`'s structured-refusal style, on any reject) so the emitter can never be
called past a reject. The patchless `--kv-cache-dtype` / no-patch rows of
the derived template are therefore *safe by construction*.
`scripts/tests/test-generate-from-profile.sh` carries the negative matrix:
`vllm/gemma-int8-mtp` → `overlay-feature`; a TQ3-KV shape → `kv`; a drafter/MTP
shape → `drafter`; a clean TP=2 shape on a simulated 1-GPU `einput` →
`gpu-count` — each asserting **no** download and **no** emit, plus one
positive clean/no-drafter shape that proceeds.
---
## 4. The derived-vllm template + quant/dtype dispatch (CONTRACT-2)
`generate_compose.generate_from_profile(root, einput) -> (compose_text,
meta)` is an **additive** entry point. It emits a **separate** `derived-vllm`
base template — **not** the curated `compose_service_template`. (The curated
template hardcodes Qwen-specific constants — `--quantization auto_round`,
`--reasoning-parser qwen3`, the Qwen chat template, `--tool-call-parser
qwen3_coder` — so reusing it for an arbitrary derived model would emit a
broken boot.) The registry-key `generate(profile)` path is **byte-unchanged**
(`test-generate-compose.sh` byte-identical-proven, the P3 precedent).
Per-arg policy of the derived template (as shipped):
| Arg / field | Derived-template source |
|---|---|
| `image` | the **resolved** `engine.install.spec` from the clean engine YAML — a pinned image string, recorded in the capture manifest. **Not** a launch-time `${VLLM_NIGHTLY_SHA}` expansion (`[E]` boot does not go through `launch.sh`; an unresolved image risks a wrong-image boot). |
| `--model` | the **container** path `/models/club3090/pulls/<slug-sanitized>`. The host dir `<HF_HOME>/club3090/pulls/<slug-sanitized>/` is bind-mounted **`:ro`** to that container path via a `host:container:ro` `volumes:` entry. **Not** `${MODEL_DIR}`, not the HF hash-cache snapshot path. |
| `--served-model-name` | the slug sanitized: lowercased, every non-`[a-z0-9._-]` → `-`, collapse repeats, trim/strip, capped to vLLM's name limit. |
| `--quantization` / `--dtype` | the CONTRACT-2 dispatch table below. |
| `--tensor-parallel-size` / `--max-model-len` / `--gpu-memory-utilization` / `--max-num-seqs` / port | from `einput.runtime` (the `--profile-like` shape) — faithful inheritance. If the profile's `--max-num-seqs` is unsafe for the derived model, `[B]` kv-calc already prices it and the on-rig run catches OOM (pending E5). |
| `--kv-cache-dtype` | `kv_arg(kv_format)` is **emission-only** here, mapping the *already-eligible* value (CONTRACT-5 already gated it): `bf16`/`fp16` → flag omitted, `fp8_e4m3` → `fp8`, `fp8_e5m2` → `fp8_e5m2`. |
| `NVIDIA_VISIBLE_DEVICES` (env) | exactly `einput.selected_gpu_indices` — the same GPUs `[B]` priced. Never unset/`all` for derived. |
| `--trust-remote-code` | emitted **only if** the `[C0]` trc gate already resolved permitted (signalled on `einput.diagnostics["trc_permitted"] is True`); absent / not-True → never emitted. |
| `--chat-template`, `--reasoning-parser`, `--default-chat-template-kwargs`, `--enable-auto-tool-choice`, `--tool-call-parser` | **not emitted** — curated-specific. Derived uses vLLM defaults; derived tool/chat-template/reasoning support is explicitly OUT of scope. |
| patch insertion points | **patchless** — no Genesis / curated patches (CONTRACT-5 guarantees the runtime never needs them). |
**Quant/dtype dispatch table** (`_QUANT_DISPATCH`):
| `der.profile.weight_format` | `--quantization` | `--dtype` |
|---|---|---|
| `awq` | `awq` | from compute-dtype resolution |
| `gptq` | `gptq` | from compute-dtype resolution |
| `compressed-tensors` | `compressed-tensors` | from compute-dtype resolution |
| `fp8` | `fp8` | from compute-dtype resolution |
| `autoround` | **REJECT** `unsupported-quant-for-derived:autoround` | — |
| `float16` (pure dtype, no quant) | omitted | `float16` |
| `bfloat16` (pure dtype, no quant) | omitted | `bfloat16` |
| anything else | **REJECT** `unsupported-quant-for-derived` — never guess a `--quantization` | — |
`autoround` is rejected because the curated AutoRound composes explicitly
pass `--quantization auto_round`; "omit" is *not* demonstrably safe for an
arbitrary derived AutoRound repo and could silently mis-load. It is deferred
honestly rather than confidently-wrong.
**Compute-dtype resolution for the quantized rows** (`_resolve_compute_dtype`,
one defined order — not implementer's choice): (1) `der.profile["torch_dtype"]`
(an additive E1 deriver surface — the deriver already fetched `config.json`,
so this is an additive field, not a frozen-module rewrite) if it normalizes
to a real vLLM compute dtype; else (2) the deriver's **existing** bounded
safetensors header probe (`deriver.probe_safetensors_dtype`, never
reimplemented), **then normalize**: accept **only** a real compute dtype
(`float16`/`half`, `bfloat16`, `float32`). The probe returns a *storage*
dtype, and quantized safetensors expose int/storage dtypes (`I8`/`U8`/`I4`/…)
which are invalid as a vLLM `--dtype` — any such value is treated as "no
usable compute dtype"; else (3) **fail closed**
`unsupported-quant-for-derived:missing-torch-dtype`. Never default-guess or
pass a raw storage dtype. Pure-`float16`/`bfloat16` rows are unaffected —
their dtype *is* the weight_format. The live header-probe fetcher is wired
by E2's `downloader.set_probe_fetcher()` (E4 calls it inside `run_pull()`);
when no fetcher/inputs are present resolution fail-closes at step (3) rather
than guess.
The emitted derived compose is **patchless default-vLLM**: it carries zero
Genesis/curated patch insertions, a single absolute-host-path `:ro` volume,
the pinned engine image, and `NVIDIA_VISIBLE_DEVICES` pinned to the priced
GPUs.
---
## 5. The download contract (CONTRACT-3)
`downloader.download_model(einput, *, fetcher=None) -> DownloadResult`. One
shared allowlist, used identically by `[C2a]` sizing, the E2 download, and
E3 smoke — there is no parallel list that can drift:
```
download_set(api) = select_weight_files(api) # *.safetensors (adapters excluded)
+ the *.safetensors.index.json (if present, top-level)
+ REQUIRED_METADATA siblings that exist # config/generation_config/
# tokenizer*/special_tokens_map/
# vocab.json/merges.txt
+ every top-level *.jinja # chat templates
```
`deriver.sized_download_gb(api)` sizes **exactly** `download_set(api)`, so
the `[C2a]` disk pre-gate prices precisely the set E2 fetches; a test
asserts fetched-set == sized-set. The fetcher is `huggingface_hub`
(`snapshot_download(repo_id, local_dir, allow_patterns=download_set)`) — the
established tool, **not** a hand-rolled fetcher and **not** the hash-oriented
snapshot cache. `allow_patterns` is mandatory and is literally the shared
`download_set` list. The real `huggingface_hub` import is lazy and the
fetcher is injectable so the test suite is hermetic (no live multi-GB pull
in CI).
**SHA verification — no-etag is a HARD fail** (the deliberate contrast):
every `*.safetensors` is verified by HF HEAD → `x-linked-etag` → local
SHA256 == etag. This reuses `setup.sh`'s *pattern*, but **`setup.sh:434/437`
prints `SKIP` and does not count a failure on a missing etag** — `[E]`
does the **opposite**: a missing/empty `x-linked-etag` is a hard
`failure:"no-etag"` abort. `[E]` never silently trusts an unverifiable
multi-GB weight (the `aria2c` corruption-incident lesson). Metadata files
are presence + size only.
`DownloadResult.failure` is one of `null | "no-etag" | "sha-mismatch" |
"gated-401" | "disk"`. This struct **is** the §6 capture-point-2 payload
shape; E2 only returns it (E3 emits the artifact).
**Atomic staging + cleanup:** download into
`<HF_HOME>/club3090/pulls/<slug-sanitized>/.incomplete/`; on full success
*and* all SHA verified, atomically move the verified tree onto
`<HF_HOME>/club3090/pulls/<slug-sanitized>/` (the CONTRACT-2 host `--model`
dir). On **any** failure — gated-401, no-etag, sha-mismatch, disk — the
`.incomplete` (and any sibling staged temp) tree is deleted: no corrupt or
partial residue, ever. `scripts/tests/test-pullgate-download.sh` carries the
no-etag fail-closed golden, the gated-401 mid-download case, and the
fetched-set == sized-set assertion.
---
## 6. The boot path (CONTRACT-4 boot half)
`booter.boot_derived(einput, compose_text, *, runner=None) -> BootResult`.
A derived compose boots **only** with the proven discipline:
* `docker compose --project-directory <project_dir> -f <compose> up -d` —
the same `--project-directory` rule as `[D]` (relative-path resolution is
project-dir-relative);
* the weights bind-mounted from the **HF_HOME host dir**
`<HF_HOME>/club3090/pulls/<slug-sanitized>/` → container
`/models/club3090/pulls/<slug-sanitized>` `:ro` — the exact mount
`generate_from_profile()` already wrote into `compose_text`. This is
**NOT** `MODEL_DIR=/mnt/models` (that is the curated Path-A convention; a
derived model's weights live under HF_HOME per CONTRACT-2/3).
The boot is **always torn down** (`runner.down`) in a `finally`, success or
failure — no orphaned container/project state (the Pull-Gate on-rig harness
rule). `runner` is injectable; the default shells real `docker compose`,
tests pass a fixture runner (no Docker/GPU in CI). `BootResult.failure`
carries the *raw* container-died reason — `[E]` does **not** classify it
into a §6.1 class (that is `[F]`'s job). The real on-rig boot is **pending
on-rig validation (E5)**.
---
## 7. The §6 capture artifacts (CONTRACT-4 capture half)
`capture.emit_capture(...)` writes, schema **v1**, JSON, redacted, under:
```
<repo>/.pull-captures/<slug-sanitized>/<utc-ts>/
```
Four capture points + a top-level manifest:
| File | Point | Fields |
|---|---|---|
| `pt1-gate.json` | pre-download gate verdict | `schema, point, slug, confidence, raw_verdict, terminal, profile_like, hardware_sm` |
| `pt2-download.json` | download | `point, ok, files, bytes, sha_verified, failure` (the `DownloadResult` shape) |
| `pt3-boot.json` | boot | `point, ok, seconds, failure` (raw reason; **not** classified) |
| `pt4-smoke.json` | post-boot capability-aware smoke | `point, smoke_capability_set, results, partial` |
| `manifest.json` | §6.2/§6.3 manifest | see below |
The manifest carries the §6.2 success-consensus key inputs as **first-class
fields** (not only hashed inside the fingerprint — `[F]` must *reason over*
them; a hash is opaque): `model`, `quant_label`, `arch_family`,
`topology_class`, `engine_pin`/`engine_version` (the resolved CONTRACT-2
image spec), `kv_calc_version`, `selected_ctx`, `kv_format`,
`smoke_capability_set`, and `topology_summary_canonical` (the deterministic
serialization of **sorted `(gpu_name, vram_mib)` tuples**, §6.2 verbatim).
It also carries the `submission_fingerprint` (the §6.2 stage-2 hash, for
quick correlation) and the §6.3 dedup-key inputs as first-class fields
(`model_id`, `arch_family`, `kv_calc_version`, `engine_version`,
`topology_class`, `club3090_commit`). **`failure_class` is left `null`** by
`[E]` — the §6.1 classifier is `[F]`'s job; `[E]` emits the inputs, `[F]`
classifies/trusts/dedups/consumes.
**Capture-point 5 — override-accepted force-capture**
(`capture.emit_override_capture(...)`): a **separate** function, written into
the *same* capture directory, emitted **only** when
`einput.is_override_accepted` (the §5.3 trigger — the `override-accepted`
`[E]` path). Its fields: `point:"override_capture"`,
`predicted_b_breakdown` (the full `[B]` kv-calc GB breakdown that produced
the verdict), `actual:{boot_peak_mib, gpu_worker_reported_mib}` (or `null`
if the boot never reached allocation), `predicted_vs_actual_delta_mib` (or
`null`), `exit_error_summary` (or `null`), and the **mandatory literal**
`calibration_signal_not_validated: true` — §5.3: a forced low-confidence
download is a calibration *signal*, never recorded as fit-validated. The
artifact is emitted even when the boot never allocated (then `actual` is
`null` and `exit_error_summary` carries why). `emit_capture()` itself never
writes pt5 (`test-pullemit-capture.sh` asserts pt1–4 + manifest only).
**Redaction:** every artifact is written via `_redact_text()`, which reuses
the `report.sh --redact` convention (the identical sed expression set,
driven by the same `USER`/hostname/HF-token keys) and hardens it further —
any absolute internal mount path (`/opt/*`, `/mnt/*`, `/data/*`) is
additionally scrubbed to `<PATH>` (defence-in-depth, the "don't leak
internal paths in public artifacts" stack rule). The capture schema carries
only slugs / verdicts / relative filenames; it must never carry an absolute
internal host path.
---
## 8. The derived capability-smoke floor (CONTRACT-4)
`capture.smoke_derived(einput, endpoint, *, client=None) -> SmokeResult`. A
derived generic profile declares no capabilities, so the conservative floor
is:
* **plain-chat ALWAYS + streaming ALWAYS** — cheap, and catches the #145
class (a model that boots and answers plain chat while streaming/tools are
silently dead).
* `tool-call` / `reasoning-streaming` / `structured-output` / `vision` /
`long-context` are smoked **only if** `der`'s `config.json` *positively*
declares them (read-only positive signals; absence is never inferred as a
capability). A generic dense derived model declares none → **floor only**.
* every optional capability not smoked → recorded `"unsmoked"`, and
`partial = any(result == "unsmoked")`. Per §6.2 an anchor with un-smoked
capabilities is `partial` and cannot graduate to Tier-1 for those
capabilities.
`client` is injectable (fixture client in CI; the live server is the on-rig
E5 leg, pending). `test-pullemit-capture.sh` asserts a derived model that
declares no tools records `tool-call:"unsmoked", partial:true`.
---
## 9. Explicitly OUT of `[E]` scope
| Out | Where it lives |
|---|---|
| The `[F]` Loop: §6.1 2-tier failure classifier, §6.2 inbound-trust pipeline, §6.3 dedup, consensus, promotion. `[E]` **emits** the §6 artifacts; `[F]` **consumes** them. `[E]` does not classify (`failure_class` stays null), trust, dedup, or promote. | **Loop phase** |
| Derived tool-call / chat-template / reasoning / curated-or-Genesis-patch support (the CONTRACT-2 deferral — derived is patchless default-vLLM). | a future scoped phase |
| GGUF / `.bin` backends, multi-quant auto-pick, whichllm hardware slice. | **v0.8.1** |
| Curated Path-A behaviour, the §4.1 strata / `[C0]` / `[C1]` state sets. | **frozen** — `[E]` is strictly post-`[C1]`, consumed not modified |
| UX doc tracks (§7). | post-Pull-Gate |
---
## 10. Running the executable specs
From the repo root:
```
bash scripts/tests/test-generate-from-profile.sh # CONTRACT-2 / CONTRACT-5
bash scripts/tests/test-pullgate-download.sh # CONTRACT-3
bash scripts/tests/test-pullemit-capture.sh # CONTRACT-4 (pt1-5 + manifest)
bash scripts/tests/test-pull.sh # the [E] continuations + g16-g22 trigger matrix
python3 tools/kv-calc.py --calibration # must stay Overall: 22/22 (100%)
```
These are the authoritative spec; this document is the explanatory
companion. Where they disagree, the test wins.