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 index b667afc..c26c1aa 100644 --- a/openspec/changes/replace-scum-projections-with-real-data-management/tasks.md +++ b/openspec/changes/replace-scum-projections-with-real-data-management/tasks.md @@ -30,7 +30,7 @@ - [ ] 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. +- [x] 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 diff --git a/plugins/examples/scum-server-plugin/manifest.json b/plugins/examples/scum-server-plugin/manifest.json index af66737..06c242b 100644 --- a/plugins/examples/scum-server-plugin/manifest.json +++ b/plugins/examples/scum-server-plugin/manifest.json @@ -284,172 +284,8 @@ "maxRecords": 1000 } ], - "queryTemplates": [ - { - "key": "scum.player.profile", - "title": "Read SCUM player profile, economy, squad, and position facts", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-player-profile.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-player-profile.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - }, - { - "key": "scum.squads", - "title": "Read SCUM squad records", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-squads.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-squads.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - }, - { - "key": "scum.squad-members", - "title": "Read SCUM squad membership records", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-squad-members.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-squad-members.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - }, - { - "key": "scum.vehicles", - "title": "Read SCUM vehicle records and coordinates", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-vehicles.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-vehicles.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - }, - { - "key": "scum.flags", - "title": "Read SCUM flag and ownership records", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-flags.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-flags.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - }, - { - "key": "scum.positions", - "title": "Read SCUM current player, vehicle, and flag coordinates", - "permission": "server.game-client.read", - "engine": "sqlite", - "transportKey": "scum-database", - "targetKey": "scum-database", - "parameterSchemaRef": "schemas/bridge/queries/scum-positions.parameters.schema.json", - "resultSchemaRef": "schemas/bridge/queries/scum-positions.result.schema.json", - "maxRows": 500, - "timeoutSeconds": 15 - } - ], - "operationTemplates": [ - { - "key": "player.fame.set", - "title": "Set SCUM player fame through RCON", - "permission": "server.game-client.command", - "approvalLevel": "operator", - "kind": "rcon", - "transportKey": "scum-management", - "targetKey": "scum-management", - "payloadSchemaRef": "schemas/bridge/player-fame-set.payload.schema.json", - "resultSchemaRef": "schemas/bridge/player-rcon-set.result.schema.json", - "confirmationSchemaRef": "schemas/bridge/player-fame-set.confirmation.schema.json", - "timeoutSeconds": 60, - "maxPayloadBytes": 2048, - "safety": { - "requiresApproval": true, - "requiresConfirmation": true - } - }, - { - "key": "player.currency.normal.set", - "title": "Set SCUM normal currency through RCON", - "permission": "server.game-client.command", - "approvalLevel": "operator", - "kind": "rcon", - "transportKey": "scum-management", - "targetKey": "scum-management", - "payloadSchemaRef": "schemas/bridge/player-currency-set.payload.schema.json", - "resultSchemaRef": "schemas/bridge/player-rcon-set.result.schema.json", - "confirmationSchemaRef": "schemas/bridge/player-currency-set.confirmation.schema.json", - "timeoutSeconds": 60, - "maxPayloadBytes": 2048, - "safety": { - "requiresApproval": true, - "requiresConfirmation": true - } - }, - { - "key": "player.currency.gold.set", - "title": "Set SCUM gold currency through RCON", - "permission": "server.game-client.command", - "approvalLevel": "operator", - "kind": "rcon", - "transportKey": "scum-management", - "targetKey": "scum-management", - "payloadSchemaRef": "schemas/bridge/player-currency-set.payload.schema.json", - "resultSchemaRef": "schemas/bridge/player-rcon-set.result.schema.json", - "confirmationSchemaRef": "schemas/bridge/player-currency-set.confirmation.schema.json", - "timeoutSeconds": 60, - "maxPayloadBytes": 2048, - "safety": { - "requiresApproval": true, - "requiresConfirmation": true - } - }, - { - "key": "player.notify", - "title": "Notify SCUM player through RCON chat", - "permission": "server.game-client.command", - "approvalLevel": "operator", - "kind": "rcon", - "transportKey": "scum-management", - "targetKey": "scum-management", - "payloadSchemaRef": "schemas/bridge/player-notify.payload.schema.json", - "resultSchemaRef": "schemas/bridge/player-notify.result.schema.json", - "confirmationSchemaRef": "schemas/bridge/player-notify.confirmation.schema.json", - "timeoutSeconds": 60, - "maxPayloadBytes": 2048, - "safety": { - "requiresApproval": true, - "requiresConfirmation": true - } - }, - { - "key": "reward.deliver", - "title": "Deliver approved SCUM reward through typed command", - "permission": "server.game-client.command", - "approvalLevel": "operator", - "kind": "rcon", - "transportKey": "scum-management", - "targetKey": "scum-management", - "payloadSchemaRef": "schemas/bridge/reward-deliver.payload.schema.json", - "resultSchemaRef": "schemas/bridge/reward-deliver.result.schema.json", - "confirmationSchemaRef": "schemas/bridge/reward-deliver.confirmation.schema.json", - "timeoutSeconds": 60, - "maxPayloadBytes": 4096, - "safety": { - "requiresApproval": true, - "requiresConfirmation": true - } - } - ], + "queryTemplates": [], + "operationTemplates": [], "commandRetentionSeconds": 604800, "maxCommands": 1000, "features": [ @@ -486,19 +322,7 @@ "players", "online.sessions" ], - "queryTemplateKeys": [ - "scum.player.profile", - "scum.positions" - ], - "operationKeys": [ - "player.fame.set", - "player.currency.normal.set", - "player.currency.gold.set", - "player.notify" - ], - "featureKeys": [ - "state.patch" - ] + "featureKeys": [] }, { "pageKey": "squads", @@ -506,11 +330,6 @@ "squads", "flags" ], - "queryTemplateKeys": [ - "scum.squads", - "scum.squad-members", - "scum.flags" - ], "featureKeys": [] }, { @@ -520,12 +339,6 @@ "vehicles", "flags" ], - "queryTemplateKeys": [ - "scum.player.profile", - "scum.vehicles", - "scum.flags", - "scum.positions" - ], "featureKeys": [] }, { @@ -533,13 +346,7 @@ "snapshotTypes": [ "players" ], - "operationKeys": [ - "reward.deliver", - "player.notify" - ], - "featureKeys": [ - "reward.delivery" - ] + "featureKeys": [] } ], "companion": { @@ -675,8 +482,7 @@ "server.game-client.maintenance" ], "bridgeActions": [ - "server.instances.read", - "remote.access.request" + "server.instances.read" ], "featureKeys": [] }, @@ -692,8 +498,7 @@ "server.game-client.read" ], "bridgeActions": [ - "server.instances.read", - "remote.access.request" + "server.instances.read" ], "featureKeys": [] }, @@ -709,8 +514,7 @@ "server.game-client.read" ], "bridgeActions": [ - "server.instances.read", - "remote.access.request" + "server.instances.read" ], "featureKeys": [] }, @@ -729,9 +533,7 @@ "bridgeActions": [ "server.instances.read" ], - "featureKeys": [ - "reward.delivery" - ] + "featureKeys": [] } ], "ai": { diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.confirmation.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.confirmation.schema.json deleted file mode 100644 index c325979..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.confirmation.schema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "fieldKey", "value", "observedAt", "checksum"], - "properties": { - "playerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "fieldKey": { "const": "855" }, - "value": { "type": "integer", "minimum": 0, "maximum": 100000 }, - "observedAt": { "type": "string", "format": "date-time" }, - "checksum": { "type": "string", "minLength": 1, "maxLength": 160 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.payload.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.payload.schema.json deleted file mode 100644 index bc08e61..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.payload.schema.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "fieldKey", "before", "after", "safetyWindow", "backupRef"], - "properties": { - "playerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "fieldKey": { "const": "855" }, - "before": { "type": "integer", "minimum": 0, "maximum": 100000 }, - "after": { "type": "integer", "minimum": 0, "maximum": 100000 }, - "safetyWindow": { "type": "string", "minLength": 1, "maxLength": 120 }, - "backupRef": { "type": "string", "minLength": 1, "maxLength": 180 }, - "reason": { "type": "string", "maxLength": 240 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.result.schema.json deleted file mode 100644 index 7e12153..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-attribute-855-set.result.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "additionalProperties": false, - "required": ["outcome", "affectedRows", "mutationChecksum"], - "properties": { - "outcome": { "enum": ["succeeded", "failed", "unknown", "stale-before"] }, - "affectedRows": { "type": "integer", "minimum": 0, "maximum": 1 }, - "mutationChecksum": { "type": "string", "minLength": 1, "maxLength": 160 }, - "safeMessage": { "type": "string", "maxLength": 240 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.confirmation.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.confirmation.schema.json deleted file mode 100644 index e4f6230..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.confirmation.schema.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerCurrencySetConfirmation", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "amount", "observedAt"], - "properties": { - "playerId": { "type": "string", "minLength": 17, "maxLength": 17, "pattern": "^[0-9]{17}$" }, - "amount": { "type": "integer", "minimum": 0, "maximum": 2147483647 }, - "currency": { "enum": ["normal", "gold"] }, - "observationId": { "type": "string", "minLength": 1, "maxLength": 160 }, - "observedAt": { "type": "string", "format": "date-time" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.payload.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.payload.schema.json deleted file mode 100644 index 7da709d..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-currency-set.payload.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerCurrencySetPayload", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "amount"], - "properties": { - "playerId": { "type": "string", "minLength": 17, "maxLength": 17, "pattern": "^[0-9]{17}$" }, - "amount": { "type": "integer", "minimum": 0, "maximum": 2147483647 }, - "reason": { "type": "string", "minLength": 1, "maxLength": 240 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.confirmation.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.confirmation.schema.json deleted file mode 100644 index 64a354b..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.confirmation.schema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerFameSetConfirmation", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "fame", "observedAt"], - "properties": { - "playerId": { "type": "string", "minLength": 17, "maxLength": 17, "pattern": "^[0-9]{17}$" }, - "fame": { "type": "integer", "minimum": -2147483648, "maximum": 2147483647 }, - "observationId": { "type": "string", "minLength": 1, "maxLength": 160 }, - "observedAt": { "type": "string", "format": "date-time" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.payload.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.payload.schema.json deleted file mode 100644 index 1cd63ef..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-fame-set.payload.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerFameSetPayload", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "fame"], - "properties": { - "playerId": { "type": "string", "minLength": 17, "maxLength": 17, "pattern": "^[0-9]{17}$" }, - "fame": { "type": "integer", "minimum": -2147483648, "maximum": 2147483647 }, - "reason": { "type": "string", "minLength": 1, "maxLength": 240 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-notify.confirmation.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-notify.confirmation.schema.json deleted file mode 100644 index 12c09c3..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-notify.confirmation.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerNotifyConfirmation", - "type": "object", - "additionalProperties": false, - "required": ["playerId", "outcome", "observedAt"], - "properties": { - "playerId": { "type": "string", "minLength": 17, "maxLength": 17, "pattern": "^[0-9]{17}$" }, - "outcome": { "enum": ["sent", "failed", "unknown"] }, - "observedAt": { "type": "string", "format": "date-time" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/player-rcon-set.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/player-rcon-set.result.schema.json deleted file mode 100644 index e52bdf9..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/player-rcon-set.result.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerRCONSetResult", - "type": "object", - "additionalProperties": false, - "required": ["outcome"], - "properties": { - "outcome": { "enum": ["queued", "succeeded", "failed", "unknown"] }, - "runJobId": { "type": "string", "minLength": 1, "maxLength": 160 }, - "summary": { "type": "string", "maxLength": 240 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/SCUM_DB_CONTRACT.md b/plugins/examples/scum-server-plugin/schemas/bridge/queries/SCUM_DB_CONTRACT.md deleted file mode 100644 index 6711fc8..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/SCUM_DB_CONTRACT.md +++ /dev/null @@ -1,14 +0,0 @@ -# SCUM.db Query Contract - -These query template keys are browser-safe declarations. They intentionally do not carry SQL text, host paths, DSNs, sockets, or credentials. The bound run/agent beside the current SCUM service owns the actual SQLite read implementation and must return rows matching the referenced result schemas. - -| Template key | SCUM.db source tables | Projection target | -| --- | --- | --- | -| `scum.player.profile` | `user_profile`, `prisoner`, `prisoner_entity`, `entity`, `bank_account_registry`, `bank_account_registry_currencies`, optional `squad_member` / `squad` joins | Player identity, economy, squad summary, and current position | -| `scum.squads` | `squad`, optional `squad_member`, optional `user_profile` leader joins | Squad records and leader/member counts | -| `scum.squad-members` | `squad_member`, `user_profile`, optional `squad` joins | Squad roster and member identity mapping | -| `scum.vehicles` | `vehicle_spawner`, `entity`, optional owner/squad joins when present | Vehicle inventory and coordinates; unknown class labels remain unknown | -| `scum.flags` | `base_element`, `entity`, `user_profile`, `squad_member`, `squad` where available | Flag ownership, ownership confidence, and coordinates | -| `scum.positions` | `prisoner_entity`, `vehicle_spawner`, `base_element`, `entity` | Current player, vehicle, and flag coordinates | - -`last_save_time` is freshness evidence only. It must not be treated as proof that a player is online; online state comes from login/logoff evidence or an explicit typed online field. diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.parameters.schema.json deleted file mode 100644 index 652ca02..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.parameters.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMFlagsParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "flagId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.result.schema.json deleted file mode 100644 index b30e349..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-flags.result.schema.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMFlagsResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["flagId"], - "properties": { - "flagId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "entityId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerPlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerSquadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerSquadName": { "type": "string", "minLength": 1, "maxLength": 80 }, - "ownershipConfidence": { "enum": ["direct", "member", "squad", "unknown"] }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "z": { "type": "number" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.parameters.schema.json deleted file mode 100644 index 7b6f247..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.parameters.schema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerProfileParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "gamePlayerId": { "type": "string", "minLength": 1, "maxLength": 96, "pattern": "^[A-Za-z0-9_.:-]{1,96}$" }, - "userProfileId": { "type": "string", "minLength": 1, "maxLength": 96, "pattern": "^[A-Za-z0-9_.:-]{1,96}$" }, - "steamId": { "type": "string", "minLength": 1, "maxLength": 96, "pattern": "^[A-Za-z0-9_.:-]{1,96}$" }, - "search": { "type": "string", "minLength": 1, "maxLength": 80 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.result.schema.json deleted file mode 100644 index 44a068d..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-player-profile.result.schema.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPlayerProfileResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["userProfileId"], - "properties": { - "gamePlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "userProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "steamId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "displayName": { "type": "string", "minLength": 1, "maxLength": 80 }, - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "squadName": { "type": "string", "minLength": 1, "maxLength": 80 }, - "famePoints": { "type": "number" }, - "normalBalance": { "type": "number" }, - "goldBalance": { "type": "number" }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "z": { "type": "number" }, - "lastSaveTime": { "type": "string", "format": "date-time" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.parameters.schema.json deleted file mode 100644 index 84f3eaf..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.parameters.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPositionsParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "subjectType": { "enum": ["player", "vehicle", "flag"] }, - "subjectId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.result.schema.json deleted file mode 100644 index 6a47e18..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-positions.result.schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMPositionsResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["subjectType", "subjectId", "x", "y"], - "properties": { - "subjectType": { "enum": ["player", "vehicle", "flag"] }, - "subjectId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "gamePlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "vehicleId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "entityId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "z": { "type": "number" }, - "lastSaveTime": { "type": "string", "format": "date-time" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.parameters.schema.json deleted file mode 100644 index a1966b6..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.parameters.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMSquadMembersParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "userProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.result.schema.json deleted file mode 100644 index cbe69d4..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squad-members.result.schema.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMSquadMembersResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["squadId", "userProfileId"], - "properties": { - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "userProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "gamePlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "steamId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "displayName": { "type": "string", "minLength": 1, "maxLength": 80 }, - "rank": { "type": "string", "minLength": 1, "maxLength": 32 }, - "isLeader": { "type": "boolean" }, - "joinedAt": { "type": "string", "format": "date-time" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.parameters.schema.json deleted file mode 100644 index 0a35e40..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.parameters.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMSquadsParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "search": { "type": "string", "minLength": 1, "maxLength": 80 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.result.schema.json deleted file mode 100644 index 6e3da4a..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-squads.result.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMSquadsResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["squadId"], - "properties": { - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "name": { "type": "string", "minLength": 1, "maxLength": 80 }, - "leaderProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "leaderPlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "memberCount": { "type": "integer", "minimum": 0, "maximum": 1000 }, - "score": { "type": "number" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.parameters.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.parameters.schema.json deleted file mode 100644 index b9f7adb..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.parameters.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMVehiclesParameters", - "type": "object", - "additionalProperties": false, - "properties": { - "vehicleId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "limit": { "type": "integer", "minimum": 1, "maximum": 500 } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.result.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.result.schema.json deleted file mode 100644 index ecef9ca..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/queries/scum-vehicles.result.schema.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMVehiclesResult", - "type": "object", - "additionalProperties": false, - "required": ["rows"], - "properties": { - "rows": { - "type": "array", - "maxItems": 500, - "items": { - "type": "object", - "additionalProperties": false, - "required": ["vehicleId"], - "properties": { - "vehicleId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "entityId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "className": { "type": "string", "minLength": 1, "maxLength": 120 }, - "label": { "type": "string", "minLength": 1, "maxLength": 120 }, - "ownerProfileId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "ownerPlayerId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "squadId": { "type": "string", "minLength": 1, "maxLength": 96 }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "z": { "type": "number" } - } - } - }, - "truncated": { "type": "boolean" } - } -} diff --git a/plugins/examples/scum-server-plugin/schemas/bridge/reward-deliver.confirmation.schema.json b/plugins/examples/scum-server-plugin/schemas/bridge/reward-deliver.confirmation.schema.json deleted file mode 100644 index be4497d..0000000 --- a/plugins/examples/scum-server-plugin/schemas/bridge/reward-deliver.confirmation.schema.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SCUMRewardDeliverConfirmation", - "type": "object", - "additionalProperties": false, - "required": ["grantId", "outcome", "observedAt"], - "properties": { - "grantId": { "type": "string", "minLength": 1, "maxLength": 160 }, - "outcome": { "enum": ["delivered", "failed", "unknown"] }, - "observationId": { "type": "string", "minLength": 1, "maxLength": 160 }, - "observedAt": { "type": "string", "format": "date-time" } - } -} diff --git a/plugins/tests/manifest-validation.test.ts b/plugins/tests/manifest-validation.test.ts index a2df842..23737ad 100644 --- a/plugins/tests/manifest-validation.test.ts +++ b/plugins/tests/manifest-validation.test.ts @@ -191,16 +191,15 @@ describe("plugin manifest validation", () => { expect(validateManifestFile("examples/scum-server-plugin/manifest.json")).toEqual([]); }); - it("removes raw protected SQL and management request command surfaces", () => { + it("removes unverified SCUM query and operation declarations", () => { const pluginDir = path.join(pluginsRoot, "examples/scum-server-plugin"); const manifest = JSON.parse(fs.readFileSync(path.join(pluginDir, "manifest.json"), "utf8")) as { gameClientBridge: { commands: Array<{ type: string; protectedRequest?: { kind: string } }>; queryTemplates: Array<{ key: string }>; operationTemplates: Array<{ key: string; kind: string }> } }; const commands = manifest.gameClientBridge.commands.filter((candidate) => candidate.protectedRequest); expect(commands).toEqual([]); expect(manifest.gameClientBridge.commands.map((command) => command.type)).not.toEqual(expect.arrayContaining(["config.read", "config.patch", "database.request", "management.rcon.request", "management.program.request"])); - expect(manifest.gameClientBridge.queryTemplates.map((query) => query.key)).toEqual(expect.arrayContaining(["scum.player.profile", "scum.squads", "scum.squad-members", "scum.vehicles", "scum.flags", "scum.positions"])); - expect(manifest.gameClientBridge.operationTemplates.map((operation) => operation.key)).toEqual(expect.arrayContaining(["player.fame.set", "player.currency.normal.set", "player.currency.gold.set", "player.notify", "reward.deliver"])); - expect(manifest.gameClientBridge.operationTemplates.map((operation) => operation.key)).not.toContain("player.attribute.855.set"); - expect(fs.existsSync(path.join(pluginDir, "schemas/bridge/queries/SCUM_DB_CONTRACT.md"))).toBe(true); + expect(manifest.gameClientBridge.queryTemplates).toEqual([]); + expect(manifest.gameClientBridge.operationTemplates).toEqual([]); + expect(fs.existsSync(path.join(pluginDir, "schemas/bridge/queries/SCUM_DB_CONTRACT.md"))).toBe(false); }); it("keeps SCUM database-backed live-data gates disabled until current-service evidence exists", () => { @@ -474,7 +473,7 @@ describe("plugin manifest validation", () => { snapshots: Array<{ type: string; schemaVersion: string; schemaRef: string }>; pages: Array<{ pageKey: string; commandTypes?: string[]; snapshotTypes?: string[]; queryTemplateKeys?: string[]; operationKeys?: string[] }>; }; - pages: Array<{ key: string; permissions?: string[] }>; + pages: Array<{ key: string; permissions?: string[]; bridgeActions?: string[] }>; fileWorkspace?: { defaultDirectoryKey: string; directories: Array<{ key: string; label: string; scope: string }>; @@ -513,16 +512,11 @@ describe("plugin manifest validation", () => { expect(manifest.gameClientBridge.snapshots.map((snapshot) => snapshot.type)).toEqual(expect.arrayContaining(["companion.health", "online.sessions", "players", "squads", "vehicles", "flags"])); expect(manifest.gameClientBridge.pages.map((page) => page.pageKey)).toEqual(["players", "squads", "live-map", "gifts"]); expect(manifest.gameClientBridge.pages.map((page) => page.pageKey)).not.toContain("files-config"); - expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "players")?.operationKeys).toEqual(expect.arrayContaining([ - "player.fame.set", - "player.currency.normal.set", - "player.currency.gold.set", - "player.notify" - ])); - expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "players")?.operationKeys).not.toContain("player.attribute.855.set"); + expect(manifest.gameClientBridge.pages.every((page) => !(page.queryTemplateKeys?.length) && !(page.operationKeys?.length))).toBe(true); expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "workflows")).toBeUndefined(); expect(manifest.pages.map((page) => page.key)).toEqual(["players", "squads", "live-map", "gifts"]); expect(manifest.pages.map((page) => page.key)).not.toContain("files-config"); + expect(manifest.pages.every((page) => !(page.bridgeActions ?? []).includes("remote.access.request"))).toBe(true); expect(manifest.pages.find((page) => page.key === "players")?.permissions).toEqual(expect.arrayContaining(["server.game-client.read", "server.game-client.command", "server.game-client.maintenance"])); expect(manifest.fileWorkspace).toBeUndefined(); expect(manifest.runtimeProfiles?.lifecycleProfiles?.find((profile) => profile.key === "scum-client")?.capabilities).not.toContain("remote.run.rcon.command"); @@ -637,7 +631,7 @@ describe("plugin manifest validation", () => { expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "live-map")?.snapshotTypes).toEqual(expect.arrayContaining(["players", "vehicles", "flags"])); }); - it("declares typed SCUM.db query templates without browser-visible SQL", () => { + it("keeps SCUM.db query templates absent until current-service evidence exists", () => { const pluginDir = path.join(pluginsRoot, "examples/scum-server-plugin"); const manifest = JSON.parse(fs.readFileSync(path.join(pluginDir, "manifest.json"), "utf8")) as { permissions: string[]; @@ -661,7 +655,7 @@ describe("plugin manifest validation", () => { pages: Array<{ key: string; permissions?: string[]; bridgeActions?: string[] }>; runtimeProfiles?: { transportProfiles?: Array<{ key: string; kind: string; targetKey?: string; capabilities: string[] }> }; }; - const expectedKeys = ["scum.player.profile", "scum.squads", "scum.squad-members", "scum.vehicles", "scum.flags", "scum.positions"]; + const expectedKeys: string[] = []; const templatesByKey = new Map(manifest.gameClientBridge.queryTemplates.map((template) => [template.key, template])); expect([...templatesByKey.keys()]).toEqual(expect.arrayContaining(expectedKeys)); expect(manifest.capabilities).toContain("remote.run.db.sqlite.query"); @@ -685,17 +679,17 @@ describe("plugin manifest validation", () => { const playersPage = manifest.gameClientBridge.pages.find((page) => page.pageKey === "players"); const squadsPage = manifest.gameClientBridge.pages.find((page) => page.pageKey === "squads"); const mapPage = manifest.gameClientBridge.pages.find((page) => page.pageKey === "live-map"); - expect(playersPage?.queryTemplateKeys).toEqual(expect.arrayContaining(["scum.player.profile", "scum.positions"])); - expect(squadsPage?.queryTemplateKeys).toEqual(expect.arrayContaining(["scum.squads", "scum.squad-members", "scum.flags"])); - expect(mapPage?.queryTemplateKeys).toEqual(expect.arrayContaining(["scum.vehicles", "scum.flags", "scum.positions"])); + expect(playersPage?.queryTemplateKeys).toBeUndefined(); + expect(squadsPage?.queryTemplateKeys).toBeUndefined(); + expect(mapPage?.queryTemplateKeys).toBeUndefined(); for (const pageKey of ["players", "squads", "live-map"]) { const pluginPage = manifest.pages.find((page) => page.key === pageKey); expect(pluginPage?.permissions).toContain("server.game-client.read"); - expect(pluginPage?.bridgeActions).toContain("remote.access.request"); + expect(pluginPage?.bridgeActions).not.toContain("remote.access.request"); } }); - it("declares typed SCUM RCON operations without arbitrary command inputs", () => { + it("keeps SCUM RCON operation templates absent until command confirmation is verified", () => { const pluginDir = path.join(pluginsRoot, "examples/scum-server-plugin"); const manifest = JSON.parse(fs.readFileSync(path.join(pluginDir, "manifest.json"), "utf8")) as { gameClientBridge: { @@ -704,7 +698,7 @@ describe("plugin manifest validation", () => { }; pages: Array<{ key: string; permissions?: string[] }>; }; - const expectedKeys = ["player.fame.set", "player.currency.normal.set", "player.currency.gold.set", "player.notify", "reward.deliver"]; + const expectedKeys: string[] = []; const operationsByKey = new Map(manifest.gameClientBridge.operationTemplates.map((operation) => [operation.key, operation])); expect([...operationsByKey.keys()]).toEqual(expect.arrayContaining(expectedKeys)); for (const key of expectedKeys) { @@ -723,8 +717,8 @@ describe("plugin manifest validation", () => { } const playersPage = manifest.gameClientBridge.pages.find((page) => page.pageKey === "players"); const giftsPage = manifest.gameClientBridge.pages.find((page) => page.pageKey === "gifts"); - expect(playersPage?.operationKeys).toEqual(expect.arrayContaining(["player.fame.set", "player.currency.normal.set", "player.currency.gold.set", "player.notify"])); - expect(giftsPage?.operationKeys).toEqual(expect.arrayContaining(["reward.deliver", "player.notify"])); + expect(playersPage?.operationKeys).toBeUndefined(); + expect(giftsPage?.operationKeys).toBeUndefined(); expect(manifest.pages.find((page) => page.key === "players")?.permissions).toContain("server.game-client.command"); expect(manifest.pages.find((page) => page.key === "gifts")?.permissions).toContain("server.game-client.command"); });