docs/COMBAT_CAUSAL_DIAGNOSTIC.md

Passive combat causal diagnostic

Saved host/friend receipts can be checked with the offline combat causal auditor for VUH-1503 AC3. It reports orphan/duplicate source links and unqualified coverage separately. Schema 1's explicitly unqualified native coverage prevents a PASS even for a consistent recorded graph; it grants no live or landing authority.

Offline product prerequisite for the two-PC shared-combat design, based on clean source 7d622b414694167c70794931bb58e253db18344f. These are new coherent DLL/runtime products, not the original JOIN27 binaries. Full combat remains BLOCKED until the source/product reviews, measured transport coverage and a separate executable fixture qualify. No game run or recording-window decision is included.

Set KH2COOP_COMBAT_CAUSAL_TRACE=1 explicitly on both the inject process and its runtime. Absent or any other value is off. The flag reuses the installed ApplyHitDamage/TakeDamage/StatHP observation hooks and owner-thread trace; it adds no hook registrations, network packets, damage calls, retries or gameplay permissions. Existing NativeHitTrace::Witness is unchanged.

Admission requires two consecutive owner frames with five living object-302/type-4 Shadows in full native tuple [5,6,0,1,1,0], fresh checked actor/object/status/controller/record roots, a two-peer roster and complete native/session/lifecycle gates. Original generation, delivery, peer deliveries, session salt, connection IDs, epoch, load, transition and target mappings remain immutable. The salt supplements the exact runtime session receipt; it is not authentication by itself. Same-pointer native incarnation remains unqualified. Any replaced scope, unexplained HP change, missing living target, extra family/wave, loss or ambiguity permanently retires diagnostic coverage. It never changes gameplay behavior.

The fixed owner-thread ledger links canonical host native hit events or actual friend claim application to the normal EnemyHp publication. It copies the existing encoded payload at the existing enqueue, source sequence and ordered per-target cause IDs. Friend hit claims retain the enclosing ApplyHitDamage event sequence and immutable actual claim key. Client HP/death decode, actual native store/lethal call and checked readback have distinct receipts. Grace/despawn cannot qualify a natural death. Native fault/partial outcome cannot qualify.

[combat-causal] receipt and association lines retain numeric kind/reason, QPC nanoseconds, complete original scope, target roots, native before/after values, actual operation outcomes, claim keys, raw payload and cause IDs. The payload FNV64 is a convenience checksum only: reviewers must compare raw bytes, framing and independently hash retained artifacts. [hittrace] remains the detailed original hit/child/policy evidence. [combat-causal-runtime] binds exact session bytes (hex), transport/producer generation and delivery to actual net submission or inbox admission. Inbox admission is not native application. All records have acceptance=0; no local boolean can substitute for cross-peer replay and the full combat oracle.

The observer uses a static 128-row receipt queue, five targets and 16 causes per target, with 4096 payload bytes per row. Hook-side work uses copied facts, fixed storage and no I/O or allocation. Owner-frame drain emits at most 16 receipts; loss is explicit and invalidates completeness. Runtime receipts are bounded to 4096 relevant packets; overflow emits a loss marker. Its logging and any envelope decoding are outside native hooks. Runtime/DLL QPC clocks are local only, never compared between PCs.

Offline controls exercise production NativeHitTrace callbacks and the actual EnemySync claim consumer and normal HP publisher over owned synthetic memory. They check unchanged original calls/arguments/returns/sends with the flag off/on, cause association, replacement, unsupported source, unknown damage, duplicate application, death classification, raw payload retention, client readback and fixed-ring loss. Copied facts and benign native leaves are not live native coverage. Build and serial CTest results, compiled-input provenance and product hashes belong to the sealed product packet.

The existing 3-second clip04 contract is unchanged. A 12-second wall-clock capture is unselected. SSH setup failures and unknown old worker closure do not provide a latency or recording-coverage measurement. No SSH, PC2 contact, game launch/input or public exposure is authorized by this diagnostic.

Diagnostic logging and census-allocation exceptions are contained: they retire coverage or emit explicit loss, and cannot enter the gameplay transport failure path. The optional WorldPump observer has a noexcept callback boundary.

