docs/ENEMY_PARITY.md

Twilight Thorn (VUH-2569, living reactions qualified; full fight pending)

The combat classifier admits exact object307 (B_EX100, objentry type12). Other type12 objects remain excluded. The existing census, manifest, point binding, motion/HP mirror, hit claims and resync paths share this classifier; no second boss simulation is introduced. Exact307 boss-leave retirement, mission4/16 and event315 support were deferred from the landed v30 reaction-only slice. The v31 cohort restores that reviewed host-only terminal path; a shared two-seat kill and onward travel remain unqualified. Live10 qualified opening and both-seat ground reactions on the exact trimmed v30 binary. The later captured426 cause remains open. Creeper population desync is a documented known gap tracked by VUH-2605.

Thorn's client decision stays suppressed while the current admitted runtime is live, including before point binding, motion warmup and stream holds. This extends the existing field decision guard and shape-checked brain hook. Animation callbacks6/16/17 also remain host-owned; native animation, effects and hitbox work preceding the BDX callback still runs locally. Capture/RC playback uses ScriptMirror and the selected actual player owner.

Installed data, per-phase ownership and remaining evidence requirements are in TWILIGHT_THORN.md. Unit checks and static pins do not qualify the full fight: bot01 filmed a host kill but failed the shared exit. The complete shared-kill acceptance remains pending.

The VUH-2628 resync path can project ordinary records from one separately qualified dormant room-script table row; see Forced resync. It leaves the strict raw Script catalog status and global317/mirror/producer denials intact and grants no mixed-table combat repair or script replay. Build34/recovery04 qualifies empty FM00 only; see its result and paired recovered-state clip.

Host controller emissions (VUH-2302, protocol 20)

For qualified static combat type-2 controllers, an emission enclosed by the verified native update (3FF000, caller 3A5063) now announces the controller key, header ID, record index and its actual triggering float4 after a successful fixed/generated wrapper return. Friends suppress each such wrapper call until the matching host receipt arrives. A successful return consumes it once; a null allocation retains it. Native cooldown, stage, defeated-set and enrollment logic still run normally. Receipt order is preserved per controller, including refills.

Pending receipts select their retained trigger point instead of the live lease point. They survive a friend's intro hold and wait for that native room to arrive. Generation, delivery, full room/epoch and native load checks retire stale authority. Reliable relay history and client receipts are bounded at 4096 emissions per room; overflow cannot grant a friend spawn. This does not enable the parked general population factory path.

Script-driven dispatch (42DC10 -> 3FE320) has no spatial trigger and remains native. Qualified wrapper calls outside the verified update log bounded unsupported producer=outside-update diagnostics. Route acceptance must verify that HB header 750 and BC header 96 use the covered update path. Non-spatial script announce/replay is a separate follow-up if the route needs it. The trigger scope uses retained fiber-owned storage and clears on native return or unwind.

D14 one brain: denylist replaces the allowlist (VUH-2251, 2026-10-14)

The host's AI now drives every censused enemy on clients: objentry type 3 (boss) or 4 (mob), not an F_ object. A family stays on local AI only when it observably breaks; it goes in kDenied (inject/src/EnemyMirrorPose.hpp) with a one-line reason. The same list gates the host's EnemyMotion rows, the client stream and driver, population cull holds and ENEMY_TARGET_ALL retargeting. The configured lines now read families=all deny=317,76,2409.

Denied familyReason
Creeper 317Client copy fails ordinary point binding (no-point-match, run 20261007-220021).
Fiery Globe 76First-point mismatch on all five bodies (run b6-02).
Lance Warrior 2409HB 04/17 btl25 load faults even with co-op flags off (run 20261013-034336).

The driver's limits are unchanged. An actor is driven only when its client copy binds to a host enemy, the host's copy is unparented and its class brain thunk has the shape-checked mov rcx,rdx; jmp 0x3B4460 form. The hooked-class table grew from 8 to 16 for boss classes. A class that fails the shape check stays on local AI. Its brain-refused-shape line, like the run lines, now names the objectId, so each boss's problems can be logged as the route reaches it. While 317/76 are denied, the default-off scoped record-binding opt-in (docs/ENEMY_RECORD_BINDING.md) drives neither of them.

The per-batch sections below are the history of the allowlist this replaced.

VUH-1789 route T2 continuation (2026-10-13)

Magic Phantom M_EX500_HB (2403) joins the explicit allowlist. Its spell orbs were visible on the friend, alongside matching native motion and HP. Final narrowed-build loopback 20261013-045806_net_route_t2_magic_phantom_1 passed in118.3s: two-player Normal max HP122→196 on both peers, deaths3/3, no relay desync notices, four protected saves unchanged and owned cleanup. Clips: host_magic_shots_0.mp4, friend_magic_shots_1.mp4, friend_magic_dead_1.mp4 under .local/vuh1789-tiers/evidence/20261013-045806_net_route_t2_magic_phantom_1/. The caster's motion/all-player family rule has one regression in EnemyMirrorTest; legacy Shadow forwarding and unqualified families remain unchanged. This does not qualify remote-Sora targeting beyond the existing clone-room scope, nor projectile timing/damage equivalence between peers.

T2 candidate batches 20261013-041609 and 20261013-043354 exercised the remaining route rows. Only2403 is newly enabled; Bookmaster5 showed lightning on both screens and retains its previous qualification. Other outcomes:

FamilyPark reason for this pass
Cannon Gun14TT29 room/Sora readiness failed.
Bulky Vendor75Required living copies did not appear.
Magnum Loader121No attributable ranged volley on both screens.
Tornado Step123Required living copies did not appear.
Crescendo124TT39 room/Sora readiness failed.
Creeper Plant125Seed effects were not visible on friend; prior motion-only allowlist unchanged.
Surveillance Robot306No laser attack observed in the casting window.
Sniper311Host shots observed; friend effect not qualified, isolated friend clip hit disk gate.
Gambler314Required living copies did not appear.
Strafer1114Required living copies did not appear.
Camo Cannon2407Effects confounded by native type-21 neighbours/helpers.
Necromancer2411Friend summon/spell not qualified; isolated retake hit disk gate.
Spring Metal2412HB23 btl25 hit the known load-fault/safety-stop path.
Aerial Viking2413HB23 room/Sora readiness failed.
Runemaster2414HB23 room/Sora readiness failed.

All candidate-only IDs were removed before final build. Type-21, bosses, story/RAW/minigame policy and classifier are unchanged. Batch completion is not family qualification; per-visit JSON and reviewed clips are retained in .local/vuh1789-tiers/evidence/. No census machinery was added.

VUH-1789 route T1 smoke (2026-10-13)

Continuation batch 20261013-035916_route_t1_remainder_1 completed ten visits (four passed, six parked). Assassin309/Dusk318 at TT02/0D btl2, Lance Soldier17 at BC05/00 btl3, Beffudler2404 at HB04/15 btl25 and Dancer312 at HB04/19 btl26 had living copies, matching HP, multiple driven motions and original-copy death agreement. They were already allowlisted; no IDs were added. The eight host/friend clips were reviewed. The HB04/19 camera partly views unrendered space, so this is an enemy smoke rather than a route-geometry pass. Four protected saves were unchanged and owned resources closed.

Parked recipes: Creeper317 (TT02/0D btl7) and Gargoyle Warrior368 (BC05/00 btl3) did not yield required living copies on both peers. Samurai310 and Neoshadow120 (TT02/1F), Gargoyle Knight367 (BC05/09), Aerial Champ2410 (HB04/17 btl26) did not meet room/Sora readiness. Their earlier qualifications and existing allowlist remain unchanged. Per-visit outcomes and clips are in .local/vuh1789-tiers/evidence/20261013-035916_route_t1_remainder_1/; the batch's overall PASS means it completed, not that every visit qualified.

Iron Hammer M_EX560_HB (2405) joins the explicit mirror allowlist. It uses the existing type-4 handler, population path and all-player targeting family rule. No classifier, hook shape, T2/T3 or boss policy changed.

Two-player loopback 20261013-032757_net_route_t1_ordinary_waves_1 passed four rooms with MIRROR, POPULATION and TARGET_ALL enabled and host Normal difficulty. Native max HP matched on both peers: Iron Hammer 122→196 (HB 04/15 btl26), Driller Mole 21→34 and Soldier 29→47 (TT 02/0D btl4), Armored Knight 16→26 (HB 04/02 btl1), Hammer Frame 63→101 and Large Body 98→157 (BC 05/0C btl10). All 312 matched-frame motion samples agreed, with zero position error; damage HP matched and deaths were 17/17. Four saves were unchanged; owned processes closed. Evidence and twelve reviewed short clips: .local/vuh1789/evidence/20261013-032757_net_route_t1_ordinary_waves_1/.

Lance Warrior 2409 stays native: HB04/17 btl25 crashed during load before qualification (20261013-032235_net_route_t1_hb_lance_warrior_1). The crash dump remained empty after a locked-file bundle failure, so the cause is unknown. The flags-off single-instance check 20261013-034336_lance_vanilla_1 also faulted: Windows Application event1000 records owned PID176932 with access violation 0xC0000005 in ntdll.dll at 0xCB776, the same module/offset as the earlier co-op run. The runner stopped on an unowned KH2 process before its observation window completed; that process's ancestry was not retained. Lance is parked as a game/rig load issue, with no family or ownership widening. Evidence: .local/vuh1789-tiers/lance-windows-fault.json and the run report. TARGET_ALL's family rule and hook were exercised; attacks against a remote Sora were not qualified here. Existing private-clone room scope is BC Courtyard and GoA, which these rooms do not widen.

VUH-1515 offline stream recovery fix (2026-10-12)

The native driver test now also connects the real stream to three fake-memory client enemies (Soldier/Shadow/Rabid Dog). It checks simultaneous moving-pose playback and alternating motions, per-enemy loss while the other copies remain driven, two-sample retake, and whole-stream loss restoring native brain/motion pass-through. The fixture supplies binding correspondence and native functions; it does not establish live colliders, incoming damage or three-instance parity.

The owned-memory NativeHitClaimTest also exercises the actual EnemySync MirrorPose admission function: living matching Soldier binding, initial two-sample acquisition, status-pointer replacement, zero HP, host removal, family mismatch, stale release, partial retake and default-off refusal. This removes the pose-gate stand-in for those checks; binding setup and native memory are still fixture-owned. Native hook/collider behavior and boss phases need live evidence before broader acceptance.

EnemyMotion ingestion now expires an enemy's previous arrival before refreshing it. A gap greater than 30 local frames requires two new samples even when the first returning packet arrives before the next stream tick. An interrupted initial acquisition or retake loses its partial sample credit; isolated packets cannot accumulate across stale gaps. Exactly 30 frames remains fresh, and only accepted, advancing per-enemy samples count toward recovery. Release counters still count active-to-released transitions, not repeated gaps while released.

Offline regression uses Soldier, Shadow and Rabid Dog streams, including the ingest-before-tick order, interrupted recovery, per-enemy omissions and local frame wrap. This changes no family admission, native hook, HP/death or default flag. Three-instance position/hit acceptance and a complete boss mirror remain open; prior family-specific live qualifications below retain their original scope.

Scoped 317/76 authority: partial live qualification (2026-10-08)

Lead approved the default-off scoped record binder/authority implementation after 20261008-211146_vuh1515_scoped_record_authority_ra06_1 (ra-06e2). Both peers need KH2COOP_ENEMY_MIRROR=1, KH2COOP_ENEMY_RECORD_BINDING=1 and KH2COOP_ENEMY_RECORD_AUTHORITY=1 for 317/76 pose, brain, hit-claim or HP/death authority. All remain default off. Binding alone grants correspondence only. Neither family can fall back to ordinary point matching or obtain rights outside the reviewed first population.

ScopeQualifiedPending / unqualified
Creeper 317, EH12/06 map0 btl2 evt32767, group286 (three bodies)Both-side spawn, engagement, coverage, motion and colocated position; native brain/hit; paired nonlethal HP and one-death authority; terminal lifecycle denialFull observation-window record coverage, walkaway position/negative, mute release/retake and scoped friend-bound acceptance
Fiery Globe 76, AL07/00 map0 btl2 evt32767, group78 (five bodies)Same gates as Creeper, including native HP/death authority and terminal lifecycleSame observation-window gates; complete live group81 positive-exclusion acceptance
SafetyCanonical launch/closure, clips and unchanged saves PASSNo broader room, population, incarnation, boss, projectile or reaction-command qualification

The runner passed, but the final acceptance verdict remains INCONCLUSIVE. The 30-second hold plus endpoint reads exceeded the record judge's 1800-frame cap on three peer windows. Scope selection also omitted walkaway/mute/retake and excluded-population evidence. Offline diagnostics recover position/negative and epoch-scoped stale agreement; they do not replace the sealed verdict. ra-06f will use bounded phase windows and incarnation-aware predecessor state without relaxing coverage, position, release, retake or authority thresholds. See build/rig/vuh1515-record-authority-20261008-01/analysis-ra06e2-window/.

ri-01 previously qualified binding-only correspondence. The population-opt-in cull combination has real-guard native controls, including positive exclusion and stale/ambiguous refusal, but ra-06e2 did not enable that combination live. Exact group81 native/catalog exclusions grant zero mirror or damage rights; unknown extras, missing originals and ambiguous/stale roots revoke the whole lease. Same-load recovery is refused; a single native death retires the scoped population. Whole-room statehash agreement and group81 mirroring are UNQUALIFIED.

The earlier batch and candidate sections below retain their historical status; this section is the current qualification record for 317/76. Other families' qualification is unchanged. See scope and guards.

Enemy parity across instances (VUH-1499 spike)

T2 batch 8 (2026-10-08): Bookmaster 5 and Creeper Plant 125 allowlisted; projectile damage UNQUALIFIED

Lead approved landing Bookmaster M_EX530 (5; HB04/09 btl2) and Creeper Plant M_EX750 (125; Olympus06/05 btl1) on the non-projectile evidence from b8-07. Enemy mirroring remains behind the default-off KH2COOP_ENEMY_MIRROR flag. This does not qualify either family's projectile damage.

