feat(scum): add versioned gift grants

This commit is contained in:
npc0-hue
2026-07-28 16:40:35 +08:00
parent 4527175a6f
commit e2d0bc0595
26 changed files with 1224 additions and 14 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-28
@@ -0,0 +1,3 @@
# add-scum-versioned-gift-catalog
SCUM versioned gift catalog and directed delivery
@@ -0,0 +1,47 @@
## Context
The SCUM plugin already declares `reward.deliver`, and the prior game-player and player-state work owns server-local identity plus a durable approval/audit pattern. Neither establishes a platform-owned item catalog, immutable gift definition, or a reliable distinction between game delivery and player notification. This change adds those controls without extending browser access to raw game commands or connection material.
## Goals / Non-Goals
**Goals:**
- Persist server-version-fenced gift catalogs, revisions, and grants in model-first storage with memory/file/MySQL implementations.
- Permit only validated item catalog references in a gift revision; freeze the revision contents and game-player identity at grant creation.
- Require a platform administrator to approve delivery, dispatch only typed `reward.deliver`, and record delivery and notification outcomes separately.
- Give the Chinese SCUM console shared-theme workflows for draft editing, preview, player selection, confirmation, approval, and readable histories.
**Non-Goals:**
- Commerce, shops, payment, offline inventory/database editing, raw item codes or generator syntax in browser requests, arbitrary RCON text, bulk grants, map trails, auto-retry of unknown delivery, or auto-redelivery after notification failure.
## Decisions
1. **Catalog ownership and version fencing.** Platform defines a small verified SCUM item catalog keyed by exact game version. A revision stores item-catalog keys, labels, quantities, and an item-catalog version; service validation rejects unknown versions, absent items, duplicate lines, and quantities beyond catalog bounds. This is safer than exposing game item IDs in page forms or accepting a client-provided command payload.
2. **Draft then immutable revision.** A `gift_catalog` carries editable metadata and a draft revision; publishing creates an immutable `gift_revision` with a monotonic revision number. A `gift_grant` copies the selected revision ID plus a deep-frozen item snapshot and game-player record/ID/display-name snapshot. Editing or publishing later revisions therefore cannot change a queued grant.
3. **Explicit approval and idempotency.** Any server-authorized operator creates a `pending-approval` grant with a required idempotency key. A platform administrator with the same server access revalidates target, revision, version catalog, and online eligibility before dispatch. The grant ID is the bridge idempotency key, and a duplicate create request returns the original grant rather than producing another command.
4. **Delivery and notification are separate terminal facts.** `reward.deliver` success becomes `delivered`; command failure becomes `failed`; expiry/cancellation/missing result becomes `unknown`. Only after a confirmed delivery does Platform queue the declared targeted notification command. A notification error produces `notification_failed` while preserving the delivery result. No terminal grant, especially `unknown` or `notification_failed`, is automatically retried or redelivered.
5. **No raw command or secret boundary crossing.** The frontend posts catalog keys, revision IDs, player record IDs, a bounded notice template, and idempotency key only. Platform composes typed bridge payloads from durable records, and browser/API projections omit run credentials, RCON strings, item codes, raw bridge payloads, and host paths.
## Risks / Trade-offs
- [A server version has no verified item catalog] → Editing, publication, and grant approval are rejected with an explicit unsupported-version result.
- [A selected player is offline] → Grant approval is denied before delivery; the pending record remains auditable and does not dispatch.
- [The bridge reports delivery success but notification fails] → Preserve `notification_failed` and do not attempt another item delivery.
- [The bridge result is lost] → Persist terminal `unknown`, do not infer success, and require a deliberate later operator workflow rather than automatic retry.
- [Two callers repeat a request] → Enforce a server/requester/idempotency-key uniqueness check and reuse the prior grant.
## Migration Plan
1. Add model-first records and repositories, then wire file/MySQL snapshots with no existing data migration required.
2. Deploy typed plugin catalog/delivery/notification schemas and Platform service/API support together; versions without a verified item catalog stay unsupported.
3. Deploy the console after APIs are available; hide all raw command details behind the API contracts.
4. Roll back by disabling the console/command declarations; immutable revision and grant history remains readable and no automatic replay is performed.
## Open Questions
None. The initial SCUM version and item list are deliberately small and can be extended through a future reviewed catalog revision.
@@ -0,0 +1,26 @@
## Why
SCUM operators can invoke a one-off reward bridge command but cannot safely curate reusable gifts, freeze what was approved, or establish whether a targeted player received an item and its notification exactly once. A version-fenced gift workflow turns that raw capability into an auditable, least-privilege server-management operation.
## What Changes
- Add editable SCUM gift catalogs with immutable published revisions and items sourced only from the currently verified server-version item catalog.
- Add durable, approval-gated targeted gift grants that freeze the selected revision and game-player identity before dispatching the declared `reward.deliver` command.
- Track gift delivery and directed-notification results independently, including visible notification failures and terminal unknown delivery outcomes that are never retried automatically.
- Add safe Platform APIs, SCUM plugin schemas, and Chinese console workflows for catalog editing, revision preview, player selection, confirmation, approvals, and grant history.
## Capabilities
### New Capabilities
- `scum-versioned-gift-catalog`: Version-scoped SCUM gift definition, immutable revisions, approval-gated directed delivery, and safe operational history.
### Modified Capabilities
- None.
## Impact
- Affects Platform domain/model/repository/service/validation/API layers and durable metadata persistence.
- Extends the SCUM plugin's typed client-bridge declarations and schemas, plus Platform Web API contracts and SCUM player console.
- Does not introduce commerce, direct RCON/game connections, arbitrary item/generator commands, raw game credentials, or raw database writes.
@@ -0,0 +1,52 @@
## ADDED Requirements
### Requirement: Version-fenced gift catalog and revisions
The system SHALL let authorized SCUM server operators create and edit gift catalog drafts whose items reference only the Platform-verified item catalog for the server's exact game version. Publishing SHALL create an immutable, monotonically versioned revision, and the system MUST reject unknown versions, stale or invalid items, duplicate items, and out-of-range quantities.
#### Scenario: Publish validated draft
- **WHEN** an authorized operator publishes a draft containing only verified items for the current SCUM version
- **THEN** the system creates an immutable revision with its frozen item list and exposes it for preview and granting
#### Scenario: Reject invalid item
- **WHEN** a draft references an item absent from the verified item catalog for the selected SCUM version
- **THEN** the system rejects the change without creating a publishable revision
### Requirement: Frozen and idempotent targeted grant
The system SHALL create a durable grant from a selected published revision and local game-player record, freezing the revision contents and target identity before approval. A repeated request with the same scoped idempotency key MUST return the original grant and MUST NOT create another delivery command.
#### Scenario: Later catalog edit does not alter a grant
- **WHEN** an operator creates a grant and subsequently edits or publishes the gift catalog
- **THEN** the existing grant retains its original revision, item snapshot, and target identity snapshot
#### Scenario: Duplicate grant request
- **WHEN** a requester submits the same target/revision grant request again with the same idempotency key
- **THEN** the system returns the original grant and queues no duplicate delivery
### Requirement: Approved bounded game delivery
The system SHALL require a platform administrator with target-server access to approve a pending grant and SHALL dispatch only the declared typed `reward.deliver` bridge command assembled from the frozen grant. Approval MUST reject offline targets, invalidated catalog/revision data, and unauthorized callers.
#### Scenario: Offline player is not dispatched
- **WHEN** a platform administrator attempts to approve a grant for a player not present in the current online-player snapshot
- **THEN** approval is rejected and no delivery command is queued
#### Scenario: Authorized approval queues delivery
- **WHEN** a platform administrator approves a valid grant for an online local game player
- **THEN** the system records the approver and queues one typed delivery command using the grant identity as its idempotency key
### Requirement: Delivery and notification lifecycle safety
The system SHALL expose queued, delivered, notification_failed, failed, and unknown grant outcomes with readable audit evidence. A succeeded delivery followed by notification failure MUST remain visible as `notification_failed`; unknown delivery outcomes and notification failures MUST NOT automatically retry or redeliver items.
#### Scenario: Notification failure after delivered item
- **WHEN** the delivery command succeeds and the targeted-notification command fails
- **THEN** the grant is retained as `notification_failed` with the successful delivery evidence and failed notification evidence
#### Scenario: Unknown delivery is terminal
- **WHEN** a queued delivery command expires, is cancelled, or has no conclusive result
- **THEN** the grant becomes `unknown` and the system queues neither a retry nor another item delivery
### Requirement: Safe console and API projections
The system SHALL provide Chinese shared-console workflows for draft/version editing, item preview, local player selection, grant confirmation, approval, and history. Browser requests and responses MUST NOT contain raw game item codes, generator commands, arbitrary RCON text, run credentials, host paths, or direct game connection data.
#### Scenario: Safe grant submission
- **WHEN** an operator confirms a gift grant in the console
- **THEN** the browser submits only bounded catalog/revision, player-record, notice, and idempotency references and renders the returned readable lifecycle record
@@ -0,0 +1,21 @@
## 1. Versioned catalog and grant lifecycle
- [x] 1.1 Add verified SCUM item catalog, gift catalog/revision/grant domain and model types, repositories, migrations, and memory/file/MySQL persistence.
- [x] 1.2 Implement validation and service transitions for editable drafts, immutable revisions, frozen/idempotent grants, server/player ownership, online eligibility, and platform-admin approval/audit.
- [x] 1.3 Reconcile typed delivery and targeted notification results without automatic replay; retain queued, delivered, notification_failed, failed, and unknown outcomes.
- [x] 1.4 Add backend tests for frozen revisions, item/version validation, duplicate idempotency, offline targets, authorization/approval, notification failure, unknown results, and safe projections.
## 2. API and plugin contract
- [x] 2.1 Add named safe DTOs, authorized handlers/routes, and API tests for catalogs, revisions, grants, approval, and histories.
- [x] 2.2 Add SCUM item-catalog, reward-delivery, and targeted-notification typed bridge schemas/declarations and plugin validation tests.
## 3. SCUM console
- [x] 3.1 Add typed frontend API/contracts and shared-console Chinese catalog, revision preview, player selection, confirmation, approval, and history workflows.
- [x] 3.2 Add frontend tests for readable status/result rendering and absence of raw command/item/credential leakage.
## 4. Verification
- [x] 4.1 Run strict OpenSpec validation, focused backend, plugin, and frontend test suites, plus `scripts/check-structure.sh`.
- [x] 4.2 Stage only this task's files, commit on `main`, and push the configured remote.