feat(scum): add local game player intelligence

This commit is contained in:
npc0-hue
2026-07-28 15:23:09 +08:00
parent c5806cc6b7
commit 73947edcee
26 changed files with 1209 additions and 65 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-28
@@ -0,0 +1,57 @@
## Context
Platform already receives sequenced, durable runtime log batches and has a `game.scum` manifest that declares `scum.login` and `scum.logout` schemas. Those entries are queryable as logs but are not durable player-domain records. The new projection must remain local to a server instance, be safe to invoke as part of log ingestion, and not make raw network data browser-visible or persistent.
## Goals / Non-Goals
**Goals:**
- Persist independent game-player records keyed by server instance and SCUM player ID, with aliases, bounded sessions, access attempts, and review-only security signals.
- Project success login/logout semantics atomically and idempotently from accepted log entries, with sequence/event keys for duplicates and timestamp ordering for stale updates.
- Derive server-isolated correlation identifiers using an HMAC secret and a normalized source value, while retaining only the derived value.
- Offer permission-scoped, server-authorized management APIs and console records that never return IP values, raw source identifiers, secrets, raw log lines, or automatic enforcement controls.
- Retain access attempts and signals for a configurable bounded period and preserve player identity/session summaries after evidence expiry.
**Non-Goals:**
- Platform-user accounts, credentials, game database reads/writes, skill/attribute editing, gifts, map trails, or any automatic ban/kick/punishment.
- Changes to Run channels, direct host/socket/database access, or browser access to raw semantic log bodies.
## Decisions
1. **Use server-local game identity.** `game_player` is unique on `(server_instance_id, game_player_id)`; it has no foreign key to `user`. This prevents platform-console authentication from being mistaken for SCUM identity. An alias table records renamed display names with first/last-seen times.
Alternative considered: use display name as the identifier. It cannot safely handle player renames or duplicate names.
2. **Project only accepted SCUM semantic events in the ingestion transaction.** The log sequence (`log_stream_id`, `seq`) is the projection idempotency key. Login/open-session changes only apply when their event time is not older than the player's latest projected event; a logout closes the latest matching open session no later than its event time. Duplicate batches perform no second projection.
Alternative considered: asynchronous parsing of raw log lines. It would duplicate declared parsing rules, complicate order guarantees, and retain unnecessary sensitive content.
3. **Store only an HMAC-derived, server-scoped network correlation key.** A server-specific HMAC domain separator plus a process secret produces the correlation key. The source is never saved in models, logs, DTOs, or signal evidence. A digest is useful only within the same server and cannot be compared across servers.
Alternative considered: hash the raw IP directly. Unsalted hashes are reversible for common address spaces and correlatable across servers.
4. **Treat failures and anomalies as review evidence.** Failed login/connection event payloads create bounded `game_access_attempt` records. A threshold (five failures for the same fingerprint within fifteen minutes) creates or refreshes an `excessive-failed-access` signal; multiple player IDs sharing one server-local fingerprint create a `possible-alt-account` signal. Signals include text status and evidence counts, and have no action API.
Alternative considered: automatic moderation. It is excluded because heuristic evidence requires an operator review.
5. **Use existing session authorization and console primitives.** New endpoints use existing server read authorization. The frontend fetches named API contracts and renders an ordinary full-width shared table/record list with explicit status labels, never raw logs or a new page-local visual system.
## Risks / Trade-offs
- [A plugin payload omits a usable player ID] → Ignore the event for projection and retain normal log ingestion; validate only bounded known fields.
- [Late logout arrives after another login] → Close only a compatible open session whose start is no later than logout; never regress `lastSeenAt`.
- [Projection failure follows log body append] → Return the ingest error and retry the acknowledged range safely; event identity prevents duplicate records.
- [HMAC secret rotates] → Derived keys intentionally cease correlating across rotations; raw data is never recoverable. Deployment config keeps the secret stable during its intended retention window.
- [Evidence tables grow] → Perform retention pruning during projection/query and cap query limits.
## Migration Plan
1. Add model-first tables and repositories; existing installations begin with no projected players.
2. Deploy manifest schemas and Platform projection; only newly ingested declared events create records. Historical log backfill remains an explicit later operation.
3. Deploy APIs and console page after backend authorization is available.
4. Rollback by disabling the page and projection. Existing records contain no raw network data and can expire through normal retention cleanup.
## Open Questions
None. Initial thresholds and retention are conservative constants covered by tests and can become declared policy in a later change.
@@ -0,0 +1,23 @@
## Why
SCUM login semantics are currently retained only as operational logs, so operators cannot safely review a local player's identity history, sessions, or suspicious access behavior. A server-scoped game-player projection turns declared SCUM login/logout events into reviewable evidence without conflating game identities with platform users or exposing network data.
## What Changes
- Add a server-scoped local game-player domain with aliases, sessions, access attempts, and review-only security signals.
- Project declared `scum.login` and `scum.logout` semantic log events idempotently, including duplicate, renamed-player, out-of-order, and session-boundary handling.
- Derive a server-isolated irreversible network correlation fingerprint; do not persist raw IP addresses or raw fingerprints.
- Add authenticated player-profile, aliases, access-trajectory, and security-signal APIs plus SCUM console contracts and records.
- Define bounded retention and manual-review semantics for access evidence and risk signals.
## Capabilities
### New Capabilities
- `scum-game-player-intelligence`: Server-local SCUM player identities, event projection, privacy-preserving access evidence, and review-only risk signals.
## Impact
- Affects Platform domain/model/repository/service/API/validation layers and durable metadata storage.
- Affects the SCUM plugin semantic-event schemas and page declaration, plus Platform Web API contracts, routing, and shared-console records.
- Adds no Platform account authentication, direct game-database access, raw network data, automatic moderation, Run protocol, or host/executor data exposure.
@@ -0,0 +1,51 @@
## ADDED Requirements
### Requirement: Server-local game-player identity
The system SHALL maintain a game-player identity independently of platform users, uniquely scoped by `serverInstanceId` and immutable game-player ID, with bounded display-name alias history.
#### Scenario: A known game player logs in under a new name
- **WHEN** a successful declared SCUM login contains an existing player ID and a different valid display name
- **THEN** the system SHALL update the player's current display name and retain the previous and new names as server-local aliases
### Requirement: Idempotent semantic login/logout projection
The system SHALL project accepted `scum.login` and `scum.logout` semantic events using a durable event identity and SHALL tolerate duplicate and out-of-order delivery without creating duplicate access evidence or regressing player state.
#### Scenario: A duplicate login event is received
- **WHEN** the same accepted log stream sequence is ingested again
- **THEN** the system SHALL return the normal duplicate acknowledgement and SHALL not create an additional session or alias record
#### Scenario: A stale logout arrives after a later login
- **WHEN** a logout event is older than the player's latest successful login
- **THEN** the system SHALL only close an eligible earlier open session and SHALL not overwrite the newer player last-seen state
### Requirement: Privacy-preserving access evidence
The system SHALL persist no raw IP address, raw network fingerprint, host path, credential, or raw sensitive log content in game-player access records or browser-visible responses. Network correlation SHALL be derived as an irreversible value scoped to one server instance.
#### Scenario: An access event carries a source address
- **WHEN** a SCUM event contains a source address or network identifier
- **THEN** the system SHALL use it only to derive a server-isolated correlation value and SHALL omit the source value from stored models and API responses
### Requirement: Review-only risk signals
The system SHALL create bounded security signals for thresholded failed access and possible shared-fingerprint identities, and SHALL expose them as manual-review evidence only.
#### Scenario: Repeated failed access crosses the threshold
- **WHEN** five failed attempts with one server-local correlation value occur within fifteen minutes
- **THEN** the system SHALL create or refresh an excessive-failed-access signal with an explicit textual review status and evidence count
#### Scenario: An operator reviews a signal
- **WHEN** an authorized operator reads a player security signal
- **THEN** the response SHALL contain no automated enforcement command, raw network identifier, or raw log line
### Requirement: Authorized player intelligence console
The system SHALL provide server-authorized player profile, aliases, sessions, access-attempt, and security-signal responses through named contracts, and the SCUM console SHALL render labels and status text rather than relying only on color.
#### Scenario: An unauthorized user requests server player data
- **WHEN** a platform session lacks read access to the requested server instance
- **THEN** the player intelligence API SHALL deny access without revealing whether a game-player record exists
### Requirement: Bounded evidence retention
The system SHALL retain access attempts and active security evidence for a bounded period, prune expired evidence during normal service operations, and keep independent player identity history intact.
#### Scenario: Evidence is older than the retention limit
- **WHEN** a query or projection runs after an access attempt exceeds the retention period
- **THEN** the system SHALL remove the expired attempt and any expired non-active signal evidence without deleting the game-player identity
@@ -0,0 +1,21 @@
## 1. Domain and persistence
- [x] 1.1 Add server-local game-player, alias, session, access-attempt, and security-signal domain/models, repositories, MySQL migration, memory/file stores, validation, and retention helpers.
- [x] 1.2 Add idempotent SCUM login/logout and failed-access projection from accepted semantic log entries, including rename, duplicate, stale event, session boundary, isolated HMAC correlation, and review-only signal thresholds.
- [x] 1.3 Add focused domain/service/repository tests for privacy, ordering, idempotency, access control, retention, aliases, sessions, and risk signals.
## 2. APIs and plugin contract
- [x] 2.1 Add named request/response DTOs, authorized handlers/routes, safe projections, and API tests for player profiles, lists, aliases, sessions, attempts, and signals.
- [x] 2.2 Extend the SCUM manifest semantic schemas/page contract for bounded player intelligence and add plugin validation fixtures/tests.
## 3. SCUM console
- [x] 3.1 Add Platform Web API/client contracts and route resolution for the SCUM player intelligence work surface.
- [x] 3.2 Render full-width shared-console player records, access trajectories, and manual-review signals with explicit text status and no raw network/log exposure.
- [x] 3.3 Add frontend contract/component tests for safe rendering and status readability.
## 4. Verification
- [x] 4.1 Run strict OpenSpec validation and focused backend, plugin, and frontend test suites.
- [ ] 4.2 Run `scripts/check-structure.sh`, stage only task files, commit on `main`, and push the configured remote.