Live run 20261008-183534_vuh1515_b8_fx06_early_world_t2_1 used fixture b8-07 (the scenario retained its fx06 name): runner PASS, six clips OK, safety PASS, protected saves unchanged. Every applicable non-projectile family and global gate passed for 5, 125 and the Soldier301 control: living spawn, engagement, identity/epoch-scoped coverage, motion, position, brain, attributed hit, friend-bound, negative-distance, stale release/retake and placement. Bookmaster motion agreement was27/27; Creeper Plant was71/71 for each of three bodies; driven position p95 was0u. The Bookmaster coverage population/epoch scoping correction is retained in the fixture.

Projectile damage: UNQUALIFIED for both5 and125. Finalize is INCONCLUSIVE because the required independent projectile-review receipt is absent. No family-specific projectile failure or duplicate application was established. Emission/owner/attack identity and complete exactly-once native Apply/Take/Stat and actual-HP windows still need independent qualification on both copies. The landed allowlist is a bounded mirror opt-in, not a complete-combat claim.

Surveillance Robot M_EX770 (306): OFF; projectile-unqualified. It is absent from the allowlist, with native tests enforcing exclusion. Prior attempts did not witness native projectile impact on both copies; that remains a separate open qualification item and does not establish duplicate damage.

Evidence: build/rig/vuh1515-batch8-variant-20261008-01/live-fixture-b8-07/verdict.json and the canonical scenario report above. No driver, binder, damage, protocol or latency changes are included in this landing.

T1 batch 7 (2026-10-07): Rabid Dog 3, Hammer Frame 8, Aerial Champ 2410 and Beffudler 2404 allowlisted

Live run 20261007-234704 (fixture b7-01, PC1, two games): PASS. All four families plus the Soldier 301 control passed spawn, engagement, coverage, motion, position, brain, hit and release/retake gates; 5 co-located host/friend clips; 4 protected saves unchanged. Report: build/scenarios/20261007-234704_vuh1515_b7_fx01_early_world_t1_1.

Candidate notes as staged:

On main4c41090 (including live-qualified spectate), enemy-mirror-b7 adds Rabid Dog3 (76 placements/8 areas), Hammer Frame8 (46/6), Aerial Champ2410 (28/1) and Beffudler2404 (26/2). Within the requested five worlds their placement counts are50,37,28,26; these rank ahead of Iron Hammer19 and Lance Warrior13 after excluding already-qualified families, batch6's in-flight candidates and Creeper. They are the next common unqualified T1 families with direct ARD programs in the requested TT/HB/LoD/BB/Olympus worlds. Aerial Knocker20 is more common globally but only has Olympus cup placements in this world set; its ordinary rooms are in Pride Lands. Iron Hammer2405 and Lance Warrior2409 follow these four by census count. Other TT/LoD common T1 families are already qualified; Creeper317 remains excluded pending its separate read-only investigation.

