Skip to main content

Production integration checklist

Use this before shipping a ROCK consumer. The API is designed to fail closed, but a consumer still has to respect extent, capability, lifetime, and thread contracts.

Discovery

  • Acquire ROCKAPI_GetDescriptorV1 through the SDK helper and validate its size, version, table pointer, and table bytes before touching optional slots.
  • Fall back to the legacy export only within the SDK helper's documented safe path.
  • Require API version 1; do not assume every V1 provider has the same table extent.
  • Check the named table-byte constant for the last function family you use.
  • Check the relevant feature bit; use the secondary feature mask when applicable.
  • Read provider limits instead of hard-coding runtime capacities.
  • Treat initialization errors as actionable dependency/compatibility diagnostics.

Owner registration

  • Request only the capabilities the product actually needs.
  • Give the registration a stable, null-terminated mod name.
  • Store ownerToken, grantedCapabilities, and provider generation as one invalidatable session.
  • Check each required capability in grantedCapabilities; never confuse a feature bit with permission.
  • Define a graceful read-only or disabled mode for optional capabilities.

Threading and callbacks

  • Make live scene/physics reads only from owner frame/animation callbacks.
  • Keep callback work bounded: no blocking I/O, unbounded scans, or avoidable allocation.
  • Never throw across the SDK callback boundary.
  • Keep callback and userData storage alive through an already-copied invocation after unregister.
  • Do not mutate native graph data during NativeGraphOutput.
  • Move durable logging/serialization out of the callback path through your own bounded value queue.

Generations and identity

  • Populate world, skeleton, and provider generation guards on stateful publications.
  • Pair weapon body/part identity with weaponGenerationKey.
  • Pair external body IDs with an addon-defined body generation.
  • Pair touch target IDs with a nonzero caller generation and increment it whenever the backing mechanism or match meaning changes.
  • Invalidate caches on lifecycle/equipped events and generation changes.
  • Never dereference or retain uintptr_t identity witnesses.
  • Never treat a numeric body ID as immortal or globally reusable.

Leases and ownership

  • Use the shortest practical nonzero lease and refresh deliberately.
  • Remember that a lease made at frame F for N frames is active while currentFrame < F + N.
  • Treat OwnerConflict as an ownership boundary, not a busy retry target.
  • Make publication replacement semantics explicit in your code; setters replace the owner's whole family state.
  • Clear state explicitly in reverse ownership order on normal shutdown.
  • Keep lease expiry as abnormal-loss protection, not normal cleanup.

Commands and streams

  • Persist command IDs until a terminal state/event arrives.
  • Do not report a queued request as completed interaction.
  • Cancel only before the command's committed stage; handle AlreadyCommitted honestly.
  • Maintain a cursor per event/contact stream and filter scope.
  • Advance to lastCopiedSequence, not blindly to the latest sequence when a page was truncated by buffer capacity.
  • Detect gap/overwrite flags and rebuild derived state from snapshots.
  • Never infer impulse magnitude from external contact weight.

Input

  • Derive button edges locally from fresh level samples and sample sequence.
  • Treat stale/unavailable samples according to availabilityReason.
  • Suppress only actions the product fully replaces.
  • Inspect caller and effective suppression state when behavior is shared.
  • Release input and offhand leases before disabling the feature.
  • Suppress native VATS release and V.A.N.S. hold independently unless the product intentionally consumes the complete Pause gesture.

Touch targets and world tools

  • Publish separate wildcard descriptors when two hands must resolve two different bodies.
  • Narrow wildcard layer/motion masks to the intended surfaces.
  • Wait for Yielded before scripted/native motion takes a held mechanism.
  • Respect the per-owner per-frame raycast budget and maximum distance.
  • Treat a successful raycast miss as a valid result, not an API failure.
  • Bind exact-hand requests to the current weapon and active handling lease.
  • Bind collider focus to the complete current weapon generation/body set.

Structures and values

  • Value-initialize every public structure with {}.
  • Preserve zero in all reserved fields.
  • Honor validity flags before reading optional transforms, vectors, IDs, or fields.
  • Use exact-size requirements for setters and getters that document them.
  • Use count/copy patterns with bounded storage and returned counts.
  • Ensure every published float/transform is finite.
  • Bound and null-terminate every public character buffer.

Performance

  • Cache table/capability/limit decisions once per provider session.
  • Cache weapon metadata by weapon generation and composition signature.
  • Use fixed arrays sized to public limits in callbacks.
  • Avoid repeated whole-buffer copies when a sequence/signature did not change.
  • Rate-limit diagnostics and disable overlay publication when not requested.
  • Never poll all optional surfaces every frame by default; read what the active product state needs.

Shutdown order

A typical stateful consumer shuts down in this order:

  1. Stop product state machines from publishing new work.
  2. Clear debug overlay, collider focus, touch scopes, and hand visual authority from the valid callback thread.
  3. Clear weapon drives/targets and animation/equipped-handling authority.
  4. Release input suppression and offhand reservation.
  5. Clear external child scopes/bodies.
  6. Cancel still-cancellable commands or mark committed ones for terminal drain.
  7. Unregister callbacks while retaining their backing storage long enough.
  8. Unregister the consumer owner.
  9. Clear the local API pointer/session cache.

Unregistering the owner revokes its provider resources, but explicit ordering keeps the visible transition controlled.

Validation matrix

At minimum, test these cases in addition to the happy path:

CaseExpected consumer behavior
ROCK DLL absentLoad without crashing; clearly disable dependent features.
Shorter V1 tableNever touch a missing slot; downgrade only affected features.
Capability deniedDisable that feature without retry spam.
Provider not readyWait for readiness/lifecycle transition.
World or skeleton generation changesStop stale writes and rebuild cached identity.
Callback unregister during dispatchNo use-after-free.
Consumer callback faultsProvider revokes state; consumer records/recovers safely.
Lease refresh stopsState expires and ROCK returns to its normal owner.
Stream ring overwritesGap is surfaced; derived continuous state is rebuilt.
Command cancellation races commitAlreadyCommitted is handled and terminal result is still observed.
External body ID is recycledOld generation is never accepted as the new body.
Equip/menu/world transitionNo writes while corresponding lifecycle permission is absent.
Touch target is yieldedNo body motion until Yielded; new acquisition waits for remove/republish.
Raycast budget exhaustedFeature degrades for the frame without an unbounded retry loop.
Collider focus weapon changesFocus invalidates and normal overlay returns.

Troubleshooting

SymptomFirst checks
Function pointer is nullDescriptor table bytes, named family extent, feature bit.
PermissionDeniedRequested capability versus granted mask.
WrongThreadMove the operation into an owner callback.
Repeated WorldNotReady / NotReady on guarded writesStop reusing old generation identity; rebuild publication from the latest snapshot.
Publication appears for one frameLease was not refreshed, or generation changed.
Input is still blocked after clearInspect effective state; another owner may hold a lease.
Part target unexpectedly gates all gripsAn exclusive target activated whitelist semantics; consider NonExclusive.
Drive resolves but does not winInspect application result and priority/owner arbitration.
No external contactsRegistration policy, row owner/scope token, capability pair, body ID/generation, collision availability.
Missing stream transitionsInspect gap/overwrite flags; increase drain cadence or page capacity within limits.
Authored authority active but no animationCheck runtime-provider availability, capture validity, and fault flags.
Hand visual call failsCallback thread, visual-writes flag, hFRIK/skeleton readiness, transform validity, priority/mask.