Remove pre-1.0 production governance surfaces

This commit is contained in:
npc0-hue
2026-08-21 00:06:00 +08:00
parent a7e2e4c6c0
commit da6c8d607e
30 changed files with 89 additions and 429 deletions
-32
View File
@@ -10,9 +10,6 @@ import type {
AIInvocationResponse,
AIConfigDiffApprovalResponse,
AIConfigDiffListResponse,
AlertListResponse,
AlertResponse,
AlertRetryResponse,
ApiErrorResponse,
ArtifactContentChunk,
ArtifactDownloadReferenceResponse,
@@ -63,8 +60,6 @@ import type {
MarketplacePluginResponse,
MarketplacePluginStateRequest,
PlatformResourceUsageResponse,
ProductionCapacitySummaryResponse,
CapacityAdmissionDecisionResponse,
PluginLifecycleActionRequest,
PluginLifecycleActionResponse,
PluginLifecycleListResponse,
@@ -506,33 +501,6 @@ export class PlatformApiClient {
return this.request<PlatformResourceUsageResponse>("/metrics/platform");
}
async getProductionCapacity(): Promise<ProductionCapacitySummaryResponse> {
return this.request<ProductionCapacitySummaryResponse>("/production/capacity");
}
async checkCapacityAdmission(request: { serverInstanceId?: string; runEndpointId?: string; capability: string; targetKey?: string; idempotencyKey?: string }): Promise<CapacityAdmissionDecisionResponse> {
return this.request<CapacityAdmissionDecisionResponse>("/production/capacity/admission", { method: "POST", body: request });
}
async listAlerts(filter: { state?: string; sourceKind?: string; sourceId?: string; severity?: string } = {}): Promise<AlertListResponse> {
const params = new URLSearchParams();
Object.entries(filter).forEach(([key, value]) => { if (value) params.set(key, value); });
const query = params.toString();
return this.request<AlertListResponse>(`/alerts${query ? `?${query}` : ""}`);
}
async acknowledgeAlert(id: string, note = ""): Promise<AlertResponse> {
return this.request<AlertResponse>(`/alerts/${encodeURIComponent(id)}/acknowledge`, { method: "POST", body: { note } });
}
async resolveAlert(id: string, note = ""): Promise<AlertResponse> {
return this.request<AlertResponse>(`/alerts/${encodeURIComponent(id)}/resolve`, { method: "POST", body: { note } });
}
async retryAlert(id: string, idempotencyKey: string): Promise<AlertRetryResponse> {
return this.request<AlertRetryResponse>(`/alerts/${encodeURIComponent(id)}/retry`, { method: "POST", body: { idempotencyKey } });
}
async listPluginLifecycles(filter: { pluginId?: string; serverInstanceId?: string; currentState?: string } = {}): Promise<PluginLifecycleListResponse> {
const params = new URLSearchParams();
Object.entries(filter).forEach(([key, value]) => { if (value) params.set(key, value); });
@@ -2,33 +2,23 @@ import { afterEach, describe, expect, it, vi } from "vitest";
import { PlatformApiClient } from "./client";
describe("PlatformApiClient production operations", () => {
describe("PlatformApiClient plugin operations", () => {
afterEach(() => vi.unstubAllGlobals());
it("uses Platform-only operations routes and bounded request bodies", async () => {
const calls: Array<{ url: string; method: string; body?: unknown }> = [];
vi.stubGlobal("fetch", vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
calls.push({ url: String(input), method: init?.method ?? "GET", body: init?.body ? JSON.parse(String(init.body)) : undefined });
return new Response(JSON.stringify({ items: [], count: 0, endpoints: [], totalMaxJobs: 0, totalRunningJobs: 0, totalQueuedJobs: 0, activeAlerts: 0, generatedAt: "2026-07-18T00:00:00Z", status: "queued", installation: {}, job: {}, decision: {}, alert: {} }), { status: 200, headers: { "Content-Type": "application/json" } });
return new Response(JSON.stringify({ items: [], count: 0, status: "queued", installation: {}, job: {} }), { status: 200, headers: { "Content-Type": "application/json" } });
}));
const client = new PlatformApiClient("/api/v1", () => "session-token");
await client.getProductionCapacity();
await client.listAlerts({ state: "active" });
await client.acknowledgeAlert("alert-1", "reviewed");
await client.resolveAlert("alert-1", "resolved");
await client.retryAlert("alert-1", "retry-1");
await client.listPluginLifecycles({ pluginId: "game.scum" });
await client.runPluginLifecycle("game.scum", { serverInstanceId: "server-1", operation: "upgrade", targetVersion: "1.2.0", idempotencyKey: "upgrade-1", confirmed: false });
await client.listAIConfigDiffs({ state: "pending" });
await client.approveAIConfigDiff("diff-1", "approve-1");
expect(calls.map((call) => `${call.method} ${call.url}`)).toEqual([
"GET /api/v1/production/capacity",
"GET /api/v1/alerts?state=active",
"POST /api/v1/alerts/alert-1/acknowledge",
"POST /api/v1/alerts/alert-1/resolve",
"POST /api/v1/alerts/alert-1/retry",
"GET /api/v1/plugin-lifecycles?pluginId=game.scum",
"POST /api/v1/plugin-lifecycles/game.scum/actions",
"GET /api/v1/ai/config-diffs?state=pending",
@@ -36,6 +26,6 @@ describe("PlatformApiClient production operations", () => {
]);
const serialized = JSON.stringify(calls);
expect(serialized).not.toMatch(/apiKey|token|secret|providerBaseUrl|runSocket|runEndpointUrl|hostPath|credential|dsn|rcon/i);
expect(calls[6]?.body).toEqual({ serverInstanceId: "server-1", operation: "upgrade", targetVersion: "1.2.0", idempotencyKey: "upgrade-1", confirmed: false });
expect(calls[1]?.body).toEqual({ serverInstanceId: "server-1", operation: "upgrade", targetVersion: "1.2.0", idempotencyKey: "upgrade-1", confirmed: false });
});
});
+1 -74
View File
@@ -1592,78 +1592,6 @@ export interface PluginProductionLifecycleDeclaration {
approvalRequired: Array<"disable" | "rollback" | "retire">;
}
export type CapacityAdmissionState = "accepted" | "deferred" | "denied";
export interface CapacityAdmissionDecisionResponse {
accepted: boolean;
state: CapacityAdmissionState;
reason: string;
retryAfterSeconds?: number;
serverInstanceId?: string;
runEndpointId?: string;
capability: string;
targetKey?: string;
maxJobs: number;
runningJobs: number;
queuedJobs: number;
pressureCodes?: string[];
checkedAt: string;
alertId?: string;
}
export interface EndpointCapacityProjectionResponse {
runEndpointId: string;
displayName: string;
status: RunEndpointStatus;
capabilities: string[];
maxJobs: number;
runningJobs: number;
queuedJobs: number;
logBacklogBatches?: number;
artifactBacklogChunks?: number;
pressureCodes?: string[];
summary?: string;
lastHeartbeatAt: string;
lastAdmissionDecision?: CapacityAdmissionState;
lastAdmissionReason?: string;
lastAdmissionCheckedAt?: string;
}
export interface ProductionCapacitySummaryResponse {
endpoints: EndpointCapacityProjectionResponse[];
totalMaxJobs: number;
totalRunningJobs: number;
totalQueuedJobs: number;
activeAlerts: number;
generatedAt: string;
}
export type AlertState = "active" | "acknowledged" | "resolved";
export interface AlertResponse {
id: string;
sourceKind: string;
sourceId: string;
ruleKey: string;
severity: "info" | "warning" | "critical";
state: AlertState;
title: string;
message: string;
occurrenceCount: number;
retryable: boolean;
retryAfterSeconds?: number;
lastJobId?: string;
lastSeenAt: string;
acknowledgedBy?: string;
acknowledgedAt?: string;
resolvedBy?: string;
resolvedAt?: string;
resolutionNote?: string;
createdAt: string;
updatedAt: string;
}
export interface AlertListResponse { items: AlertResponse[]; count: number; }
export interface AlertRetryResponse { status: string; alert: AlertResponse; decision: CapacityAdmissionDecisionResponse; }
export type PluginLifecycleOperation = "install" | "enable" | "disable" | "upgrade" | "rollback" | "retire" | "dependency-check";
export interface PluginLifecycleInstallationResponse {
id: string;
@@ -1678,14 +1606,13 @@ export interface PluginLifecycleInstallationResponse {
compatibility?: string;
dependencyState?: string;
jobId?: string;
alertId?: string;
failureReason?: string;
createdAt: string;
updatedAt: string;
}
export interface PluginLifecycleListResponse { items: PluginLifecycleInstallationResponse[]; count: number; }
export interface PluginLifecycleActionRequest { serverInstanceId: string; operation: PluginLifecycleOperation; targetVersion?: string; idempotencyKey: string; confirmed: boolean; }
export interface PluginLifecycleActionResponse { status: string; installation: PluginLifecycleInstallationResponse; job: JobResponse; decision: CapacityAdmissionDecisionResponse; alert?: AlertResponse; }
export interface PluginLifecycleActionResponse { status: string; installation: PluginLifecycleInstallationResponse; job: JobResponse; }
export interface AIConfigDiffPreviewResponse {
id: string;