Fixture: Olympus06/07 btl1 (he07 b_00 group53), BB05/0C btl10 (bb12 b_20 group49, a Hammer retry away from batch4's unsuccessful BB09 setup), HB04/17 btl26 (hb23 b_81 group265), HB04/15 btl25 (hb21 b_80 group713), then TT02/0D btl4 Soldier301 control (tt13 b_10 group107). HB candidates are Cavern content, not first-visit encounters. These are static ARD candidates, not confirmed live spawns; mandatory living spawn confirmation and engagement must pass.

Packet: build/rig/vuh1515-batch7-variant-20261007-01/. Landed on main after the live pass; Same class/hook compatibility and unchanged driver/binding/gates as prior T1 batches. Batch6 remains unlanded on this pinned base; rebase/repin before batch7 live if main gains its qualified families. No absence passes.

T1 batch 6 (2026-10-08): Silver Rock 71, Icy Cube 77 and Assassin 309 allowlisted; Fiery Globe 76 stays off

Live run 20261007-235458 (fixture b6-03, PC1, two games): PASS. All three families plus the Soldier 301 control passed every gate; 3 co-located host/friend clips; 4 protected saves unchanged. Report: build/scenarios/20261007-235458_vuh1515_b6_fx03_common_t1_1. Landed on main after batch 7.

Candidate notes as staged:

On main4c41090, the test-only variant adds Silver Rock71, Icy Cube77 and Assassin309. Fiery Globe76 and Creeper317 stay native. Batch6 b6-02 (20261007-234257) passed Silver Rock71 and Soldier301 before failing the Fiery Globe readiness gate; 77 and309 were not reached. All five76 bodies spawned on both copies, but every friend bind reported no-point-match. The nearest rounded host first points were43–125u away versus the8u radius; rounding cannot explain the gap. Entry orientation versus capture timing remains unproven; the tolerance is unchanged.

b6-03 retains direct ARD legs Agrabah07/00 btl1 Silver Rock+Soldier, 07/01 btl2 Icy Cube+Soldier, and EH12/0B btl1 Assassin (Sniper311 native). Every load explicitly selects unused evt32767 and requires settled receipts. Living spawn/engagement, brain/hit, positions/coverage, stale release and retake gates stay unchanged. Old packets/scenarios are moved into the lane's attempt-archive with original FAIL/safety PASS receipts retained. New products, native tests and live qualification require separate adoption. Packet: build/rig/vuh1515-batch6-variant-20261007-01/live-fixture-b6-03/.

T1 batch 5 (2026-10-07): Dusk 318, Samurai 310 and Dancer 312 allowlisted; Creeper 317 stays off

Live run 20261007-220021 (batch-5 fixture-01, TWTNW, rooms from the no-mirror build/scenarios/combat_rooms.json):

  • Dusk at 12/0F btl 1, and Samurai and Dancer at 12/0C btl 1, each passed coverage, motion, position and engagement. The Soldier 301 and Driller Mole 18 controls (TT) also passed.
  • Creeper at 12/06 btl 2 failed. Its client copy never bound: epoch 4 candidate0 reason=no-point-match, then 29 unmatched statehash rows, all object 317. That alone caused the run's global positions and friend-bound failures. Driven XYZ p95 was 0.
  • An offline rejudge that omits only that native epoch-4 visit (original judge and thresholds) passes every family and every global. It is retained in build/rig/vuh1515-batch5-variant-20261007-01/partial-rejudge-20261007-01/.
  • The exact cause of the Creeper point mismatch is not logged; timing or burrow motion is only a hypothesis. Reaction commands, grabs and special states remain unqualified for all four.

Question (plan D5, hard problem 3, risk R4): with the same save and room, do two instances spawn the same enemies, and what key matches a host enemy to its client copy?

Open native-wave geometry finding, 2026-10-05

The strict impaired Mac-relay wave run remains unpassed. In 094748, the original first-pack damage and exact-ID/HP census gate passed after 2.26 seconds, but the first permitted 250 ms correction moved outward: radius 563.030 to 605.943. The fixture stopped before another pulse or kill. The approved limit stays three measured 250 ms pulses, with immediate failure on outward movement or overshoot; no further input budget is authorized.

Drift also occurs before damage. In 095701, two qualified neutral endpoint samples 5.907 seconds apart showed the same host actor moving from radius 58.208 to 224.005 before the first hit. The following read-only run 100816 collected a 3.5-second interval outside the original hit gate, then intentionally failed without issuing damage or correction. Its 140 rows included 138 qualified samples across owner frames 9340–9549. Those samples retained neutral raw and processed input, idle motion and zero sampled velocity at actor+0xB98, while the actor moved 309.349 planar units. Actor, room, controller and camera identities stayed fixed. Two rows crossed frame boundaries and remain unqualified; sequential reads do not establish unsampled continuity.

Zero sampled velocity does not identify the position writer or exclude native collision, carried displacement or other motion terms. The source audit found no demonstrated local transform overwrite in this launch configuration; network pose activity alone does not prove a puppet transform was applied. The existing protection helper writes team membership; its indirect effect on native collision and motion is unproven. Attribution continues through native-field/static analysis, with no speculative suppression. All four protected saves stayed unchanged; the owned relays stopped and fetched receipts match their remote originals. See the interval result and source audit.

The bounded caller diagnostic 115734 narrowed the observed writes to the native position calculator's solved-position copy. All 61 captured candidates had complete context/value/stack reads at leaf1A8E69, with stack-top candidate return3B9561 and 21 distinct finite X values. Retained leaf/caller disassembly supports the copy from actor+700 to actor+670 at3B955C. All 24 surrounding sparse native samples qualified, including before, during and after the one-second watch, and movement occurred with neutral sampled input and zero sampled B98. The originating force remains unknown. The watch lacks a DR6 audit and per-hit timestamps; the copy does not establish a unique writer or continuous neutral execution. This intentional diagnostic FAIL and the earlier incomplete112744 FAIL remain intact. See the caller result and independent interpretation.

The private typed-RPM census transport passed live equivalence in 130211: all retained fields and entities responses matched the CLI on three paused games. The paused canonical census kept gameplay eligibility false and skipped its causal-context branch; this is transport parity only. The unchanged 75-step wave attempt 130654 then reduced the complete two-snapshot pre-hit census from 16.66 seconds to 0.640 seconds. Host damage needed no correction, and all original four IDs matched HP153 at a fresh hash and a strictly later independent native HP snapshot. The full run still failed before kill: radius 268.812 grew to 366.348 after the first 250 ms pulse, triggering immediate abort. Later-wave/death acceptance remains unexposed. See the transport comparison and wave result.

Endpoint control 131241 moved 325.571 planar units over a QPC-qualified 16.661754-second gap with no added observer reads. Both endpoints had neutral raw/processed input, safe gameplay, stable identities and advancing owner frames. Bulk census reads are therefore not required for movement. The normal protection actor/team loop, renderer, runtime and network continued; endpoints do not prove continuous neutrality or causal read-load scaling. Enemy contact, knockback and terrain remain possible contributors. All four saves stayed unchanged in these runs; owned processes and relays closed. See the endpoint result.

Matched empty controls 132932 (protection OFF, team1) and 134125 (protection ON, team0) both retained exactly the same position over qualified 16.702387/16.662934-second waits. Both had complete empty native census bookends on all three peers, matching room/controller state and selected products/config. Protection alone did not induce movement in this empty preactivation setup. Its interaction with populated enemies remains open; the empty starting point/phase differs from the populated control. Earlier 133550 remains FAIL before the wait because its START read crossed one owner frame; the fresh ON invocation retained every sampling guard. Saves stayed unchanged and owned processes closed. See the OFF result and ON result.

Retained 130654 damage receipts account for hittrace unmatched1->4 through the four fixture HP calls, not enemy attacks. Its sampled camera direction and nonzero native velocity point inward while position moves outward, arguing against a simple joystick sign/axis reversal. No host hit reaction or paired body-contact proof was captured. Keep the correction budget and immediate outward abort; do not infer a force from sparse velocity/position samples. See the contact audit and direction audit.

Region-qualified kill and second-wave binding failure, 2026-10-05

The first-pack kill fixture initially changed to check fresh full original IDs/HP/native provenance on all peers, gameplay safety, neutral host input and actual native region bit8 immediately before the canonical kill. The fixed 100-unit radius was a fixture stability convenience, not a native kill prerequisite. That first change removed the radius gate and corrective input only for this kill. Sora's position was observed and uncontrolled; the remaining gates stayed unchanged. An out-of-region host still fails. See the source decision.

Run 143735 reached the kill with the original IDs 3 through 6 at HP153 on all three games, region bit8 true and radius 35.55. Four native kills and each original death's once-only native application on both clients are confirmed in the raw logs. The cumulative six host death notices include two earlier alive departures, not duplicate first-pack deaths. This run happened to remain within 100; it does not demonstrate an outside 100 kill. Four protected saves stayed unchanged.

The full wave run FAILED at second-pack parity. Friend1 bound two new actors to ID7 while only the first append manifest was available, then rebound one to older dead ID1 and killed it. Friend2 later published two different living actors as ID8. Both clients consumed the later manifests. Ordinary matching in that DLL allowed spawn-index fallback across mismatched points and has no live-ID reservation; it can select an older tombstone after a provisional binding. These are product binding failures, not reasons to weaken the second-pack test or retry movement. Second-pack combat and reconnect were not reached. Native spawn/removal timing and same-address incarnation remain separate unresolved boundaries. See the run result and raw-log attribution.

The reviewed ordinary resolver now selects the whole fresh census before native writes. It removes mismatched-point index fallback, retains each tracked row's ID high-water mark and holds all conflicting live claimants. A tombstone needs the established ID and adjacent owner-frame samples with equal current generation/epoch and actor/object/objentry/status/controller/record roots. Roots are checked again before writing. One ordinary lethal ends that frame's write batch; the next frame resolves the remaining bodies afresh. Held bodies publish unmatched. Exact-content resync and native write leaves are unchanged.

The production resolver passed 137 controls normally and under Windows ASan, including reversed order and split manifests; the full DLL linked. Run 152041 failed before damage because Friend1 never sampled the native 311 pair, despite receiving the manifest. An unchanged retry, 153018, confirmed all four original native deaths exactly once on both clients and two fresh matching second-pack samples: unique IDs8/9, both309 HP160. Two independent native census rounds joined every current body to its ID, HP and record. That live run did not expose the worst reversed-order split-manifest timing. It still FAILED before second damage when the existing correction pulse crossed its fixed target axis. The whole-wave gate stays open; sampled roots do not prove incarnation or support deaths across an observation gap. See the native binding audit.

The approved fixture extension now uses region bit8 for the remaining hits. Before each victim hit, reread the complete all-peer pack and require the saved IDs, expected HP, native actor/controller/record identities, neutral input and safe gameplay. An inward correction stops as soon as bit8 is true. The budget remains three 250ms pulses total per damage/kill step, with immediate outward or axis-overshoot refusal. The original first-pack region kill stays unchanged. The intermediate six-second post-kill wait can be removed, but the final pack retains a six-second quiet window followed by a complete all-peer census with no unexpected IDs and counts matching the host. A later replacement ID10 cannot substitute for saved ID9. This is a declared fixture change that reduces drift exposure; it does not explain drift or establish a wave PASS.

The first per-victim run,161016, reached exact all-peer HP153 for IDs3/4, then lost bit8 before ID5. Its first250ms pulse moved outward255.22 to264.32 and correctly aborted before that hit. No kill or second pack was reached. The next approved fixture batches propagation: a client may lag only through values already issued for that victim, in order, and each native/publication observation stream must never regress after a newer value is seen. Full fresh pack reads and all identity/region/safety guards remain before every hit. Every lag must resolve at the unchanged exact all-peer phase checkpoints. The first-pack post-damage shortcut uses one fresh matching hash sample followed by an independent native HP snapshot that matches it exactly. Pack admission, next-pack and final checkpoints retain their two-fresh checks.

The batched run,162442, applied all four original hits once and reached HP153 on all three games with no correction pulses. It then lost bit8 before the first kill, at radius276.74, despite neutral input and qualified safety/identity. It correctly failed without any kill or second pack. Stop timing trims here; the next diagnostic is one native R1 lock-on/Cross attack with visual target confirmation. Damage-free homing is not required: a countable native hit could become the wave damage step, but this one-game probe cannot prove network claim handling. Sora's position remains uncontrolled. See the per-victim result and batched result.

Native attack trace receipts, 2026-10-05

The one-game R1/Cross diagnostic captures the enemy lock reticle immediately and reviews the image after attacking. Missing or unclear reticle evidence is unqualified. Native departures are recorded; the current member/HP, process, player, controller and safety bracket must still qualify immediately before Cross. This changes no original network-wave ID or acceptance requirement.

Requested KH2COOP_TRACE_HITS=1 now permits an idle summary every1000ms on an actual owner drain, in addition to existing activity summaries. Appended owner frame/thread, summary sequence and GetTickCount64 time support fresh log bookends. The reviewed three-file logger change leaves hooks, producers, storage, event serialization and damage policy unchanged. Both affected TUs build warning-clean;34 focused actual-logger checks pass. Independent counter loads and emission attempts are not an atomic seal or acknowledged log write.

A covered interval requires fresh advancing owner receipts, unchanged requested configuration/mask7, balanced started/published/drained counters, complete event groups and no unexplained loss/refusal. Zero covered activity requires all three activity counters unchanged. That covers ApplyHitDamage, TakeDamage and ApplyStatDelta; it cannot exclude every HP path, contact or physics push, or certify fiber ancestry. NativeHitTrace's network witness flag describes client enemy-to-player damage. Sora-to-enemy evidence instead requires the complete normal native Apply/Stat causal join and HP decrease, including Take when that route uses it. The observed direct Stat caller3D37D2 under Apply caller410EFF does not have an enclosing Take token; its retained child explains exactly one unmatched increment. Only complete supported groups may account for those increments; every other change refuses qualification, and zero activity still requires unmatched unchanged. Absent or incomplete rows stay unknown. One Cross may land zero or multiple hits.

Native175242 captured one real R1/Cross attack and one qualified direct-Stat HP160-to-122 application to current311/record34, with fresh owner bookends and no other loss/refusal. The final current list kept records14/15/34/35, with record34 at122 and the others at160; no post-Cross additions/removals. Bit8 began true and ended false, so region restoration remains unexposed. The canonical scenario retains its intentional diagnostic FAIL and earlier174135 qualification FAIL remains. All91 sources/inputs/products and four saves unchanged. The production claim path intercepts at Apply before native Stat and does not depend on a Take witness. See the one-game attack result.

Native181752 supplies the first observed real-client button case. Friend1's direct-Stat call had TakeCalls0, queued connection2/claim1 for attack127/damage5, and held local HP160 while its damage became0. The host received that claim once and applied native160-to-155 once. Two fresh all-peer samples and two independent native censuses retained the original four bindings:3/309/160,4/309/160, 5/311/160,6/311/155. This is one observed production interception and replication, not general attack-incarnation or wave acceptance. Its canonical FAIL remains: the fixture demanded a positive claim from a subsequent zero-amount callback. That complete callback retained HP160 and Native/ZeroAmount policy, with no claim. Both retained direct-Stat children account for the client's unmatched increments; all other client loss counters stayed zero. Host replay's orphan Stat counter has no retained child, so host damage evidence is the claim/application join and HP convergence, without a whole-host clean-trace claim.

The corrected diagnostic scopes no-death to the admitted original pack and explicitly retains outside-pack IDs 1/2 despawn receipts. Complete initial/final native and published samples must exclude outside IDs, extras and replacements; this is not continuous room-wide lifecycle coverage. The old FAIL is unchanged. The zero callback used the same observed hit/attack buffer but a different target. Client suppression does not restore that buffer's amount after native return; whether this loses intended multi-target damage remains open pending a matched host-button control. A zero callback is not proof that the second target should receive zero damage. See the real-client result and independent review.

Fresh183547 passes that corrected one-cycle client diagnostic over the Mac relay50/10/2: one positive claim/native host application160-to-155, one retained zero callback, exact original four-ID native/HP convergence, no other client loss/refusal, and unchanged source/product inputs and four saves. It leaves the multi-target question open. Host183019 produced native zero callbacks with suppression off, including attack615/damage38 to311 followed by zero to309; the exact positive127/damage5 comparison was not exposed, so that control remains unqualified for the specific client concern. See the passing client result and host comparison.

Native185918 retained the original all-peer HP153 wave checkpoint, then used one host R1/Cross and a full five-second observer. The unchanged strict trace seal qualifies zero covered callbacks across the three damage hooks: eight advancing owner summaries, activity0 unchanged, unmatched4 unchanged from setup, all other loss counters0, and no event or unknown rows. All four original IDs and native identities remain at153 in two fresh samples and two independent censuses. Its canonical nonempty-hit FAIL stays unchanged. Of81 post-Cross samples,79 pass the frame bracket; only the last two show bit8 true. The sampled return is not proof that the attack caused it. See the zero-window audit.

The approved next wave fixture adds a fixed maximum five-second neutral region wait at the first kill and second-pack damage/kill gates. It records every sample and adds no input or writer. A successful wait still requires the full original pack reread and a fresh immediate bit8/neutral/safety check; a flag lost during that reread fails without another wait or correction fallback. Original IDs, HP, deaths, correction bounds and the final six-second quiet census remain required. Two failures of the same kind end this approach without changing the wait length; native attack with full HP accounting is next.

Both unchanged attempts,191401 and191801, failed at the first kill's five-second region deadline. Their46 samples each never showed bit8 true;45 and46 samples, respectively, passed the frame bracket. Measured radius grew221.58-to-791.84 and 288.34-to-942.98, with no sampled decrease. Neither run killed an enemy or reached the second wave. Sources and protected saves stayed unchanged. The neutral wait is retired; the next fixture uses one native attack and accounts for its exact HP result before the original fresh region/native kill checks. These observations do not identify the movement writer. See the second attempt.

The full-wave native-attack attempt193532 also failed before the first kill. One R1/Cross sequence completed; the enclosing three-hook trace qualified zero callbacks, and two fresh all-peer samples plus two independent native censuses retained original IDs3/4/5/6 at HP153. The later current region bit was false, so no kill or second wave occurred. No attack retry or timing trim followed. See the result.

Its motion timeline does not show idle with continuing displacement: all61 qualified idle0/0 samples had exactly the same position. Earlier motion41/164 has the retained local REFLECT label; the native selection cause is unknown. Movement resumed before the later kill gate, outside the sampled attack window. The follow-up diagnostic kept natural team1 with a one-time HP-only survival budget before the original3.5s endpoint interval. Both clients also died in142114, so each owned game's local Sora needs that budget to preserve the all-peer census guards. This control does not establish protection causality or wave acceptance.

Run195832 exposed356.879 units of displacement during qualified3.5s endpoints without a team writer. One native48-HP application occurred inside the frame bracket, but endpoints could not locate movement onset. Run201526 added a bounded read-only50ms timeline using the identical reviewed HP leaf. All71 samples qualified: Sora remained exactly stationary at600HP through frame6617; the recorded native hit applied at6618, and frame6619 first showed552HP, displacement and motion10/DAMAGE_S_FRONT (variant42). Displacement decayed to a stable position before LAND2 and idle; sampled inputs and B98 velocity stayed neutral/zero. The later already-applied callback caused no additional HP loss. This establishes hit-associated onset to the sampled resolution, not the responsible position writer or an explanation of every earlier protected run. The external S0/solver debugger probe is parked. See the timeline and frame join.

Both full profiles remain FAIL: complete/safe native censuses changed six to four on all peers, losing original IDs16/17; no native-six guard was weakened. Protected saves and production sources stayed unchanged. No validated native invulnerability/no-reaction setter was found; the next fixture accepts native reaction and restores the required region through bounded native movement, then retains the original fresh pack/HP/census checks before each kill.

The camera-relative fixture203609 failed before the first kill. Its four original damage calls reached exact all-peer HP153 with the independent native checkpoint. The first250ms correction delivered the requested raw bytes140/2, but sampled processed movement was0/-1 rather than the fixture's expected 0.09377/-0.99559 within0.05 per axis. Neutral release was observed. The pulse remains unqualified; no retry, kill or second pack followed. Sampled radius increased279.725-to-348.959, but the closing/direction guard was not reached. No known hit appeared in the available pulse receipts; they do not seal hit absence. Check native axis processing and the actual input transform before loosening the witness or changing steering. The private variant explicitly adds one shared3x250ms budget across the four first-kill victims; existing protection and fresh per-victim pack checks remain. See the closed run result.

The bounded input interpretation found that native processing removes the small X component, while B98 velocity points inward along sampled camera-forward. The native transfer threshold and full camera/input transform remain unproved; this supports neither an LY flip nor an explanation for outward position. The one corrected attempt 211819 used deliberate (0,+1) only after fresh forward/target alignment passed .95. Ten qualified samples witnessed raw left bytes 128/1 and processed (0,-1); neutral release followed in 16 ms. All 13 samples qualified, but sampled radius increased 282.612 to 310.758, so the unchanged position-closing guard failed at step 45. All original IDs 3/4/5/6 again matched HP 153 on all three games and the independent native checkpoint. No kill, second pack or retry followed. Available receipts have no known hit/reaction, without sealing absence; B98 still points inward and does not identify total displacement. Saves, sources and the preserved 203609 fixture are unchanged. The interpretation, one correction and one live attempt are complete; the strict two-pack gate remains open. James selected assessment of a fully reviewed one-shot fixture position restore, with the original failure retained. See the corrected run and options.

The reviewed XYZ-only scalar restore control 215309 failed at step 45 before any kill. Original IDs 3/4/5/6 again matched HP 153 on all three games and the independent native checkpoint. Three f32 pokes to canonical unparented host Sora targeted 555/-1100/-2356; each response and axis readback passed. X then changed from 555 to 556.9389 between writes. The qualified post-Z sample already differed from the full target, and the final full-XYZ read crossed a native frame and was refused. A frame-timing correction alone cannot qualify these retained observations. Native bit8 became true before Z, without a flag write, but the required later-frame post-XYZ region window and post-restore enemy control were not reached. No retry or full wave run followed. Saves, sources and pinned inputs are unchanged, and owned processes are closed. The one-shot scalar assessment is complete; persistence and the strict two-pack gate remain unproved. See the closed restore control.

The later reviewed single-call XYZ control 004941 passed without kills: original3/4/5/6 remained HP153 on all three games in fresh hashes and two independent native rounds. Its unchanged full wave gate 010014 failed the canonical living-set equality at step 45 after issued kills3/4, before ID5. The last host native round has original5/6 living at HP153 and3/4 dead at0; pending client streams had not all settled. The fresh failing canonical reply is missing, so no mismatch cause is assigned. This leaves final first-wave death parity, second-wave IDs/HP/deaths and quiet/no-extras unproved. All earlier FAILs remain. Both runs are closed with saves unchanged. See the control and full result.

The logging-only candidate required a fresh control for its changed signature. That control 012309 failed the exact XYZ readback before any kill or later region/enemy qualification. One 12-byte request succeeded, but the qualified frame 6750 sample was 555.928955/-1100/-2353.774170, not 555/-1100/-2356. No retry, restore adjustment, tolerance or dependent full gate follows. The agreed fallback is another two-pack room; a passive host stability observation alone cannot qualify two waves. All checks and recorded FAILs remain. See the closed FAIL.

Passive 015317 activated BC05/04's exact header25 stage0 pack: records 55/70/71/72/object302 at HP20 and73/object303 at HP98. Five independent fresh samples through12 seconds kept exact native/publication IDs, HP, actor/status/ controller bindings and full record bytes. Native bit8 was true initially, false at offset9 and true again at12. The terminal15-second census was unsafe after a native frame1399 hit took Sora from HP24 to0. The no-writer collection aborted globally before courtyard05/06. It remains FAIL, with no complete stability, second-pack or join proof. The reviewed next step is one no-kill BB04 control with the existing unchanged wave protection; a full five-then-three gate follows only its PASS. Every fresh region, identity, HP/death and no-extras guard stays. See the closed passive result.

Protected BB04 control 021001 remains FAIL at the terminal15-second fresh bit8 check. The same five enemies kept exact native/publication bindings and HP20/98; Sora remained alive at HP24 and team0. Position moved outside the region, but the retained sequential reads and logs do not establish its cause. Its one control is consumed; no full gate or retry followed. All saves and owned PC/Mac closure passed. The bounded source review finds no region-bit precondition in the selected diagnostic hit entry; ordinary emission instead uses region admission with separate cooldown, weight/cache and stage gates. The advisor clarified the original goal and approved relocating fresh bit8 to emission points in a new declared fixture. Every HP/ID convergence, original binding, exactly-once HP0 death, second-pack, no-extra and quiet acceptance assertion stays. The changed method requires a fresh control; 021001 is not requalified. No deeper entrance preserving this pack was established by the bounded native lookup. See the control FAIL, native-versus-fixture audit and entrance lookup.

Fresh emission-scoped control 023926 passed: all six samples retained the original five enemies and HP, with bit8 required at admission and the later false value retained. Full 025347 remains FAIL before the third damage call. The first two host applications were98->91 and20->13; the exact whole-phase checkpoint, deaths and second pack were not reached. Actual entry weights were8/15, unchanged. Its two-round reader refused one raw flags9B8 change, 0x4C83 -> 0x483 (xor0x4800), while the other returned fields agreed. This does not establish the flag cause or final all-peer damage convergence. Independent review accepted the closed FAIL; saves, execution pins and owned PC/Mac closure passed. The advisor approved a new fixture comparison using source-backed native eligibility bits, retaining raw words and every acceptance assertion, followed by one fresh control and one full only after PASS. Old FAILs remain. See the control PASS, full FAIL and independent review.

Fresh semantic-mask control 030712 passed. Full 030933 remains FAIL, although all five first-wave enemies reached exact all-peer damage HP and exactly-once deaths on both clients. It stopped at step47 before proving an empty gap: consecutive native reads shared the coarse time.monotonic() value, and the strict ordering guard refused. The second pack was unobserved; the initialized step status does not prove completion. Closed independent review adopted that scope. The advisor approved a new fixture that brackets each actual native read with perf_counter_ns() and requires strictly ordered, non-overlapping reads, retaining the coarse fields and every acceptance check. One fresh control precedes one full run. No pauses or budgets were added. See the control PASS, full FAIL and independent review.

The fresh QPC no-kill control 032130 passed and its closed evidence was requalified by the actual full launcher. Full 032656 remains FAIL at initial count convergence, before strict admission or any hit: the saved counts were empty in all three games, and retained host publications stayed empty. All three peers were verified. The final sampled host point was about20 units short of the retained activation cylinder; why movement differed is unproved. No QPC emission read or wave acceptance was exercised. Execution pins, four saves, six owned PC closures and the closed Mac relay receipts passed. No retry. See the fresh control and full FAIL. The independent review adopted that scope. The advisor approved a new fixed fourth900ms activation round with position logging after every round, a fresh control and one full after PASS. A further activation miss calls for a capped native-activation stop, not another fixed round. All original acceptance checks remain.

Fresh four-round control 034300 passed with four actual XYZ logs and the same five enemies/HP in all six samples. Full 034523 activated the pack and passed exact all-peer damage HP91/13/13/13/13. It remains FAIL after lethal calls for IDs1/2, before the third call: one client native census changed during its read, so the reader refused complete absence evidence. All four round-end positions are retained for all three games. Whole first-wave death, empty gap, second pack and final quiet acceptance remain unproved. All197 execution pins, four saves and16 foreign files are unchanged; six owned PC processes and the Mac relay are closed. No retry. See the control and full FAIL. The independent review adopted this scope: both issued deaths applied once per client. The sole changing field was nextHandle on an original client actor already issued lethal. Its mutation cause and successor identity remain unproved. The advisor approved a new narrow adapter that retains such incomplete reads and polls a fresh whole census within the original20s/48-round bounds, before any new hit. Only that field on an already-issued-death actor is eligible; every other changing field or failed guard still refuses. Discard counts must be reported per phase. Complete native acceptance remains mandatory, with a fresh control and one full only after PASS. No hit is reissued and no deadline is renewed.

Fresh linkpoll control 040051 passed and the full consumer requalified its closed evidence. Full 040547 passed original all-peer admission and exact damage HP91/13/13/13/13, then issued three lethal calls for IDs1/2/3. Each reached hostHP0 and applied once on each client. It remains FAIL before the fourth call: complete census03 and its canonical living reply retained two survivors, but the first weight snapshot found a changed nextHandle on living netId5/record55. Core identity pointers matched. This comparison was against the fresh census, not admission; mutation cause and successor are unproved. Census discards were zero in both reached phases, so the narrow classifier was not exercised live. Whole-wave deaths, empty gap, second pack and final quiet acceptance remain unproved. Saves, foreign files and owned PC/Mac closure passed; no unchanged retry. See the control, full FAIL and independent review.

The advisor approved a new fixture that retains raw nextHandle but excludes it from identity equality between the census and weight read, and between two independent weight snapshots. Core pointers, native weights, eligibility, HP, list bounds and all remaining guards stay. Within-walk list consistency and its existing narrowly bounded whole-census re-read remain mandatory. One fresh matching control precedes one full only after PASS. All acceptance assertions and recorded FAILs remain unchanged.

Fresh control 042344 and full 042645 now PASS the declared BB04 five-then-three gate through the private Mac relay. All77 steps completed on three real KH2 instances on the Windows PC, with50ms delay,10ms jitter and2% configured loss confirmed in each runtime log. Original IDs1-5 matched on all three games at HP98/20/20/20/20, then91/13/13/13/13. Second-wave IDs6-8 matched at HP98 each, then91 each, with original native bindings and no extras. All eight lethal calls reached hostHP0 and applied exactly once per client. The living-empty gap was observed before actual second-pack admission. After the6.031s no-refill window, two fresh all-peer empty hashes and two complete native censuses had zero living and zero native enemy rows. Final weight, source-backed eligibility, fresh bit8 and QPC emission checks passed.

Independent review ADOPT and179 reviewed hashes matched. Four-phase census discards were zero; the narrow re-read branch remains unexercised. Raw links changed between separate censuses, but neither omitted comparison encountered a mismatch here. Full198 execution pins/91 historical sources matched, saves and16 foreign files remained unchanged, and all owned PC/Mac resources closed with25 fetched hashes matching. Every earlier FAIL stays. See the accepted result, fresh control and independent review. This qualifies the automated same-PC rig gate. Separate-PC friend play and reconnect remain outside this evidence; retained relay divergence captures also prevent an uninterrupted-equality or desync-free claim.

Selected native lifetime observer, 2026-10-05

Default-OFF KH2COOP_LIFETIME_TRACE=1 observes factory3DF930, selected outer destructor419AB0 and allocator19C470 only under the matching destructor scope and original return419ACD. Originals, arguments, returns, LastError and native SEH are preserved. A bounded POD queue drains on the owner frame; no native actor/header/domain is read after release. Exposed module, hooks, unwind metadata and MinHook dependencies remain retained until process exit.

Scope storage uses a retained Windows FLS slot and fixed owned POD contexts, without retained pointers into any fiber stack. Thread/stack/key/token failures, pool contention/exhaustion and depth overflow refuse observation and report the first reason. Unknown stack changes and thread migration are unsupported. Windows FLS initialization can allocate internally; no allocation-free OS claim is made.

The independent source review adopted the change. Normal137 controls and seven isolated ASan fiber boundary cases passed; the combined ASan fiber-stack-reuse run remains unqualified with its failures retained. Four current install-failure modes also pass normally and under ASan after a control-only retention fix.

Live153816 qualified five courtyard Shadows and killed one natively, HP20 to0. It captured one raw factory-return pair for the actor, then the selected outer destructor and matching static-arena release pair on the same actual Windows fiber. Both returned once; no guard refusal, loss, unwind or exception occurred. No reload was needed; all four protected saves were unchanged. This is selected path evidence, not death-bookkeeping, native creation authority, OS deallocation, address-reuse proof or dead-pack recovery.150636 remains FAIL/NOT_EXPOSED.

Legacy SPAWN_TRACE and NATURAL_RESOURCE_TRACE stayed OFF in153816. Their earlier TLS stack-scope pointers had a separately demonstrated interleaving hazard; that did not establish a live crash cause. The separately reviewed legacy fix now uses retained FLS-owned POD for factory/construction, lifecycle/predicate and resource scopes. Its PREPARE=0 raw profile disables dispatcher/script hooks and tick, geometry, enrollment, original-phase and first-emission associations. PREPARE=1 refuses these diagnostics; core activation update policy is unchanged.

The full Release DLL builds from91 pinned source inputs.168 normal and168 isolated Windows ASan checks, plus nine installer controls, passed. Combined ASan fiber-stack-reuse remains unqualified. Installed native run164208 ended FAIL/NOT_EXPOSED without a crash. Five HP20 Shadows qualified; no kill or retry was issued, and all four saves and91 source inputs stayed unchanged. Its parser required initialized actor metadata at wrapper return, exceeding the raw-return contract. Read-only inspection found the target's exact fixed-wrapper/factory return,55 construction rows,18 resource groups and later natural predicate/script return pairs. Wrapper-time status/HP metadata remains unavailable and cannot be filled from the later current list. The corrected parser retains that distinction and every scope/record/fiber check; the original failure remains. Generated-wrapper exposure is absent.

The separately reviewed additive health export appends flsRefusedCumulative and flsFirstReason to each factory, lifecycle and resource owner summary. They sample existing process-lifetime atomics and never reset. They count refusal calls, not unique fibers or native calls; first reason follows successful CAS order. Require both zero from all three stores in a later owner summary after the selected observed returns. Missing/nonzero/unknown/regressing fields refuse qualification. Independent loads are not an atomic event seal; earlier zero samples cannot cover later calls. The seven-file delta builds in the full Release DLL, and18 focused actual-getter/log-format controls pass. No native hook, storage or activation behavior changes. Fresh no-kill run170022 observed one exact fixed raw return/construction/resource join and explicit zero count/reason samples from all three stores, with installation and loss checks passing. Its selected natural predicate was absent within15s, so the combined profile remains FAIL/NOT_EXPOSED; after-predicate qualification is not established. No kill, reload, retry or crash; four saves unchanged. See the native health result.

The single-kill diagnostic173000 then passed: five fresh HP20 Shadows, one canonical 20-to-0 kill, one normal death-bookkeeping return and selected removal-predicate returns, followed by later zero-refusal/zero-reason samples from all three stores. Four living HP20 Shadows remained. The prior171900 pre-kill FAIL is retained; its fixture compared transient physics bit22 as identity. The corrected fixture permits only that bit to differ between completed qualifications; pointer, HP, deletion, membership and safety gates remain. No retry, reload, retired-pointer read or reconstruction; four saves unchanged. This qualifies the selected raw-return observer, not a complete emission history or dead-pack recovery. See the selected native death result.

No lifetime, incarnation, creation or dead-pack recovery authority follows. See the selected FLS review, legacy source review, native raw result, parser correction and health export review.

Current resync binding, 2026-10-04

The current protocol9/WorldBridge11 resync path now qualifies the complete ordinary native catalog and exact actor-to-record membership before any HP/death write. Full projected header/ordered record bytes and native record index supply the resync association; spawn point and manifest observation order cannot supply a fallback while fenced. This does not change the historical ordinary-message key or establish controller incarnation, continuous lifetime or creation.

The unchanged 89-step courtyard population fixture passed in201.7s on one PC over loopback (20261004-043836). The host and both friends qualified all10 definitions/26 records and five living references; each friend returned five native20-to-requested17 positive stores, then observed all five atHP17/max20 on two distinct native frames. Fresh independent censuses/hash samples preserve the original IDs1-5/object302/type4 and progress. All101 prelaunch inputs/four saves remained unchanged through terminal verification, and all8 owned processes exited. Exact result and evidence.

This is living Bootstrap content/HP acceptance. The outside-region first-rejoin FAIL (5/0/5), zero complete ten-cycle repetitions and disabled creation remain; the absent surviving pack still needs safe reconstruction. Positive geometry, dead recovery and physical remote acceptance remain open. The observations and chosen ordinary key below retain their original historical scope.

Method

tools/scenario/spikes/enemy_parity.py (2026-10-02):

  • Boot two rig instances from the same save.
  • Per room:
    • Warp both instances there (default battle program, or a forced one with --btl).
    • Keep both Soras untouchable.
    • Drive both with the same inputs, interleaved, about 1 s apart.
    • Record each enemy's first sighting on each instance: name (objentry), entity-list order, actor address and position. Enemies are objentry type 3/4; F_ objects are excluded.
  • Later waves: kill every enemy on both sides with kh2ctl hit kill, repeating rounds until both lists are empty, then record what spawns next.
  • Rooms: from tools/scenario/spikes/combat_rooms.py, a sweep of 224 world/room pairs with default programs plus 144 with forced battle programs 1–3.
    • On this save, six rooms spawn enemies with default programs. Forced programs add many more.
    • 40 rooms were held by events or cutscenes.

Results (first wave; 14 room setups, 3 worlds)

room (btl)enemiescount A/Bname+order matchaddress matchspawn pos delta median / max (units)
05/00M_EX5204/4100%75%13.7 / 13.7
05/00 btl 3M_EX050, M_EX6903/3100%67%0.0 / 1.6
05/06M_EX0205/5100%80%0.0 / 0.0
05/08M_EX0203/3100%100%0.0 / 0.0
05/09 btl 1M_BB010_SWORD, M_EX5203/3100%100%13.7 / 13.7
05/0B btl 2M_EX520, M_EX6906/6100%0%6.9 / 6.9
05/0C btl 1M_EX0203/3100%100%0.0 / 0.0
08/05 btl 1M_EX6605/5100%0%15.6 / 15.6
12/03M_EX020, M_EX4204/580%40%272 / 603
12/06 btl 2M_EX880, M_EX9204/4100%100%3.8 / 33.5
12/0B btl 1M_EX900, M_EX920 (two sub-waves)6/6100%100%0.0 / 0.5
12/0C btl 2M_EX880, M_EX9104/4100%100%14.9 / 14.9
12/0E btl 1M_EX950, M_EX9903/3100%100%0.0 / 0.0

Position deltas of a few units come from the instances first sighting an enemy at slightly different moments of its spawn animation (inputs run about 1 s apart). 08/00 is left out: its type-3 actor B_MU110 has no status block (HP reads −1) and isn't a combat enemy.

Findings

  • Same set, same order, same spawn points. 12 of 13 rooms matched exactly on name and spawn order, with spawn positions equal within the sampling noise above. That includes a timed second sub-wave (12/0B: four M_EX900, then two M_EX920 about 3.8 s later).
  • The battle program decides the set. 05/00 spawns 4× M_EX520 with the save's program but M_EX050 + M_EX690 with btl 3. So it has to be in the key.
  • Actor addresses are not a key. Addresses matched 0–100% depending on the room (05/0B: every address on one side offset by exactly 0xA0, i.e. one extra allocation). Actor pool slots depend on allocation history.
  • Behaviour diverges immediately after spawn. Positions drift apart within a second (each instance runs its own AI), as D5 expects. The host has to own enemy state.
  • Continuous spawners diverge (12/03). The first spawns match. After that, Shadows keep appearing at times and places that depend on where Sora is, and the counts differed (4 vs 5) in both runs.
  • Wave ends. With every enemy killed on both sides, battles ended the same way on both: no further wave in any of the rooms tested. The one asymmetric "wave 2" (12/0B, first run) came from a kill round that missed two enemies on one side, which kept that side's battle running. With kill rounds repeated until both lists were empty, it disappeared.

Chosen correlation key

(world, room, battle program, spawn sequence index, objentry name/id). The spawn sequence index is the order in which the room's spawner emits the enemy, counted from room entry. The key is type-checked on every message, and the actor address is never used.

Match rate on this data: 12 of 13 rooms at 100% and 1 of 13 (a continuous spawner) at 80%, so 53 of 54 first-wave enemies were matched by the key.

Fallback for spawners (scoped, not built)

For rooms whose spawner emits enemies over time based on player position (12/03 class), use host-commanded spawns:

  • Clients suppress that spawner's local emissions.
  • The host sends {spawner key, objentry, position} per spawn, and clients create the enemy through the same spawn call the spawner uses.
  • The spawner's identity (room + btl + spawner entry index) still comes from the static room data.
  • Detection: a room is a "spawner room" if a host spawn arrives with no local match within a short window; it can then be marked statically per room.

Limits

  • One save (BC first visit), three worlds (05, 08, 12). Forced battle programs stand in for story progress.
  • Spawns were triggered with the same inputs about 1 s apart; a real session has players arriving at different times. That is exactly where continuous spawners diverge.
  • No boss fight was reachable on this save (see VUH-1501).

Step 2 candidate: mirrored Shadows (VUH-1515, default off, not live-verified)

KH2COOP_ENEMY_MIRROR=1 on the host and on each client. The full design note, the fixture and its parser are in the VUH-1515 step-2 rig lane (design.md, fixture_check.py).

Protocol 13 contract: EnemyMotion (type 44).

  • Payload: epoch, a nonzero producer sequence, host frame, and up to 32 rows of {netId, objectId, motionId, motionTime, position, rotationY, alive} (18 + 31·n bytes).
  • Codec bounds: motionId < 4096, 0 <= motionTime <= 10000, |rotationY| <= 64, |x|,|y|,|z| <= 1e5, finite values, unique nonzero netIds.
  • Client spawn bound: a stream pose more than 8000 u from the copy's spawn point is refused (the copy stays on local AI), and the first 16 refusals are logged as refused-far. It was 2000 until live fixture-03, where it acted as a leash: the host's Sora drifted about 1300 u while "colocated", its Shadows chased him up to 3103 u from their spawns, and 4112 refused poses sent those copies back to local AI. Positions and the negative control then failed, and nothing was driven when the mute began.
  • The host sends it every 3 frames, for each bound spawn that is announced, living, unparented and allowlisted (round-robin start past 32). The allowlist is objectId 302, M_EX020 Shadow.
  • Relay: accepts it from the host only, for the current room/manifest epoch, with a strictly increasing sequence. It forwards it unreliably and never caches or replays it.
  • It is not material world state, so resync and StateHash are unchanged.
  • The version bump is not flag-gated: every v13 build refuses v12 peers, so friend packages and the relay are rebuilt together.
DateProtocolChange
2026-10-0612VUH-1519 PartyLayout (42), PartyReapply (43)
2026-10-0713VUH-1515 step 2 EnemyMotion (44), candidate, default off

Client stream state. inject/src/EnemyMirrorState.hpp:

  • An 8-sample ring per netId.
  • A host-frame render cursor defaults to 6 frames behind the newest sample (previously 9), with KH2COOP_ENEMY_CURSOR_DELAY_FRAMES=4..18 as a bounded override. It catches up past the configured delay +3 and snaps past 18 back to the configured delay. The displayed cursor holds at newest-1 while the stream stalls, and the overflow keeps the motion time running. The two latency comparisons record the 80 ms avatar / 6-frame enemy default decision.
  • A track is released after 30 frames without a sample, and needs 2 samples to be taken again. It resets on session retire and room transition; a host death erases its track.

Client driver. inject/src/EnemyMirror.inl. It drives a bound, living, allowlisted Shadow whose stream is fresh, after a 60-frame spawn settle:

  • skips the brain through a per-class +0x20 thunk hook, shape-checked as in the VUH-1500 probe;
  • swallows the game's motion sets (death motions always pass);
  • after the update, sets the host motion (forced on each take-over and on a same-motion restart) and time (clamped inside a finite motion end), and writes position, facing and the zeroed motion terms, with an 8-frame take-over blend. Missed updates of up to 4 frames are gaps, not take-overs.
  • Logs per-actor counters (updates, skips, bound pass-throughs, sets) and one attribution line per hit by a tracked attacker, each on its own budget.

The motion tick, hurtboxes, physics and the hit pass keep running. A mirrored attack therefore hits the client's own Sora natively, through DamagePolicy LocalVictim.

Death, spawn and fallback.

  • Death is unchanged: it comes from the host's EnemyDeath, and a dead copy is never driven.
  • A new spawn runs local AI until it is bound, settled and its stream is fresh.
  • A stream gap releases the Shadow to local AI (step 1).

Fixture controls. KH2COOP_ENEMY_MIRROR_TRACE=1 logs host positions and every tracked client copy's position (with driven=0/1) on host frames that are multiples of 30. KH2COOP_ENEMY_MIRROR_CONTROL=<file> (host) reads a phase word from a disk file every 30 frames; mute pauses publishing. Use kh2ctl injection for fixtures (Panacea's double frame tick suppresses the client trace).

