Elamur: **Mova** · [Parse](https://mova.elamur.ai/free/en/parse/) · [Dictionary](https://md.dictionary.elamur.ai/free/en/) · [Translate](https://md.translate.elamur.ai/free/en/) · [Research](https://md.research.elamur.ai/free/en/) · [MCP](https://mcp.elamur.ai/) · [Groupants](https://md.groupants.elamur.ai/free/en/)

[Mova](https://md.mova.elamur.ai/free/en/) · [this page in HTML](https://mova.elamur.ai/free/en/docs/tools/eel/)

[home](https://md.mova.elamur.ai/free/en/) / [docs](https://md.mova.elamur.ai/free/en/docs/) / [tools](https://md.mova.elamur.ai/free/en/docs/tools/) / Mova Eel

# Mova Eel

Eel is Mova's learner (Rust on Mova), supervised by Crab; the Octopus — a large language model (LLM) — develops it. See [the sea animals of Mova](https://md.mova.elamur.ai/free/en/docs/repo-docs/animals/).

Reusable cooperative idle-GPU continuation through Mova's native parser. This crate owns the working controller and trainer: independent GPU leases, immutable annotation export, actual treeagree invocation, native gparse baseline/train/ reload, finite CUDA evidence, developer gates, conditional weight installation, crash reservations, durable receipts and bounded artifact retention. It has no private-source dependency. It does not launch a teacher or another AI provider.

Eel trains only the native syntax (AST) model, gparse. Training of the pragmatics model is not implemented in this crate.

A deployment implements `TrainingData::status` and `TrainingData::export` and calls `mova_eel::run(&configuration, once, &mut data)`. Ordinary foreground training uses `mova_eel::trainer::run`. Status is a polling hint; a concurrent annotation writer may advance the generation before the immutable export. The export's SHA-256 identity owns the reservation. Both identities are validated before use in generation paths. Export supplies `train_path`, `dev_path`, `agreed_input_train_path`, `parsers_dir`, `missing_training_witness_ids` and `generation_sha256` using the existing versioned snapshot contract. Missing real parser witnesses stay excluded; the engine cannot manufacture them.

The configuration injects absolute native `gparse`, `treeagree`, `model_dir`, `run_root`, shared `gpu_lock`, pinned developer/protected data and runtime limits. The native executable must be gparse itself, not a wrapper taking the same GPU lock. `controller_executable` rejects an additional wrapper by path/content. The legacy `peta_executable` alias, owner identifiers and installer lock filenames remain accepted or retained to cooperate with older controllers during upgrades. Those are compatibility protocol identifiers, never deployment paths or data.

Fresh training admits only ids with a `school:` prefix by default. A deployment that admits another kind of reviewed annotation names it: `fresh_train_prefixes` (each a lowercase name and `:`, for example `["hard:"]` for the hard-case lane of `tools/hard-cases`). Every other gate is unchanged; an id outside the named prefixes still fails the round as nonteaching.

The idle policy remains one epoch, learning rate 0.00003, sampling 0.15 by default (admissible 0.01..0.25), a new checked seed, bounded child deadlines, an explicit fixed LAS floor and cooperative cooldown. A sample fraction is a work budget, not an output-error percentage. Probe-idle does not guarantee the next trainer lease. Deferred rounds preserve rejection streaks and may advance the counter without training. Three rejections increase cooldown; they do not establish a new rejection on each deferred round.

`evidence::inspect` accepts historical trainer/Eel receipts and separates `deferred`, `below_threshold`, `rejected`, and `installed`. Recorded candidate or installation evidence needs actual-parent/generation/output digest fields; proposed-parent hashes cannot replace actual-parent lineage. Partial historical receipts remain incomplete. This classifies declared local evidence, not artifact authenticity, successful generalization or current deployed-weight identity. New Eel summaries add this interpretation without changing existing fields.

Tests use finite synthetic CoNLL-U and fake native executables to exercise real Rust callpaths, command arguments, locks, gates and installation. They perform no operational training, teacher calls or protected-label assessment. A public crate build and private adapter build are separate from deployment: an existing running binary continues its previous implementation until explicitly replaced at a verified quiescent boundary. See the source-bound groupants for limitations.

Optional urgent reviewed diagnostics use `TrainingData::priority`. `Reviewed` bypasses ordinary polling/export and consumes a deployment-verified immutable snapshot; `AwaitingReview` yields without ordinary training. An untrusted failure queue must not be mapped blindly to AwaitingReview: only an operator-admitted active urgent case may block ordinary work. Ambiguity can require root/consultant review first. Backends rank deterministically and implement durable/idempotent `priority_terminal`; the default acknowledgement refuses rather than silently forgetting terminal work. Failed acknowledgement preserves the terminal native receipt, and same-run retry cannot repeat compute. Eel propagates uncertainty and pauses. Installation, queue acknowledgement and Eel summary are separate commits; manual reconciliation may be required after a crash between them. A matching data generation alone cannot acknowledge urgent work: the terminal receipt must also carry the selected diagnostic identity. Historical ordinary receipts therefore remain ordinary even if their data generation matches.

## Autoencoder rounds

With `eel_autoencoder` in the configuration, the Eel alternates its parser rounds with autoencoder rounds: round n is an autoencoder round when n mod `every` = `every` − 1 (`every` = 2 alternates). The kind is chosen at the round boundary; a round of either kind runs to its end, so a parser round is never interrupted and a switch of configuration happens between rounds (STOP, then a restart with the new configuration and a new run root). An autoencoder round runs on CPU and never takes the GPU lease; while it runs the GPU is free for other work, and the next parser round probes the GPU as before.

An autoencoder round runs the pinned native `roundtrip wiki-round` (tools/roundtrip, `wiki.rs`): a fixed dev sample and a fixed test sample of Wikipedia articles (split by article title, never trained on), the k-th fresh train window, the residual bits of the exact round trip on dev and test with the tables in use and with a candidate (`en`'s order generator adapted on the installed domain and the window). The Eel checks the files itself — sizes, no train article among the dev or test articles, dev and test equal to the pin written by the first round, the measured tables are the installed ones — and installs only when the dev bits go down and every dev volume comes back byte for byte: the candidate is copied to `state_dir/gen-<round>/` and `state_dir/current` (a symlink) switches to it in one rename, the previous generation stays beside it (three are kept). A refused candidate leaves the tables as they are and is a terminal `rejected` receipt (`autoencoder_dev_bits_gate`, `autoencoder_exact_gate`); a failed check pauses the Eel. The test bits are recorded and decide nothing. The parser rejection streak is not changed by autoencoder rounds.

| key of `eel_autoencoder` | meaning |
| --- | --- |
| `every` | the schedule, 2..1000 |
| `roundtrip`, `roundtrip_sha256` | the native executable, pinned |
| `base_model`, `base_model_sha256` | `en.bin`, pinned; the parent before the first install |
| `corpus` | the Wikipedia corpus root (tier-1 shards) |
| `state_dir` | the installed tables, `dev.json`, generations; outside `run_root` |
| `shards`, `train_sentences`, `dev_sentences`, `per_article`, `domain_max` | the sample and the domain cap |
| `threads`, `nice`, `timeout_seconds` | the child's CPU share and deadline |

The tables and the samples are learned from Wikipedia text (CC BY-SA 4.0): they stay in the data store, never in git or a release.

## The turn schedule and the other round kinds

With `eel_schedule` the Eel takes turns among round kinds; without it, the schedule above holds. `eel_schedule.cycle` is either a list of kinds, taken as written and repeated, or an object of weights, expanded once by the smooth weighted round robin (each turn every kind gains its weight; the kind with the most credit runs and pays the total; ties go in the order of `schedule::KINDS`). Round n is turn n mod L; its ordinal among rounds of its kind (the k-th French parser round, the k-th autoencoder window) counts the earlier rounds of that kind. The kind is chosen at the round boundary, as before: a round of any kind runs to its end.

| kind | work | configuration | GPU |
| --- | --- | --- | --- |
| `parser` | the English parser round | top-level keys | lease |
| `ae` | the English autoencoder round | `eel_autoencoder` | no |
| `ae-fr` | the French autoencoder round (the same code) | `eel_autoencoder_fr` | no |
| `parser-fr`, `prag-fr`, `cross`, `tr-en-fr`, `tr-fr-en` | a gated native round | `eel_native.<kind>` | no |

An autoencoder section may carry its `condition`: `{"language": "fr", "dialect": null | "CA" | …, "style": null | "encyclopedic" | "official" | "house:<publication>" | …}`. A dialect and a style are deltas over the language's standard; the tables of one state directory belong to one condition, pinned in its `dev.json` (an English section without a condition keeps its earlier pin). Every kind needs its own `state_dir`.

A gated native round (`native.rs`) runs a pinned executable with pinned arguments, `--round k --out <round>/out --threads t [--current <state>/current] [--base <base>]`, and checks the files itself: the report's metric is the configured one, the measured parent is the installed generation (or the base), the dev sample's hash equals the pin of the first round, no train key is a dev or test key. Gate `install`: the candidate's files are installed as a new generation (`gen-<round>`, `current` switched by one rename, three kept) when the dev metric improves by more than `min_gain`; otherwise a terminal `rejected` receipt (`<kind>_dev_gate`). Gate `measure`: a measurement round, outcome `measured`, nothing installed; with `control`, the round's own negative control must look worse than the real value by `ratio` in the control metric's direction, or the receipt is `rejected` (`<kind>_control_gate`) and nothing is queued. Proposals (`out/proposals.jsonl`) go to `state_dir/proposals/round-<n>.jsonl`, each marked `proposed`, review-only: the Eel never admits them as gold. A native round never changes the English parser's rejection streak. The executables of these kinds are `peta/tools/eelfr` (internal: it reads Wikipedia).

`examples/cpu_rounds.rs` drives a schedule without English parser rounds, for measurements outside a deployment; `examples/plan.rs` validates a configuration and prints its planned turns without starting anything.

## Build and test

A standalone workspace (own `Cargo.lock`), not built by the root `cargo build`:

```
cargo build --release --manifest-path tools/eel/Cargo.toml
cargo test --release --manifest-path tools/eel/Cargo.toml
```

This crate is a library (`mova_eel`); a deployment links it and calls `mova_eel::run` as described above.

## Sources

Library ids are folders of the paper library (`docs/usage.tsv` lists the works outside it).

- Autoencoder rounds kept by held-out description length: grunwald-2007 (MDL), hinton-1993 (autoencoders and MDL), hinton-2006 (autoencoder compression); see also [roundtrip — where each layer of Mova loses information](https://md.mova.elamur.ai/free/en/docs/tools/roundtrip/).
- The smooth weighted round robin of the turn schedule: the interleaving used by nginx's upstream balancer; no paper.
- The control gate of a measurement round follows the project rule that a gate must be able to show red.
- [← previous db — the annotation database and its tool (DuckDB)](https://md.mova.elamur.ai/free/en/docs/tools/db/)
- [next → Elephant — mova-elephant](https://md.mova.elamur.ai/free/en/docs/tools/elephant/)
- [↑ back to tools](https://md.mova.elamur.ai/free/en/docs/tools/)
