fix: separate worker observation freshness

This commit is contained in:
2026-09-26 07:32:43 +09:00
parent e3587be3bd
commit 4d978b8cd8
11 changed files with 185 additions and 15 deletions
@@ -1,6 +1,6 @@
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:80be292e32441730f7de890e64836f4ca9655576d655e60e6d44daf5227a1b1c)
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
// Output: web/workspace/src/lib/generated/repository-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
@@ -55,6 +55,8 @@ export type RepositorySshHostTrust = { created_at: string; current_revision: num
export type RepositorySummary = { default_selector?: string | null; diagnostics?: Array<RepositoryDiagnostic> | null; git?: GitRepositorySummary | null; kind: string; observed_at?: string | null; observed_status: RepositoryObservedStatus; provider: string; record_authority: string; repository_key: string; source: RepositorySource; source_fingerprint: string; source_revision: number; };
export type SubscriptionWorkerAvailability = "observed" | "unavailable";
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
@@ -69,7 +71,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
@@ -1,6 +1,6 @@
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:80be292e32441730f7de890e64836f4ca9655576d655e60e6d44daf5227a1b1c)
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/runtime-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
@@ -105,7 +105,7 @@ export type RuntimeWorkerLifecycleResult = { diagnostics?: Array<Diagnostic>; ru
export type RuntimeWorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
export type RuntimeWorkerShowResponse = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerShowResponse = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerSpawnAcceptanceEvidence = { detail: string; kind: string; };
@@ -125,6 +125,8 @@ export type RuntimeWorkerSummary = { capabilities: WorkerCapabilitySummary; diag
export type RuntimeWorkerTicketAssignmentRequest = { operation_id: string; ticket_id: string; };
export type SubscriptionWorkerAvailability = "observed" | "unavailable";
export type UpdateRemoteRuntimeRequest = { display_name?: string | null; endpoint: string; };
export type UploadedFileAvailability = "available" | "unavailable" | "integrity_failed";
@@ -159,7 +161,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
@@ -1,6 +1,6 @@
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:80be292e32441730f7de890e64836f4ca9655576d655e60e6d44daf5227a1b1c)
// Input contract: 0.1.0 (sha256:a92b7346166ec2316878ef38b0426090cb4bdd0d5b96cae3014bef35c60df02a)
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
@@ -35,6 +35,8 @@ export type RuntimeWorkingDirectorySummary = { cleanliness?: string | null; clea
export type Segment = { content: string; kind: "text"; } | { chars: number; content: string; id: number; kind: "paste"; lines: number; } | { artifact: PasteArtifactRef; kind: "paste_artifact"; } | { file: UploadedFileRef; kind: "uploaded_file"; } | { kind: "file_ref"; path: string; } | { kind: "flow"; selector: string; } | { kind: "unknown"; };
export type SubscriptionWorkerAvailability = "observed" | "unavailable";
export type UploadedFileAvailability = "available" | "unavailable" | "integrity_failed";
export type UploadedFileRef = { artifact_id: string; availability: UploadedFileAvailability; byte_len: number; created_at_ms: number; file_name: string; media_type: string; sha256: string; source_entry_id?: string | null; };
@@ -63,7 +65,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; working_directory: WorkingDirectorySummary; };
@@ -31,6 +31,7 @@ import {
parseBrowserWorkspaceOrchestratorResponse,
parseCreateWorkspaceWorkerRequest,
parseWorkerLaunchOptionsResponse,
parseWorkerSummary,
} from "./workers.ts";
const worker = {
@@ -62,6 +63,39 @@ const worker = {
diagnostics: [],
};
Deno.test("Worker summary parser enforces observation freshness", () => {
const unavailable = {
...worker,
resource_key: "W-1",
availability: "unavailable",
state: "unavailable",
};
const parsed = parseWorkerSummary(unavailable);
assertEquals(parsed.availability, "unavailable");
assertEquals(parsed.worker_state, undefined);
assertThrows(
() =>
parseWorkerSummary({
...unavailable,
worker_state: {
last_command_id: 0,
state: { kind: "idle" },
},
}),
Error,
"worker_state must be absent",
);
const observedStopped = parseWorkerSummary({
...unavailable,
availability: "observed",
state: "stopped",
});
assertEquals(observedStopped.availability, "observed");
assertEquals(observedStopped.state, "stopped");
});
Deno.test("Worker launch options parser accepts the generated wire shape", () => {
const parsed = parseWorkerLaunchOptionsResponse({
workspace_id: "workspace-a",
+17 -5
View File
@@ -343,6 +343,10 @@ export function parseWorkerSummary(
label = "Worker summary",
): ParsedWorkerSummary {
const item = record(value, label);
const availability = string(item.availability, `${label}.availability`);
if (availability !== "observed" && availability !== "unavailable") {
throw new Error(`${label}.availability is invalid`);
}
exact(
item,
[
@@ -356,6 +360,7 @@ export function parseWorkerSummary(
"singleton_key",
"tags",
"workspace",
"availability",
"state",
"worker_state",
"last_seen_at",
@@ -368,6 +373,16 @@ export function parseWorkerSummary(
],
label,
);
const workerState = optional(
item.worker_state,
`${label}.worker_state`,
workerStateSnapshot,
);
if (availability === "unavailable" && workerState != null) {
throw new Error(
`${label}.worker_state must be absent when availability is unavailable`,
);
}
return {
runtime_id: string(item.runtime_id, `${label}.runtime_id`),
worker_id: string(item.worker_id, `${label}.worker_id`),
@@ -387,12 +402,9 @@ export function parseWorkerSummary(
? []
: array(item.tags, `${label}.tags`, string),
workspace: workspaceSummary(item.workspace, `${label}.workspace`),
availability,
state: string(item.state, `${label}.state`),
worker_state: optional(
item.worker_state,
`${label}.worker_state`,
workerStateSnapshot,
),
worker_state: workerState,
last_seen_at: optional(item.last_seen_at, `${label}.last_seen_at`, string),
pinned: item.pinned === undefined
? false
@@ -146,6 +146,7 @@ function projectWorker(
visibility: "workspace",
identity: "runtime_subscription_worker",
},
availability: worker.availability,
state: liveWorkerState(worker),
worker_state: worker.worker_state,
pinned: false,