Known gaps.

  • Default host aggro still chooses the host's Sora. The default-off KH2COOP_ENEMY_TARGET_ALL=1 plus mirror mode extends the common search path to eligible remote players; BC Soldier passed loopback with native damage on the friend, and a short Soldier/contact check found no stuck/push loop. Other families remain unqualified. See enemy targeting.
  • Projectiles and other script-spawned attacks are not mirrored.
  • FIELD_COMMAND/time-snap edge triggers can repeat VFX/SFX.
  • Whether skipping the brain during spawn bookkeeping leaves a copy un-hittable is unknown; the settle is a time bound.

Controls: kh2coop_enemy_mirror_test and kh2coop_enemy_mirror_driver_test.

Live result (2026-10-07, live-fixture-01, PASS, one attempt; run build/scenarios/20261007-041214_vuh1515_enemy_mirror_courtyard_two_1). Two games in 05/06, five to six Shadows:

  • Brain off: every driven Shadow had skips equal to updates (for example 3707/3707), noBrain 0 and no gaps.
  • Native hit: 1 of 2 hits on the friend's Sora came from a driven Shadow whose attack motion our set entered mid-run; the other came from an undriven Shadow.
  • Mute: each driven copy was released and re-taken in place.
  • Walkaway: the host moved 365 u and was 262 u from the friend.
  • Safety: saves unchanged; SaveGuard on with no save attempts.

