Card grants produce a post-state-total entry and run the CardCosmeticReward
cascade (foil twin → id-1 lookup). Cascade additions are skipped when the
viewer already owns the cosmetic; missing-master-row failures are logged
and dropped without failing the parent grant.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sleeve/Emblem/Skin/Degree/MyPageBG grants are idempotent on the viewer's
owned-collection but always emit a wire entry at the top level (preserves
"+1 sleeve" purchase popup). Unknown ids throw InventoryCatalogException.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Crystal/Rupy/RedEther/SpotCardPoint grants mutate ViewerCurrency in place
and emit post-state-total wire entries. Op log records the post-state for
later currency-collision resolution in CommitAsync.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Includes Cards/Sleeves/Emblems/LeaderSkins/Degrees/MyPageBackgrounds/Items
under AsSplitQuery, plus caller-supplied extras via InventoryLoadConfig.
Opens a DB transaction and returns an InventoryTransaction shell. All
mutation methods throw NotImplementedException until subsequent tasks
land them.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Empty interfaces + records for IInventoryService, IInventoryTransaction,
InventoryCommitResult, InventoryLoadConfig, InventoryCatalogException.
Implementation lands in subsequent commits.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>