Adoption gate
The go/no-go check before any web code. All four model types must run end to end from config files, from a clean kernel, with numbers you can repeat.
Where Where to implement
Runner
- Extend
sutra_core/run.pysotype: imageandtype: object_detectioncall your Step 04 and Step 09 code
Report
reports/gate.md: one row per model, generated by the notebook
Do Do it
1Add the detection config
name: detect_v1
dataset: data/raw/detect
input: { type: image, width: 96, height: 96, color: grayscale }
processing: { type: image, normalize: true }
learning: { type: object_detection, arch: centroid_mobilenetv2_050, epochs: 60, lr: 0.001, object_weight: 20 }
export: [onnx, tflite_int8, tensorrt]2Route image and detection through run()
Wrap your Step 04 training code in train_image(cfg, out) and the Step 09 code in train_detect(cfg, out), both in sutra_core/train.py. Each returns a metrics dict. Then dispatch on the input or learning type:
cfg = yaml.safe_load(open(config_path))
out = Path(out_dir) if out_dir else ROOT
if cfg["learning"]["type"] == "object_detection":
from .train import train_detect
return train_detect(cfg, out)
if cfg["input"]["type"] == "image":
from .train import train_image
return train_image(cfg, out)
# ... timeseries path from Step 08 continues here3Run all four from a clean kernel
import sys, json, time
from pathlib import Path
ROOT = Path.home() / "sutraai"; sys.path.insert(0, str(ROOT))
from sutra_core.run import run
results, timing = {}, {}
for name in ["image", "sensor", "audio", "detect"]:
t = time.perf_counter()
results[name] = run(ROOT / "configs" / f"{name}.yaml")
timing[name] = round((time.perf_counter() - t) / 60, 1)
score = lambda m: m.get("test_f1", m.get("test_acc"))
lines = ["| model | metric | test score | minutes |", "|---|---|---|---|"]
for k, m in results.items():
lines.append(f"| {k} | {'F1' if 'test_f1' in m else 'accuracy'} | {score(m):.3f} | {timing[k]} |")
(ROOT / "reports/gate.md").write_text("\n".join(lines)); print("\n".join(lines))4Repeat once to prove it's stable
Kernel → Restart and Run All a second time. Every score should land within about 1 point (0.01 F1) of the first run. If not, check your seeds and data splits.
5Decide
All boxes below ticked: tag the repo and start Step 14 tomorrow.
cd ~/sutraai && git add -A && git commit -m "Phase A complete" && git tag phase-a-doneSomething failing: use Days 22–23 to fix it and slide Phase B by up to two days. Don't start FastAPI with a broken model: debugging ML through a web stack is much harder.
Test Test it
assert results["image"]["test_acc"] >= 0.85
assert results["sensor"]["test_acc"] >= 0.85
assert results["audio"]["test_acc"] >= 0.80
assert results["detect"]["test_f1"] >= 0.75
print("✅ ADOPTION GATE PASSED: go to Phase B")Done The gate
- NB00 is green (GPU, cuDNN, TensorRT, ONNX Runtime CUDA)
- Image, sensor, audio and detection each go train → evaluate → export → int8 check
- Every int8 model: accuracy drop under 3 points (detection: F1 drop under 0.05)
- All four run from configs/*.yaml via run(), from a clean kernel
- Second run reproduces scores within about 1 point
- MFCC golden vectors and profile.md saved
- Device simulator: v1 → v2 update, sha256 refusal, telemetry all work
- Nemotron advisor correct; RAG hit@4 ≥ 8/10
- Reusable code lives in sutra_core/, not only in notebook cells
- BUILDLOG has the numbers; repo tagged phase-a-done
If it breaks
| Symptom | Fix |
|---|---|
| One model passes in its own notebook but fails in run() | A setting differs between the notebook and the YAML (size, lr, epochs, normalization). Diff them. |
| Scores jump between runs | Seed random, numpy and torch at the top of run(); keep splits by file and seeded. |
| Kernel dies mid-run | Free GPU memory between models: del model; torch.cuda.empty_cache() at the end of each train function. |
Learn more
- Section 10 of the beginner guide: the same checklist with context