Caveat on the position numbers. The colocated and walkaway median and p95 of 0.0 compare trace-client with trace-host. trace-client reads back the pose our own driver wrote the frame before, so 0.0 proves the driver applied the stream, frame-matched and through the full pipeline, and that nothing native moved the copy afterwards. It does not show that the result looks right on screen: animation blending, VFX, camera and collision push-out are not measured. The driven coverage, the walkaway negative control and the native-hit attribution carry that claim, and clips (live-fixture-02) are the visual check.

Population follows the host (VUH-1788 candidate, default off, not live-verified)

KH2COOP_ENEMY_POPULATION=1 on the client, which also needs KH2COOP_ENEMY_MIRROR=1. There is no protocol change: it is still protocol 13.

What is on by default under the flag. The cull hold and the forced-copy cleanup run with KH2COOP_ENEMY_POPULATION=1 alone.

Force-spawn needs its own sub-flag, KH2COOP_ENEMY_POPULATION_SPAWN=1, default off.

  • Without it the factory is never verified or called, and the configured line says spawn=0.
  • Why it stays off: in live runs 063223 and 065831 the friend's own game spawned every later-wave enemy natively, through the type-2 controller on the host's spawn-authority lease.
  • The one miss (fixture-05) is unexplained, and no forced copy has been created live.

Hook Bat M_EX520 (objectId 4) is allowlisted for the mirror (candidate). It is a winged flyer with the "Bat Cry" reaction command; it was first mis-named a Soldier here. It is objentry type 4 and is built by the same factory path as the Shadow: constructor 0x419E30, handler 0x7528E8, vtable 0x5D2D68. So its brain (+0x20) and removal predicate (+0x40) are the same shape-checked thunks, and the configured line reads families=302,4.

Soldier M_EX010 (objectId 301) is allowlisted for the mirror (candidate, the first T1 family of the enemy family census). It is objentry type 4, so it has the same class and hooks as the Shadow and the Hook Bat.

  • In the BB courtyard (05/06), Soldiers are only in battle program 2 (b_01), in spawn groups 68 (three at the west corner) and 69 (two, plus two Hook Bats, at the east end). Each group fires when the player enters its activator box.
  • The save's own program is 1 (b_00: groups 30/31 near the centre, 32/33 at the same corners with Shadows and Hook Bats). So live run 075643 never spawned a Soldier. The Soldier fixture warps with btl 2 and places the host in the two boxes.
  • Live run 085322 passed every log criterion: 5 Soldiers judged, motion agreement 100% per netId, position p95 0, hits 16/21. The btl 2 override worked on both games.
  • The skins (_NM 1838, _TR 1839, _WI 1849) are allowlisted with it, with no separate live run: they share its enemy stats id (neoStatus 1000), so the same AI and motion layout. The configured line reads families=302,4,301,1838,1839,1849.

