diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/.openspec.yaml b/openspec/changes/replace-scum-projections-with-real-data-management/.openspec.yaml new file mode 100644 index 0000000..a8821c7 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-11 diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/design.md b/openspec/changes/replace-scum-projections-with-real-data-management/design.md new file mode 100644 index 0000000..5597ca7 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/design.md @@ -0,0 +1,181 @@ +## Context + +The current SCUM implementation has two disconnected local player models and an unimplemented real-data path. Login ingestion can upsert `GamePlayer` only after Run has already supplied synthetic `eventType/playerId/playerName` fields, while the repository's only SCUM parser recognizes an invented `SCUM LOGIN/LOGOUT` console format rather than the game's real login file. The plugin manifest declares six SQLite query keys but contains no query asset, workflow dispatch changes local statuses without creating read jobs, and job completion never calls the SCUM row-ingestion service. The page therefore renders empty local objects, fabricated maintenance/backup references, hard-coded actions, a non-georeferenced dot board, and a hard-coded gift. + +The reference `scum_robot` demonstrates the useful direction—tail the current server's login log, create a server-scoped local player, and let a machine-side process query its current SCUM.db—but its static SCUM structs are not migrated or authoritative, its production roster/world refresh mostly parses administrator-command output, and its raw SQL, permissions, XML rewrite, early gift-success recording, and forced player death are unsafe to copy. + +This change crosses `platform/`, `platform_web/`, the SCUM plugin and SDK, and the independent Run repository. It must preserve the repository boundary: the SCUM plugin owns game-specific formats and declarations; Platform owns authorization, durable local business data, jobs, and safe APIs; Run owns generic machine-side execution and observed runtime facts. Browser code never receives SQL, raw XML, database paths, credentials, sockets, or raw RCON. + +The implementation is blocked from declaring production SQL or `855` semantics until a read-only probe against the current bound service produces evidence. An unbound copied/reference database, historical cache, or generated model is only a hypothesis source. Run may create an execution-time read-only snapshot of the active database only when the snapshot is fenced to the current binding/database identity, timestamped, checksummed, short-lived, and invalidated on rebinding or schema change. + +## Goals / Non-Goals + +**Goals:** + +- Replace SCUM projection/observation/Workflow product concepts with automatic synchronization into dedicated local records. +- Create player identity and session data from authentic SCUM login/logout logs and enrich it only with verified current-service database facts. +- Make the plugin own versioned parsers, SQL, result contracts, map metadata, RCON templates, and controlled mutation metadata while Run remains generic. +- Provide trustworthy user, squad, map, gift, and AI surfaces with explicit effective-user permissions and no fabricated facts or evidence. +- Keep unknown values null/absent, preserve the last successfully synchronized rows after a failed sync, and show ordinary connection/last-sync information without projection/freshness jargon or manual refresh actions. +- Make manual and AI-originated writes use one typed authorization, review, dispatch, and confirmation path. +- Preserve required server deployment, metadata, and administrator controls after removing the `管理` tab. + +**Non-Goals:** + +- Do not add a `run/` tree, billing, cloud-host sales, agent-provider workflows, or unrelated marketplace behavior. +- Do not use a repository/reference/cached `SCUM.db`, trust `scum_robot/model/scum_server.go` as a production schema, or ship guessed joins, enum values, coordinates, ownership, balances, or default zero values. +- Do not expose arbitrary SQL, raw RCON, host paths, direct sockets, SCUM.db credentials, or raw `template_xml` to Platform Web or AI. +- Do not hardcode SCUM tables, query keys, commands, or lifecycle behavior in Platform or Run. +- Do not provide a Workflow status page, refresh/audit buttons, a manual synchronization API, or product-facing projection/observation terminology. +- Do not automatically kill/respawn a character, invent a missing XML skill, or claim a write/gift succeeded before conclusive execution and confirmation evidence exists. +- Do not promise a sub-second realtime map when the verified database or companion source cannot supply that cadence. + +## Decisions + +### 1. Bootstrap a generic probe, then treat current-service discovery as a release gate + +The first cross-repository prerequisite is to confirm or add the minimal generic, bounded diagnostic probe executor in the independent Run repository and deploy that compatible Run to the current binding. Platform and Run must establish the probe request/result envelope, binding fence, safe limits, and redaction without introducing any SCUM-specific table or path knowledge. + +Only then will the implementation execute a bounded, read-only probe through the currently bound Run. The evidence must include `sqlite_master`, `PRAGMA table_info`, foreign-key/index information for candidate tables, small redacted samples, relevant enum distributions, coordinate ranges/cadence, and read-lock behavior. It must confirm player/profile/entity joins, squad rank meaning, flag ownership relationships, vehicle identity fields, currency types, and whether/where a mutable profile XML payload actually exists. + +No production query or mutation asset may be merged until the probe evidence is captured in the change or an explicitly referenced test artifact. The probe is diagnostic-only, is not exposed as a browser action, and performs no write. + +Alternative considered: start with the reference structs and fix queries after deployment. Rejected because the reference models are incomplete hypotheses and the current implementation already failed by treating guessed fields as facts. + +### 2. Package game-specific behavior as signed plugin assets + +The SCUM plugin will contain versioned assets for: + +- login/logout parsing and field mapping; +- read-only SQLite queries for player details, squads, squad members, vehicles, flags, and positions; +- result JSON schemas and schema-version compatibility; +- map identity, asset reference, world bounds, and coordinate transform; +- RCON command templates for supported economy and gift operations; +- database/XML mutation declarations for fields without a safe game command. + +Manifest declarations will reference each asset and its digest. The generated Run package will contain those immutable assets. Platform queues a template key plus bounded parameters and expected digest; it does not construct SCUM SQL or command text. Run verifies the packaged asset/digest and executes it through a generic capability. + +Alternative considered: make Run implement the six `scum.*` keys. Rejected because it makes Run game-aware and requires a Run release for every SCUM schema change. Alternative considered: accept SQL from the browser or a general Platform endpoint. Rejected because it creates an arbitrary database interface. + +### 3. Add generic bounded Run contracts instead of SCUM workflows + +The external Run contract will support: + +- a generic current-target schema probe; +- read-only SQLite template execution with parameter binding, a single SELECT/CTE or approved introspection statement, query-only mode, timeout, row/result-size limits, and no `ATTACH`, extension loading, or mutation; +- plugin-owned typed RCON template execution; +- plugin-owned guarded SQLite/XML mutation execution in a bounded transaction; +- typed result envelopes containing server/plugin binding, template key, asset digest, schema version, observed time, checksum, rows or affected-row count, and a safe error/result code. + +Platform will use ordinary durable Run jobs and the existing channel priority/lease/fencing rules. A new terminal-job hook validates the result envelope and schema, then invokes the matching local sync or write-confirmation service. There is no SCUM Workflow instance/step scheduler. + +Alternative considered: repair the current SCUM workflow engine. Rejected because synchronization is a background data-ingestion concern, direct resource mutations already have a single target operation, and the workflow layer currently adds user-visible states without performing work. + +### 4. Persist SCUM facts in dedicated normalized local stores + +The local model will use dedicated repositories for at least: + +- `scum_players` with unique `(server_instance_id, external_player_id)`; +- `scum_player_sessions` with durable source-event identity; +- `scum_player_details` for nullable profile/economy/squad facts and source checksum/time; +- `scum_squads` and `scum_squad_members`; +- `scum_vehicles`, `scum_flags`, and `scum_positions`; +- `scum_gift_packages`, `scum_gift_items`, and `scum_gift_deliveries`; +- internal `scum_sync_cursors` and successful sync generations. + +High-frequency SCUM data will not be appended to the global metadata snapshot. The `mysql` backend will use normalized MySQL tables and migrations. The default `file` backend will use a platform-owned SQLite sidecar under the configured data directory; the `memory` backend will use an in-memory implementation for tests. The storage interface remains under `platform/repo`, database models/migrations under their fixed platform directories, and domain/API types remain separate. + +A full successful resource scan uses a generation marker: rows are upserted transactionally, and records missing from the completed generation can be marked absent. A partial or failed scan never deletes or overwrites the last successful rows. Missing source fields remain `NULL`; zero is stored only when the source explicitly reports zero. + +Alternative considered: retain the existing generic snapshot repositories and rename projection types. Rejected because every coordinate update would rewrite the whole metadata snapshot and would preserve the misleading data architecture the change is intended to remove. + +### 5. Synchronize automatically from logs, binding state, and declared cadence + +Run tails the plugin-declared login source and applies the plugin parser locally. Each typed login/logout event carries both a transport cursor `(source identity, stream generation, sequence)` for acknowledgement/resume and a privacy-safe logical event identity that is native to the log when available or derived from normalized non-network event fields and remains stable across rotation-overlap replay. A successful login atomically upserts the player, updates the current display name and last-seen time, and opens a session; logout closes the matching session without regressing a newer session. The source contract handles file rotation, truncation, Run restart, partial lines, and duplicate/overlapping batches without duplicating a logical event. Malformed lines, failed-login attempts, and events from an obsolete binding never create a player. Raw IP/network material is discarded before durable storage or logical fingerprinting. + +The sync scheduler starts an initial bounded database scan when a compatible Run binding becomes ready, schedules resource scans at plugin-declared intervals with jitter and per-server concurrency limits, and may enqueue a bounded player-detail lookup after a new login. Positions use the measured safe cadence. If SCUM.db cannot provide the required map cadence, the plugin must declare a companion position-event source; the product must not compensate with fabricated motion or aggressive unsafe polling. + +Platform Web always reads local resource APIs and receives updates through a platform-owned event stream/SSE. Opening a page never dispatches a database query, and there is no user refresh button. + +Alternative considered: query Run on every page load. Rejected because it couples browser latency to machine connectivity, multiplies database reads, and makes pagination/filtering dependent on a remote SQLite file. + +### 6. Replace the player-intelligence model with a lean roster + +The SCUM product flow retains only the server-scoped player identity, current display name, first/last seen times, online session, login history, and verified player details. It removes alias-history, access-attempt, shared-IP, automatic-risk, and player-intelligence features from SCUM manifests, APIs, UI, and persistence when they have no non-SCUM consumer. + +List APIs operate on the local store and support bounded pagination, search by name/external ID, online state, squad filter, and allowlisted sorting. Player detail returns nullable verified facts and last synchronized time. The UI uses a table and detail/edit surface rather than a fixed list of cards and hard-coded increments. + +Alternative considered: keep the intelligence records hidden. Rejected because the user requested a smaller player model and the hidden ingestion side effects would still complicate login creation and retention. + +### 7. Use one controlled-write path for manual and AI requests + +Existing permission families remain explicit: + +- `server.game-client.read` for local SCUM reads; +- `server.game-client.command` for declared RCON/economy/gift actions; +- `server.game-client.maintenance` plus an explicit synchronous danger confirmation for database/XML mutations. + +The plugin page host must receive the current session's effective server permissions, not merely the permissions declared by the plugin/page. The backend reauthorizes every request and remains authoritative. An AI draft records the initiating user and cannot be dispatched unless that same confirming user still has the permission required for a manual request. AI never runs under an independent component write principal. + +Fame and currencies use plugin-declared game commands when verified. Character attributes use a version-scoped XML patch declaration only after the active adapter confirms the actual profile XML source: Run reads the current payload, checks the expected row/checksum, changes only allowlisted named attributes or existing skill nodes, preserves all unknown nodes/attributes, updates at most one row with bound parameters, and reads back for confirmation. A real backup reference, verified offline/maintenance condition when required, before values, reason, idempotency key, and explicit confirmation are mandatory. A timestamp-shaped fake backup or maintenance string is invalid. There is no separate platform-admin approval domain, audit-initiation action, or approval queue. + +`855` is not a field key. It can be declared only as a preset that expands to explicitly named attributes after its exact mapping is confirmed. Any respawn/death action needed to activate values is a separate explicit destructive operation and is never part of the default attribute save. + +Alternative considered: reuse `player.attribute.855.set` and a generic integer field mutation. Rejected because the source is XML containing several named values. Alternative considered: let AI or Platform generate raw SQL/XML. Rejected because it leaks protected content and bypasses plugin version fencing. + +### 8. Model gifts as local business data with typed delivery + +Gift packages and items are server/plugin-instance scoped and have normal create, read, update, and delete operations, bounded eligibility/quantity rules, and explicit active state. A delivery freezes the target player and item definitions, atomically reserves any period-limited entitlement, uses a server-scoped idempotency key, and dispatches only a plugin-declared typed command. In-progress and unknown outcomes retain their reservation so concurrent requests cannot exceed the limit; only a conclusive non-executed failure may release it. The API reports creation/dispatch separately from delivered success. `delivered` is stored only after conclusive Run success; failed and unknown outcomes retain safe evidence and never auto-redeliver. + +Alternative considered: preserve the current hard-coded starter package and notification. Rejected because neither is backed by catalog data. Alternative considered: copy `scum_robot`'s Redis command list. Rejected because it stores success before execution and accepts raw game command strings. + +### 9. Make the SCUM surface contain exactly five tabs + +The server detail order is `用户管理`, `队伍管理`, `实时地图`, `礼包管理`, `AI 助手`; the first plugin page is the default. `Workflow 状态` is removed from the manifest and the generic `管理` entry is excluded for the SCUM detail view. Deployment remains reachable from server-list actions. Server name and administrator membership move into a server-settings drawer opened from the detail header. + +All copy and actions referring to projection, observation, freshness/staleness, refresh projection, refresh real data, initiate audit, pending review counts, or Workflow state are removed. Pages may show ordinary connection status and last synchronized/collected time. Empty states describe the missing business record without offering a manual refresh or implying generated data. + +AI configuration keeps the existing reviewable config-diff path. Player-operation AI suggestions produce the same named-field edit draft used by the manual form. + +Alternative considered: hide the two tabs without moving their content or changing the default route. Rejected because it would strand required server controls and leave invalid route fallbacks. + +### 10. Keep legacy completed changes historical instead of importing obsolete specs + +The repository's main OpenSpec baseline currently contains no SCUM capabilities, while the changes that introduced player intelligence, trajectories, the versioned gift catalog, player-state patching, projection/Workflow automation, controlled operations, and the old product surface are complete but unarchived. This replacement therefore declares only uniquely named `ADDED` capabilities. It supersedes those historical artifacts through explicit implementation deletion and acceptance coverage; it does not first archive them into the baseline and then attempt to remove them. + +The old completed changes must not later be archived in a way that publishes their obsolete SCUM requirements as current baseline specs. Historical cleanup is a separate reviewed consolidation after this replacement is implemented, using skip-specs or an equivalent approach that preserves history without resurrecting removed behavior. + +## Risks / Trade-offs + +- [Risk] SCUM schema changes between game versions. → Require live probe evidence, schema-versioned assets, exact result schemas, digest fencing, and a disabled/incompatible state rather than fallback queries. +- [Risk] Reading the live SQLite file can block or observe inconsistent rows. → Use query-only connections, short timeouts, bounded scans, measured cadence, jitter/backoff, and keep the last completed generation on failure. +- [Risk] Game saves may overwrite direct database/XML changes. → Verify offline/maintenance semantics against the current service, require before/checksum guards and backup evidence, and disable unverified mutations. +- [Risk] XML reserialization can destroy fields unknown to the current plugin. → Patch only named attributes/existing nodes while preserving raw document structure, then confirm by readback; never synthesize missing skills. +- [Risk] Cross-repository Run support can lag the browser release. → Gate synchronization and write UI on compatible asset-executor capabilities and deploy Run support before enabling the new pages. +- [Risk] Dedicated local tables add a second persistence path for the file backend. → Keep it behind a narrow `SCUMStore` interface, use explicit migrations and health checks, and fail the SCUM feature closed without affecting core server lifecycle. +- [Risk] Position polling can generate large write volume or still not be realtime. → Measure source cadence, retain only current positions by default, make history explicitly bounded, and use a declared companion event source when database cadence is inadequate. +- [Risk] Removing `管理` can make server settings undiscoverable. → Add header-level server settings and preserve server-list deployment actions before removing the tab. +- [Risk] Old projection/Workflow snapshot data can look real after upgrade. → Never migrate it into the new tables; populate only from post-upgrade authenticated logs/current-service sync. + +## Migration Plan + +1. Confirm or implement the minimal generic diagnostic probe contract in the independent Run repository, deploy a compatible Run to the active binding, and verify binding fencing/redaction without adding SCUM-specific behavior to Run. +2. Probe the active service database in read-only mode, capture schema/cadence/lock evidence, and confirm whether the `855` preset has a real named-attribute mapping. Stop any affected capability if the evidence cannot support safe query or mutation declarations. +3. Add plugin/SDK/validator contracts and immutable SCUM parser/query/map/command/mutation assets backed by that evidence; implement and deploy the remaining compatible generic Run executors in the independent repository. +4. Add the dedicated SCUM store implementations, migrations, health checks, local resource contracts, and automatic sync scheduler behind a disabled-by-default compatibility gate. +5. Wire authentic, rotation-safe login events and terminal Run query results into local transactional upserts; verify initial and periodic sync against the current service without enabling writes. +6. Build the player, squad, map, and gift APIs/pages, effective-permission context, server-settings relocation, and preserved AI configuration flow against the new local records. +7. Enable controlled RCON writes, then separately enable guarded XML mutations only after actual source mapping, backup/offline/readback verification, effective permission, and explicit confirmation succeed on the current service. +8. Cut navigation and clients to the five new tabs; remove Workflow/projection/observation APIs, services, repositories, snapshot fields, page actions, banned copy, fake gifts/map/actions, and obsolete tests/spec assumptions. +9. Run focused backend/frontend/plugin tests, external Run contract acceptance, browser acceptance against real synchronized data, `scripts/check-structure.sh`, and `openspec validate replace-scum-projections-with-real-data-management --strict` before marking tasks complete. + +Rollback disables the SCUM compatibility gate and write actions while leaving the new local tables for diagnosis. It must not re-enable fake projection data or migrate new facts back into old Workflow/projection records. Core server lifecycle, logs, jobs, and AI provider management remain available. + +## Open Questions + +- What are the exact current-service tables, columns, joins, enum values, coordinate cadence, and safe read behavior? +- What exact named attribute mapping does the operator mean by the `855` preset, and what game action—if any—is required for those values to take effect? +- Does the verified current SCUM version support safe RCON readback for fame/currencies, or must confirmation use a database query? +- Which map asset/version and coordinate transform are authorized for first-party redistribution? +- Which gift item aliases and delivery transports can be verified without exposing or accepting arbitrary commands? +- Which pure-Go SQLite driver and migration mechanism will be pinned for the default file-backend sidecar after dependency and build verification? diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/proposal.md b/openspec/changes/replace-scum-projections-with-real-data-management/proposal.md new file mode 100644 index 0000000..bce5083 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/proposal.md @@ -0,0 +1,45 @@ +## Why + +The current SCUM plugin presents projection and Workflow concepts as if they were real operations, but its declared SCUM.db queries contain no SQL, its read workflows do not dispatch Run jobs, its login parser does not understand the real SCUM login-log format, and several player, map, gift, and `855` controls fabricate data or evidence. The product needs a smaller SCUM management surface backed only by current-server login logs, verified SCUM.db facts, durable local records, and permission-checked writes. + +## What Changes + +- **BREAKING**: Supersede the projection/observation/Workflow architecture introduced by `integrate-real-scum-ops-workflows`; remove SCUM Workflow/status product APIs, repositories, services, page actions, refresh/audit controls, freshness terminology, and the `Workflow 状态` page. +- **BREAKING**: Remove the built-in `管理` tab from the SCUM server detail navigation, make the first SCUM plugin page the default, and relocate necessary deployment, metadata, and administrator controls to existing server-list actions and a server-settings drawer. +- Discover the schema of the current bound service through a read-only Run probe before defining production queries; do not treat an unbound copied/reference `SCUM.db`, `scum_robot/model/scum_server.go`, historical cache, or guessed joins/enums as authoritative. A Run-created execution snapshot is acceptable only when it is fenced to the active binding/database identity, timestamped, checksummed, and invalidated on rebinding or schema change. +- Make the SCUM plugin own versioned login-log parsers, SQLite query assets, result schemas, coordinate metadata, RCON command templates, and controlled mutation declarations. Run remains a generic bounded executor and never hardcodes SCUM keys, tables, commands, or paths. +- Store players, sessions, squads, squad members, vehicles, flags, current positions, gifts, deliveries, and sync cursors in dedicated platform-owned local records rather than a monolithic metadata snapshot or fabricated product projection. +- Automatically create/update players and login sessions from authentic login/logout log events, and automatically synchronize verified SCUM.db facts in the background without user-facing refresh, projection, or audit buttons. +- Rebuild user management as a searchable, filterable, paginated player roster with detail and explicit edits; remove player-intelligence, shared-IP, automatic-risk, alias-history, fake values, and hard-coded increment actions from the SCUM product flow. +- Rebuild squad management and the realtime map from verified squad/member/vehicle/flag/coordinate data, a declared SCUM map asset, and a tested coordinate transform; never infer ownership or coordinates that the source cannot prove. +- Rebuild gift management as server-scoped local CRUD plus bounded, idempotent delivery records whose success is recorded only after a conclusive Run result. +- Preserve the AI assistant for plugin configuration and player-operation drafts. Manual and AI-originated writes use the same effective-user permissions, reviewable before/after diff, allowlisted plugin action, Run execution path, and read-after-write confirmation. +- Replace the fake `player.attribute.855.set` integer column with named, version-scoped character attributes backed only by a targeted patch of the profile XML source confirmed by the current-service adapter; the patch preserves unknown XML content, and `855` may remain only as a user-confirmed preset label. +- Remove all product copy and controls for projection, observation, stale projection, refresh real data, refresh projection, initiate audit, pending-review counters, and Workflow status while retaining non-product authorization, idempotency, safety, and internal audit evidence for writes. + +## Capabilities + +### New Capabilities + +- `scum-live-data-sync`: Authentic login-log ingestion, current-service schema discovery, plugin-owned SQL assets, generic Run execution, automatic synchronization, and dedicated local SCUM records. +- `scum-player-management`: Lean player roster/session management, search/filter/pagination/detail contracts, null-for-unknown semantics, and explicit player editing surfaces. +- `scum-squad-management`: Verified squad, member, leader/rank, flag, territory, search, pagination, and detail behavior without inferred relationships. +- `scum-realtime-map`: Verified player, vehicle, flag/territory coordinates, a distributable map asset, tested transforms, and automatically updated layers without fabricated positions. +- `scum-gift-management`: Server-scoped gift package CRUD, eligibility, bounded delivery, idempotency, result handling, and delivery history. +- `scum-controlled-writes`: Plugin-owned RCON and database/XML mutation declarations, effective-user permissions, manual/AI parity, safety guards, and confirmation requirements. +- `scum-real-data-management-surface`: The exact SCUM navigation, AI-assistant preservation, server-settings relocation, and removal of projection/Workflow/audit-refresh product concepts. + +### Modified Capabilities + +- None. The main baseline contains no SCUM capability that can validly receive a `MODIFIED` or `REMOVED` delta. The completed-but-unarchived SCUM change artifacts remain historical implementation records: this change uses unique `ADDED` capability names and explicitly supersedes those old projection/Workflow/product requirements. They must not later be synchronized into the main baseline as current requirements; any history consolidation is a separate reviewed archival task using skip-specs or an equivalent non-resurrection path. + +Supersession mapping: `scum-real-data-projections` is replaced by live sync plus the player/squad/map stores; `scum-workflow-automation` is retired; `scum-controlled-operations` and `scum-player-state-patch` are replaced by `scum-controlled-writes`; the old `scum-product-surface` is replaced by `scum-real-data-management-surface`; `scum-game-player-intelligence` is reduced to the lean player capability; `scum-map-trajectories` is replaced by current-position map behavior with trajectories removed; and `scum-versioned-gift-catalog` is replaced by server-local gift management and conclusive delivery receipts. + +## Impact + +- `platform/`: new SCUM data models and normalized repositories/migrations, automatic sync services, Run job completion handling, typed resource and mutation APIs, authorization checks, removal of projection/Workflow domains and endpoints, and migration away from SCUM snapshot fields. +- `platform_web/`: SCUM navigation/default section, server-settings relocation, plugin host contracts, API types/clients, player/squad/map/gift pages, permission-aware edit flows, AI drafts, and removal of banned copy/actions. +- `plugins/examples/scum-server-plugin/` and plugin SDK/schema validation: versioned log parser/query/mutation/command assets, result schemas, permissions, map metadata, page bundles, and removal of Workflow declarations. +- External `git@git.npc0.com:admin343/run.git`: generic read-only SQLite template execution, safe result envelopes, plugin-owned mutation execution, and current-service schema-probe support. No `run/` source tree is added to this repository. +- Persistence and deployment: dedicated local tables require explicit migration/rollback handling; old SCUM projection/Workflow snapshot data is not authoritative and is not migrated as real game facts. +- Security: browser APIs continue to exclude SQL, raw XML, database paths, credentials, sockets, raw RCON, and host paths; AI gains no independent execution authority. diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-controlled-writes/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-controlled-writes/spec.md new file mode 100644 index 0000000..22225e5 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-controlled-writes/spec.md @@ -0,0 +1,117 @@ +## ADDED Requirements + +### Requirement: Effective-user permission enforcement +Every SCUM state-changing request SHALL be authorized against the current user's effective target-server permission at UI presentation, request creation, review/confirmation, and dispatch, with the backend as the authoritative enforcement point. + +#### Scenario: Read-only operator opens a writable surface +- **WHEN** a user has `server.game-client.read` but lacks the required write permission +- **THEN** data remains readable, write controls are hidden or disabled with a textual reason, and a direct API attempt is forbidden + +#### Scenario: Economy command is requested +- **WHEN** a user edits Fame, cash, or gold +- **THEN** Platform requires `server.game-client.command` and target-server access before accepting the named-field request + +#### Scenario: Gift delivery is requested +- **WHEN** a user sends a declared gift package to a server-local player +- **THEN** Platform requires `server.game-client.command`, target-server access, and the gift capability's eligibility/idempotency checks before dispatch + +#### Scenario: Database/XML attribute edit is requested +- **WHEN** a user edits a maintenance-level character attribute or preset +- **THEN** Platform requires `server.game-client.maintenance`, target-server access, a synchronous explicit danger confirmation, and the declared safety gates before dispatch; it SHALL NOT create a separate platform-admin approval domain or approval queue + +#### Scenario: Plugin page receives permissions +- **WHEN** Platform Web constructs the plugin page host context +- **THEN** it supplies the current session's effective permissions rather than treating manifest-declared permissions or callback presence as proof of authority + +### Requirement: Manual and AI write-path parity +Manual forms and AI/Agent-originated SCUM changes SHALL create the same named-field draft and SHALL use the same allowlist, validation, effective-user authorization, review, dispatch, and confirmation service. + +#### Scenario: AI suggests an allowed player change +- **WHEN** a user with the required write permission asks AI to change a declared player field +- **THEN** AI produces a reviewable target/player/field/current/proposed diff and no execution occurs until the user explicitly confirms it + +#### Scenario: AI requester lacks write permission +- **WHEN** AI can generate or display a suggestion for a user who lacks the field's write permission +- **THEN** the apply action remains unavailable and an API attempt is forbidden; AI receives no component-principal bypass + +#### Scenario: AI invents a field or protected payload +- **WHEN** an AI response contains an undeclared field, raw SQL, raw XML, raw RCON, path, credential, or arbitrary command +- **THEN** Platform rejects the draft and stores no executable protected payload from it + +### Requirement: Plugin-owned immutable write assets +The SCUM plugin SHALL own versioned typed command templates and guarded mutation declarations, and every executable write asset SHALL be digest-referenced by the plugin manifest and generated Run package. + +#### Scenario: Declared write is dispatched +- **WHEN** Platform dispatches a confirmed named-field command or mutation draft +- **THEN** Run executes only the packaged asset whose plugin ID/version, adapter/schema version, action key, server binding, and digest all match the reviewed draft + +#### Scenario: Write asset identity changed +- **WHEN** an action key, adapter version, packaged asset, or digest no longer matches the reviewed draft +- **THEN** Platform or Run rejects the write before any game command or database mutation executes + +### Requirement: Plugin-owned command execution +SCUM writes with a verified game command SHALL use plugin-owned typed command templates, and Platform and Run SHALL NOT hardcode SCUM command strings. + +#### Scenario: Fame or currency is changed +- **WHEN** the compatible plugin adapter declares a supported Fame, normal-currency, or gold command +- **THEN** Platform dispatches its template key and validated parameters through the generic Run/RCON transport and performs the declared confirmation read + +#### Scenario: Command template is not compatible +- **WHEN** the current plugin/game adapter cannot verify the command and confirmation contract +- **THEN** the write capability is disabled and SHALL NOT fall back to direct SQLite mutation or Platform-built command text + +### Requirement: Named and preserving XML attribute mutation +Character attribute writes SHALL target version-scoped named attributes or existing skill nodes in the profile XML source verified by the active current-service adapter and SHALL preserve all untargeted XML content. + +#### Scenario: One allowed attribute changes +- **WHEN** Run reads a valid current XML document and applies an authorized and explicitly confirmed named-field change +- **THEN** only the targeted allowlisted attribute/node changes and unknown attributes, nodes, ordering-sensitive extensions, and all other values remain semantically intact + +#### Scenario: Unknown field or missing skill is requested +- **WHEN** a requested attribute/skill is absent from the version adapter or the XML lacks the targeted existing skill node +- **THEN** Run rejects the mutation and SHALL NOT invent a node, default an `Attribute` value, or rewrite the document from an incomplete struct + +#### Scenario: XML is malformed +- **WHEN** the current adapter-confirmed profile XML payload cannot be parsed by the preserving patcher +- **THEN** no database write occurs and Platform receives a bounded safe failure + +### Requirement: `855` is an explicit preset, not a database field +The system SHALL NOT declare or execute `855` as a table column or generic integer field; it MAY expose `855` only after an operator-confirmed preset maps it to explicit version-scoped named character attributes and values. + +#### Scenario: Preset meaning is not confirmed +- **WHEN** the plugin adapter has no reviewed mapping for the `855` label +- **THEN** the preset is absent/disabled and no `fieldKey=855`, `prisoner.value`, or `0..100000` mutation can be created + +#### Scenario: Confirmed preset is reviewed +- **WHEN** a compatible adapter declares the preset and an authorized user selects it +- **THEN** the review shows every named attribute's current and proposed value rather than a single opaque `855` value + +### Requirement: Guarded single-row database mutation +Every database/XML mutation SHALL require a current compatible probe, target identity, expected before values/checksum, reason, idempotency key, genuine same-server backup evidence, required offline/maintenance evidence, a single-row bound, and read-after-write confirmation. + +#### Scenario: Safety evidence is missing or fabricated +- **WHEN** the player's online state is unknown/unsafe, maintenance is unverified, the backup reference is absent/not restorable/not for the same database instance, or a timestamp-shaped placeholder is supplied +- **THEN** Platform rejects dispatch and no mutation job is created + +#### Scenario: Current value changed +- **WHEN** the row identity, current value, XML digest, or schema fingerprint no longer matches the reviewed before state +- **THEN** Run aborts the transaction as a conflict without applying the requested value + +#### Scenario: Affected row count is not one +- **WHEN** a mutation would affect zero or more than one row +- **THEN** Run rolls back and reports failure + +#### Scenario: Readback does not confirm the target values +- **WHEN** execution may have occurred but the confirmation read is missing or mismatched +- **THEN** Platform SHALL NOT report success and SHALL require confirmation before any explicit retry + +#### Scenario: Attribute save completes +- **WHEN** the single-row mutation and readback confirm every named target value and new digest +- **THEN** Platform records the safe result and updates local verified details without exposing the raw XML + +### Requirement: No implicit destructive activation +Saving character attributes SHALL NOT implicitly kill, respawn, kick, or otherwise disrupt the player. + +#### Scenario: Game requires respawn for new values +- **WHEN** current-service verification shows a respawn/death action is necessary for activation +- **THEN** that action is a separate explicitly named destructive command with its own permission and fresh user confirmation and is not automatically chained to attribute save diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-gift-management/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-gift-management/spec.md new file mode 100644 index 0000000..2e555a3 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-gift-management/spec.md @@ -0,0 +1,95 @@ +## ADDED Requirements + +### Requirement: Server-scoped gift package CRUD +The system SHALL provide effective-user-authorized create, read, update, enable/disable, and delete operations for gift packages and typed items scoped to one server instance and compatible plugin/game version. + +#### Scenario: User has gift read access only +- **WHEN** the current session has `server.game-client.read` but lacks `server.game-client.maintenance` +- **THEN** package data and delivery history remain readable while create/edit/enable/delete controls are unavailable and direct mutation requests are forbidden + +#### Scenario: Operator creates a valid package +- **WHEN** an operator with effective `server.game-client.maintenance` submits a name, classification, eligibility/limit rules, and bounded quantities of plugin-catalogued item keys +- **THEN** Platform stores the package and items for the target server without storing raw RCON, shell, SQL, or arbitrary command strings + +#### Scenario: Package item is invalid +- **WHEN** a package contains an unknown or incompatible item key, duplicate item, out-of-range quantity, or game-version mismatch +- **THEN** Platform rejects the change and preserves the previous package + +#### Scenario: Package is deleted +- **WHEN** an authorized operator confirms deletion of a package not protected by an active delivery +- **THEN** Platform removes or retires the package without deleting immutable completed delivery facts + +### Requirement: Plugin-owned immutable gift catalog and transport +Gift item aliases, compatibility rules, quantities, and delivery transport declarations SHALL come only from versioned digest-referenced assets in the plugin package and, where executable, the generated Run package. + +#### Scenario: Catalog or transport digest changed +- **WHEN** a package or frozen delivery references a catalog/transport version or digest that no longer matches the active compatible plugin package +- **THEN** Platform rejects creation or dispatch and SHALL NOT translate the item into an arbitrary command or newer unreviewed alias + +### Requirement: Validated gift eligibility and limits +The system SHALL evaluate package eligibility and atomically reserve database-backed per-player, per-server, and configured period limits in the server's declared timezone before a delivery can dispatch. + +#### Scenario: Player belongs to another server +- **WHEN** a caller attempts to deliver a package to a player record outside the package's server instance +- **THEN** Platform rejects the request before creating a delivery or Run job + +#### Scenario: Period limit is reached +- **WHEN** a player already has the allowed number of reserved, in-progress, partial, unknown, or delivered grants in the active daily/weekly or declared period boundary +- **THEN** Platform rejects another delivery without relying on an in-memory count + +#### Scenario: Concurrent eligibility requests occur +- **WHEN** two workers request the same limited package for the same player and period concurrently +- **THEN** a server-scoped uniqueness/idempotency constraint allows at most one request to reserve the remaining entitlement + +#### Scenario: Delivery conclusively did not execute +- **WHEN** Run returns a conclusive failure proving that no gift effect occurred +- **THEN** Platform may release the reserved period entitlement transactionally; partial or unknown outcomes SHALL continue to hold it until reconciled + +### Requirement: Frozen and idempotent gift delivery +The system SHALL freeze the target player, package/item definitions, plugin/game version, and delivery parameters before dispatch and SHALL use a stable server-scoped delivery ID and idempotency key. + +#### Scenario: Package changes after delivery request +- **WHEN** an operator edits or disables a package after a delivery has been created +- **THEN** the existing delivery retains its frozen target/items/version and the edit does not mutate an in-flight or completed delivery + +#### Scenario: Same idempotency key is submitted again +- **WHEN** the same scoped delivery request is repeated or submitted concurrently +- **THEN** Platform returns the original delivery and queues no duplicate effect + +#### Scenario: Run receives a delivery +- **WHEN** a user with current effective `server.game-client.command` confirms an eligible frozen delivery +- **THEN** Run receives only the plugin-declared typed item aliases/quantities and stable delivery identity, not arbitrary browser commands + +### Requirement: Conclusive delivery outcomes +The system SHALL record a gift as delivered only after conclusive Run execution evidence, and ambiguous or partial outcomes SHALL not trigger automatic whole-package redelivery. + +#### Scenario: Job is queued or accepted +- **WHEN** Run has only claimed, acknowledged, or begun the delivery job +- **THEN** Platform records the delivery as in progress and SHALL NOT create a successful claim/receipt + +#### Scenario: Delivery succeeds conclusively +- **WHEN** Run returns a schema-valid success receipt for every required item under the delivery idempotency key +- **THEN** Platform records the delivery as delivered exactly once + +#### Scenario: Connection is lost after possible execution +- **WHEN** delivery may have executed but the result is missing, timed out, cancelled, or cannot be confirmed +- **THEN** Platform records an unknown outcome, performs confirmation before any explicit retry, and never automatically queues the entire delivery again + +#### Scenario: Multi-item delivery is partial +- **WHEN** the transport cannot guarantee atomic delivery and only some item receipts are conclusive +- **THEN** Platform records per-item receipts and a partial/unknown package outcome and SHALL NOT label the whole package delivered or blindly redeliver confirmed items + +#### Scenario: Notification fails after delivery +- **WHEN** all items are confirmed delivered but a post-delivery notification fails +- **THEN** Platform preserves the delivered fact, records the notification failure separately, and SHALL NOT redeliver the package + +### Requirement: Gift management surface and history +The gift page SHALL provide statistics, a searchable/filterable paginated package table, package create/edit/detail/delete controls, a real player selector, a reviewed send dialog, and server-scoped delivery history without Workflow terminology. + +#### Scenario: Operator opens gift management +- **WHEN** local gift data is available +- **THEN** the page shows package totals/enabled counts/delivery statistics, package contents and limits, and compact row actions without a hard-coded `starter-pack`, fixed player cards, or fixed notification text + +#### Scenario: Operator reviews delivery result +- **WHEN** a delivery is in progress, delivered, failed, unknown, partial, or has a notification failure +- **THEN** the page shows the ordinary gift-delivery result and safe reason without exposing a Workflow instance, Workflow step, raw command, or audit-initiation action diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-live-data-sync/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-live-data-sync/spec.md new file mode 100644 index 0000000..a9cd517 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-live-data-sync/spec.md @@ -0,0 +1,174 @@ +## ADDED Requirements + +### Requirement: Current-service schema compatibility gate +The system SHALL enable each SCUM database-backed capability only after the bound Run has performed a read-only probe against the current server database and the result matches a versioned plugin schema adapter for that capability. + +#### Scenario: Supported current schema is detected +- **WHEN** the bound Run reports a schema fingerprint whose required tables, columns, types, joins, and cardinality match the plugin adapter for player reads +- **THEN** Platform enables the player-read capability for that server and records the adapter version, fingerprint, probe time, and safe capability result + +#### Scenario: A current binding has no valid probe evidence +- **WHEN** a compatible Run binding becomes ready, reconnects, or reports a changed database/plugin identity without current probe evidence +- **THEN** Platform automatically schedules the bounded read-only probe before any affected query or write and exposes no browser action for starting it + +#### Scenario: Generic probe execution is unavailable +- **WHEN** the bound Run lacks the required generic diagnostic-probe contract +- **THEN** database-backed SCUM capabilities remain disabled with a safe connection/capability reason and SHALL NOT fall back to a copied database, cached schema, reference model, or guessed query + +#### Scenario: One world-data requirement is incompatible +- **WHEN** a required vehicle column is missing, has an incompatible type, or the declared join is not unique while player and squad requirements still match +- **THEN** Platform disables only the affected vehicle capability and SHALL NOT treat an empty vehicle list as a successful current-server result + +#### Scenario: Compatibility evidence becomes invalid +- **WHEN** the game version, database instance identity, Run binding, plugin adapter version, or schema fingerprint changes +- **THEN** Platform invalidates the affected capability evidence and requires a new successful probe before another query or write uses that evidence + +#### Scenario: Probe result is exposed safely +- **WHEN** Platform stores or returns schema compatibility status +- **THEN** the result excludes the database path, DSN, socket, credentials, raw SQL, raw row content, and host identity + +#### Scenario: Run snapshots the active database for a safe read +- **WHEN** Run must use an execution-time read-only snapshot to avoid locking the active SQLite database +- **THEN** the snapshot is bound to the current server/Run/database identity, timestamped, checksummed, short-lived, and rejected after rebinding or source-identity change + +### Requirement: Plugin-owned immutable parser and query assets +The SCUM plugin SHALL own versioned login parsers, SQLite query assets, and parameter/result schemas, and each executable data asset SHALL be referenced by an integrity digest in the plugin manifest and generated Run package. + +#### Scenario: Declared query is dispatched +- **WHEN** Platform schedules the declared player query with schema-valid bounded parameters +- **THEN** Run executes the matching packaged asset only after the plugin ID, version, template key, server binding, and asset digest all match + +#### Scenario: Caller supplies arbitrary query material +- **WHEN** a browser, AI request, Platform API caller, or job payload supplies raw SQL, an unknown template key, extra parameters, or a different asset digest +- **THEN** the request is rejected before SQLite execution and no protected query content is stored in a browser-visible response + +#### Scenario: SCUM behavior is absent from Run +- **WHEN** Run selects an executor for a SCUM plugin query +- **THEN** it uses generic SQLite and packaged-asset contracts and contains no branch keyed by SCUM, a `scum.*` template name, a SCUM table, or a SCUM command + +### Requirement: Bounded and correlated SQLite reads +Run SHALL execute plugin query assets with bound parameters and query-only restrictions, and Platform SHALL correlate every result to its original durable job before validating and storing it. + +#### Scenario: Query violates the read boundary +- **WHEN** an asset or parameter expansion attempts multiple statements, DDL, mutation, `ATTACH`, extension loading, a write PRAGMA, or string-concatenated parameter injection +- **THEN** Run rejects execution with a stable safe error and returns no rows + +#### Scenario: Query exceeds a declared bound +- **WHEN** execution times out, the database remains locked, or rows/result bytes exceed the template limits +- **THEN** Run stops the read and returns a bounded safe error without converting the failure into an empty successful result + +#### Scenario: Fast, duplicate, or late result arrives +- **WHEN** a result arrives immediately, is delivered more than once, or arrives after a newer scan +- **THEN** the pre-existing job correlation prevents loss or cross-server association, duplicate delivery is idempotent, and an older result cannot replace a newer completed generation + +#### Scenario: Result envelope is malformed +- **WHEN** the server/plugin binding, template key, schema version, asset digest, checksum, observed time, or row schema does not match the queued job +- **THEN** Platform rejects the result before any local SCUM record changes + +### Requirement: Authentic login-driven player and session records +The system SHALL parse the plugin-declared current SCUM login/logout format and atomically maintain a player and session uniquely scoped by server instance and external player identifier. + +#### Scenario: Parser version is enabled +- **WHEN** a plugin login parser is registered for a SCUM/game version +- **THEN** sanitized fixtures captured from the active service prove its successful login/logout mapping and parser digest before it can create durable players + +#### Scenario: Unknown player logs in successfully +- **WHEN** an authentic successful login event contains a valid external player ID, display name, event identity, and occurrence time +- **THEN** Platform atomically creates or updates exactly one `(server_instance_id, external_player_id)` player and opens one matching local session + +#### Scenario: Concurrent first-login delivery occurs +- **WHEN** two workers process the same new player's first successful login concurrently +- **THEN** a database unique constraint and idempotent event identity produce one player and one session without a duplicate-key user-visible failure + +#### Scenario: Duplicate or older event arrives +- **WHEN** an acknowledged login/logout event is replayed or an older logout arrives after a later login +- **THEN** Platform creates no duplicate session and does not regress the player's current display name, last-seen time, or newer online session + +#### Scenario: Source format has no native session identifier +- **WHEN** a valid login line has a transport cursor and player identity but no game-provided event/session ID +- **THEN** Platform derives a privacy-safe logical event fingerprint and deterministic server-scoped session identity from normalized non-network event fields, independent of stream generation, so replaying that logical line cannot create a second session + +#### Scenario: Line is malformed or login did not succeed +- **WHEN** a partial, malformed, undecodable, or oversized line, failed authentication attempt, disconnect without a matching identity, or unrelated log message is received +- **THEN** the parser emits no successful-login event and Platform creates no player or fabricated session + +#### Scenario: Logout has no matching session +- **WHEN** a valid logout event has no matching open session under the same server/player/source epoch +- **THEN** Platform records no fabricated login session and does not close a different or newer session + +#### Scenario: Network material is present +- **WHEN** the source login line includes an IP address or another network identifier +- **THEN** raw network material is discarded before durable player/session storage and is absent from SCUM APIs + +#### Scenario: Database save time changes +- **WHEN** a SCUM.db row reports `last_login_time`, `last_save_time`, or another persistence timestamp without a corresponding current login session event +- **THEN** Platform SHALL NOT mark the player online from that database timestamp alone + +### Requirement: Login stream continuity and binding fences +The login source SHALL keep transport cursor identity separate from stable logical event identity and preserve current-binding isolation across batch replay, file rotation/truncation, Run restart, reconnect, and partial-line boundaries. + +#### Scenario: Log file rotates or truncates +- **WHEN** the declared login file is replaced, rotated, or truncated +- **THEN** Run starts a new durable transport generation and resumes only at a complete-line boundary while any overlapped logical event retains the same privacy-safe fingerprint + +#### Scenario: Rotation overlap replays an acknowledged login +- **WHEN** a previously acknowledged logical login line is observed again under a new stream generation during copy-truncate or rotation overlap +- **THEN** the new transport event is acknowledged idempotently and Platform creates no second player or session + +#### Scenario: Run restarts with an acknowledged cursor +- **WHEN** Run restarts or reconnects after Platform acknowledged a source sequence +- **THEN** replay begins from a safe acknowledged boundary and duplicate batches remain idempotent + +#### Scenario: Event belongs to an obsolete binding +- **WHEN** a typed login/logout event carries a Run binding, server instance, plugin version, stream generation, or source identity that no longer matches the active binding +- **THEN** Platform rejects it before changing a player or session + +#### Scenario: Online session loses authoritative log continuity +- **WHEN** the binding is replaced, the server stops, or log continuity is lost without a matching logout event +- **THEN** Platform closes or marks the affected session unknown with a bounded terminal reason and SHALL NOT continue presenting it as a confirmed current login + +### Requirement: Automatic server-bound synchronization +The system SHALL synchronize verified SCUM.db resources automatically when a compatible Run binding becomes ready and at plugin-declared bounded cadences, without a user-facing manual data-refresh operation. + +#### Scenario: Compatible Run becomes ready +- **WHEN** a server obtains a current Run binding and successful capability probe +- **THEN** Platform schedules an initial bounded scan and later jittered resource scans within per-server concurrency limits + +#### Scenario: New login needs enrichment +- **WHEN** login ingestion creates a player whose database details are not yet known +- **THEN** Platform may schedule a bounded player-detail lookup without delaying player creation or filling unknown values with defaults + +#### Scenario: Page is opened +- **WHEN** an operator opens users, squads, map, or gifts +- **THEN** the page reads the platform-local data API and SHALL NOT dispatch a Run query, schema probe, projection refresh, audit, or synchronization command + +#### Scenario: A later scan fails +- **WHEN** a resource previously synchronized successfully and a later scan fails or is partial +- **THEN** Platform retains the last completed local generation, records the safe connection/sync failure internally, and does not delete rows or present generated replacements + +#### Scenario: Resource synchronization status is requested +- **WHEN** a local resource API reports its availability +- **THEN** it distinguishes not-yet-synchronized, successfully-synchronized-empty, schema-incompatible, current/last-complete data, and connection/read failure with concrete collection time and a safe reason + +#### Scenario: No completed local generation exists +- **WHEN** a current scan has not completed successfully +- **THEN** Platform returns the appropriate unavailable/not-yet-synchronized state and SHALL NOT fall back to a legacy projection, sample record, reference database, cached unbound row, or fabricated empty success + +### Requirement: Dedicated local SCUM database records +The system SHALL persist SCUM identities, sessions, details, squads, squad members, vehicles, flags, positions, gifts, deliveries, and sync cursors in dedicated queryable local stores rather than in SCUM projection/Workflow snapshot fields. + +#### Scenario: File storage backend is active +- **WHEN** Platform runs with the default file metadata backend +- **THEN** SCUM records use a platform-owned local database under the configured data directory and a position update does not rewrite the global metadata snapshot + +#### Scenario: MySQL storage backend is active +- **WHEN** Platform runs with the MySQL backend +- **THEN** explicit migrations create normalized SCUM tables with server-scoped indexes and uniqueness constraints instead of storing SCUM collections only inside `platform_metadata_snapshots.snapshot_json` + +#### Scenario: Source omits a numeric fact +- **WHEN** a verified row omits fame, currency, a coordinate, an owner, or another fact +- **THEN** the corresponding local field remains null/absent and SHALL NOT be set to zero, an inferred owner, a generated coordinate, or an unrelated identifier + +#### Scenario: Full scan completes +- **WHEN** every page of a bounded full resource scan passes schema and checksum validation +- **THEN** Platform transactionally commits that generation and may mark records absent only from that completed generation diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-player-management/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-player-management/spec.md new file mode 100644 index 0000000..208b077 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-player-management/spec.md @@ -0,0 +1,68 @@ +## ADDED Requirements + +### Requirement: Lean SCUM player record +The SCUM product SHALL maintain only server-scoped player identity, current display name, first/last seen times, online session/login history, and verified current-server player details required for management. + +#### Scenario: Player changes display name +- **WHEN** a newer authentic login event reports a different display name for an existing server-scoped player +- **THEN** Platform updates the current display name and SHALL NOT create alias-intelligence, shared-IP, access-risk, or automatic-enforcement records + +#### Scenario: SCUM player model is migrated +- **WHEN** the new player store becomes authoritative +- **THEN** SCUM page/API/manifest/log-ingestion flows no longer create, update, read, or expose player-intelligence, access-attempt, shared-fingerprint, security-signal, alias-history, projection, observation, or Workflow records; a shared non-SCUM domain may remain only for a proven non-SCUM consumer + +### Requirement: Searchable and paginated player roster +The system SHALL provide a server-authorized local player-list API and full-width table with server-side pagination, bounded search, online-state and squad filters, and allowlisted sorting. + +#### Scenario: Operator searches the roster +- **WHEN** an authorized operator searches by display name or external player ID and selects online or squad filters +- **THEN** Platform returns only matching players from the target server with total/page information and deterministic ordering + +#### Scenario: Cross-server player identifier is supplied +- **WHEN** the same external player ID exists on another server or a filter references another server's squad +- **THEN** the response includes no cross-server row and reveals no other server association + +#### Scenario: Unauthorized user requests players +- **WHEN** the session lacks effective read access to the target server +- **THEN** Platform denies the request without revealing whether any player exists + +### Requirement: Trustworthy roster values +The player roster SHALL display current stored business fields without fabricating defaults and SHALL distinguish online-session evidence from database details. + +#### Scenario: Verified player details exist +- **WHEN** local records contain verified fame, cash, gold, squad, and last activity facts +- **THEN** the roster shows player name, unique identifier, online state, those verified facts, and their last synchronized time + +#### Scenario: Database details are not yet known +- **WHEN** a login-created player has no successful detail row yet +- **THEN** the roster shows the player identity/session with unknown detail fields and SHALL NOT substitute zero, `1`, sample data, or a guessed profile identifier + +#### Scenario: No players have been recorded +- **WHEN** the local player table is confirmed empty +- **THEN** the page shows a normal player-data empty state without projection/Workflow terminology, sample players, or an action that starts data collection + +### Requirement: Player detail and login history +The system SHALL provide a player detail surface containing server-scoped identity, current verified facts, current known coordinate, login history, and last synchronized/collected times. + +#### Scenario: Operator opens player detail +- **WHEN** an authorized operator selects a roster row +- **THEN** a drawer, dialog, or detail route shows the player's known fields and bounded login history without exposing raw logs, IP addresses, database rows, SQL, XML, paths, or credentials + +#### Scenario: Coordinate is unavailable +- **WHEN** no verified current coordinate exists for the player +- **THEN** the detail surface states that the coordinate is unavailable and SHALL NOT calculate or render a default map point + +### Requirement: Explicit player edit form +The user-management surface SHALL edit player values through a named-field form that shows current and proposed values and delegates execution to the controlled-write capability. + +#### Scenario: Operator edits an economy field +- **WHEN** an operator opens the Fame, cash, or gold edit control +- **THEN** the form requires an explicit target value and reason and SHALL NOT use hard-coded `+100`, `+1000`, or other fixed increment behavior + +#### Scenario: Attribute current value is unknown +- **WHEN** an operator opens an attribute or `855` preset edit without verified current named values +- **THEN** the UI prevents submission and explains that current values must be known; it SHALL NOT default the before or after value to `0` or `1` + +#### Scenario: User has read but not write access +- **WHEN** the current session may read players but lacks the effective permission for the selected field +- **THEN** the roster and detail remain available while the edit action is hidden or disabled with a readable permission explanation diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-real-data-management-surface/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-real-data-management-surface/spec.md new file mode 100644 index 0000000..a64b581 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-real-data-management-surface/spec.md @@ -0,0 +1,95 @@ +## ADDED Requirements + +### Requirement: Exact SCUM detail navigation +The SCUM server detail view SHALL contain exactly five tabs in this order: `用户管理`, `队伍管理`, `实时地图`, `礼包管理`, `AI 助手`. + +#### Scenario: SCUM detail opens normally +- **WHEN** an operator opens a SCUM server detail without a valid section selector +- **THEN** the page selects `用户管理` as the default and renders no standalone `管理` or `Workflow 状态` tab + +#### Scenario: Legacy section is requested +- **WHEN** a legacy `manage`, `workflows`, or otherwise invalid SCUM section is requested +- **THEN** the page replaces/falls back to `用户管理` without an empty screen or a Workflow/management placeholder + +#### Scenario: Non-SCUM server detail is rendered +- **WHEN** another plugin/server type legitimately declares different navigation +- **THEN** the SCUM-only five-tab restriction does not silently remove that plugin's declared pages + +### Requirement: Required management controls are relocated +Removing the SCUM `管理` tab SHALL NOT remove server deployment, metadata, or administrator-membership capabilities. + +#### Scenario: Operator edits deployment +- **WHEN** an authorized operator needs to change the SCUM deployment definition +- **THEN** the existing server-list deployment action remains available and no replacement permanent detail tab is introduced + +#### Scenario: Server owner opens settings +- **WHEN** the server owner selects the compact settings action in the detail header +- **THEN** a drawer or dialog permits display-name and administrator membership changes with the existing ownership authorization + +#### Scenario: Non-owner opens server settings +- **WHEN** a server member who is not the owner views the settings surface +- **THEN** owner-only membership mutations are unavailable and a direct API attempt remains forbidden + +### Requirement: Projection and Workflow concepts are removed from the product +SCUM pages and browser contracts SHALL NOT render or offer projection, observation, manual synchronization, audit-initiation, pending-review counter, or Workflow product concepts. + +#### Scenario: Any retained SCUM page renders +- **WHEN** users, squads, map, gifts, or AI content is displayed +- **THEN** it contains none of `Workflow 状态`, `投影`, `真实投影`, `玩家投影`, `刷新投影`, `刷新世界投影`, `刷新真实数据`, `发起审计`, `创建发放 workflow`, `typed workflow`, `typed observation`, `typed operation`, `待审操作`, `审批/确认队列`, `清理旧入口`, `目前暂无真实投影数据`, `暂无真实投影数据`, `暂无玩家投影`, or `Companion 可用` + +#### Scenario: Plugin page loads data +- **WHEN** any of the four SCUM management pages initializes or retries a failed local read +- **THEN** it calls only its local resource API and does not list/create Workflow instances/steps or start a query, projection refresh, real-data refresh, or audit + +#### Scenario: Removed endpoint is requested +- **WHEN** a browser requests the removed SCUM Workflow, Workflow-step, observation, operation-list/approve, projection/real-data refresh, or audit-initiation endpoint +- **THEN** Platform returns not found or a stable removal response without dispatching a job or exposing a replacement raw execution path + +#### Scenario: Legacy operation approval route is requested +- **WHEN** a caller invokes a legacy SCUM operation-list, `/scum/operations/{id}/approve`, pending-review, or confirmation-queue route +- **THEN** Platform returns not found or a stable removal response and SHALL NOT create an approval record, dispatch a write, or revive an approval product domain + +#### Scenario: Internal write safety is recorded +- **WHEN** Platform records authorization, idempotency, backup, execution, or confirmation evidence for a write +- **THEN** the record remains internal/safe and does not create a user-facing audit-start action or Workflow status page + +### Requirement: Trustworthy management page layouts +The user, squad, map, and gift pages SHALL use full-width business data layouts and shared theme-aware table, drawer, dialog, and status patterns without placeholder product data. + +#### Scenario: Management page is implemented +- **WHEN** a first-party SCUM page adds or changes styles +- **THEN** it preserves black-mecha and magical-girl theme readability, reuses shared tokens/components, keeps CSS declarations compact, and does not add unrelated opaque SaaS cards or page-local fixed decorative effects + +#### Scenario: Data load fails +- **WHEN** a local API request fails +- **THEN** the page shows a readable error and may retry only the local read; it does not generate sample players, squads, vehicles, flags, positions, gifts, maintenance evidence, backups, or operation results + +### Requirement: AI assistant is preserved with reviewable effects +The `AI 助手` SHALL remain the final SCUM tab and SHALL support plugin-declared configuration suggestions and controlled player-operation drafts without receiving provider secrets or independent write authority. + +#### Scenario: AI suggests plugin configuration +- **WHEN** an authorized operator requests SCUM plugin configuration assistance +- **THEN** AI proposes only plugin-declared fields, Platform validates and displays a reviewable diff, and the authorized review-and-confirm config-write path applies the change only after explicit confirmation + +#### Scenario: User can view but cannot apply a suggestion +- **WHEN** the user may invoke/read an AI suggestion but lacks the permission required for the proposed config or player write +- **THEN** the suggestion remains reviewable while the apply action is disabled and backend application is forbidden + +#### Scenario: AI provider is invoked +- **WHEN** Platform sends the allowed prompt/context to the configured AI provider +- **THEN** raw AI keys, database credentials, SCUM.db paths, raw XML, and protected Run material never reach the plugin page/browser + +### Requirement: Obsolete UI actions and placeholders are removed +The SCUM product SHALL replace hard-coded actions and placeholder map/gift behavior with the declared business flows. + +#### Scenario: Player actions render +- **WHEN** a player has writable verified fields +- **THEN** the UI offers explicit named-field editing and contains no `Fame +100`, `现金 +1000`, `855 审批`, fake before value, fake maintenance ID, or fake backup reference + +#### Scenario: Map renders +- **WHEN** the map page is available +- **THEN** it uses the verified map capability and contains no gradient-only board or arbitrary percentage-dot transform + +#### Scenario: Gift page renders +- **WHEN** gift management is available +- **THEN** it reads local gift packages and contains no hard-coded `starter-pack`, fixed player-card delivery, or fixed notification text diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-realtime-map/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-realtime-map/spec.md new file mode 100644 index 0000000..b80e31c --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-realtime-map/spec.md @@ -0,0 +1,69 @@ +## ADDED Requirements + +### Requirement: Independently verified current map facts +The system SHALL store and present current player, vehicle, flag, and squad-territory coordinates only when each resource's plugin adapter maps a compatible current-service source, identity, coordinate, and observation time. + +#### Scenario: One position resource is incompatible +- **WHEN** player and flag positions are compatible but the vehicle query lacks a required column, type, identity, or unique join +- **THEN** Platform keeps the verified player/flag layers available, disables only the vehicle layer, and SHALL NOT return an empty vehicle list as a successful current result + +#### Scenario: Vehicle ownership is unverified +- **WHEN** the source proves a vehicle identity/class and coordinate but does not prove a player or squad owner +- **THEN** Platform stores the verified fields and leaves ownership null instead of inferring it from nearby players, movement history, or an expiry heuristic + +#### Scenario: Position scan later fails +- **WHEN** verified positions were previously stored and a later current-service scan fails or is partial +- **THEN** the map may retain the last completed rows with their concrete collection time and connection interruption, but SHALL NOT call them current or replace them with empty/generated points + +### Requirement: Declared SCUM map asset and coordinate transform +The realtime map SHALL use a plugin-declared distributable map asset/version and integrity digest, verified world bounds, and a tested coordinate transform version/digest compatible with the current SCUM adapter. + +#### Scenario: Verified coordinate is rendered +- **WHEN** a player, vehicle, flag, or territory coordinate falls within the declared bounds and transform version +- **THEN** the map places the marker at the tested map position and shows object type, name/ID, source coordinate, and collection time + +#### Scenario: Map metadata is incompatible or absent +- **WHEN** the map asset, version, bounds, or transform does not match the current server adapter +- **THEN** the map shows a readable unavailable/error state and SHALL NOT fall back to a gradient board, arbitrary percentage transform, fake points, or sample routes + +#### Scenario: Map asset digest does not match +- **WHEN** the packaged/browser-served map asset or transform contract fails its plugin-declared integrity check +- **THEN** the map is unavailable and SHALL NOT render coordinates against an unverified replacement asset + +#### Scenario: Coordinate is outside bounds +- **WHEN** a source coordinate is non-finite or outside the declared world bounds +- **THEN** Platform rejects it from the current map dataset and records a bounded validation failure + +### Requirement: Automatically updated and distinguishable map layers +The realtime map SHALL consume platform-local data automatically and provide distinguishable player, vehicle, and flag/squad-territory layers with player/squad filtering. + +#### Scenario: Operator changes layer visibility +- **WHEN** an operator toggles players, vehicles, or flags/territory or applies a player/squad filter +- **THEN** the map updates the visible verified markers without dispatching a Run query or manual refresh operation + +#### Scenario: Platform receives a newer coordinate +- **WHEN** a verified automatic sync or declared companion position event updates a current position +- **THEN** Platform publishes a safe local update and the open map can update through the platform event stream + +#### Scenario: Source cadence is insufficient +- **WHEN** measured SCUM.db updates cannot support the declared realtime threshold +- **THEN** the plugin uses a declared verified companion position source or the feature presents the measured cadence honestly; it SHALL NOT increase unsafe polling or fabricate intermediate movement + +#### Scenario: Map legend is rendered +- **WHEN** multiple entity types are visible +- **THEN** the UI provides icons or textual legend labels so entity meaning does not rely only on color + +#### Scenario: Historical movement was not requested +- **WHEN** only current positions are available under this change +- **THEN** the product SHALL NOT fabricate trajectories, 24-hour trails, ride associations, sampling history, or playback controls to satisfy realtime-map acceptance + +### Requirement: Server-isolated realtime-map API +The realtime-map API SHALL authorize the target server and return only bounded local current-position and safe object-summary fields needed by the map. + +#### Scenario: Foreign map selector is supplied +- **WHEN** a player, squad, vehicle, flag, or territory selector belongs only to another server +- **THEN** Platform returns no foreign marker and does not reveal its existence or server identity + +#### Scenario: Browser requests protected source material +- **WHEN** a browser attempts to request raw database rows, SQL, host paths, database identifiers, map-source credentials, or Run connection details +- **THEN** the API rejects the request and returns only named safe map fields diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-squad-management/spec.md b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-squad-management/spec.md new file mode 100644 index 0000000..74ad6dc --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/specs/scum-squad-management/spec.md @@ -0,0 +1,53 @@ +## ADDED Requirements + +### Requirement: Independently gated squad, member, flag, and territory facts +The system SHALL store and present squads, squad members, leader/rank meaning, flags, territories, and their relationships only from current-service rows validated by the matching per-resource plugin adapter capability. + +#### Scenario: Squad and member adapters are compatible +- **WHEN** squad and member queries complete successfully with verified identifiers, ranks, and player/profile relationships +- **THEN** Platform transactionally stores server-scoped squads and members and exposes only the leader/rank meaning declared by that adapter + +#### Scenario: One squad resource is incompatible +- **WHEN** squad/member queries are compatible but flag ownership or territory coordinates are not +- **THEN** Platform keeps the verified squad/member capability available, disables only the incompatible resource, and SHALL NOT treat its absence as a verified empty list + +#### Scenario: Leader meaning is unverified +- **WHEN** the current schema contains a rank value but the adapter cannot prove which value represents leader +- **THEN** Platform keeps leader unknown and SHALL NOT assume that a reference-project constant such as rank `4` is authoritative + +#### Scenario: Flag ownership join is ambiguous +- **WHEN** a flag/base/profile relationship yields multiple possible squad owners or no verified squad link +- **THEN** Platform records no squad owner for that flag and exposes no inferred confidence label as fact + +### Requirement: Searchable and paginated squad roster +The system SHALL provide a server-authorized local squad-list API and full-width table with bounded name/identifier search, server-side pagination, allowlisted sorting, and deterministic results. + +#### Scenario: Operator searches squads +- **WHEN** an authorized operator searches or pages the target server's squads +- **THEN** Platform returns only matching server-local rows with total/page information, and the table shows squad ID, name, verified leader, member count, flag/territory status, known coordinate, and collection time + +#### Scenario: No completed squad generation exists +- **WHEN** squads have not synchronized successfully or the squad adapter is incompatible +- **THEN** the page shows the corresponding not-yet-available/error state and SHALL NOT render reference, sample, projection, or generated squads + +### Requirement: Semantic squad detail +The squad surface SHALL provide a drawer, dialog, or detail route that separates leader, members/ranks, flags, and territory instead of merging unrelated rows into one list. + +#### Scenario: Operator opens a squad +- **WHEN** a server-authorized operator selects a squad +- **THEN** the detail shows only verified leader/member/rank and flag/territory facts with collection times and nullable unknown fields + +#### Scenario: Verified territory coordinate is selected +- **WHEN** a squad or flag has a compatible verified coordinate and the realtime-map capability is available +- **THEN** the detail may navigate to that coordinate on the map without dispatching a new Run query or inventing a fallback point + +### Requirement: Server-isolated squad APIs +Squad APIs SHALL authorize the target server and return only bounded local squad, member, flag, and territory fields needed by the management surface. + +#### Scenario: Foreign selector is supplied +- **WHEN** a squad, player/member, flag, or territory selector belongs only to another server +- **THEN** Platform returns no foreign record and does not reveal its existence or server identity + +#### Scenario: Browser requests protected source material +- **WHEN** a browser attempts to request raw SCUM.db rows, query text, host paths, database identifiers, or Run connection details +- **THEN** the API rejects the request and returns only named safe resource fields diff --git a/openspec/changes/replace-scum-projections-with-real-data-management/tasks.md b/openspec/changes/replace-scum-projections-with-real-data-management/tasks.md new file mode 100644 index 0000000..a9cfa00 --- /dev/null +++ b/openspec/changes/replace-scum-projections-with-real-data-management/tasks.md @@ -0,0 +1,168 @@ +## 1. Prompt Boundaries + +- [ ] 1.1 正向提示词 (Positive prompt): Rebuild the SCUM portion of the first-party `服务器管理` area around authentic current-server login events, verified current-service database facts, dedicated local records, trustworthy user/squad/map/gift management, and a preserved AI assistant. Success requires exactly five SCUM tabs, automatic player creation and synchronization, no fabricated values, and permission-checked reviewable writes. +- [ ] 1.2 方向提示词 (Directional prompt): Work in `platform/`, `platform_web/`, `plugins/`, and explicit browser-repository protocol contracts while coordinating a separately authorized task in the independent `git@git.npc0.com:admin343/run.git` repository. Use `/Users/tasia/Desktop/code/go/scum/scum_robot` only as a read-only behavioral reference for login ingestion and user/squad/map/gift interactions; derive schema, joins, commands, coordinates, and mutation semantics exclusively from the active bound service. Preserve durable jobs, channel isolation, plugin ownership, API/type directory boundaries, and the black-mecha/magical-girl visual system. Required evidence includes Platform/Plugins/Web and SCUM companion tests, the external Run task's own tests/commit/deployment evidence, current-service and browser acceptance, `scripts/check-structure.sh`, and strict OpenSpec validation. +- [ ] 1.3 任务边界 (Boundary prompt): Do not add a `run/` source tree to this repository; modify `/Users/tasia/Desktop/code/go/scum/scum_robot`; edit the independent Run repository except inside its own separately authorized/rooted task; touch unrelated roots; use an unbound repository/reference/cached `SCUM.db` as current-service evidence; trust generated/reference structs as production schema; expose raw SQL/RCON/XML/paths/credentials/sockets to browser or AI; add billing/cloud-host/agent-provider workflows; fabricate players/world facts/backups/results; create a platform-admin approval queue; or reintroduce projection, observation, audit-initiation, manual-refresh, pending-review, or Workflow product concepts. A short-lived read-only snapshot created by Run is allowed only when fenced to the active binding/database identity, timestamped, checksummed, and invalidated on source change. +- [ ] 1.4 Before implementation, confirm the browser repository is on `main` and record existing dirty files; if the branch is not `main` or local changes block a safe switch, stop without creating another branch or editing files. + +## 2. Minimal Run Probe and Current-Service Evidence Gate + +- [ ] 2.1 Add a release gate that keeps every database-backed SCUM read and write capability disabled until capability-specific current-service evidence matches a versioned plugin adapter; do not add production SQL or mutation assets before this group is complete. +- [ ] 2.2 Define the minimal generic schema-probe request/result contract, safe error model, binding identity, bounds, and redacted evidence DTO needed by Platform and the plugin without embedding SCUM table names or host paths in Run-facing generic code. +- [ ] 2.3 If the active binding lacks the minimal bounded query-only probe executor, create/hand off a separately authorized task rooted in the independent Run repository, wait for its tests/commit/deployment evidence, and record that evidence here; do not edit or vendor Run source from this change. +- [ ] 2.4 Use the personal server-management MCP (`list_devices`, `test_connection`, then `ssh_exec` only when needed) for device inventory, connectivity checks, and bounded diagnostics. Execute the actual schema probe only as a Platform durable job through the active authenticated Run binding; never run SCUM SQL directly over SSH or bypass the Run channel. +- [ ] 2.5 Capture `sqlite_master`, applicable read-only PRAGMA metadata, indexes, foreign keys, declared types, cardinalities, and small redacted samples for candidate player, profile/entity, squad/member, vehicle, flag/base, economy, coordinate, and character-profile payload sources. +- [ ] 2.6 Verify actual joins and meanings for external player identity, profiles/entities, squad ranks/leaders, flag ownership, vehicle identity, currency units/types, nullable fields, and the real table/column containing character XML; do not assume that `user_profile.template_xml` or any reference-project field exists. +- [ ] 2.7 Measure coordinate ranges and update cadence, query latency, lock/busy behavior, snapshot consistency, safe timeout/row limits, and whether a verified companion position source is needed for the advertised realtime-map cadence. +- [ ] 2.8 Confirm separately which economy commands support safe confirmation, which gift item aliases/transports are real, which distributable map asset/transform is authorized, and what named attributes—if any—the operator means by the `855` preset. +- [ ] 2.9 Store sanitized probe evidence or an immutable referenced test artifact and derive the observed schema fingerprint/evidence matrix; do not claim final adapter compatibility until the versioned adapters and query contracts in group 3 exist. + +## 3. Plugin SDK, Manifest, and Immutable SCUM Assets + +- [ ] 3.1 Add SDK and manifest types for versioned log parsers, SQLite query assets, parameter/result schemas, capability-specific schema fingerprints, sync cadence/limits, map metadata, typed RCON templates, gift item catalogs, and guarded mutation declarations. +- [ ] 3.2 Extend plugin validation to require asset digests, contained package paths, unique template keys, bounded parameters/results, compatible adapter versions, and explicit permission bindings, and to reject raw caller-supplied SQL, RCON, XML, paths, or undeclared parameters. +- [ ] 3.3 Capture sanitized authentic login-log fixtures from the active service and bind their expected events to server, Run binding, plugin version, parser version/digest, a transport cursor `(source identity, stream generation, sequence)`, and a separate privacy-safe logical event identity stable across rotation overlap. +- [ ] 3.4 Implement the versioned SCUM login/logout parser and tests for successful login/logout, failed login, partial/undecodable/oversized/malformed lines, copy-truncate/rotation overlap under a new generation, Run restart/resume, duplicate delivery, and out-of-order delivery while discarding IP/network material before storage or logical fingerprinting. +- [ ] 3.5 Add parameterized, read-only player identity/detail/economy/session-enrichment query assets and exact result schemas only for joins and fields proven by the probe. +- [ ] 3.6 Add parameterized squad/member, vehicle, flag/territory, and position query assets and exact result schemas, keeping ambiguous ranks, ownership, coordinates, and missing numeric values null. +- [ ] 3.7 Add query-asset tests for single SELECT/CTE or approved introspection boundaries, parameter binding, pagination/cursors, timeout/row/byte limits, schema-version matching, and rejection of DDL, mutation, `ATTACH`, extension loading, write PRAGMAs, and multi-statement input. +- [ ] 3.8 Package the authorized SCUM map asset, identity/version, verified world bounds, layer metadata, and coordinate transform, with fixture tests for known points, out-of-bounds/non-finite coordinates, and adapter incompatibility. +- [ ] 3.9 Declare only verified typed RCON templates for supported Fame/currency/notification/gift operations and a version-scoped gift item catalog; omit any command whose execution and confirmation semantics remain unknown. +- [ ] 3.10 Declare a guarded preserving XML mutation only after the real XML source and named attributes are proven; expose `855` only as a reviewed named-attribute preset and never as a database column, generic integer field, or guessed mapping. +- [ ] 3.11 Add immutable asset/digest declarations and plugin package validation; defer generated Run-package execution wiring until the complete protocol/result envelope and independent Run capability evidence in group 4 are frozen. +- [ ] 3.12 Remove SCUM Workflow/projection declarations and obsolete page/action declarations from the plugin manifest while preserving the five required pages and AI configuration assistance. +- [ ] 3.13 Match the observed fingerprint/evidence matrix against each completed adapter, add per-capability compatibility/release-gate tests, and leave every unsupported or ambiguous player/squad/vehicle/flag/position/write capability disabled. + +## 4. Generic External Run Execution and Result Contracts + +- [ ] 4.1 Add Platform protocol contracts under `platform/protocol`, API DTOs under `platform/dto`, validation under `platform/validator`, and plugin contracts/assets under `plugins/sdk` and `plugins/schemas`, plus contract documentation/mocks for probes, read-only template execution, typed RCON, guarded SQLite/XML mutation, parsed log events, and terminal result envelopes. +- [ ] 4.2 Freeze the generic executor/result contract and hand off a separately authorized Run-repository task for packaged SQLite-template execution with query-only connections, bound parameters, one-statement validation, short busy/operation timeouts, cancellation, and row/result-byte limits. +- [ ] 4.3 Require the independent Run task to return typed envelopes containing server/plugin binding, adapter/schema version, template key, asset digest, job identity, observed time, checksum, rows or affected-row count, and stable safe result/error codes. +- [ ] 4.4 Require the independent Run task to implement generic plugin-owned typed RCON-template execution without accepting browser command text or adding branches for SCUM, SCUM keys, SCUM commands, or SCUM tables. +- [ ] 4.5 Require the independent Run task to implement generic guarded single-row SQLite/XML mutation execution with expected identity/value/checksum guards, a bounded transaction, preserving XML patching, rollback on zero/multiple affected rows, and read-after-write confirmation. +- [ ] 4.6 Require the independent Run task to implement or extend generic plugin-declared log-source tailing so cursor persistence, rotation, truncate, restart, partial-line buffering, parser digest fencing, logical event fingerprinting, and replay remain independent of SCUM-specific source paths. +- [ ] 4.7 Verify from the independent Run task's acceptance evidence that control/job/log/artifact priorities, leases, fencing, acknowledgements, idempotency, and late/duplicate terminal-result handling remain intact for the new generic capabilities. +- [ ] 4.8 Add Platform-side capability negotiation so probe, player/squad/vehicle/flag/position reads, typed commands, gifts, and guarded mutations are gated independently for each active Run/plugin/adapter binding. +- [ ] 4.9 After the external Run contract tests/commit/deployment evidence is available, wire immutable assets and digests into generated Run packages and add distribution/contract tests proving Platform sends only template keys, bounded parameters, adapter version, and expected digest. + +## 5. Dedicated Platform SCUM Persistence + +- [ ] 5.1 Define SCUM domain types and narrow repository/service interfaces in the required `platform/` directories, keeping API DTOs, database models, validation, and repository contracts separate. +- [ ] 5.2 Add dedicated player, session, player-detail, source-event, sync-cursor, capability-evidence, and completed-generation records with server-scoped identities and nullable unknown fields. +- [ ] 5.3 Add dedicated squad, squad-member, vehicle, flag/territory, and current-position records with source checksum/time, adapter version, generation, and server-scoped indexes. +- [ ] 5.4 Add dedicated gift-package, gift-item, frozen-delivery, per-item receipt, eligibility-period reservation, notification-result, and immutable completed-delivery records. +- [ ] 5.5 Implement normalized MySQL models and explicit migrations with uniqueness constraints for player/event/session identity, generation rows, gift idempotency, and concurrent eligibility reservations. +- [ ] 5.6 Implement the default file-backend SCUM store as a platform-owned SQLite sidecar under the configured data directory, with pinned driver/migration behavior and no high-frequency writes to the global metadata snapshot. +- [ ] 5.7 Implement the memory backend with the same server isolation, uniqueness, transaction, null, generation, and idempotency semantics for tests. +- [ ] 5.8 Implement transactional generation commits so a complete validated scan may mark missing rows absent, while partial/failed/older scans preserve the last completed generation unchanged. +- [ ] 5.9 Add health, migration, rollback/disable, and database-instance invalidation behavior; never migrate old projection/Workflow snapshot values into the new tables as game facts. +- [ ] 5.10 Add backend-parity tests for migrations, uniqueness, concurrent first login, nullable numeric values, failed-generation retention, server isolation, and gift reservation/idempotency constraints. + +## 6. Authentic Login Ingestion and Automatic Synchronization + +- [ ] 6.1 Add a typed parsed-log event ingress that authenticates and correlates server binding, plugin/adapter/parser digest, transport cursor `(source identity, stream generation, sequence)`, separate stable logical event identity, and occurrence time before calling SCUM ingestion. +- [ ] 6.2 Atomically upsert one `(server_instance_id, external_player_id)` player and open one session for an authentic successful login without waiting for database enrichment. +- [ ] 6.3 Close only the matching current session on logout, do not fabricate a session for an unmatched logout, and prevent older logout/login events from regressing a newer display name, last-seen time, or online session. +- [ ] 6.4 Close or mark sessions unknown with a bounded reason when a binding/source epoch is replaced, server stops, or log continuity is lost without a logout; never leave them permanently confirmed online from database save timestamps. +- [ ] 6.5 Strip raw IP addresses and all network identifiers before durable player/session/event storage and exclude them from every SCUM API, diagnostic, and AI context. +- [ ] 6.6 Add ingestion tests for concurrent first login, replayed events, duplicate/out-of-order events, failed login, unmatched logout, partial-line resume, copy-truncate/rotation overlap replay under a new generation, Run restart, parser-digest mismatch, cross-server events, and database timestamps that must not imply online state; an overlapped logical login SHALL still produce one player/session. +- [ ] 6.7 Add an automatic scheduler that starts a capability-specific probe when an active binding lacks current evidence, starts an initial bounded scan after compatibility succeeds, then uses plugin-declared jittered cadences, backoff, and per-server/per-capability concurrency limits. +- [ ] 6.8 Schedule bounded player-detail enrichment after a new login without delaying player creation, and use the measured safe position cadence or a declared verified companion source without fabricated intermediate motion. +- [ ] 6.9 Create every durable Run job before dispatch and attach the expected server/plugin/template/digest/schema/generation correlation needed for immediate, late, and duplicate results. +- [ ] 6.10 Add a terminal-job hook that validates the full result envelope and row schema before calling the matching transactional SCUM sync service. +- [ ] 6.11 Reject malformed, foreign, duplicate, or older results idempotently; commit only complete generations and retain prior rows plus a safe connection/sync error after locks, timeouts, partial results, or incompatible schemas. +- [ ] 6.12 Publish safe player/session/squad/map updates through a platform-owned event stream/SSE while keeping Platform Web reads backed by local records. +- [ ] 6.13 Add tests proving page opens/retries never create schema probes, Run queries, projection refreshes, real-data refreshes, manual syncs, or audit jobs. + +## 7. Player Management APIs + +- [ ] 7.1 Add safe player-list/detail/session DTOs, request schemas, validators, API clients/contracts, and routes in their fixed directories without exposing raw logs, database rows, XML, SQL, paths, or network material. +- [ ] 7.2 Implement server-side player pagination, bounded name/external-ID search, online and squad filters, deterministic allowlisted sorting, and total/page metadata against the local SCUM store. +- [ ] 7.3 Implement player detail with identity, verified nullable facts, current verified coordinate, bounded login history, source collection times, and explicit not-yet-synchronized/confirmed-empty/incompatible/connection-failed states. +- [ ] 7.4 Enforce target-server read authorization before lookup and prevent cross-server player IDs, squad filters, selectors, counts, or existence from leaking. +- [ ] 7.5 Preserve unknown values as null/absent throughout storage, service, DTO, and JSON handling; never substitute zero, sample data, guessed profile IDs, or database save time as online evidence. +- [ ] 7.6 Remove player-intelligence, alias-history, shared-IP, access-attempt, automatic-risk, security-signal, and hard-coded increment dependencies from the SCUM player API and ingestion flow. +- [ ] 7.7 Add repository/service/API tests for search/filter/sort bounds, pagination stability, confirmed-empty versus unavailable data, nullable facts, login history, authorization, cross-server isolation, and absence of manual-refresh endpoints. + +## 8. Squad Management and Realtime Map APIs + +- [ ] 8.1 Implement server-scoped paginated/searchable/sortable squad list and detail APIs with verified members, adapter-declared rank meanings, leader when proven, flags/territory, and ordinary collection times. +- [ ] 8.2 Keep leader, rank, territory, and ownership unknown when joins or enum meanings are ambiguous, gate squad/member/flag/territory resources independently, and test that reference constants or proximity/history heuristics are not evidence. +- [ ] 8.3 Implement bounded local vehicle and flag APIs containing only verified identity, class/status, coordinate, ownership, and collection fields supported by each active adapter capability. +- [ ] 8.4 Implement a safe current-map dataset API for players, vehicles, flags, squads/territories, layer filters, and source collection times without returning database or Run connection material. +- [ ] 8.5 Apply the plugin-declared map version/bounds/coordinate transform server-side or through a shared tested contract, rejecting incompatible, non-finite, and out-of-bounds coordinates instead of generating fallback points. +- [ ] 8.6 Publish newer verified position/map updates through the platform event stream with entity identity and server/version fencing; page subscriptions must not dispatch Run reads. +- [ ] 8.7 Enforce server authorization, bounded selectors/result sizes, and no cross-server existence leaks across all squad/map endpoints. +- [ ] 8.8 Add service/API tests for successful and failed generations, per-resource gating, unknown ownership/ranks, last-complete rows after interruption, transform fixtures, layer filtering, event ordering, and incompatible-map unavailable results. + +## 9. Gift Management, Eligibility, and Delivery + +- [ ] 9.1 Add server/plugin-version-scoped gift package and typed item validators for names, classification, active state, quantities, eligibility rules, period limits, and only plugin-catalogued item keys. +- [ ] 9.2 Implement `server.game-client.read` package/history reads, `server.game-client.maintenance` package create/update/enable/delete, and `server.game-client.command` reviewed delivery APIs using the current session's effective target-server permissions. +- [ ] 9.3 Evaluate per-player/server/period eligibility in the server's declared timezone and reserve limit capacity transactionally for in-flight, partial, and unknown deliveries so concurrent requests cannot exceed the configured limit. +- [ ] 9.4 Freeze target player, package/items, quantities, plugin/game/adapter version, period reservation, delivery identity, and idempotency key before dispatch; later package edits must not alter a delivery. +- [ ] 9.5 Dispatch only plugin-declared typed item aliases and quantities through the controlled command path, never arbitrary browser command strings. +- [ ] 9.6 Treat queued, claimed, acknowledged, or started jobs as in progress; record `delivered` only after a schema-valid conclusive receipt for every required item. +- [ ] 9.7 Preserve reservations and per-item receipts for timed-out, missing, partial, or unknown outcomes, require confirmation before an explicit retry, and never automatically redeliver the whole package or already confirmed items. +- [ ] 9.8 Release a period reservation only after conclusive evidence that no game effect occurred; record post-delivery notification failure separately without changing the delivered fact or triggering redelivery. +- [ ] 9.9 Add server-scoped package statistics, searchable/filterable pagination, real player selection, reviewed send requests, and ordinary delivery-history/result APIs without Workflow or audit terminology. +- [ ] 9.10 Add concurrency, idempotency, timezone-boundary, cross-server, catalog-version, partial/unknown outcome, reservation-release, notification-failure, permission, and immutable-history tests. + +## 10. Controlled Manual and AI/Agent Writes + +- [ ] 10.1 Define one named-field write draft containing server/player/action/field, verified current value/checksum, proposed value, reason, adapter/digest, idempotency key, safety requirements, and a safe reviewable diff. +- [ ] 10.2 Authorize the current user's effective target-server permission when a draft is created, reviewed, confirmed, and dispatched, with backend checks authoritative and no component-principal, manifest-declaration, or callback-presence bypass. +- [ ] 10.3 Supply the plugin page host with the current session's effective permissions and readable denial reasons while keeping direct API denial authoritative. +- [ ] 10.4 Route verified Fame/cash/gold writes through plugin-owned typed RCON templates with `server.game-client.command`, validated absolute target values, explicit reason, idempotency, and declared confirmation reads. +- [ ] 10.5 Route database/XML writes only with effective `server.game-client.maintenance`, verified target/offline or maintenance state when required, genuine same-instance restorable backup evidence, expected before values/checksum, and an explicit dangerous-operation confirmation; do not create a platform-admin approval workflow or approval queue. +- [ ] 10.6 Execute preserving named-attribute XML patches only against the probe-confirmed source, reject malformed XML or absent/undeclared nodes, preserve unknown content, and update exactly one guarded row. +- [ ] 10.7 Keep `855` absent until its named mapping is confirmed; when available, expand it into an explicit per-attribute before/after review rather than accepting `fieldKey=855`, `prisoner.value`, or a generic integer. +- [ ] 10.8 Validate command/mutation terminal envelopes and readback before success, update local verified details only after conclusive confirmation, and represent missing/mismatched results as failed, conflict, or unknown without automatic retry. +- [ ] 10.9 Never chain kill, death, respawn, kick, or another destructive activation to attribute save; any verified required activation must be a separate explicitly named, permission-checked, confirmed action. +- [ ] 10.10 Preserve AI-assisted plugin configuration through the existing platform-mediated reviewable config-diff path without exposing provider keys or granting the plugin page direct write authority. +- [ ] 10.11 Make AI/Agent player-operation suggestions create the exact same named-field draft as manual forms, reject undeclared fields/protected payloads, retain the initiating user, and require that user's current effective permission plus explicit confirmation. +- [ ] 10.12 Add tests for read-only users, revoked permissions between draft and dispatch, cross-server targets, invented AI fields, stale checksums, fake backup evidence, unsafe online state, zero/multiple rows, malformed XML, missing nodes, unknown results, confirmation mismatch, duplicate requests, and no approval-queue creation. + +## 11. Five-Tab SCUM Product Surface + +- [ ] 11.1 Place SCUM API clients/types, route definitions, page contracts, component contracts, schemas/validators, bridge/SDK types, and shared utilities in their fixed frontend/plugin directories rather than inside page components. +- [ ] 11.2 Make the SCUM detail navigation contain exactly `用户管理`, `队伍管理`, `实时地图`, `礼包管理`, `AI 助手` in that order, default to `用户管理`, and fall back from legacy `manage`, `workflows`, or invalid sections without affecting non-SCUM plugins. +- [ ] 11.3 Preserve the existing server-list deployment action and relocate display-name and administrator-membership controls to a compact detail-header settings drawer/dialog with existing owner authorization; do not add another permanent management tab. +- [ ] 11.4 Build `用户管理` as a full-width server-paginated table with bounded filters/search/sort, online evidence, nullable verified facts, detail/login-history drawer, and explicit named-field edit dialogs. +- [ ] 11.5 Build `队伍管理` as a full-width paginated squad table and semantic detail drawer separating leader/ranks, members, flags, and territory while showing unknown facts honestly. +- [ ] 11.6 Build `实时地图` from the authorized map asset and tested transform with distinct player/vehicle/flag/territory layers, filters, legend, source coordinates/collection time, safe live updates, and a clear incompatible/unavailable state. +- [ ] 11.7 Build `礼包管理` with real package statistics/table, CRUD dialogs, typed items and limits, real player selection, reviewed delivery, and delivery history for in-progress/delivered/failed/partial/unknown/notification-failure outcomes. +- [ ] 11.8 Keep `AI 助手` as the final tab for plugin configuration diffs and controlled player-operation drafts, with apply disabled when effective permission is absent. +- [ ] 11.9 Hide or disable write controls according to current effective permissions with textual reasons, and re-check authorization server-side on every apply request. +- [ ] 11.10 Load only platform-local resource APIs and the platform event stream; display ordinary connection and last synchronized/collected information, and let retry repeat only a local read. +- [ ] 11.11 Reuse shared tables, drawers, dialogs, status, `console-*`, and theme tokens; preserve black-mecha and magical-girl readability, keep CSS declarations compressed, and add no page-local fixed decoration or generic opaque SaaS card system. +- [ ] 11.12 Cover keyboard/focus behavior, non-color-only status, responsive full-width working surfaces, bounded compact actions, and readable destructive confirmations. +- [ ] 11.13 Add frontend tests for exact navigation/order/default/fallback, settings ownership, local-only loading, permission presentation, null/empty/error states, real map/gift data, AI review parity, and absence of fake actions or placeholder records. + +## 12. Projection, Workflow, Intelligence, and Placeholder Removal + +- [ ] 12.1 Inventory references before deletion and distinguish SCUM-only projection/Workflow/player-intelligence code from generic durable Run jobs, internal write evidence, and non-SCUM consumers. +- [ ] 12.2 Remove SCUM Workflow instance/step/status APIs, repositories, services, routes, clients, manifest declarations, page components, workflow creation/listing, pending-review counters, operation approval routes, and approval/confirmation queue surfaces without removing generic Run job execution. +- [ ] 12.3 Remove SCUM projection/observation/freshness snapshot types, ingestion, metadata fields, refresh/audit services, page actions, and manual synchronization endpoints; removed endpoints must return not found or a stable removal response and dispatch no job. +- [ ] 12.4 Remove SCUM dependencies on alias history, shared IP/fingerprint, access attempts, automatic risk/security signals, and player intelligence; delete shared implementation only after proving it has no remaining non-SCUM consumer. +- [ ] 12.5 Remove the standalone `管理` and `Workflow 状态` tabs, legacy placeholders/routes, fake maintenance/backup evidence, hard-coded increments, opaque `855` action, hard-coded `starter-pack`, fixed notification, gradient-only map, arbitrary percentage points, and sample/generated players/world data. +- [ ] 12.6 Remove runtime product copy including `Workflow 状态`, `投影`, `真实投影`, `玩家投影`, `刷新投影`, `刷新世界投影`, `刷新真实数据`, `发起审计`, `创建发放 workflow`, `typed workflow`, `typed observation`, `typed operation`, `待审操作`, `审批/确认队列`, `清理旧入口`, `目前暂无真实投影数据`, `暂无真实投影数据`, `暂无玩家投影`, and `Companion 可用`. +- [ ] 12.7 Add upgrade behavior that starts the new SCUM stores empty, populates only from post-upgrade authenticated logs/current-service sync, invalidates incompatible bindings, and never translates old snapshot values into real facts. +- [ ] 12.8 Add a rollback/feature-disable path that disables incompatible SCUM reads/writes while leaving diagnostic local records intact and never re-enables fake projection or Workflow data. +- [ ] 12.9 Add scoped runtime-source/manifest/API tests or assertions proving banned copy/actions/routes are absent, removed endpoints cannot dispatch jobs, and generic lifecycle, logs, jobs, AI provider management, and non-SCUM plugin navigation still work. +- [ ] 12.10 Record the supersession mapping from the completed-but-unarchived legacy SCUM changes to these unique replacement capabilities; do not archive obsolete deltas into the main baseline, and leave any history consolidation to a separate reviewed skip-specs/equivalent archival task. + +## 13. End-to-End Verification and Release + +- [ ] 13.1 Run focused Go tests after each Platform repository, migration, ingestion, scheduler, API, gift, permission, and terminal-result change, then run `(cd platform && go test ./...)`. +- [ ] 13.2 Run plugin SDK/parser/query/map/manifest tests and final checks with `(cd plugins && npm run typecheck && npm run test && npm run validate:manifest)`, then run `(cd plugins/examples/scum-server-plugin/companion && go test ./...)`. +- [ ] 13.3 Run frontend tests and final checks with `(cd platform_web && npm run typecheck && npm run test && npm run build)`. +- [ ] 13.4 In the separately authorized Run-repository task, run `go test ./...` from that repository's own root and record its tested commit/version plus deployment compatibility evidence here; do not edit, stage, or commit Run source from the browser-repository apply task. +- [ ] 13.5 Against the active current service, verify read-only schema compatibility, authentic login-created local player/session data, automatic player/squad/vehicle/flag/position sync, generation retention after an induced safe read failure, and no unbound copied/cache/fixture database use. +- [ ] 13.6 Verify login-log acceptance with sanitized real fixtures covering partial lines, failed login, rotation, truncate, restart/resume, duplicate, and out-of-order events plus server/Run binding/plugin/parser-digest fencing. +- [ ] 13.7 Extend and run `scripts/browser-acceptance.sh` against synchronized local data for the exact five tabs, local-only page reads, user/squad/map/gift behavior, permission-aware edit reviews, AI configuration/player drafts, legacy-route fallback, and absence of projection/Workflow/manual-refresh/audit controls. +- [ ] 13.8 Verify controlled writes against isolated test data or an explicitly authorized test player only; prove permission, explicit confirmation, guards, backup/offline requirements, idempotency, readback, unknown-result handling, XML preservation, and no implicit respawn. +- [ ] 13.9 Perform scoped security checks proving browser/API/AI/job-safe responses contain no raw SQL, RCON, XML, host/database paths, credentials, sockets, IP data, or cross-server resource existence, and that external Run has no SCUM-specific executor branches. +- [ ] 13.10 Run `scripts/check-structure.sh` and fix every relevant structural violation without moving implementation outside its owning root. +- [ ] 13.11 Run `openspec validate replace-scum-projections-with-real-data-management --strict`, review task evidence and the final diff, and leave any task unchecked if its real-service, external-Run, test, or safety evidence is missing. +- [ ] 13.12 On `main`, stage only files belonging to this change, create a concise commit after all required verification succeeds, and push the configured remote without including unrelated pre-existing worktree changes.