Teacher's Wave-6 review flagged a money-ledger hole: a mid-batch embed
throw discarded the spend of batches that had already landed (extraction
only sees success results). Owner ruling 2026-09-23 (option A, pay-once):
the landed vectors persist too — a retry embeds only what remains, so
each text is billed exactly once.
- embedNewNodes never throws on embed failures: per-batch try/catch,
result gains `failed` (error message), `embedded` counts what actually
landed, and usage carries the completed batches' steps either way
(usage-on-error).
- Zero-landed failures write nothing — the old ledger (its own
model/dim) survives untouched. Stale-wipe semantics unchanged.
- scripts/embed-graph.ts: honest failure output (lands count, not the
in-memory total), exit 1 on failure.
- tests: 4 new cases — mid-run failure (32 land, 8 remain; retry
resumes and re-bills only the rest), first-batch failure (no write, no
spend, old vectors survive), success carries no failed key.
Live-verified on port 3004: bogus-model 400 from OpenRouter → exit 1,
ledger untouched; healthy re-run embeds 0 (no re-spend); reset scratch
setting to null. Gates: typecheck, lint, 899/899 tests, build.