feat(scum): remove fake management surfaces

This commit is contained in:
npc0-hue
2026-08-11 12:30:45 +08:00
parent 9184f83480
commit e5d26e5420
15 changed files with 120 additions and 333 deletions
+7 -7
View File
@@ -197,8 +197,8 @@ describe("plugin manifest validation", () => {
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", "player.attribute.855.set"]));
expect(manifest.gameClientBridge.operationTemplates.find((operation) => operation.key === "player.attribute.855.set")?.kind).toBe("sqlite-mutation");
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);
});
@@ -491,17 +491,17 @@ describe("plugin manifest validation", () => {
"maintenance.prepare"
]));
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(expect.arrayContaining(["players", "squads", "live-map", "gifts", "workflows"]));
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",
"player.attribute.855.set"
"player.notify"
]));
expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "workflows")?.queryTemplateKeys).toEqual(expect.arrayContaining(["scum.player.profile", "scum.squads", "scum.vehicles", "scum.flags", "scum.positions"]));
expect(manifest.pages.map((page) => page.key)).toEqual(expect.arrayContaining(["players", "squads", "live-map", "gifts", "workflows"]));
expect(manifest.gameClientBridge.pages.find((page) => page.pageKey === "players")?.operationKeys).not.toContain("player.attribute.855.set");
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.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();
+27 -37
View File
@@ -10,15 +10,12 @@ import { scumMigrationParityFixtures } from "./fixtures/scum-migration-parity.js
const pageSource = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../examples/scum-server-plugin/features/page.ts"), "utf8");
const projectionData = {
players: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", userProfileId: "profile-1", displayName: "Mira", squadName: "Wolves", online: true, famePoints: 42, normalBalance: 1000, goldBalance: 3, position: { x: 10, y: 20, z: 3, hasCoordinates: true }, freshness: { status: "fresh" }, unknownFields: { "855": 100 } }],
players: [{ gamePlayerId: "steam-1", steamId: "76561198000000001", userProfileId: "profile-1", displayName: "Mira", squadName: "Wolves", online: true, famePoints: 42, normalBalance: 1000, goldBalance: 3, position: { x: 10, y: 20, z: 3, hasCoordinates: true }, freshness: { status: "fresh" } }],
squads: [{ squadId: "squad-1", name: "Wolves", memberCount: 3, leaderProfileId: "profile-1", freshness: { status: "fresh" } }],
members: [{ gamePlayerId: "steam-1", displayName: "Mira", squadId: "squad-1", rank: "Leader", freshness: { status: "fresh" } }],
vehicles: [{ vehicleId: "veh-1", label: "Laika", position: { subjectType: "vehicle", subjectId: "veh-1", x: 400, y: 200, z: 0, hasCoordinates: true }, freshness: { status: "fresh" } }],
flags: [{ flagId: "flag-1", ownerSquadId: "squad-1", ownershipConfidence: "verified", position: { subjectType: "flag", subjectId: "flag-1", x: 100, y: 80, z: 0, hasCoordinates: true }, freshness: { status: "fresh" } }],
positions: [{ subjectType: "player", subjectId: "steam-1", gamePlayerId: "steam-1", x: 10, y: 20, z: 3, hasCoordinates: true, freshness: { status: "fresh" } }],
operations: [{ id: "op-1", templateKey: "player.fame.set", status: "waiting", safeSummary: { message: "awaiting approval" } }],
workflows: [{ id: "wf-1", templateKey: "scum.world-refresh", status: "queued", currentStepKey: "read-positions", createdAt: "2026-08-10T00:00:00Z", safeSummary: { message: "world refresh queued" } }],
steps: [{ stepKey: "read-positions", status: "queued", capability: "remote.run.db.sqlite.query", safeSummary: { message: "queued safely" } }]
positions: [{ subjectType: "player", subjectId: "steam-1", gamePlayerId: "steam-1", x: 10, y: 20, z: 3, hasCoordinates: true, freshness: { status: "fresh" } }]
};
describe("SCUM plugin feature module", () => {
@@ -62,33 +59,30 @@ describe("SCUM plugin feature module", () => {
expect(migrationStatus([...flags, flags[0]], "server-1", "configuration")).toMatchObject({ authority: "transitional-read-only", pluginWritesEnabled: false });
});
it("renders projection-backed user management without raw file/config panels", () => {
it("renders local user management without projection or fake-write controls", () => {
const view = renderAndCollect();
expect(view.nodes).toContain("section:用户管理");
expect(view.texts.join("\n")).toContain("登录日志和 SCUM.db typed observations");
expect(view.texts).toContain("投影/Companion 可用");
expect(view.texts).toContain("刷新投影");
expect(view.texts).toContain("刷新真实数据");
expect(view.texts.join("\n")).toContain("登录日志和已验证同步结果");
expect(view.texts).toContain("本地数据通道可读");
expect(view.buttons.find((button) => button.label === "重试本地读取")?.disabled).toBe(false);
expect(view.texts).toContain("Mira");
expect(view.texts.join("\n")).toContain("Steam 76561198000000001");
expect(view.texts.join("\n")).toContain("Profile profile-1");
expect(view.texts.join("\n")).toContain("Fame 42");
expect(view.buttons.find((button) => button.label === "Fame +100")?.disabled).toBe(false);
expect(view.buttons.find((button) => button.label === "现金 +1000")?.disabled).toBe(false);
expect(view.buttons.find((button) => button.label === "855 审批")?.disabled).toBe(false);
expect(view.buttons.map((button) => button.label)).not.toEqual(expect.arrayContaining(["Fame +100", "现金 +1000", "855 审批"]));
for (const removedText of ["ServerSettings.ini", "Game.ini", "配置表单", "键值视图", "原文模式", "读取文件", "提交写入"]) expect(view.texts.join("\n")).not.toContain(removedText);
});
it("does not invent fake players when projections are empty", () => {
it("does not invent fake players when local records are empty", () => {
const view = renderAndCollect({ data: { ...projectionData, players: [], positions: [] } });
expect(view.texts.join("\n")).toContain("暂无玩家投影");
expect(view.texts.join("\n")).toContain("不会显示假玩家");
expect(view.texts.join("\n")).toContain("暂无玩家记录");
expect(view.texts.join("\n")).toContain("登录日志或已完成的本地同步");
expect(view.texts).not.toContain("Mira");
expect(pageSource).not.toContain("fallbackFiles");
expect(pageSource).not.toContain("samplePlayers");
});
it("renders squad and flag governance from projections", () => {
it("renders squad and flag governance from local records", () => {
const view = renderAndCollect({ pageKey: "squads", pageTitle: "队伍管理" });
expect(view.nodes).toContain("section:队伍管理");
expect(view.texts).toContain("队伍");
@@ -98,33 +92,34 @@ describe("SCUM plugin feature module", () => {
expect(view.texts.join("\n")).toContain("verified");
});
it("renders realtime map overlays without sample coordinates", () => {
it("renders realtime map overlays without sample coordinates or arbitrary fallback points", () => {
const view = renderAndCollect({ pageKey: "live-map", pageTitle: "实时地图" });
expect(view.nodes).toContain("section:实时地图");
expect(view.texts).toContain("地图覆盖物");
expect(view.texts.join("\n")).toContain("坐标点");
expect(view.texts.join("\n")).toContain("X 10 / Y 20 / Z 3");
expect(pageSource).toContain("map-projection-board");
expect(pageSource).toContain("map-local-board");
expect(pageSource).not.toContain("sampleCoordinates");
});
it("renders gift and workflow typed status surfaces", () => {
it("renders gift management without hard-coded delivery actions", () => {
const gifts = renderAndCollect({ pageKey: "gifts", pageTitle: "礼包管理" });
expect(gifts.nodes).toContain("section:礼包管理");
expect(gifts.texts.join("\n")).toContain("typed delivery workflow");
expect(gifts.buttons.find((button) => button.label === "创建礼包发放")?.disabled).toBe(false);
expect(gifts.buttons.find((button) => button.label === "发送通知")?.disabled).toBe(false);
const workflows = renderAndCollect({ pageKey: "workflows", pageTitle: "Workflow 状态" });
expect(workflows.nodes).toContain("section:Workflow 状态");
expect(workflows.texts.join("\n")).toContain("scum.world-refresh");
expect(workflows.texts.join("\n")).toContain("read-positions");
expect(gifts.texts.join("\n")).toContain("本地礼包接口");
expect(gifts.buttons.map((button) => button.label)).not.toEqual(expect.arrayContaining(["创建礼包发放", "发送通知"]));
expect(pageSource).not.toContain("starter-pack");
});
it("loads projections through typed workspace actions instead of file snapshots", () => {
it("falls legacy workflow routes back to user management", () => {
const legacy = renderAndCollect({ pageKey: "workflows" });
expect(legacy.nodes).toContain("section:用户管理");
expect(legacy.texts.join("\n")).not.toContain("scum.world-refresh");
});
it("loads local SCUM resources without write or workflow workspace actions", () => {
expect(pageSource).toContain("listSCUMPlayers");
expect(pageSource).toContain("createSCUMOperation");
expect(pageSource).toContain("createSCUMWorkflow");
expect(pageSource).not.toContain("createSCUMOperation");
expect(pageSource).not.toContain("createSCUMWorkflow");
expect(pageSource).not.toContain("getFileSnapshot");
expect(pageSource).not.toContain("requestFile");
expect(pageSource).not.toContain("writeFile");
@@ -162,12 +157,7 @@ function renderAndCollect(options: { data?: typeof projectionData; permissions?:
listSCUMSquadMembers: async () => ({ items: projectionData.members, count: projectionData.members.length }),
listSCUMVehicles: async () => ({ items: projectionData.vehicles, count: projectionData.vehicles.length }),
listSCUMFlags: async () => ({ items: projectionData.flags, count: projectionData.flags.length }),
listSCUMPositions: async () => ({ items: projectionData.positions, count: projectionData.positions.length }),
listSCUMOperations: async () => ({ items: projectionData.operations, count: projectionData.operations.length }),
listSCUMWorkflows: async () => ({ items: projectionData.workflows, count: projectionData.workflows.length }),
listSCUMWorkflowSteps: async () => ({ items: projectionData.steps, count: projectionData.steps.length }),
createSCUMOperation: async () => ({ id: "op-new", status: "waiting" }),
createSCUMWorkflow: async () => ({ id: "wf-new", status: "queued" })
listSCUMPositions: async () => ({ items: projectionData.positions, count: projectionData.positions.length })
}
});
return { nodes, texts, buttons };