NativeHitTrace unmatched counts child callbacks outside ApplyHitDamage and in-scope mismatched children, including StatHP reached by the existing claim TakeDamage trampoline. It is retained as a counter, not reinterpreted as a dropped hit or canonical event. That known claim operation has its independent checked HostApply receipt; an HP delta with no admitted native-hit or HostApply cause still cannot qualify. Dropped, foreign, unwound, nested and overflow observations remain coverage failures.

Clock callback publication uses an atomic function pointer and release/acquire admission; the init thread cannot expose a partially published pointer to owner-frame diagnostics. Controls include a separate native reader thread. The fixed ledger also decodes the existing HP/death/claim framing without allocation and checks raw target/epoch/sequence/value fields before marking a local receipt qualified; seven encoded-byte mutants remain permanent controls. This adds no encoder, send or protocol field.

Native02 stopped at compilation before discovery/tests: including Codec.hpp from the copied-facts observer collided with HitChannel.hpp's separate HitClaim type in EntityHook. The observer now keeps three wire tags local, with compile-time controls comparing each to the production codec enum; it does not import Protocol.hpp into that translation unit. Native02 remains FAIL and its build/evidence are preserved. A fresh source-matched build slot is required.

Rev2 consumer outcomes are distinct from runtime inbox enqueue and local causal qualification. At actual HP/death decode/admission branches, a bounded ConsumerRejected row retains the exact raw inner frame or the outer envelope when rejection happens before inner extraction, the actual reason, current scope and immutable admission scope, expected epoch and sequence floor. Unknown-target entries get their own rejected row with the raw target ID and no fabricated native roots. Framing, decode (including malformed inner data rejected by the existing WorldEnvelope validator), epoch, zero/stale sequence, envelope/source binding, unavailable ordered generation and wrong-role exits are inventoried. A zero-sequence thrown by the outer codec is a Decode rejection of that outer envelope; no inner admission is inferred.

An actual accepted HP batch or death frame also gets a ConsumerAccepted row before existing mutations, including empty HP batches and equal reliable cache replays. Per-target causal HpReceive/DeathReceive remains separate and can stay unqualified; an accepted packet containing an unknown target can have a rejected entry. Native decisions, continues, high-water updates, HP/death/cache writes and failure handling are unchanged. Rejection rows never qualify a causal node. Payloads beyond4096 retain an explicit prefix/original size and retire completeness as loss, rather than presenting a prefix as a complete raw frame. Fixed-ring overflow and logger failure still retire diagnostics without changing native admission. After trace retirement, its existing permanent retirement/loss evidence prevents completeness and the trace cannot re-anchor.

Permanent NativeHitClaimTest controls feed actual consumer branches (19 rejected/accepted cases), compare OFF/ON cache/native/call/sequence/revision/send decisions and check raw bytes/reasons/current and original scopes. Rejection tests enter both the actual envelope validator and the lower decoder as appropriate; accepted cases use a genuine scoped envelope. These remain owned-memory offline controls, not live native coverage. Product rev1 and its review outcomes remain preserved.

The rev2 positive set also runs the actual local claim encoder/send inside a real NativeHitTrace Apply token after earning manifest/HP/native-readback release, and the actual host native-zero death encoder/send after one checked lethal claim application. OFF/ON payload/native-call/HP/sequence/state equality and exact qualified raw claim/death receipts are checked, alongside the existing normal HP publisher positive. The Apply scope uses copied context facts; canonical native-hit qualification is covered separately and this does not synthesize a live complete graph. Client controls set their original owned native-arrival/ACK adapter leaves before diagnostic scope admission.

Native04 is preserved FAIL: build/discovery passed,59/60 serial tests passed; seven new consumer raw-outcome assertions failed (cases0,1,2,3,7,8,16). Retained source shows the controls expected a later rejection than the actual first gate: malformed HP/outer-envelope headers throw Decode, and bare unscoped facts exit at the authenticated-scope gate before payload/epoch/sequence parsing. That scope exit lacked a receipt and is now observed before its unchanged continue. Authenticated epoch/stale tests now use valid envelopes; bare cases expect Scope and malformed header cases expect Decode. Envelope decoder malformed/zero/trailing cases still check exact outer raw rejection. Controls label their mode/expected reason to preserve first-gate evidence. Production claim/normal HP/native-zero death positives and all OFF/ON gameplay-state comparisons passed in native04; no retry or revised native success is claimed.