The donor-scene harvest engine for Outward BepInEx mods: additively load any area, clone a live creature into a dormant template, and unload cleanly. Library dependency, installed automatically when another mod (SpawnKit, CompanionKit) needs it.
ItemUidGuard: a duplicate item UID no longer wedges all item initialization on a guest.
Vanilla ItemManager.UpdateItemInitialization calls ProcessInit() and only thenm_itemsToInitialize.RemoveAt(0) — so an item whose init throws is never dequeued and every item
queued behind it is blocked for the rest of the process. Field evidence: 3,368 ArgumentException
throws, every frame to end-of-log, on a co-op guest; zero on the host. The trigger is a
donor-harvested clone colliding with a live scene NPC's UID, giving two Bags one UID + "_Content"
key. We already guarded CharacterManager.m_characters and the soul-spot registry and had missed
this third sibling — grep AddStaticItemUID returned zero hits repo-wide. The prefix keeps the
existing registration, never throws, and warns once per UID. Safety argument recorded in the source:
the losing Bag is deactivated by vanilla one method later regardless, so registering its container
would be pointless and re-keying would orphan a container under a dead bag.
Boot assertion that the guards actually attached. A mismatched Harmony patch neither applies nor
errors, and a guard whose success looks like silence must be able to prove it is installed. Covers
the soul-spot prefix too.
[MEM] per-cycle resource census (PRE-1): mono heap, total allocated/reserved and an
object-count leak proxy at each donor-harvest cycle boundary, self-timing with a 2-of-3 back-off, and
omitting rather than fabricating a skipped probe. src/ previously had zero memory instrumentation,
which blocked both the stall work and the donor-ceiling test.
The harvest stopwatch stops charging queue time to the load (L3a). [HARVEST] donor scene loaded in … now reports the load phase only and carries an explicit waited=X.XXs loaded=Y.YYs split, where
waited is the admission hold plus guard-window serialization; the "proceeding after Xs wait" line
times only its own wait. done in Xs total is unchanged. Read every pre-2026-08-30 "loaded in" timing
as an upper bound under contention, not as a load cost.
Row L3A1 in docs/guest-mirror-harvest-testplan.md.
Dependency pins raised to the sweep floors (NetKit 0.2.8).
0.1.7 — 2026-08-28
Dependency pin hygiene: manifest.json/thunderstore.toml now correctly declare ForgeKit>=0.4.10
and NetKit>=0.2.5, matching what this build actually compiles against (part of a repo-wide sweep
after the same drift left SpawnKit 0.5.0 unable to load on a fresh Thunderstore install).
SpawnKit warm mirror Phase A: publish + mirror every peer's mintable species (observe only); co-op
gate on cold guest-mirror donor harvests.
Save-replay/harvest guard hardening wave (AF2/AF8 series): the late abandoned-donor unload runs
inside its own guard window, a throwing deferred-save replay re-arms instead of dropping the save,
a merely-queued save no longer refuses harvest admission, and the harvest reports its own abandon
to the save-replay decision rather than leaving it to infer one.