Files
Jeremy fdad29cdd4 feat(engine-burn): run SAM 2.1 for image.segment on Burn (#90)
* refactor(engine-rten): let another engine reuse the SAM 2.1 request handling

Loaded, Backend, Prediction, read_prompt, prompt_points and best_proposal become
public. Visibility only: the click and box mapping, the picture kept between
requests, the empty-mask answer and the size checks then live in one place for
every SAM 2.1 engine.

* feat(engine-burn): crate shell and the script that generates the SAM 2.1 architecture

tools/burn/generate_sam21.py checks the two published ONNX files against the
pinned size and SHA-256, runs the pinned burn-onnx 0.22.0 (an example of
craft-ai-burn-setup), applies the five asserted fixes, drops the generated
loaders that panic on a bad file, splits by submodule so every file is under
700 lines, formats and writes. --check proves the tree is what the script
produces. REVISION must equal the saved-weights cache revision. Cargo.lock
additions are Burn with wgpu and ndarray (generated).

* feat(burn-setup): prepare SAM 2.1 weights for Burn once, on this computer

Brings in craft-ai-burn-setup (feature `conversion`): checks the two published
ONNX files by size and SHA-256, converts them to Burn weights with the pinned
burn-onnx 0.22.0, and keeps one checked, locked, shared copy. Nothing is hosted
or downloaded. Mutation group bp (10 cases). Cargo.lock additions are the
optional burn-onnx tree (generated).

* feat(engine-burn): GENERATED SAM 2.1 tiny architecture (30 files)

Output of tools/burn/generate_sam21.py, revision sam21-tiny-burn-0.22.1-onnx-0.22.0-v1,
from the published encoder.onnx and decoder.onnx with burn-onnx 0.22.0 and its five
asserted fixes. Do not review line by line; rerun the script with --check instead.
Longest file 699 lines. Marked linguist-generated.

* feat(engine-burn): SAM 2.1 runner for image.segment on Burn

Sam21Runner (engine burn, model sam21) over the generated architecture. The request
handling, picture kept between requests, empty-mask answer and click/box mapping are
the shared Loaded from craft-ai-engine-rten, so only the model run lives here.
Weights load through BurnpackStore and come back as errors; every call into the
generated code is guarded against panics. Graphics card when one answers, else the
processor. An .onnx file is answered with 'prepare it first', not a guess.
16 unit tests on a fake backend: click and box mapping, empty mask, short mask,
a failing model, shared conformance run with Cancel, damaged and truncated files.

* test(engine-burn): live comparison with rten, and the shared revision check

The ignored live test runs the real SAM 2.1 files through rten (published ONNX) and
Burn (weights prepared on this computer) on the astronaut sample: one click and a box,
best-mask IoU, timings, and a truncated prepared file refused. The revision test fails
when the generator, the compiled architecture and the saved-weights cache key disagree.

* test+docs(engine-burn): mutation group be, weight-loading tests and the Burn engine guide

Group be: 15 cases, one target each, all caught (saved-weights marker, load completeness,
panic guard, answer length, best proposal, file names, declared card makers, the
revision shared by script, architecture and cache key, the catalogue route and the
.bpk binding rule). fully_applied is split out so the load checks can be tested without
the store's own refusals. Group nf's onnx case follows the rewritten extension check.
docs/BURN-ENGINE.md: how to regenerate, the five fixes, the revision bump rule, limits.

* feat(engine-burn): CRAFT_AI_BURN_DEVICE=cpu forces the processor, and the processor path is measured

* feat(engine-burn): prepare the saved copy when loading from the downloaded ONNX files

The host step: given the downloaded encoder.onnx with decoder.onnx beside it, the runner calls
craft-ai-burn-setup (exact source bytes checked, reused when already saved) and loads from the
burn-prepared folder beside the model folder. Behind the default 'prepare' feature; mutation
group be gains two cases (17/17); docs say what is measured.

* fix(burn-setup): sweep the scratch folders a killed run left, and keep craft-ai-features a dev dependency

CodeRabbit on #89: tempdir_in(cache) folders hold the two source copies (about 130 MB) and were
removed only by Drop, so a killed app leaked them for good. They now carry the cache key and a role
in their names, and after the key's lock is taken the same key's leftovers are removed (other keys'
folders, the lock file and links are left alone). Red first: leftovers_of_a_killed_run_are_swept_for_this_key_only.
Mutation cases burn-killed-run-leftovers-kept and burn-sweep-takes-other-keys, both caught.
craft-ai-features is only used by a unit test, so it moves to dev-dependencies.

* fix(engine-burn): review findings on #90

CodeRabbit: the generator now refuses an unknown option (a mistyped --chek used to select the run that
rewrites src/model; red first: tools/burn/test_generate_sam21.py failed to import parse_args); the
preparation live test needs the prepare feature and is ignored by default; the refusal test no longer
leaves burn-prepared/<key>.lock in the shared system temp folder (the model folder is nested one level
inside the test's own folder; confirmed the old layout leaked it on this PC); docs, STATUS and the
mutation README no longer describe the client feature and catalogue route, which arrive in the next
PR, as available.

* fix(burn-setup): sweep only the scratch folders, not a renamed copy of the key's folder

CodeRabbit on #89 (second round): sweep_stale removed every folder starting with <key>., so a damaged
copy a person renamed to <key>.backup would be deleted on the next preparation. It now matches only
<key>.work., <key>.conv. and <key>.out., the names the scratch folders are made with (one constant
for both). Red first: the sweep test gained a <key>.backup folder that must survive. Mutation group
bp 13/13 caught, including the new case burn-sweep-takes-a-renamed-copy.

* test(burn): the generator's usage errors must exit with code 1

CodeRabbit on #90 (second round): the parse_args tests asserted only SystemExit, which a SystemExit(0)
would also satisfy. They now assert the code. Checked against a mutant that exits 0: 6 failures.

* fix(engine-burn): a damaged saved copy says it is damaged and where it lives

CodeRabbit on #90 (third round) pointed out that a saved copy with a bad manifest or weights fails
the same way on every retry, behind the message 'could not be read or written. Try again.' It
proposed deleting the copy. The rule that a derived copy is refused, never repaired or deleted for
the person, stays (#89 and its tests pin it); the dead end was the wording. craft-ai-burn-setup now
answers every unusable saved copy with DAMAGED_COPY (remove it, prepare again, no 'try again'), and
the Burn engine adds where it lives: the burn-prepared folder beside the model folder.
Tests written first (they did not compile without DAMAGED_COPY and explain): a damaged copy of three
kinds gets that answer and is left untouched; the engine explains it and passes other errors on.
Mutation: bp 2 new cases and be 1 new case, all caught.

* fix(burn-setup): a missing or unreadable saved weight is a damaged copy too

CodeRabbit on #90 (fourth round): hash_file(...)? on a saved encoder.bpk or decoder.bpk that is gone
returned the generic 'try again' error before the damaged-copy branch could run. It now maps to
DAMAGED_COPY. Red first: the damaged-copy test gained 'missing encoder' and 'missing decoder' cases and
failed with the old message. New mutation case burn-missing-saved-weight-answered-with-try-again; the
saved-hash case was re-aimed at the new line. bp 16/16 caught.

* fix(burn-setup): a manifest that cannot be opened or read is a damaged copy too

CodeRabbit on #91 (round 5): File::open and read_to_end on an existing manifest returned the generic
'try again' error, so the engine gave no deletion guidance. Both now map to DAMAGED_COPY. Red first:
a_manifest_that_cannot_be_opened_is_a_damaged_copy (Windows: another handle holds it exclusively;
Unix: mode 0, ending quietly where permissions are not enforced) failed with the old message. The
Unix variant was not run here. New mutation case burn-unopenable-manifest-answered-with-try-again;
bp 17/17 caught (Windows).

* test(burn-setup): write the Unix permission as octal (clippy::non_octal_unix_permissions, CI only)
2026-10-22 21:42:04 +01:00

7 lines
185 B
Plaintext

# Keep line endings stable whatever the contributor's git settings.
* text=auto eol=lf
*.png binary
*.ico binary
*.zip binary
crates/ai-engine-burn/src/model/** linguist-generated=true