feat(scum): add map trajectory projection
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-28
|
||||
@@ -0,0 +1,3 @@
|
||||
# add-scum-map-trajectories
|
||||
|
||||
SCUM player and vehicle map trajectory projection
|
||||
@@ -0,0 +1,45 @@
|
||||
## Context
|
||||
|
||||
The existing SCUM player intelligence projection owns server-local identities and sessions, while the game-client bridge owns declared Companion snapshots and commands. Neither layer presents movement. The map must remain an explainable, bounded operational view and may not turn the browser into a route to raw logs, Run, game databases, or Companion sockets.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Collect only declared semantic position/vehicle transition events from a platform-managed Companion or accepted log projection.
|
||||
- Convert plugin-declared world coordinates into safe normalized map coordinates and retain only a sampled, bounded trail per server/entity.
|
||||
- Return a fixed bounded window with player/vehicle filters, vehicle-riding segments, data source, collection time, map version, and precision.
|
||||
- Enforce existing server authorization before resolving map status or trajectory data; preserve server isolation.
|
||||
- Render readable point and line trails with explicit empty and missing-map states and detail navigation contracts.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- OCR, screenshot parsing, mouse/keyboard injection, desktop automation, direct game-window access, direct sockets, direct database access, raw coordinate/database querying, indefinite retention, real-time all-server heatmaps, or raw log/browser delivery.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **A small typed event catalog is the only collector contract.** The SCUM manifest declares four semantic events: `player.position`, `vehicle.position`, `player.vehicle.enter`, and `player.vehicle.leave`. Every event includes a bounded entity ID, occurred time, collection time, source (`companion` or `log-projection`), and a plugin map ID/version. Position events carry only finite world X/Y values. They enter through the existing durable log/Companion snapshot channel, never browser-to-game traffic.
|
||||
|
||||
2. **Plugin map declaration defines the safe projection.** `mapTrajectories` in the manifest declares map ID/version, world bounds, image dimensions, axis orientation, sampling distance/time, and retention seconds. Platform validates it once, converts world coordinates to normalized 0–1000 map units, rounds to declared precision, and rejects mismatched map metadata or points outside declared bounds. The frontend receives no host path, original world coordinate, Companion endpoint, or raw record body.
|
||||
|
||||
3. **Project by server/entity/time with event identity and compression.** `GameMapTrackPoint` is unique by accepted event ID and is scoped by server plus entity kind/ID. Projection sorts logically by event time; duplicates are ignored, late points remain ordered in query results, and a point is retained only when it advances the declared sampling interval or distance (transitions are always retained). The repository filters time on server/entity indexes and prunes expired points and ride segments during projection and query.
|
||||
|
||||
4. **Derive riding intervals from enter/leave events.** A player enter opens one vehicle segment; entering a different vehicle closes the prior segment at the new event time. A leave closes only the matching active vehicle. Out-of-order and duplicate transitions cannot produce overlapping active segments. The map response projects these segments as player-associated vehicle trail intervals, not inferred ownership.
|
||||
|
||||
5. **Use a bounded read model instead of arbitrary map queries.** The API accepts a maximum 24-hour time window and at most 20 known player IDs plus 20 known vehicle IDs. It authorizes server access before lookup, verifies player IDs belong to that server, limits output points per entity, and returns map metadata plus empty/missing-map statuses. Vehicle IDs are only accepted if observed in the same server's declared vehicle snapshots or trajectory records.
|
||||
|
||||
6. **Keep detail linking as explicit identifiers.** Player trail summaries provide the existing `gamePlayerRecordId`; vehicles provide their safe vehicle ID and link intent. The frontend may navigate to the existing player selection/detail endpoint or invoke the pre-existing vehicle lookup context. It does not receive a route to Run, a raw query template, or vehicle storage details.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Companion cannot provide typed position events] → the map shows a clear collection-unavailable/empty state; no substitute screen or input automation is attempted.
|
||||
- [Map version changes] → points are queried only for the declared map version; mismatched events are rejected and the response explains the missing compatible map.
|
||||
- [High event volume] → server-side sampling, per-entity output caps, and retention pruning bound storage and response size.
|
||||
- [Late events] → query sorting and identity deduplication keep trails deterministic; transition rules avoid reopened or cross-vehicle overlap.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add model-first track/segment records, memory/file/MySQL persistence, projection, retention, and test coverage.
|
||||
2. Register the plugin map declaration and typed schemas; unsupported deployments remain visibly empty.
|
||||
3. Deploy the authorized API and console map. Existing player and vehicle views remain unchanged.
|
||||
4. Roll back by removing the map panel/declaration; expired projected records are pruned normally and no raw data needs migration.
|
||||
@@ -0,0 +1,23 @@
|
||||
## Why
|
||||
|
||||
SCUM operations currently show player identity and vehicle snapshots, but operators cannot explain where a selected player or vehicle has been over a bounded period. A server-scoped, permission-checked map projection is needed without exposing raw logs, Companion connectivity, host data, or arbitrary coordinate queries.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Define controlled SCUM Companion/log-projection events for `player.position`, `vehicle.position`, `player.vehicle.enter`, and `player.vehicle.leave`.
|
||||
- Require the plugin to declare map version, coordinate conversion, sampling precision, and retention policy; project accepted events into server-isolated trajectory records.
|
||||
- Add a bounded, authorized map API with time windows, player/vehicle filters, vehicle-riding segments, source/collection timestamps, and explicit missing-map/empty states.
|
||||
- Add a Chinese SCUM console map view with point-and-line trajectories and links to the existing player detail and vehicle context.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `scum-map-trajectories`: Controlled collection, projection, retention, authorization, and map rendering of SCUM player and vehicle trajectories.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affects platform domain/model/repository/service/validation/API DTOs and durable metadata snapshots.
|
||||
- Extends the SCUM plugin manifest and schemas with bounded map metadata and semantic trajectory events.
|
||||
- Adds platform-web API contracts and a shared-console map surface; it receives only safe projected coordinates and metadata.
|
||||
- Does not add OCR, screen/input automation, direct game/window access, raw logs, unbounded location retention, or live heatmaps.
|
||||
@@ -0,0 +1,59 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Controlled SCUM trajectory event contracts
|
||||
The system SHALL accept SCUM location information only as platform-managed Companion or accepted log-projection semantic events named `player.position`, `vehicle.position`, `player.vehicle.enter`, and `player.vehicle.leave`, each carrying bounded IDs, occurrence and collection timestamps, declared source, and matching map metadata.
|
||||
|
||||
#### Scenario: An undeclared or malformed location event arrives
|
||||
- **WHEN** an event has an unknown type, malformed bounded ID, non-finite coordinate, invalid source, or mismatched map declaration
|
||||
- **THEN** the system SHALL reject it from trajectory projection and SHALL not expose raw event material to the browser
|
||||
|
||||
### Requirement: Plugin-declared safe map conversion
|
||||
The SCUM plugin SHALL declare a map ID/version, coordinate transform/world bounds, sampling precision, and finite retention period. The platform SHALL convert accepted world points into a rounded safe map projection before persistence or API delivery.
|
||||
|
||||
#### Scenario: A point is outside declared map bounds
|
||||
- **WHEN** a valid position event has world coordinates outside the declared transform bounds
|
||||
- **THEN** the platform SHALL not persist or return a map point for that event
|
||||
|
||||
#### Scenario: Map metadata is absent
|
||||
- **WHEN** a server plugin has no compatible map declaration
|
||||
- **THEN** the map API and console SHALL return a readable missing-map state without attempting alternative collection
|
||||
|
||||
### Requirement: Ordered, sampled, and retained server-isolated trajectories
|
||||
The system SHALL index points by server, entity, and occurrence time; tolerate duplicate and out-of-order events; apply declared sampling compression; and remove points and closed ride segments after the declared retention period.
|
||||
|
||||
#### Scenario: Duplicate or delayed position event
|
||||
- **WHEN** the same accepted event is delivered twice or an older point arrives after a newer point
|
||||
- **THEN** the system SHALL retain no duplicate and SHALL return all accepted points ordered by occurrence time without regressing current sampling state
|
||||
|
||||
#### Scenario: A point is below the sampling threshold
|
||||
- **WHEN** a same-entity point occurs inside the declared minimum time and distance thresholds
|
||||
- **THEN** the system SHALL compress it rather than persist another display point
|
||||
|
||||
#### Scenario: Retention expires
|
||||
- **WHEN** normal projection or map retrieval occurs after a point or closed riding segment passes its retention deadline
|
||||
- **THEN** the system SHALL remove the expired record while preserving unrelated player identity and vehicle snapshot data
|
||||
|
||||
### Requirement: Vehicle ride association
|
||||
The system SHALL derive player vehicle segments from typed enter/leave events and SHALL close a prior active segment before opening a segment for a different vehicle.
|
||||
|
||||
#### Scenario: A player changes vehicles without a leave event
|
||||
- **WHEN** a player enters a second vehicle while a first vehicle segment remains active
|
||||
- **THEN** the system SHALL close the first segment at the second enter time and open one segment for the second vehicle
|
||||
|
||||
### Requirement: Authorized bounded map read model
|
||||
The system SHALL authorize server access before returning a maximum 24-hour trajectory window and SHALL expose only safe projected points, declared map metadata, collection/source labels, entity summaries, and detail-link identifiers. It SHALL not expose raw coordinates, raw logs, IPs, paths, credentials, host information, or Run/Companion connectivity.
|
||||
|
||||
#### Scenario: Unauthorized map request
|
||||
- **WHEN** a session lacks access to the requested server instance
|
||||
- **THEN** the API SHALL deny the request without revealing map availability, entity existence, or trajectory data
|
||||
|
||||
#### Scenario: Cross-server entity selector
|
||||
- **WHEN** a requested player or vehicle ID belongs only to another server
|
||||
- **THEN** the response SHALL not include its points or reveal the other server association
|
||||
|
||||
### Requirement: Explainable SCUM map console
|
||||
The SCUM console SHALL render declared map metadata, collection source/times, selected player and vehicle points/lines, ride segments, time and entity filters, and textual empty or missing-map states. Map entity interactions SHALL use the returned safe detail-link identifiers.
|
||||
|
||||
#### Scenario: An operator selects a trail entity
|
||||
- **WHEN** an operator selects a player or vehicle map item
|
||||
- **THEN** the console SHALL navigate or invoke the matching player/vehicle detail context using the returned identifier without constructing arbitrary coordinate or data queries
|
||||
@@ -0,0 +1,19 @@
|
||||
## 1. Specification and contracts
|
||||
|
||||
- [x] 1.1 Define the platform domain/model/repository contracts for declared map metadata, safe points, ride segments, bounded filters, and map read response.
|
||||
- [x] 1.2 Add SCUM manifest map declaration and typed semantic event schemas for position and vehicle transitions.
|
||||
|
||||
## 2. Platform projection and API
|
||||
|
||||
- [x] 2.1 Implement map declaration validation, safe coordinate conversion, sampling compression, event deduplication/order handling, ride-segment projection, and expiry pruning.
|
||||
- [x] 2.2 Add authorized server map route, named DTOs, and safe response mapping with time/entity bounds and missing-map state.
|
||||
- [x] 2.3 Add backend tests for conversion, duplicate/out-of-order events, cross-vehicle segments, filters, authorization, sampling, retention, and cross-server isolation.
|
||||
|
||||
## 3. Console
|
||||
|
||||
- [x] 3.1 Add frontend API/types/contracts and a shared-theme SCUM map component with time/player/vehicle filters, point/line trails, source/timestamp labels, and empty/missing-map states.
|
||||
- [x] 3.2 Wire safe player/vehicle detail interactions and add focused component/schema tests.
|
||||
|
||||
## 4. Verification
|
||||
|
||||
- [x] 4.1 Run relevant Go, plugin, and frontend tests/build; run `openspec validate add-scum-map-trajectories --strict` and `scripts/check-structure.sh`.
|
||||
Reference in New Issue
Block a user