refactor(scum): use runtime capability probes

This commit is contained in:
npc0-hue
2026-07-29 18:34:16 +08:00
parent 03339fb3e8
commit d7465bfd32
26 changed files with 530 additions and 533 deletions
@@ -1,81 +1,29 @@
## Context
## Design
The current SCUM work has a generic platform command/log bridge, but the five SCUM feature areas are implemented as SCUM-named services, models, API handlers, and React panels in `platform/` and `platform_web/`. The SCUM plugin only declares schemas and command names. Its Companion can register, heartbeat, claim, acknowledge, complete, and upload snapshots, but has no long-running dispatcher, SCUM command handlers, semantic-log uploader, or event collector.
The platform owns only reusable authorization, server isolation, auditing,
queues, opaque storage, and channels to Run. The SCUM plugin owns its page,
allowlists, schemas, event parsers, and Companion adapters. `platform_web`
mounts the declared plugin page generically.
The repository requires platform/run communication to remain channelized and forbids plugins from receiving credentials, raw host paths, direct sockets, or raw AI keys. The referenced legacy SCUM client uses OCR and keyboard/mouse automation, which is explicitly excluded from the trajectory feature and is not an acceptable replacement adapter.
Run emits SCUM process stdout/stderr records through the durable log channel;
these are not server execution logs. The Companion parses only declared,
bounded record formats into semantic events. Unknown records make a bounded
diagnostic and are skipped. A per-server correlation digest may be derived
locally but never includes a raw network value in an upload.
## Goals / Non-Goals
The Companion receives only typed commands and invokes only registered typed
ports. Its game-data port exposes allowlisted player, vehicle, and position
data as bounded projections, never DSNs, paths, credentials, or rows. Fixed
server-management ports expose only declared operations. State changes read
the precondition, verify a safe window, write allowed fields, then confirm the
write. Reward delivery freezes a grant and maps each receipt to delivered,
failed, or unknown without retrying unknown outcomes. A command's failure or
unknown result affects that command alone.
**Goals:**
Runtime capability/schema probes decide whether a particular handler is
available. They do not depend on a server/game/UE4SS/database version, build,
or source revision, and a failed probe never disables unrelated features.
- Make `plugins/examples/scum-server-plugin/` the owner of SCUM configuration semantics, feature APIs/types/UI, Companion behavior, event parsing, coordinate transforms, and command adapters.
- Keep `platform/` limited to reusable plugin primitives: authorization, server isolation, plugin-scoped opaque record storage, review/audit, typed command transport, durable log transport, retention scheduling, and plugin-bundle hosting.
- Establish a safe long-running Companion protocol that handles only declared typed commands, emits declared semantic events, and never exposes raw game/database/network data to the browser.
- Migrate without discarding existing records until equivalent plugin-owned reads and writes have been verified.
**Non-Goals:**
- Reintroducing `scum_robot`, `scum_client`, direct game-database access, OCR, screenshots, keyboard/mouse injection, desktop automation, or unrestricted RCON/SQL/JSON commands.
- Adding payment, QQ/SMS, cloud, or other legacy robot services.
- Automatically banning, punishing, or retrying unknown item-delivery outcomes.
- Claiming support for a SCUM version/operation before a versioned adapter has integration evidence.
## Decisions
### 1. Plugin-owned feature modules, generic platform primitives
SCUM feature contracts, validators, repository adapters, Companion handlers, and UI modules SHALL live under the SCUM plugin directory. The platform SHALL provide generic names and opaque/plugin-scoped payloads rather than SCUM-named domain services or routes.
The alternative of retaining SCUM services in the platform makes a manifest-only plugin easy to render but permanently couples every SCUM release to the platform binary. It is rejected because it is the ownership failure being corrected.
### 2. Plugin page bundles mounted by a generic host
The SCUM plugin SHALL declare a versioned page-bundle entry and page contracts. `platform_web` SHALL authenticate, load the declared bundle through a generic plugin-page host, and provide shared theme/navigation/permission context. It SHALL not import SCUM component classes or branch on `game.scum`.
The alternative of metadata-only generic forms is insufficient for the map, player timeline, gift preview, and controlled attribute workflow. The alternative of a standalone plugin web application is rejected because it would bypass platform session, tenancy, and theme integration.
### 3. Long-running SCUM Companion adapter
The Companion SHALL run a bounded dispatch loop after registration. It SHALL claim declared commands, validate the exact command schema and SCUM capability/version, execute only a registered handler, and acknowledge/completely report idempotent typed results. It SHALL produce no output containing raw paths, credentials, IPs, database rows, or arbitrary RCON command text. A version-bound typed UE4SS adapter MAY record the exact generated command text in the command's protected audit payload (for example, the fixed `#spawnvehicle <vehicleCode>` generated by `vehicle.spawn`); that audit record does not create a browser-visible or arbitrary-command RCON interface.
The adapter SHALL include independent handlers for configuration read/patch, semantic log/event production, `reward.deliver`, `player.notify`, `game-state.patch`, and the separately bounded `vehicle.spawn`. A handler unavailable for a discovered server version SHALL return an explicit unsupported result; the platform must keep the operation disabled.
Direct raw-RCON or raw-SQL dispatch is rejected: legacy code is reference material only and must be translated into narrow typed adapters.
### 3.1 Fixed vehicle-spawn adapter
`vehicle.spawn` is the sole authorized exception for a generated SCUM command template. Its manifest payload contains exactly one `vehicleCode`, constrained by the plugin's versioned allowlist and identifier pattern. The Companion independently validates the same allowlist, requires its bound server, approval, declared handler capability, pinned UE4SS 3.0.1 build, and pinned reference revision before calling a Companion-local, platform-authorized vehicle-spawn transport port.
The adapter itself creates the exact `#spawnvehicle <vehicleCode>` string and holds it only in a private transport/audit field. It accepts no command text, prefix, extra argument, target, shell text, SQL text, host path, socket, RCON credential, or reply text from callers. The pinned reference removes one leading `#` before dispatch, but the adapter does not infer completion from that implementation's unstructured response. The port returns a bounded receipt that the adapter maps to `succeeded`, `failed`, or `unknown`; unknown is never retried automatically. The plugin UI exposes only catalogued choices and enables its action only when the Companion reports the declared handler available.
### 4. Declared semantic event pipeline
The Companion SHALL parse only plugin-declared allowed log/extension sources and upload contiguous typed semantic event batches using the durable log channel. Login/logout, player/vehicle position, and vehicle transitions SHALL be emitted only when their source and required fields can be validated. Map coordinate conversion, sampling, and retention declarations remain SCUM-plugin configuration.
The platform may persist and query events as opaque plugin records for isolation and retention, but it SHALL not contain SCUM-specific parsers or projectors. Events without a verified producer SHALL remain unavailable in the plugin UI rather than being simulated from test data.
### 5. Staged migration and compatibility
Migration SHALL proceed feature by feature behind a plugin capability/version flag. Platform-owned SCUM records are read-only migration input until the plugin module has parity tests and at least a controlled end-to-end Companion test. The generic platform host is switched only after the plugin bundle is available; SCUM-specific platform routes/components are removed only after no remaining callers exist.
## Risks / Trade-offs
- [SCUM may not expose a safe API for a requested operation] → require capability/version discovery and show disabled/unsupported, never fall back to raw DB writes or automation.
- [Plugin bundle isolation introduces a loading/deployment surface] → version page bundles with the manifest, verify integrity, and fail closed to an unavailable-page state.
- [Record migration can lose audit traceability] → preserve immutable audit linkage and migration provenance; do not bulk-delete old records before retention expiry and parity verification.
- [Semantic log formats can drift with SCUM updates] → version parser adapters, keep fixtures from supported formats, and reject unknown formats without inventing fields.
- [Moving too much out of platform duplicates security logic] → keep authorization, tenancy, queue, audit, and storage primitives generic and platform-owned.
## Migration Plan
1. Add generic plugin-page bundle and plugin-scoped record/event/command primitives without new SCUM-specific platform APIs.
2. Create the SCUM feature module and Companion dispatcher with read-only diagnostics and event-producer proof.
3. Migrate configuration and player/event reads, then gifts and state patches behind capability/version gates.
4. Replace the hard-coded SCUM imports in the platform host with the generic mount; run compatibility and end-to-end tests against an isolated non-production server.
5. Remove SCUM-named platform services/routes/models only after plugin parity, migration audit, and a rollback window. Rollback keeps the prior platform records read-only and disables the plugin capability flag; it never re-enables unsafe execution paths.
## Open Questions
- Which current SCUM server versions and legitimate extension/log sources can produce player position and vehicle transitions without OCR or input automation?
- Which skill/attribute and reward operations have a safe, documented, version-bound server-side adapter rather than legacy direct database mutation?
- Should plugin bundles be compiled from TypeScript into the manifest package or loaded as signed static artifacts from the plugin registry? The implementation must choose one before frontend migration begins.
`vehicle.spawn` is the one fixed administration template. It accepts only a
catalogued identifier and builds exactly `#spawnvehicle <vehicleCode>` inside
the Companion. The text stays private to its typed transport/audit boundary.
@@ -1,73 +1,17 @@
# Verified implementation blockers
## Runtime probe evidence
Checked 2026-07-29 against the pinned read-only UE4SS reference at
`bae91527355f14faa63c1df65f742cc48594ba1b` (UE4SS 3.0.1). The accompanying
capability evidence is recorded in
`plugins/examples/scum-server-plugin/companion/UE4SS_CAPABILITY.md`.
The former UE4SS reference/build/revision requirement has been removed. SCUM
features are not disabled by an update string. The Companion uses typed,
platform-authorized non-production fixtures for configuration, player-state,
reward, notification, and vehicle operations; no remote server is contacted.
The reference offers a fixed, online-recipient `SendChat` path, which is
already bounded by the supported `player.notify` adapter. It also removes one
leading `#` before dispatching a command, but its raw response is not a stable
operation acknowledgement. Under the separately authorized fixed-template
exception, the plugin's `vehicle.spawn` adapter can generate only
`#spawnvehicle <vehicleCode>` from its allowlist through a local authorized
transport port and maps its bounded receipt to success, failure, or unknown.
It is not a general RCON surface. The reference otherwise has no versioned
server-side schema, identity binding, acknowledgement contract, or isolated
non-production fixture for login/logout events, network correlation, position
or vehicle events, reward delivery, or state reads and writes.
Run's required integration boundary is a bounded stdout/stderr record stream,
typed database projections, and fixed administration ports. It must not expose
paths, DSNs, credentials, raw rows, arbitrary SQL, shell, socket, or RCON to
the plugin, platform web, or AI. Unknown console formats create a bounded
diagnostic and no event.
Controlled read-only migration fixtures now verify configuration, player
history, gifts, state-patch audits, and trajectories in
`plugins/tests/fixtures/scum-migration-parity.ts`. They preserve only
allowlisted plugin fields and maintain transition provenance. The existing
isolated Companion tests continue to cover its safe command boundary. Neither
test set provides an end-to-end SCUM executor or event producer.
Consequently these tasks remain open and blocked rather than simulated:
- 4.14.4: no legitimate versioned event producer exists for semantic player,
network, position, or vehicle data.
- 5.1 and 5.3: no documented, version-bound state-patch or reward-delivery
adapter exists.
- 6.2: controlled read-only migration fixtures and isolated Companion
typed-port coverage now exist for the supported configuration, notification,
and vehicle-spawn adapters, but no legitimate versioned producer exists for
the remaining player-history, reward, state-patch, or trajectory parity.
- 6.3: transitional SCUM APIs and models still have callers and cannot be
removed before the parity and rollback evidence required by 6.2.
- 6.4: final full verification is deferred until the blocked adapters and
isolated integration environment exist.
No fallback to raw RCON, credentials, SQL, direct game-database access, OCR,
screenshots, keyboard/mouse injection, or desktop automation is permitted.
## 6.3 frontend cleanup and rollback evidence (2026-07-29)
The generic `PluginPageHostPage` has no hard-coded SCUM import or `game.scum`
branch. Static `rg` call-graph audit found zero non-test callers for the
following former `platform_web` implementation, so this batch removed it with
its private tests, contracts, schemas, API-client methods/types, and map-only
styles:
- `ScumOperationsPanel`, `ScumFileConfigWorkbench`, and the private
`scumOperations` contract/schema;
- `GamePlayerIntelligencePanel` and `GameGiftCatalogPanel`;
- `ScumMapTrajectoryPanel`.
Their plugin-owned replacement is `features/page.ts`, with typed bridge reads
and commands in `features/api.ts`, and the read-only provenance adapters in
`features/migration.ts`. The replacement remains capability-gated: missing
login/position event producers and missing state-patch/reward-delivery
handlers render unavailable controls and never synthesize records or enable a
fallback execution path.
The platform-side `/game-players`, `/game-gifts`, and `/game-map-trajectories`
routes, DTO/domain/model/service/repository implementations, and their
fixtures remain intentionally. `plugins/tests/fixtures/scum-migration-parity.ts`
continues to consume their historical record shapes through allowlisted,
`transitional-read-only` migration records. Rollback therefore consists of
disabling the exact server/version plugin authority flag, leaving those prior
records visible and read-only; it does not restore any deleted host panel or
re-enable an unsafe execution route. Backend removal remains blocked until 6.2
parity and the required versioned event/operation protocols exist.
Remaining production enablement is operational: a deployed Run implementation
must provide the declared typed ports. Until then only the affected operation
is reported unavailable; the plugin page and unrelated feature capabilities
remain active.
@@ -1,30 +1,23 @@
## Why
The five recent SCUM deliveries implemented most SCUM-specific domain services and React panels in `platform/` and `platform_web/`, leaving the SCUM plugin as a manifest and schema declaration. This makes the plugin non-portable, hard-codes SCUM into the platform host, and does not provide a real server-side adapter that can collect events or execute approved game operations.
SCUM plugin behavior must survive server updates without treating a game, UE4SS,
database, build, or revision string as a feature kill switch. The prior plan
incorrectly used static compatibility gates.
## What Changes
- Move SCUM-specific feature ownership for configuration, local game-player intelligence, controlled player state changes, gifts, and map trajectories into the SCUM plugin package and its Companion runtime.
- Introduce a long-running, platform-authorized SCUM Companion adapter that receives only typed commands, emits only declared semantic events, and reports typed, idempotent results.
- Add one explicitly enabled, version-bound `vehicle.spawn` operation. It accepts only plugin-catalogued vehicle codes and can generate only the fixed `#spawnvehicle <vehicleCode>` template through a Companion-local, platform-authorized transport port; it is not a raw-RCON interface.
- **BREAKING** Replace platform-owned SCUM panels and SCUM-specific API/domain endpoints with a plugin-page module mounted by the generic platform plugin host.
- **BREAKING** Replace platform-owned SCUM projections and persistence with plugin-scoped local data accessed through generic platform isolation, audit, job, and storage primitives.
- Preserve the existing platform responsibilities for authorization, server/tenant isolation, review and approval, durable job delivery, audit records, retention enforcement, and generic page hosting.
- Treat current platform-side implementations as transitional control-plane behavior; do not claim an operation is available until the Companion has a verified executor or event producer.
- Move all SCUM feature authority to the plugin and its Companion, with generic
platform authorization, isolation, audit, queue, storage, and Run channels.
- Replace build/version/revision gates with runtime schema and capability probes.
- Let Run provide bounded SCUM stdout/stderr records, typed database reads, and
fixed administration operations only through platform-authorized channels.
- Require field allowlists, pre-read/safe-window/write-confirmation flows, and
`succeeded`/`failed`/`unknown` results for mutating adapters.
- Preserve fixed-template `vehicle.spawn`; its private `#spawnvehicle
<vehicleCode>` audit text never enters a result or page payload.
## Capabilities
## Non-Goals
### New Capabilities
- `scum-plugin-feature-ownership`: Defines the required ownership boundary between the generic platform and the SCUM plugin, including plugin-page mounting and migration of the five SCUM feature areas.
- `scum-companion-runtime-adapter`: Defines the safe, typed Companion command/event adapter needed for real SCUM operation execution and semantic event collection.
### Modified Capabilities
- None. The prior SCUM requirements currently exist only in completed change artifacts, not in the repository's canonical `openspec/specs/` tree; this change establishes their replacement canonical contract.
## Impact
- Affected roots: `plugins/examples/scum-server-plugin/`, `plugins/sdk/`, `platform/`, and `platform_web/`.
- The SCUM Companion becomes the only place that translates approved typed operations into SCUM/RCON/legitimate-extension work and translates server signals into semantic events.
- Existing SCUM-specific platform APIs, models, services, and hard-coded frontend panels will require a staged migration with compatibility checks; unrelated platform and plugin behavior remains out of scope.
No arbitrary RCON, SQL, shell, socket, path, DSN, credential, raw database
row, OCR, screenshot, keyboard/mouse injection, or desktop automation is
introduced. No SCUM import or `game.scum` branch is added to `platform_web`.
@@ -1,45 +1,52 @@
## ADDED Requirements
### Requirement: Companion dispatches only declared typed SCUM operations
The SCUM Companion SHALL run a bounded authenticated command-dispatch loop and SHALL execute only command types declared by the installed SCUM plugin, validated against their payload schema, server binding, permission/approval result, and compatible SCUM capability/version. It SHALL return an idempotent typed result for every claimed command.
### Requirement: Companion uses runtime capability isolation
#### Scenario: Supported gift delivery command
- **WHEN** the Companion claims a valid, unexpired `reward.deliver` command for a server version with a registered delivery handler
- **THEN** it executes only that handler and completes the command with a typed delivered, failed, notification-failed, or unknown result
The SCUM Companion SHALL dispatch only declared typed handlers bound to its
authorized server. Handler availability SHALL come from runtime capability and
schema probes, not a game, UE4SS, database, build, revision, or version gate.
A probe or command failure SHALL affect only that handler invocation.
#### Scenario: Unsupported or malformed command
- **WHEN** the Companion claims a command whose type, schema, capability, or version is not supported
- **THEN** it does not invoke SCUM, RCON, a database, OCR, or desktop automation and completes the command with an explicit unsupported or validation failure result
#### Scenario: A runtime adapter is unavailable
### Requirement: Vehicle spawn uses one fixed, version-bound template
The SCUM Companion SHALL execute `vehicle.spawn` only when the installed plugin declares it, the bound server is approved, the Companion reports its handler available, and the pinned UE4SS 3.0.1 build/reference revision is present. The payload SHALL contain exactly one plugin-allowlisted vehicle code matching the declared identifier pattern. The adapter SHALL generate exactly `#spawnvehicle <vehicleCode>` internally and SHALL retain that text only in protected transport/audit data. It SHALL not accept or expose raw command text, additional arguments, targets, RCON credentials, sockets, shell/SQL text, host paths, or raw transport replies. It SHALL return a structured `succeeded`, `failed`, or `unknown` outcome and SHALL not automatically retry an unknown outcome.
- **WHEN** a typed port or schema probe is unavailable
- **THEN** the Companion returns a typed unavailable/failed/unknown result for
that command and does not disable an unrelated plugin feature
#### Scenario: Approved, supported vehicle spawn
- **WHEN** an approved `vehicle.spawn` command carries a declared vehicle code for the pinned UE4SS adapter and the local authorized transport reports acceptance
- **THEN** the Companion sends only the internally generated fixed template, completes with a structured `succeeded` outcome, and omits the generated text from the command result
### Requirement: Run data channels are bounded
#### Scenario: Unsafe vehicle-spawn input or unavailable handler
- **WHEN** a vehicle-spawn payload has an unlisted code, extra field, command text, target, credential, or the Companion has not declared the compatible handler
- **THEN** the Companion performs no transport call and returns validation-failed or unsupported without exposing protected audit text
Run SHALL send SCUM stdout/stderr records to the Companion through the durable
log channel and SHALL provide database data only as typed allowlisted
projections and fixed server-management operations. No plugin, web page, or
AI request SHALL receive a path, DSN, credential, raw row, arbitrary SQL,
shell, socket, or RCON command.
### Requirement: Companion emits validated semantic SCUM events
The SCUM Companion SHALL collect only declared allowed sources and upload contiguous semantic event batches through the platform's durable log channel. It SHALL validate required event fields before upload and SHALL not emit raw IP addresses, network fingerprints, host paths, credentials, database rows, screenshots, or arbitrary RCON command text. A version-bound typed UE4SS adapter MAY retain the exact generated command text in protected command audit data; it SHALL never expose that text as a general RCON command surface or semantic event payload.
#### Scenario: Unknown console output
#### Scenario: Valid login event
- **WHEN** a supported SCUM source produces a successful-login record containing the declared player identity and timestamp fields
- **THEN** the Companion uploads a validated `scum.login` semantic event and the plugin can create or update the local game-player profile
- **WHEN** stdout or stderr does not match a declared semantic parser
- **THEN** the Companion records a bounded diagnostic and uploads no semantic
event or raw line
#### Scenario: Unknown source format
- **WHEN** a log or extension source does not match a supported parser version or lacks required fields
- **THEN** the Companion records a bounded diagnostic and does not fabricate a semantic login, position, vehicle, or security event
### Requirement: Mutations prove safety
### Requirement: Map event collection remains controlled
The SCUM Companion SHALL emit `player.position`, `vehicle.position`, `player.vehicle.enter`, and `player.vehicle.leave` only from a verified legitimate server-side source declared by the plugin. The plugin SHALL apply its declared coordinate transform, sampling precision, and retention policy before exposing trajectory data.
State patch adapters SHALL use field allowlists, a pre-read, safe-window
verification, a bounded write, and read-after-write confirmation. Reward
adapters SHALL freeze their typed grant and return delivered, failed, or
unknown without automatically retrying unknown outcomes.
#### Scenario: Position source is unavailable
- **WHEN** no supported server-side source can provide a validated player or vehicle position
- **THEN** the trajectory page reports collection unavailable and does not use OCR, screenshots, keyboard/mouse injection, client-screen reading, or inferred synthetic tracks
#### Scenario: Confirmation cannot be established
#### Scenario: Cross-server isolation
- **WHEN** events are emitted for two bound SCUM servers
- **THEN** the Companion tags each batch with its bound server identity and no trajectory, player, or vehicle data from one server is returned for the other
- **WHEN** a typed write or post-write read cannot establish success
- **THEN** the Companion returns `unknown` and does not repeat the operation
### Requirement: Vehicle spawning remains fixed
`vehicle.spawn` SHALL accept only a catalogued vehicle code and create exactly
`#spawnvehicle <vehicleCode>` inside the Companion. Protected audit text SHALL
not be present in command results or browser payloads.
#### Scenario: Unsafe spawn input
- **WHEN** input includes an unlisted code, an extra field, command text, SQL,
a path, credential, socket, shell text, or RCON text
- **THEN** no transport call occurs and validation fails
@@ -1,38 +1,37 @@
## ADDED Requirements
### Requirement: SCUM feature ownership is plugin-local
The system SHALL place SCUM-specific configuration semantics, player/gift/map/state-patch behavior, schemas, validators, Companion handlers, and feature UI modules in the SCUM plugin package. The platform SHALL expose only generic authorization, isolation, audit, storage, queue, retention, and plugin-host primitives and SHALL NOT add new SCUM-named domain services, API handlers, or frontend panels.
#### Scenario: A new SCUM capability is added
- **WHEN** a SCUM-specific configuration field, event type, command, or view is introduced
- **THEN** its implementation and tests are added to the SCUM plugin package while the platform change, if any, is reusable by non-SCUM plugins
The SCUM plugin SHALL own SCUM schemas, allowlists, migration adapters,
Companion behavior, and feature UI. The platform SHALL retain only reusable
authorization, isolation, auditing, queues, storage, and generic plugin-host
primitives. `platform_web` SHALL not import SCUM code or branch on `game.scum`.
#### Scenario: Existing platform SCUM code is migrated
- **WHEN** an existing SCUM service or panel is replaced by its plugin equivalent
- **THEN** the platform retains only a generic primitive and no hard-coded `game.scum` branch or SCUM component import remains in the plugin host
#### Scenario: Page mounting
### Requirement: Plugin-owned pages mount in the platform host
The SCUM plugin SHALL declare versioned page-module entries and their required permissions/capabilities. The platform web host SHALL mount the declared module inside the existing authenticated themed shell and SHALL pass only server-scoped, permission-filtered host context.
- **WHEN** an authorized administrator opens the installed plugin route
- **THEN** the generic host mounts the declared plugin bundle with only
server-scoped permission context
#### Scenario: Authorized administrator opens a SCUM page
- **WHEN** an administrator with the declared permission opens a SCUM plugin route for an assigned server
- **THEN** the host loads the SCUM-declared page module with that server-scoped context and does not use a platform-owned SCUM page implementation
### Requirement: Feature availability is runtime scoped
#### Scenario: Page module is unavailable or incompatible
- **WHEN** the declared SCUM page bundle fails integrity/version/capability validation
- **THEN** the host shows an unavailable-page state and does not fall back to a hard-coded SCUM panel
The plugin SHALL expose a feature as actionable only when its declared
Companion handler or event producer is currently available for that server.
Availability SHALL not be gated by a game or adapter version/build/revision.
### Requirement: Feature availability requires a plugin implementation
The system SHALL expose a SCUM feature as actionable only when the installed plugin declares the feature and its Companion reports a compatible handler or event producer for the bound server version. Transitional platform records MAY be displayed as migrated read-only history but SHALL NOT imply executable capability.
#### Scenario: One adapter fails
#### Scenario: Unsupported state patch adapter
- **WHEN** the bound SCUM version has no verified `game-state.patch` handler
- **THEN** the plugin disables the edit control and reports that the version is unsupported without queuing a generic command
- **WHEN** a schema probe for state patching fails
- **THEN** state patching is unavailable with a typed reason while other
declared capabilities remain independently available
#### Scenario: Vehicle spawn handler is unavailable
- **WHEN** the bound Companion does not report the declared `vehicle.spawn` handler for its compatible version
- **THEN** the plugin keeps vehicle spawning unavailable and does not display a raw command field or queue a generic RCON command
### Requirement: Transitional records are read-only migration input
#### Scenario: Historical records during migration
- **WHEN** records created by the transitional platform implementation exist for a bound server
- **THEN** the plugin can display them with migration provenance while new writes use the plugin-owned feature path
Platform records MAY be displayed with provenance while plugin-owned records
become authoritative per server and feature. Migration flags SHALL be scoped
to the server and feature, never to a game version.
#### Scenario: Migration flag is absent
- **WHEN** no unique server-feature migration flag is present
- **THEN** historical records remain readable and plugin writes stay disabled
@@ -1,48 +1,22 @@
## 1. Establish generic extension primitives
## 1. Replace version gates with runtime probes
- [x] 1.1 Audit every SCUM-named platform API, model, service, route, and hard-coded frontend import introduced by the five transitional deliveries; document its plugin-owned replacement and migration dependency.
- [x] 1.2 Define and test generic plugin-scoped record/event storage, audit linkage, retention, and typed command-result primitives without SCUM field names.
- [x] 1.3 Extend the plugin manifest/SDK with versioned page-bundle entries, feature capability declarations, and Companion handler/event-producer availability reporting.
- [x] 1.4 Add generic platform authorization, server isolation, bundle integrity/version validation, and unavailable-feature behavior for those declarations.
- [x] 1.1 Remove SCUM/game/UE4SS/database build, revision, and version feature gates from the change contract, manifest-facing feature layer, Companion registry, adapters, and tests.
- [x] 1.2 Make handler availability server-bound and capability/schema-probe based; isolate failure to the affected command.
## 2. Build the SCUM plugin module and page bundle
## 2. Establish typed Run/Companion boundaries
- [x] 2.1 Create a SCUM plugin-owned feature module with contracts, API client, schemas, validators, and migration adapters for configuration, players, gifts, state patches, and trajectories.
- [x] 2.2 Move the file/config workbench into the plugin page bundle and replace the four example settings with versioned SCUM configuration-field catalogs and explanatory controls.
- [x] 2.3 Move player profile, login/session/risk, gift, controlled-state, and map UI components into the plugin bundle with server-scoped permission checks.
- [x] 2.4 Replace `platform_web` SCUM component imports and `game.scum` branches with generic manifest-driven plugin page mounting; add host and plugin UI tests.
- [x] 2.1 Define restricted typed ports for configuration, player state, rewards, notifications, and fixed server administration with no raw paths, DSNs, rows, credentials, SQL, shell, sockets, or RCON.
- [x] 2.2 Parse bounded Run stdout/stderr records into semantic events; skip unknown formats with bounded diagnostics and irreversible per-server correlation.
- [x] 2.3 Implement state pre-read, safe-window, allowlisted write, and read-after-write confirmation with typed results.
- [x] 2.4 Implement frozen typed reward delivery results without automatic unknown retries.
- [x] 2.5 Preserve the fixed private vehicle-spawn template and its allowlist.
## 3. Implement the long-running SCUM Companion runtime
## 3. Complete plugin-owned migration
- [x] 3.1 Implement authenticated registration, bounded dispatch polling, acknowledgement, idempotent result completion, backoff, and typed diagnostics in the SCUM Companion.
- [x] 3.2 Add a handler registry that validates declared schema, bound server, approval, server version, capability discovery, expiry, and idempotency before invoking an adapter.
- [x] 3.3 Implement safe configuration read/patch and diagnostics adapters that use only platform-authorized channels and redact host paths, credentials, and raw command text.
- [x] 3.4 Add Companion integration tests for command claiming, duplicate delivery, cancellation/expiry, malformed payloads, unsupported versions, and redaction.
- [x] 3.1 Remove version-scoped feature catalogs, page context, API requests, and migration flags in favor of runtime schema/capability availability.
- [x] 3.2 Keep platform records read-only with provenance and leave platform-web generic.
## 4. Add verified SCUM data collectors
## 4. Verify and deliver
- [ ] 4.1 Identify supported SCUM log or legitimate server-side extension sources for successful login/logout and implement versioned parsers that emit validated semantic events.
- [ ] 4.2 Implement server-isolated, irreversible per-server network correlation inside the Companion when a supported source provides it; never upload or persist raw IP/fingerprint values.
- [ ] 4.3 Identify a legitimate non-OCR/non-desktop-automation source for player position, vehicle position, and vehicle transitions; implement coordinate conversion, sampling, and retention according to the plugin declaration.
- [ ] 4.4 Implement durable semantic-event batch upload with ordering, duplicate acknowledgement, parser fixtures, unknown-format diagnostics, and cross-server isolation tests.
## 5. Add version-gated SCUM operation adapters
- [ ] 5.1 Implement a version-discovered `game-state.patch` adapter for only documented supported skill/attribute fields, including precondition read, safe-window verification, read-after-write confirmation, and typed old/new/result audit data.
- [x] 5.2 Keep unsupported player state fields, versions, or unsafe windows disabled in the plugin UI and return explicit unsupported results from the Companion.
- [ ] 5.3 Implement a `reward.deliver` adapter that freezes the approved revision, performs idempotent delivery, and reports delivered/failed/unknown without automatically retrying unknown results.
- [x] 5.4 Implement a separate `player.notify` adapter that never repeats item delivery after notification failure; verify server-scoped recipient identity and redact message transport details.
- [x] 5.5 Implement the explicitly enabled, version-bound `vehicle.spawn` adapter with a strict vehicle-code catalog, the fixed internal `#spawnvehicle <vehicleCode>` template, protected audit text, structured success/failure/unknown outcomes, Companion-local transport fixture, and fail-closed UI availability.
- [x] 5.6 Add isolated non-production end-to-end tests for every supported adapter and ensure no raw SQL, unrestricted RCON, OCR, screenshots, keyboard/mouse injection, or direct game database write path exists.
## 6. Migrate transitional platform behavior safely
- [x] 6.1 Introduce feature/version flags and read-only migration adapters so existing platform records remain visible with provenance while plugin-owned records become authoritative per server.
- [ ] 6.2 Verify plugin parity for configuration, player history, gifts, state-patch audits, and trajectories against controlled fixtures and an isolated Companion integration environment.
- [ ] 6.3 Remove SCUM-named platform APIs, models, services, routes, and frontend components only after no callers remain and migration/rollback evidence is recorded.
- [ ] 6.4 Run full platform, plugin, frontend, manifest, OpenSpec strict, structure, and isolated end-to-end verification; commit and push only the scoped migration files.
## Verification evidence
- 5.6: `cd plugins/examples/scum-server-plugin/companion && go test ./...` passed on 2026-07-29. The isolated typed-port fixture covers safe configuration read/patch, `player.notify`, and version-bound `vehicle.spawn` through claim/ack/registry/complete; it checks approval, binding, version/capability gating, idempotency, bounded outcomes, and redaction. A production-source test rejects raw SQL/direct database access, unrestricted command/RCON execution, OCR/screenshot/input automation, and direct socket paths.
- 6.3 preparation: `platform_web` static call-graph audit on 2026-07-29 found that the legacy SCUM operation/config/player/gift/trajectory panels, their private contracts/schemas, and their game-player/gift/map client calls had no non-test caller after generic plugin-page hosting. The orphan frontend implementation was removed; the backend historical routes/models/services/repositories remain read-only migration input as documented in `implementation-blockers.md`. `cd platform_web && pnpm test && pnpm build`, `cd plugins && pnpm test && pnpm typecheck && pnpm validate:manifest`, `openspec validate move-scum-feature-ownership-to-plugin --strict`, and `scripts/check-structure.sh` passed.
- [x] 4.1 Run Companion, plugin, manifest, OpenSpec strict, structure, and scoped source-boundary verification.
- [x] 4.2 Stage scoped files, commit, and push `main`.