T1 batch 2: Lance Soldier M_EX690 (17) and Large Body M_EX050 (303) are allowlisted, from the enemy family census. Both are objentry type 4, so they use the Shadow's class and hooks.

  • The allowlist is one array, kFamilies, and the configured line prints it: families=302,4,301,1838,1839,1849,17,303.
  • Live run 092758 (BB Entrance Hall 05/00, battle program 3, both Soras placed in each group's activator box): both families passed. Lance Soldier netIds 1 and 4 matched 89/89 and 64/64; Large Body netIds 2, 3 and 5 matched 20/20, 16/16 and 63/63. Position p95 was 0, and 9 of 14 hits were attributed.
  • Spawn-row identity fix (live run 094908). The friend's Large Body for host netId 4 never bound. Its actor reused the actor, objentry and status addresses of an earlier Large Body row, which had left the list alive (hp 90). The old rule kept that row and its historical spawn point, so binding matched dead host netId 2.
    • Rows now record the native spawn controller (+0x9E8) and record (+0x9F0) at creation. A known address that comes back with a different controller or record is a new row: new index, first-seen point taken now. A burrowed enemy keeps both, so it stays the same row. If either side can't read them, the old rule decides.
    • The same rule fixes the host side: before, a recycled address revived the old host row (often already deathSent), so the new enemy was never announced. Now it's announced as an append, and the old row takes the normal despawn path.
    • Rules: SpawnRowIdentity.hpp; tests: kh2coop_spawnrow_identity_test. This runs in spawn tracking for every enemy-sync session, with or without the mirror flag. It's step-1 binding, not the mirror. The controller and record are written only by the actor constructor (zeroed) and the provenance setter 0x3B4BD0.
  • Random spawn picks (candidate, KH2COOP_SPAWN_PICK=1, default off). Live run 102159: the host drew the Gargoyle Knights (b_80) and the friend the Warriors (b_81). The friend's Warriors never bound.
    • Where the draw happens. The area-script opcode dispatcher FUN_1403a24c0 draws RandomSpawn (opcode 2, one of n groups) and CasualSpawn (opcode 3, p%) from the game-wide LCG at 0x783CA0. That LCG has 274 references, so the two games' states never agree. The draw happens at area load, before any spawn controller exists. 42 sites across 23 areas (bb, ca, hb, lk, mu) use it.
    • The fix. SpawnPickHook.cpp detours the dispatcher. For opcodes 2 and 3 it replaces the draw with SpawnPick.hpp's shared pick, a hash of:
      • the salt: FNV-1a64 of the relay's world incarnation id, published by each runtime at world-bridge bytes [120,128); no protocol change;
      • the host's instance epoch for this visit (the host predicts g_epoch + 1; a client uses the epoch of the host-issued load it is executing);
      • the location, opcode, op offset, n and the group names.
    • It still advances the native LCG once per op, registers the chosen group with the native FUN_1403a4e80, and returns what the native op returns.
    • Fallback. Every other opcode, and any op without a salt, session or host-issued epoch (for example the first, pre-session load), runs the original. The dispatcher entry, both case bodies and the register prologue are shape-checked, and their rip-relative targets are tied to the LCG and the register function, before the detour installs.
    • Logs: [spawn-pick] configured=1 hooked=1, and one line per shared pick with the index (or fired) and the native index it replaced.
    • Shared bit (landed with the spawn picks, default off; follow-up to review F1). A friend following into a room the host loaded natively used to draw the shared pick, which matched the host only 1/n of the time. Run 111055 hit this on its first follow, at epoch 1; fixture-06 (run 121709) confirmed the fix live (reason=host-native at the join). Now:
      • The host stamps its own load's outcome on the RoomTransition packet: spawnPickShared is 1 only if every random op of that load took the shared path under the current salt, and spawnPickSaltTag carries the low 32 bits of that salt.
      • A client in a host-issued load uses the shared pick only if the bit is set and the tag equals its own salt's. Otherwise it keeps its native draw, logged reason=host-native or reason=salt-tag.
      • The bit is 0 when the host's own spawn-pick hook is not live (flag off, or the shape check refused). A hook that never ran sees no op, which does not mean the room has no random op.
      • A load whose shared ops ran under two salts counts as native.
      • A resync bootstrap target is the embedded form, with no trailer. It reuses the trailer of the last accepted RoomTransition packet for the same epoch and location. Otherwise the client keeps its native draw, logged reason=resync-unknown.
      • The fields travel only in the RoomTransition packet (a 5-byte trailer, writeRoomTransitionPacket), so the relay's late-join replay keeps them. Embedded RoomTransitions (activation, resync, party) keep their 16-byte form, and location comparisons ignore the new fields.
      • Protocol v14, unshipped. The trailer changes the v14 RoomTransition packet without a version bump. Builds from before and after it reject each other's room transitions (wrong length), so host and friend must run matching builds.
      • A retired world session clears the stored packet (RetireWorldSession).
  • Run 092758 never reached the Gargoyles (367/368). It stopped before their boxes: one Large Body hit (24 damage) killed the host's Sora at 24 max HP, and the death removed the field actors.
  • Gargoyle Warrior M_BB010_AX (368) is allowlisted. The configured line reads families=302,4,301,1838,1839,1849,17,303,368. Two runs, both with the spawn-pick variant and both Soras at 999 max HP:
    • 121127, visit 1: motion agreement 94/94, position p95 0.
    • 121709, both visits: motion 235/235, p95 0. The Warrior engaged Sora on both screens.
  • Nightwalker M_EX580 (10) is allowlisted (census T1 batch 3). The configured line reads families=302,4,301,1838,1839,1849,17,303,368,10. Live run 20261007-131606 (Land of Dragons 08/03 btl 1, LoD fixture-01) mirrored it on both visits: motion agreement 50/50 and 78/78, position p95 0, and 30/30 hits attributed. The Shadow control passed as well. Rapid Thruster M_EX660 (304) stays off until its own run.
  • Rapid Thruster M_EX660 (304) and its skins M_EX660_WI (1843) and M_EX660_AL (1889) are allowlisted (census T1 batch 3). The configured line reads families=302,4,301,1838,1839,1849,17,303,368,10,304,1843,1889.
    • Live run 20261007-132550 (LoD fixture-02) passed every criterion. 304 passed at 08/05 btl 1, 08/06 btl 1 and the 08/05 revisit, with position p95 0. The Nightwalker and Shadow regressions, walkaway, mute, re-take and friend-bound all passed.
    • The skins share 304's enemy stats id (neoStatus 1020), so they follow the family pass without their own run, as the Soldier skins did.
  • T1 batch 4: Armored Knight M_EX760 (305), Driller Mole M_EX700 (18), Neoshadow M_EX420 (120) and Gargoyle Knight M_BB010_SWORD (367) are allowlisted. The configured line reads families=302,4,301,1838,1839,1849,17,303,368,10,304,1843,1889,305,18,120,367. Their skins (1833, 1836, 1845) and the neighbours 306, 119, 121 and 366 stay off. The batch-4 fixture-01 used the rooms from the no-mirror sweep-02:
    • HB 04/02 btl 1: 12 Armored Knights and nothing else.
    • TT 02/0D btl 4: 6 Driller Moles and 2 Soldiers.
    • TT 02/1F btl 5: 2 Neoshadows and 2 Crimson Jazz, which run native.
    • BB 05/09 btl 10: 4 Gargoyle Knights.
    • Live run 20261007-141148 (batch-4 fixture-01) passed every criterion. Motion agreement was complete for every driven enemy, with position p95 0: 305 (7 netIds, 51/51 each), 18 (3 netIds, 52/52), 120 (2 netIds, 60/60) and 367 (3 netIds, 157-159 each). The Soldier control, walkaway, mute, re-take and friend-bound all passed; 54 of 56 hits were attributed.
    • The Gargoyle Knight engaged this time: it moved 3626 units through 11 motion ids. It had been held back after 121127 visit 2, where it mirrored (106/106) but stayed a dormant statue.
    • The 10 Hz frame sampler had full coverage (1799 rows, none null). Pauses of 0.3-1.7 s came in pairs on both games about every 35 s, consistent with room loads. One host-only 0.55 s pause at +136 s is not attributed yet. The run did not reproduce a multi-second host-only stall.

Live run 073546. The bats were driven with motion agreement 66/66 and position p95 0, and 14 of 17 hits were attributed.

  • The failure: from friend frame 4106 to 7120, the trace stopped for every netId, Shadow 7 included.
  • The cause: a host stall (host frames stopped, here around the host's clip capture) left the client's natural cursor permanently ahead of the host clock.
    • The displayed cursor pinned at newest−1. Newest is a multiple of 3, so newest−1 is never a trace frame.
    • The motion-time overflow grew by the stall length.
  • The fix: while the stream is live and the lag is under DELAY−3, the natural cursor holds a frame (+0) until it is about DELAY−3 behind again.

Static findings (saved PE 9002B2DE…):

  • Alive removal is AI-script driven. Generic actor update 0x3BFD30 asks handler slot +0x40 (Shadow class: tail thunk 0x419B90 → 0x3DAC30) only when actor +0x120 bit 28 is set, and calls slot +0x48 (0x419BA0 → 0x411800: controller bookkeeping if +0x9E8, then dispose) when it answers true.
    • 0x3DAC30 steps the actor's AI script (0x3B4420 → 0x3E1C80) and answers true once the live script-thread count +0x5B8 is zero, +0x80/+0x98 allow it and the +0xBB4 child does not object.
    • So the "too far, vanish" decision is in the enemy's AI script data, not in a distance constant in the executable.
    • Slot +0x38 (fade complete, +0xA08/+0xAAC zero) starts shutdown, rather than disposing the body. Its base 0x3B4700 stops scripts/motion, returns the actor's admission weight and sets +0x120 bit 28. Actual disposal still needs +0x40 → +0x48.
    • In live fixture-04 the friend's copies were removed alive about 50 frames after release to local AI, roughly 3000 u from their player.
  • Host-left fades (VUH-2304). A completed fade can leave the actor's effects alive: +0x80 is the embedded effect table's resource pointer and +0x98 its list head. Native +0x40 refuses while both are nonzero. For a confirmed host-left copy still present after 90 frames, the cull hook drains that list through byte-checked 0x2C6490(actor+0x80) (obj_effect_kill_all, also used by native cleanup slot +0x30). The helper unlinks effects before killing/freeing them. The table stays registered until normal class disposal; no pointer is zeroed by the mod. The resource/child checks and final identity check still precede native +0x48, preserving controller bookkeeping without kill credit. An ambiguous cleanup fault disables forced removal for the DLL lifetime. Independent review and native listings: build/rig/vuh2304/review-removal.md.
  • Spawn controllers in 05/06. Two controllers reach 0x3FF000: header 30 (type 2, the five-Shadow first wave, mirrored by the spawn-authority lease) and header 1 (type 1: dispatcher case 0x3FFB40, a room-exit/transition controller, not a wave).
    • The later Shadow at (−40, −1, −349) (host frames ≈6366–6539 in three of six runs, y on the floor rather than the records' y −130) is not one of header 30's five fixed records. Its emitter is not identified statically.
    • The fixture enables KH2COOP_SPAWN_TRACE=1 on both games to name it.

Client behaviour (rev 2):

  • Missing host enemies. A host manifest enemy qualifies when it is:

    • alive, and of an allowlisted family (Shadow 302) whose object id this client's own game has already spawned in this instance, so its resources are loaded;
    • has a fresh EnemyMotion stream;
    • has had no local binding for 600 frames. That gives its own controller's fixed emitter (0x3FE83F, fed by the host's spawn-authority lease) its chance; in live run 063223 the friend's game spawned the later wave natively about 30–200 frames after the host.

    It is then created with the native generic factory 0x3DF930(objectId, point4, yaw) at its host spawn point.

    • The factory entry is byte-checked at install; the call runs on the game thread from the client frame, behind SafeNativeGameplay.
    • A fault disables the factory for the session.
    • Before each call the client reads the factory's own admission (0x3A1F00): weight (objentry +0x54) must be at most limit (0x2A0F7DC) minus used (0x2A0F830). While it is not, the client waits (budget-wait), with no call and no counted attempt.
    • A null return is logged with the budget (factory-null). Null with admission available means the 0xD50 allocation failed.
    • The ordinary binding (objectId plus spawn point within 8 u) binds the new copy, and the mirror drives it.
    • Limits: one creation per 30 frames, at most 8 per epoch, at most 3 attempts per netId, and a retry only after the earlier copy has gone and 900 frames have passed.
  • Forced-copy identity. A forced copy is identified by actor + objentry + status, never the address alone. The status is logged at creation.

    • An entry is forgotten when its copy leaves any complete census (any role), or when the cull hook commits its removal.
    • A copy not bound to any netId within 300 binding-resolved frames, while its host enemy lives, is removed (unbound-timeout). Frames under a resync fence do not count, and planning pauses then too.
    • The table is cleared only by this client's own transition or load (the native teardown).
    • It survives an epoch change or session retire inside the same instance, so those copies are still removed.
  • Cull hold. Per class, the removal predicate (handler +0x40, shape mov rcx,rdx; jmp 0x3DAC30) runs natively. It is then refused (held) for a living copy that is:

    • a forced copy whose host enemy lives, from creation, through its settle;
    • or bound within the last 30 frames, so one None-gate frame does not count, and driven now or within 1800 frames, using per-netId drive history.

    Dying actors, other actors and other classes keep the native answer.

  • Removal with the host. A forced copy is removed through the native slot +0x48 (forced predicate) once:

    • its host enemy is dead or unknown, the epoch moves, or there is no client session;
    • or a native local copy claims its netId (the forced copy yields).

    Forcing overrides only the script-thread term. The native +0x80/+0x98 term and the +0xBB4 child-busy check (child +0x14) still apply; otherwise the removal is retried on the next update. Ordinary copies keep the step-1 path: the host reports an alive despawn as a death after 3 s.

  • Logging. The [enemy-mirror] stats line is unchanged. While population is on, a separate [enemy-pop] stats line carries the cull counters.

Known gaps:

  • Provenance. The generic factory skips the wrapper's +0x68 provenance call (0x3B4BD0). So +0x9E8/+0x9F0 and the AI parameters +0x620/+0x9F8/+0x9FC keep their constructor defaults. A forced copy belongs to no controller, so its natural respawn, rewards and count bookkeeping stay on the host.
  • No death animation. A forced copy whose host enemy is killed is removed alive, without one (S3).
  • Not held: the fade-complete route (+0x38).

Controls: kh2coop_enemy_population_test (planner, identity, rebase/clear, yield, hold and cull decisions) and kh2coop_enemy_mirror_driver_test (cull hook: hold, pass, dying, forced hold, force with the native terms, bind-gap tolerance, refusal).

Step 1 implementation (VUH-1502)

inject/src/EnemySync.cpp, over the WorldBridge. The role comes from the runtime's session slot (WorldBridge::LocalSlot: 0 = host, 1–2 = client); KH2COOP_ROLE=host|client overrides it for tests.

  • Room instance. Native transition-request and load-completion hooks in Warp.cpp advance separate generations. Requests and completed loads clear cached enemy actors, including same-room reloads; spawn tracking pauses while a transition is pending. A new instance starts on a gameplay frame after native completion. NOW changes and frame stalls alone do not establish arrival; lifecycle details are in pointer_map_v1.md.
  • Host.
    • Every instance: epoch++ and a RoomTransition. When hosting starts mid-room (the runtime connected late), the room and everything already spawned go out at once.
    • New enemies go out as EnemyManifest (netId = spawn index + 1).
    • EnemyHp goes out about every 6 frames.
    • EnemyDeath is sent once per netId, when HP first reaches 0.
    • VUH-2495: the census that sees HP 0 runs only in open field play. When the killing hit lands on the frame a fight-end event starts, the census next sees the enemy already gone from the list, with its last HP still positive, and the room can end within the 3 s despawn grace, so the death was never sent (run 20261019-150147: the hall's last Dusk stayed alive on the friend). The host now also records a kill at the hooked 0x3D2EB0 funnel (an announced enemy brought to 0). The first census that finds it gone publishes a real death (left=0) at once, not a leave or nothing. Debug kills through kh2ctl hit kill bypass the hook; hit damage takes the real path.
    • VUH-2884 candidate: also retain the checked native lethal-notification edge (3D4A40, dead flag newly set) for an announced occurrence with unchanged roots and owner scope. A copied terminal fact is independent of later HP samples and drains before mission state, including held-census frames. Alive removal still grants no kill. Native coverage of the Mansion base run's missing wave-two deaths awaits live qualification; see result and original-log fixtures.
    • VUH-2497: the friend's census is held while it plays the room's own events, so its binder can meet a Dusk only after the host has killed it (runs 154343, 160928, 160418). Two shapes:
      • First sight after the death: the host cleared wave 1 while the friend was still in the hall's entry event. The resolver refused the dead ID (death-without-continuous-binding), the Dusk stayed alive and unmatched, and the friend's wave 2 never came. A body that this instance never sampled before, at full HP, with no ticket, whose point's newest host ID is dead (not left) and was never carried by an earlier local body, now takes that ID (death-before-first-sighting) and the normal guarded lethal applies it. A local refill after a bound death, a hurt body, a gap after the first sample and two claimants of one ID all still refuse.
      • Death just before the fight-end event: replaying the host's TT19_MS602 end started the friend's event before its census applied the last death, and the binding didn't survive the gap. That end now waits for a clean census like HB08/MU01 (180-frame cap).
  • Host despawns. Some enemies leave the list alive: the courtyard Shadow on its ledge spawn point, host only; and Dusks (M_EX900), which vanish and reappear as new actors.
    • If a new enemy appears at the same spawn point, the host retires the announced old ID before publishing the refill manifest. An old row last seen alive carries left=1 (VUH-2292). Emission receipts follow successful terminal/manifest publication so a fresh body cannot bind the old live ID. When both packets drain in one frame, a continuously bound ordinary body retains its old dead+left ID through native leave and disposal (VUH-2304); it never relabels to the refill ID. A fresh native body binds the newer ID. Missing frames, changed roots, and changed session/epoch revoke that old-body authority.
    • If none appears within 3 s, it's reported as a death, so clients don't keep a copy that would hold the room open.
  • Client.
    • Replays each accepted host epoch through the native transition path. Arrival requires a load completion after that request, the playable-state gate, and exact world, room, entrance, map, battle and event programs. Enemy matching waits for arrival; TransitionAck retries if the outgoing bridge ring is full.
    • Matches each local spawn by spawn point + objentry to the host's newest enemy at that point. Spawn index is the fallback.
    • A new local spawn binds only to a live host entry, and waits for the manifest otherwise. A bound copy follows re-binds, including to a dead entry, which is how deaths reach it.
    • Holds matched HP at the host's absolute value (never writing 0).
    • Applies host deaths through ApplyStatDelta(-hp), the native death path.
    • Zeroes its own hits on enemies ([drop]): the host owns enemy HP.
  • Why spawn points rather than spawn order. Spawn order breaks as soon as one machine despawns and refills a point and the others don't. Spawn points matched to 0.0 units across instances in the spike above.

Verified 2026-10-02 (net_enemy_sync_courtyard, net_enemy_sync_waves: host + 2 clients, relay, host-only damage):

  • HP: the same on all three after host damage (courtyard 20 → 13, 12/0B 160 → 153), read 0.4 s later.
  • Deaths: every host kill killed each client copy exactly once (5 and 6 deaths per client).
  • 12/0B second wave: spawned on all three, bound to the host's new entries and cleared.
  • Battle end: battle state ended (0) on all three.

Transition-lifecycle regression evidence, 2026-10-02. The courtyard rerun failed its after-client-hits population/HP equality check. The original five Shadows were at 13 HP on every instance after host damage and remained there. Client 1 independently spawned a sixth Shadow at (-40,-1,-349), with 20 HP and no host manifest match. Its four subsequent hits targeted that actor and were zeroed (client log). The failed assertion's message describes changed enemy HP; the raw samples show a real extra-client-actor mismatch. No further epoch or load occurred during that mismatch. Keep this failure as unresolved spawn divergence.

The earlier passing courtyard run also had native despawn/refill variation, eventually settling at four enemies. The new lifecycle intentionally performs a real initial follow reload even when the location matches; the old fixture only recorded that first epoch. Player/camera trajectories were not captured, so these reports cannot establish why the additional spawn appeared. Shared HP/death checks on fixed scripted waves provide separate lifecycle evidence; they do not retire the courtyard population mismatch.

The fixed-wave rerun passed with the new lifecycle (154.8 s). Four initial enemies changed from 160 to 153 HP on all three instances after host damage. The second wave had two 160-HP enemies on every instance; each client recorded six native death applications in total, and battle state ended at 0 everywhere. Four save-file hashes were unchanged. This verifies fresh bindings and HP/death application after real join reloads, while leaving spawn convergence open.

Current first-pack evidence, 2026-10-03. The provenance run passed in 170.6 s: complete native censuses showed two object-309 and two object-311 enemies per peer, zero unmatched bindings and shared 160 to 153 HP after host damage. Four subsequent native kills applied once per client. Its second wave was empty and the native controller count remained two; six host death announcements included two earlier alive-despawn policy events. This is bounded first-pack replication, not multi-wave or barrier acceptance. The independent audits and limits retain the earlier strict divergence and incomplete creation provenance.

Actual-state hash evidence, 2026-10-02. The nonempty hash run passed with three instances (180.2 s). Four live native enemies had matching bindings, object IDs and 160 HP on all peers, then 153 HP after host damage. The scenario independently recomputed the published enemy hash from each peer's native observation rows. Unmatched living actors participate in the hash with net ID 0; missing, extra or duplicate actors cannot be hidden by hashing the received host cache. Positions are excluded while AI runs locally.

That run used actual native actors observed by the per-entity update hook, rather than the received host cache. Callback coverage alone did not establish that every linked native actor entered the hook. The subsequent independent census below resolves that uncertainty for its sampled courtyard reproduction.

The progress hash reads 8,108 masked, verified SAVE bytes. A client-only change to chest flag 409 produced a different actual progress hash and the relay's progress mismatch bit (fields=4). Restoring that bit restored agreement; complete before/after snapshots showed no remaining changes in the shared ranges or sampled character, inventory, munny and EXP ranges. All four on-disk save hashes were unchanged. This proves detection and restoration of a progress mismatch; forced resync, a deliberately failed native enemy death, and hash agreement across the full transition suite need separate evidence. At that checkpoint, the protocol 8 fresh transaction was verified offline; native acceptance remained pending (FORCED_RESYNC.md); historical dead targets remain explicitly unavailable without safe identity proof. The courtyard population failure above remains open.

The enemy negative-control runs remain overall failures. In the two-participant run, the detection checkpoint passed twice: a client HP-lock bit prevented the native lethal call (153 -> 153), the actual living target remained in its hash, and the relay reported DesyncEnemies (fields=2). The temporary bit was restored with native identity/epoch checks, preserving other flags. The later reload reached epoch 2 on both peers but failed because the native friend pointers were null and no remote Sora actors existed in 12/0B, battle program 1. Logical avatar poses alone did not satisfy the native actor check. This establishes detection/bit restoration, not successful reload recovery. The separate party diagnostic passed its observation steps (95.3 s), without combat or the enemy fault. Both peers had valid companion pointers in the loaded-save room, then null friend pointers on first native entry into 12/0B before networking. They remained null at settled connected epoch 1 and identical reload epoch 2. The world-18 party word stayed 0x12121200 throughout; each actor sample contained only local Sora, PRIZE and W_EX010, while connected logical puppet poses were active. All four on-disk saves were unchanged. This establishes preexisting native companion absence in this fixture, consistent with plan risk R12; it does not establish native puppet support or change the failed negative-control recovery result. The earlier three-participant controls also exposed an independent client-2 spawn of an unmatched 160-HP object 309. Keep those failures and the strict population/puppet checks; neither spawn convergence nor recovery is complete.

The 20-load hash route also failed (203.3 s), after ten passing fresh hash checkpoints. At route transition 8, epoch 10, all three peers had arrived at the complete location 05/06, door 0, map 1, battle 1, event 0; native puppet checks passed. The host published no observed enemies, while both clients published five living, unmatched object-302 actors at 20 HP. Their enemy hashes differed (401581688 versus 712275580, relay fields=2), while all progress hashes were 105337703. All four on-disk save hashes were unchanged.

That report did not capture an independent native-list snapshot, so it could not establish host absence. Native spawn appearance-ID caches and controller state also lie outside the SAVE progress hash. The subsequent checked census below supplies those missing observations. The strict route remains failed; matching progress bytes alone do not prove matching enemy activation.

The subsequent checked census collected three complete native-list/cache snapshots on every peer; the retained strict hash check still failed (208.9 s). The first snapshot had zero native enemies and an empty active cache everywhere. The later two had zero host enemies and five living client enemies, agreeing with each published hash population. This establishes real spawn divergence in this run, without a hidden host actor in the update registry.

The same type-2 controller (header ID 30) had flags 2 on the host and 10 on both clients after their appearance, while each client cache gained record IDs 11,12,13,14,18. The host cache stayed empty. Its activation actor remained near (45,-260,1950); the clients moved near (-1019,-180,1636) and (-923,-206,1638). Native analysis identifies controller bit 3 as an accepted activation region. These observations support local activation as the next authority boundary to investigate; they do not validate a hook or suppression strategy. Initially equal caches also rule out differing retained IDs as a sufficient explanation for this particular reproduction. All four disk save hashes were unchanged.

Checked native-list coverage. EnemySync now commits presence only from a complete canonical native-list traversal with checked metadata, links, tail, handle regions and lifecycle. A failed read, cycle, changing list or continuation beyond the 256-node safety bound makes the entire sample unavailable; it never publishes a truncated or invented empty roster. Unknown intervals restart despawn grace and suspend enemy writes/messages/hashes. Checked native target identity guards HP/lethal calls, and a fresh post-application census supplies hash rows independently of tracker presence. Unmatched live client actors remain visible. This corrects coverage; it does not synchronize spawn activation.

The native-wave regression passed (153.6 s) after the change: two real second-wave enemies, six native deaths on each client and battle state zero everywhere. The nonempty hash regression also passed (166.1 s), including actual HP/hash agreement and reversible progress mismatch detection. Its later empty second-wave observation remains separate from the real-wave proof. All four disk save hashes were unchanged.

The focused native-death detector passed (102.4 s) on the same DLL: the HP-locked client target survived its native lethal call, appeared in two fresh actual hash samples with relay fields=2, and its temporary bit was restored. All four saves were unchanged. The fixture ends after detection/restoration; it does not replace the still-failed full negative-control reload-recovery scenario.

The follow-up geometry diagnostic is FAIL (164.6 s): one changing actor identity made the first client sample unavailable, so its trailing strict parity check never ran. Eight of nine native and causal snapshots were complete. Their seven BOX descriptors, inverse matrices and extents matched across peers. In both later snapshots, sampled host activation was outside all seven regions while both clients were inside regions 5 and 6, away from the numerical uncertainty bounds. These are checked reads and offline float32 calculations, not native predicate-return tracing. They strengthen the local-activation explanation without turning a partial diagnostic into a passing acceptance test. Four disk saves stayed unchanged.

Scoped native activation authority. NativeSpawnController hooks verified 0x3FF000 calls from the ordinary controller task. Qualification checks current table/key membership and every record: type-2 combat, delayed mode 2, fixed position mode 0, finite coordinates and actual direct-ID objentry type 3/4, excluding F_ objects and dynamic aliases. The controller type is one byte; header byte 1 is flags. No room, header-30 or enemy-ID allowlist grants authority.

Clients request an exact epoch/full-location host-native float4 every 100 ms. A response must echo their incarnation and request identity and come from a native hook capture after the host consumed that request. Its lease ends at the original client request time plus 500 ms; receipt cannot renew it. This bounds capture age including bridge, relay and network backlog without comparing PC clocks. The relay verifies the sender, stamps the requester and routes only matched challenges. Both packets are ephemeral and never enter late-join or resync snapshots. Visual puppet poses do not supply activation authority.

Current WorldBridge v11 retains the immediate session generation introduced in v5 and adds exact generation/delivery reset markers and per-peer delivery floors. Protocol 9 retains the producer source identity introduced in protocol 8; these fences do not replace fresh activation challenges. Native use stays unarmed until that exact marker arrives. Native transition/load changes, including same-room reload, invalidate the lease. Host capture and response flush require safe gameplay, the announced epoch/full location and unchanged native serials; flush follows the fresh census and manifest barrier. A qualified client calls the original update once with a fresh copied host point, or explicitly holds the whole native tick when authority is unavailable. Hold pauses flags/cooldown/emission and never catches up skipped ticks. Host/off roles and unsupported controllers retain native execution.

Qualification read failures pass through with coverage diagnostics: an unknown controller may produce events, so it cannot be broadly held. Mixed/dynamic or initializer records, type 9, cache/stage divergence and transient triggers remain outside this boundary. A recent sampled point does not guarantee every host spawn decision; host-commanded emission remains D5's fallback. Native census and strict unmatched-row hashes continue to expose those gaps. Portable lease/relay tests passed with ASan/UBSan, and Windows bridge tests and the Release DLL build passed. The original 20-load route now passed (246.9 s), preserving all location, native puppet and strict hash checks, including the previously divergent room. Its accepted hash populations were empty; this proves the scoped client-only trigger regression, not nonempty spawn/HP/death convergence or the full P2 hash gate. Four disk saves stayed unchanged. The source-expiry control also passed (93.5 s). START produced an observed native unsafe menu/pause gate; the client stayed safely in field and both runtimes kept reporting connected network traffic. After a wait exceeding one second, fresh qualified Hold counts rose 505 -> 749 while Apply stayed 388 and no new lease was accepted. Resume accepted a newer source (752 -> 836) and Apply advanced to 389, with the same controller, epoch, native serials and full location. The report retains the gate predicate, not its raw values; its screenshot does not prove visible menu UI. The exact 500 ms expiry is the portable lease contract; this live control proves cessation and recovery beyond that bound. Four saves stayed unchanged.

The new native-wave regression failed (155.5 s) before native deaths or second-wave acceptance. Before damage, the host had four object-309 enemies while each client had two 309s and two unmatched object-311 enemies. Equal total counts had admitted unequal identities. All four selected host actors actually took 160 -> 153; surviving matched client netIDs 3/4 also reached 153. A damaged host actor then left alive and refilled at 160 HP before the snapshot. The strict failure is real population and lifecycle divergence, not list order, missed damage or demonstrated matched HP transport failure. The six-record controller 115 was qualified and used leases in this room, but the run did not capture the 311 producer/provenance or prove that lease holds caused the difference. Four saves stayed unchanged. Keep this failure alongside the earlier passing wave run; the scoped activation change has not established nonempty wave convergence. Creation, removal and controller bookkeeping need correlated native evidence. Supported nonempty activation and those new diagnostics are prepared offline, pending live runs.

Either living player starts a wave (VUH-2864, protocol 38). Native code ticks every controller with one point: FUN_1403a4f90 passes the position of the activation actor 0x2A10420 (accessor 0x3B5B40) to 0x3FF000, and only while that actor's +0x9B8 bit 2 is clear. A type-2 controller dispatches its delayed records when any of its regions contains the point; the dispatcher (0x3FE320 case 1) ignores which region accepted. So a friend who walks into a group's region while the host stays behind starts nothing on either game, and a downed host (logically downed, VUH-2465, so the bit stays clear) still starts groups only at its own feet.

For each combat-qualified host controller, NativeSpawnController now passes the host's own point when one of the controller's regions holds it, otherwise the first remote seat (slot order) whose point a region holds, otherwise the host's point. That is "any living human in any region" for type 2, with one original call per tick, so no cooldown or timer runs twice. Controllers admitted only for emission keep the native point and record no row. These are the HB04/15 mixed helpers (key 825778018, headers 749/753) and the LoD generated waves. Review found that an earlier draft let a friend's point activate those noncombat helpers (VUH-2864 review r2, comment 17575fc7). The rules are common/include/kh2coop/ActivationSeats.hpp: BOX, CYLINDER and INFINITY containment as the native predicates compute it (docs/pointer_map_v1.md, "Runtime region nodes"). Before using them the DLL checks each predicate's vtable slot and an FNV-1a hash of its whole body, and the two constants the predicates read; any mismatch leaves every tick native. The region walk follows the controller's own list (head +0x10, encoded next +0x58, tail +0x18). An unknown class, a descriptor outside the controller's array, a cycle, a list that misses the tail or a nonfinite matrix or extent keeps the host's point.

A seat's point is its clone's native position on the host (+0x670, the accessor's no-parent case; w = 1). Seats are eligible by EnemyTargetRemote's target rule (CloneCandidate): an active player-class clone with its own status, alive, a fresh unheld pose from the same room, and neither downed nor in a cutscene.

The host's actual decision is authoritative; a client never chooses again. Each static host tick records a row (group key, header ID, the seat whose point it passed, 0 for its own, and that exact point), including the fallback to its own point when its region read or predicate pins fail. HostActivationPoint carries every row recorded since the last response flush (count, truncated flag, 23-byte rows, at most 24). A client applies its controller's row exactly. With no row it keeps the leased host point only when that window used no seat at all. It holds the whole tick, as for a missing lease, on a conflicting row (two controllers deciding differently under one identity), on a truncated table, or on a missing row in a window in which the host passed a seat point. Review found that an earlier draft let each side choose from its own region reads, so a read that failed on one side alone gave the two games different points (the VUH-2864 review, comment c471a6fd).

A replayed host emission already carries the chosen trigger point, and a historical or population replay is the host's point alone. KH2COOP_SEAT_ACTIVATION=0 (or unverified pins) turns the host's candidates off and records no rows, so every client tick keeps the leased host point. [spawnctl] seat-activation side=host|client slot=N ... lines (at most one a second) log the choices, unavailable region lists and client holds. Tests: kh2coop_spawntrace_test drives the real host and client RunUpdate over test-owned controllers and region nodes. It also runs a paired round trip (host tick, recorded row, the real Codec and ActivationLease, client tick) with the region read or the predicate pins failing on the host only, the client only, both or neither, and the two points always match. kh2coop_world_test and kh2coop_activation_test cover the wire and the lease.

Limits: a type-6 controller's per-region filter and the type-4 area controllers are untouched (type 4 already tests every actor). The friend's point is a position latency behind it, the same as the host-world hits on its clone.

Historical offline creation and lifecycle diagnostics. The following records the earlier TLS profile, not the current PREPARE=0 FLS profile described above. Its dispatcher/script/tick associations are not certified by the current build. Exact opt-in KH2COOP_SPAWN_TRACE=1 adds independent byte-verified observers for all callers of fixed wrapper 3FE590 and generated wrapper 3FE650, dispatcher 3FE320 and script callback 42DC10. Each original executes once with its return value preserved. Events retain raw record bytes, actual returned actor metadata, generated point where applicable, full NOW/load/transition stamps and separate wrapper and enclosing 3FF000 controller/cache snapshots. Script and dispatcher scope are explicit dynamic enclosure; the script's native tail jump can yield a DLL dispatcher return address, so unavailable caller ancestry remains visible.

Five independently verified lifecycle probes observe removal bookkeeping 3FFD90, disposal 3B45C0, lethal notification 3D4A40, death bookkeeping 3FED10 and count decrement 3FED40. Nested events retain entry sequence, parent/depth and checked pre/post actor/controller/cache facts. Disposal may invalidate poststate; count decrement has no actor argument. Neither missing poststate nor a later disappearance proves death or allocation reuse. Native exceptions continue to their original handler, with interrupted poststate and restored scope. Fault counters count observer filter hits, which can include several nested observations of one exception.

Only the registered game thread samples role and Warp serial callbacks. Unknown/foreign threads preserve raw facts with unavailable role/stamps. The game-thread drain records events even when current correlation is unavailable. Fresh post-apply native census plus identity rereads establish current membership; binding additionally requires one sampled generation matching current, activation and consumed ordered-reset generations. bindingEpoch/netId is a current hint, not a creation incarnation, and is never derived from emission order.

Per-hook availability, partial installation, unsupported callers, unavailable reads, queue loss and interrupted events remain explicit. Generic factory calls, unhooked subtype removal, actual deallocation and producers outside these boundaries are unobserved. Same-address reuse and controller reincarnation remain unproven. Bounded queues, missing shutdown drain and diagnostic overhead prevent full coverage claims. This instrumentation changes no creation authority or activation lease/Hold/Apply policy and does not repair the failed wave. At that offline checkpoint, the strict wave diagnostic and separate nonempty activation control were prepared; no live trace run had occurred while James used the desktop for Rivals.

The expanded Release DLL and both Windows headless targets build with native tests under MSVC /W4 /WX. Spawn tests passed 38 checks and lifecycle tests 24, then both passed in the isolated Windows AddressSanitizer build. Tests use actual observer code, synthetic originals and test-owned memory, including exception propagation, original-call count, nested/TLS recovery, queue loss and real foreign-thread controls. They do not execute game functions, install hooks or validate live ordering/census bindings. The saved-log auditor passed 37 controls and rejects the archived untraced wave logs as incomplete evidence. Activation deadline evidence is reused for unchanged inputs. Subsequent relay claim-epoch and co-op host-loss changes have fresh world/fake/avatar/bridge checks, Windows ASan and portable relay ASan+UBSan evidence in the relay lifecycle receipt. The Windows native trace path has no UBSan evidence. Fresh logs and source/DLL hashes are in the expanded offline receipt. The earlier fixed-only receipt retains its historical 19-check scope.

Not covered yet:

  • Bosses: none reachable on this save.
  • Drops and barrier objects (battle state stands in for "barriers lift").
  • Continuous spawners.
  • Broader client-hit authority (VUH-1503): native courtyard acceptance now confirms 22 ordinary client claims and three Shadow kills, delivered once to both clients with matching applied HP/population/progress. Boss finishers, survival/caps, attack-specific effects, victim-side enemy attacks and native reconnect remain unproven. See native D4 evidence.
  • Hash agreement across repeated native room loads and varied populations, plus successful recovery after the enemy mismatch control. The nonempty proof covers one fixed-wave room; it does not establish spawn convergence or native remote actors after its battle-room reload.

Historical scoped record binder proposal (2026-10-08)

317/76 remain outside the production pose allowlist. A default-off binding-only candidate addresses the reviewed point mismatch using exact content/controller keys in EH12/06 btl2 group286 and AL07/00 btl2 group78 only. Any population, content, root or incarnation ambiguity holds binding; HP/death/claims/pose remain fenced. Protocol v15 rejects old peers. See design and limits and build/rig/vuh1515-record-binder-20261008-01/; no live qualification yet.

Historical scoped Creeper/Fiery Globe authority proposal

Binding-only ri-01 passed20261008-024015. A separate default-off candidate adds317/76 to stream eligibility, but native pose/brain/claim/HP rights require both KH2COOP_ENEMY_RECORD_BINDING=1 and KH2COOP_ENEMY_RECORD_AUTHORITY=1 plus mirror opt-in and a complete current-frame scoped record proof. Only reviewed12/06 btl2 Creeper and07/00 btl2 Fiery Globe populations qualify. No ordinary point fallback is used for either family.

The first population must be complete/living with continuous checked roots and exact record content. A single host death can hand off one native lethal on that frame from an installed lease; then the whole selected population retires until a fresh local load and shared epoch. Multiple simultaneous deaths, missing bodies and same-record reuse hold authority. This is deliberately conservative first-population support, not global or incarnation-safe identity. Full qualification packet includes standard batch mirror gates plus explicit host-only native damage/kill and friend HP/death receipts; code and fixture remain PENDING.

Historical ra-05 positive outside-population proposal

ra-03 withdrew the original five Fiery Globe group78 bindings when group81 appeared during the walkaway. This was a real binder withdrawal; Creeper's authority probe passed. Retained run:20261008-181351.

ra-05 keeps the original eight immutable record pins in EH12/06 btl2 (three Creepers, group286) and Agrabah07/00 btl2 (five Fiery Globes, group78). Only the six exact group81 records in the same Agrabah program may be excluded. Every local extra requires fresh complete native census/catalog membership, repeated roots/content and disjoint original roots. Every peer317/76 row requires a full record key checked against the fresh local catalog. Protocol15 publishes positive outside keys with zero binding, mirror, claim, HP or death rights. Unknown or missing keys, aliases, missing originals and reincarnations withdraw the lease.

Withdrawal clears current keys/rights, bindings and pending317/76 claims. Retained HP/death work is denied at the actual native boundary. Brain, motion and pose callbacks recheck authority, including after a reentrant motion setter. A fresh load AND transition plus advanced epoch (or changed generation AND connection) is still required to reset a consumed population. No same-load recovery or point fallback is added; the one-death handoff remains terminal.

build/rig/vuh1515-record-authority-20261008-01/live-fixture-ra-05 retains the walkaway, standard mirror gates and paired native authority probes. It requires a fresh group81 body and opposite peer catalog-key receipt. PASS is scoped to the original populations; whole-room friend-bound and group81 mirroring remain UNQUALIFIED. Code and fixture are PENDING, without a live qualification claim.

Population repair-06 owner-frame disposal

Repair-05's retained late-join run 20261008-230919 installed cut12 and produced terminal tickets, but both unbound Shadows had actor+120 bit28 clear in all five complete samples. Native removal-predicate dispatch was therefore insufficient. See .local/repair05-live-230919-diagnosis.json and the earlier .local/pj08-live-203406-diagnosis.json for the persistent mismatched sets.

The repair-06 candidate consumes certified terminal tickets on the owner frame using the verified native ApplyStatDelta one-shot. It checks full scope, terminal incarnation, current unbound ownership, catalog membership and five roots again at dispatch. Ordinary bound death authority stays unchanged. A process-lifetime, bounded five-root/load/transition journal prevents repeat native calls after a fault, readback failure, ticket cancellation, or cut reauthorization. Journal exhaustion refuses further calls; it never evicts attempted incarnations.

Every native call or fault stops the frame after a fresh census; tracking resumes only from a complete current census. HP zero is pending native removal, and only fresh physical absence after an attempted call produces a disposed receipt. Per-ticket outcome JSON records refusal checks, call outcomes, pending removal, cancellation and confirmed absence; repeated identical outcomes are summarized on the next transition, and receipt loss is explicit. Native admission weights, used budget, controller counts and constructor records are not changed.

Live run 20261009-000023_vuh1788_late_join_population_repair_1 PASSed the fixture oracle and safety closure: terminal ID1 consumed at frame159, physically absent at219; both complete three-peer samples match IDs2/6/7 at20/20 HP and 8/9/10 at28/28 HP with stable unique bindings. No admission/budget waits remain in the late-client log. Controller count falls5 ->4 while used budget stays48. Reconnect, forced-host-id and used-budget reclamation are not claimed. Build and 120/120 serial CTest PASS; codec ASan/UBSan PASS. Helper sanitizer is INCOMPLETE because of a GCC13 compiler ICE, waived by Lead as a live gate. See population repair and evidence limits. The landing tree rebased onto079f9a3 awaits its own scheduled build and full serial CTest.

Field objects: host decisions (VUH-2276)

ENEMY_MIRROR=1 also drives every censused F_ actor on clients. Field objects use a separate complete periodic roster (FieldObjects, protocol 21), with high-bit identities, immutable spawn anchors, native type, pose and motion. They never enter enemy HP, hit or population tables. The relay accepts only the current native host, room tuple and increasing sequence; periodic snapshots are not replayed as world state. Script calls may name a currently present field ID.

Client decisions are suppressed before pose takeover, including while waiting for a binding or fresh snapshot. The native puzzle updater needs a verified class-slot hook because it performs proximity pickup directly. Host pickup retains an absent identity in subsequent snapshots. A uniquely bound client copy calls its verified native class leave once, including the puzzle effect unlink, then lets native removal and destruction finish. No host pointers or inventory writes are copied. Chests retain the existing shared-progress path. The callback gate, pinned original and recorded page protection cover hook installation and shutdown.

A binding requires unique host and local occurrences at an anchor, matching actor/objentry/handler roots, current owner frame, session, load and transition. A changed identity or interrupted established binding holds. Snapshots older than 500 ms hold pose while client field decisions remain suppressed. The room roster retains at most 64 live and retired occurrences; overflow refuses the whole snapshot. New live occurrences outrank old tombstones at the same point; multiple live matches refuse binding.

A boss whose death its own script plays (VUH-2367). On a client the host's death is applied as native lethal damage. A brainless boss copy can refuse it: Shan-Yu B_MU100 went 9 -> 221 HP (20261017-070818), because on the host his script drives the defeat (mission trap 4/16, re_deadboss). When the post-lethal sample is still alive and its objentry is a boss (type 3), the client fades the copy out once with the native leave (VUH-2272), never inside a resync's record-authority write fence. The leaf ApplyNativeBossLeave re-checks the type at write time. The census is then re-resolved on the next owner frame, and the log line is boss lethal refused; native leave applied. No kill is counted and the friend gets no boss reward. Ordinary enemies keep the failed lethal as before. net_lod_shanyu checks that the friend's bosses match the host's after the defeat, and that neither Shan-Yu nor the hawk B_MU110 is left after the friend follows the host out.

Natively run fields (VUH-2342). LoD's wind gusts F_MU070 (object 0x151, 08/08) are not field objects for the mirror: every game runs its own, and the host leaves them out of the roster (ReadNativeField). They are remade every few seconds and push whoever walks into them. Posed from the host with no brain, they never pushed the friend, and the host's remade gusts would have filled the 64-row roster with tombstones. net_lod_gusts walks each player into the wind.

net_field_objects checks HB04/15's six F_EX030 chests, two F_EX260 pieces and rotating F_HB040: friend-only pickup must leave both pieces, then host pickup must remove one on all three instances. Remaining type, motion and rounded positions must agree, with rotating motion time within eight frames.

HB753 mixed emission (VUH-2302)

Controller753 in HB04/15 map1 btl26 evt32767, key825778018, contains the static ordered records2406,2407,2407,2407,2406. Live identification 20261015-160201 confirmed2406 as M_EX640_HB, objentry type21, on both friends. This exact mixed shape uses the existing host emission receipts for all five records, including its helpers. It grants no combat activation authority. Clients tick it only on a pending receipt's historical point; without a receipt they hold the ordinary update. Other mixed/noncombat controllers remain excluded. All object-table, layout, static-mode and lifecycle checks still apply. Native admission and HP handling are unchanged.

VUH-2315 extends this emission-only path to the observed HB749 shape in the same room/key: four ordered records2406,2406,2407,2407 and two regions. The retained native inventory identifies the same M_EX640_HB/type21 helpers. Route173525 left one friend-only749 Camo Cannon alive after host clear; route174204 left two on each friend. Without this qualification,749 passed through locally because of its helpers. Only749 and753 use this mixed exception; other mixed controllers remain excluded. The route's20-second clear bound and native admission, HP and death policies are unchanged.

Late native births (VUH-2302)

Protocol22 appends the exact host manifest netId to each combat emission receipt. The host joins the normally returned native birth to a fresh census and an announced manifest occurrence after HostFrame succeeds. Unreadable combat roots refuse publication; only positively identified noncombat helpers use netId0. The relay requires a known current-room occurrence, including terminal ones.

Clients reserve one immutable receipt sequence across the native wrapper. A normal null return cancels the reservation for retry; a successful or ambiguous allocation spends it once. A successful checked combat birth retains actor, handle, objentry, status, controller, header, indexed record and record content, plus session/delivery/load/transition scope. Native status can still be null at wrapper return; a fresh census completes it once only after revalidating all captured immutable roots and the native handle. Nonzero status is then frozen. A still-null status may wait at most32 owner observations with fresh complete linked-list membership and unchanged birth roots; absence or drift refuses it. This pending observation supplies no binding authority. Every census rechecks these roots and continuous membership. An unspent ticket selects only its exact netId, including a host death delivered before local allocation. It cannot select a newer refill at the same point. Whole-census conflicts still refuse all claimants; certified lifecycle, record-family and resync authority remain separate.

First committed adoption, live or dead, spends the exception. Later gaps use the ordinary unchanged continuous-death rules. Native death/removal still runs once through the existing checked path. No positional dead-body exception, admission budget, capacity or HP-policy adjustment is introduced. Matched protocol22 products are required on all peers.