workspace: remove worker status field

This commit is contained in:
Keisuke Hirata 2026-07-11 15:22:23 +09:00
parent 69560addf8
commit 2d2c29a775
No known key found for this signature in database
8 changed files with 51 additions and 29 deletions

View File

@ -1,8 +1,8 @@
--- ---
title: 'Remove duplicate Worker status field' title: 'Remove duplicate Worker status field'
state: 'inprogress' state: 'done'
created_at: '2026-07-11T06:05:38Z' created_at: '2026-07-11T06:05:38Z'
updated_at: '2026-07-11T06:06:13Z' updated_at: '2026-07-11T06:22:05Z'
assignee: null assignee: null
queued_by: 'yoi ticket' queued_by: 'yoi ticket'
queued_at: '2026-07-11T06:06:13Z' queued_at: '2026-07-11T06:06:13Z'

View File

@ -39,4 +39,35 @@ Ticket を `yoi ticket` が queued にしました。
State changed to `inprogress`. State changed to `inprogress`.
---
<!-- event: implementation_report author: hare at: 2026-07-11T06:22:05Z -->
## Implementation report
Removed duplicate Workspace Worker `status` from browser-facing Worker summaries.
- `WorkerSummary` now exposes `state` only for Worker state.
- Backend Worker projections populate only `state`; registry-only Workers remain `state: archived`.
- Frontend Worker type, sidebar, Workers page, and Console header no longer reference `worker.status`.
- Runtime/Host/Workdir/protocol statuses are unchanged where they are distinct domain concepts.
Validation:
- cargo test -q -p yoi-workspace-server
- cd web/workspace && deno task check
- cd web/workspace && deno task test
- cargo test -q
- git diff --check
- nix build .#yoi --no-link
---
<!-- event: state_changed author: "yoi ticket" at: 2026-07-11T06:22:05Z from: inprogress to: done reason: cli_state field: state -->
## State changed
State changed to `done`.
--- ---

View File

@ -238,7 +238,6 @@ pub struct WorkerSummary {
pub profile: Option<String>, pub profile: Option<String>,
pub workspace: WorkerWorkspaceSummary, pub workspace: WorkerWorkspaceSummary,
pub state: String, pub state: String,
pub status: String,
pub last_seen_at: Option<String>, pub last_seen_at: Option<String>,
#[serde(default)] #[serde(default)]
pub pinned: bool, pub pinned: bool,
@ -1191,8 +1190,7 @@ impl EmbeddedWorkerRuntime {
visibility: "backend_internal".to_string(), visibility: "backend_internal".to_string(),
identity: "runtime_registry_worker".to_string(), identity: "runtime_registry_worker".to_string(),
}, },
state: embedded_worker_status_label(summary.status).to_string(), state: embedded_worker_execution_status_label(summary.status, &summary.execution)
status: embedded_worker_execution_status_label(summary.status, &summary.execution)
.to_string(), .to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
@ -1228,8 +1226,7 @@ impl EmbeddedWorkerRuntime {
visibility: "backend_internal".to_string(), visibility: "backend_internal".to_string(),
identity: "runtime_registry_worker".to_string(), identity: "runtime_registry_worker".to_string(),
}, },
state: embedded_worker_status_label(detail.status).to_string(), state: embedded_worker_execution_status_label(detail.status, &detail.execution)
status: embedded_worker_execution_status_label(detail.status, &detail.execution)
.to_string(), .to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
@ -1931,8 +1928,7 @@ impl RemoteWorkerRuntime {
visibility: "remote_runtime".to_string(), visibility: "remote_runtime".to_string(),
identity: "runtime_registry_worker".to_string(), identity: "runtime_registry_worker".to_string(),
}, },
state: embedded_worker_status_label(summary.status).to_string(), state: embedded_worker_execution_status_label(summary.status, &summary.execution)
status: embedded_worker_execution_status_label(summary.status, &summary.execution)
.to_string(), .to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
@ -1967,8 +1963,7 @@ impl RemoteWorkerRuntime {
visibility: "remote_runtime".to_string(), visibility: "remote_runtime".to_string(),
identity: "runtime_registry_worker".to_string(), identity: "runtime_registry_worker".to_string(),
}, },
state: embedded_worker_status_label(detail.status).to_string(), state: embedded_worker_execution_status_label(detail.status, &detail.execution)
status: embedded_worker_execution_status_label(detail.status, &detail.execution)
.to_string(), .to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
@ -3104,7 +3099,6 @@ pub fn placeholder_worker(host_id: impl Into<String>) -> WorkerSummary {
identity: "unsupported".to_string(), identity: "unsupported".to_string(),
}, },
state: "unsupported".to_string(), state: "unsupported".to_string(),
status: "Worker runtime control is not wired yet".to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
retention_state: "transient".to_string(), retention_state: "transient".to_string(),
@ -3431,8 +3425,7 @@ mod tests {
visibility: "opaque".to_string(), visibility: "opaque".to_string(),
identity: host_id.to_string(), identity: host_id.to_string(),
}, },
state: "running".to_string(), state: "available".to_string(),
status: "available".to_string(),
last_seen_at: None, last_seen_at: None,
pinned: false, pinned: false,
retention_state: "transient".to_string(), retention_state: "transient".to_string(),
@ -3673,7 +3666,7 @@ mod tests {
.worker(&worker.worker_id) .worker(&worker.worker_id)
.worker .worker
.expect("worker detail"); .expect("worker detail");
if detail.status == "idle" { if detail.state == "idle" {
assert!(detail.capabilities.can_accept_input); assert!(detail.capabilities.can_accept_input);
break; break;
} }
@ -4078,15 +4071,15 @@ mod tests {
worker.worker_id worker.worker_id
); );
} }
assert_eq!(workers.items[0].status, "stale"); assert_eq!(workers.items[0].state, "stale");
assert_eq!(workers.items[1].status, "unconnected"); assert_eq!(workers.items[1].state, "unconnected");
assert_eq!(workers.items[2].status, "rejected"); assert_eq!(workers.items[2].state, "rejected");
assert_eq!(workers.items[3].status, "errored"); assert_eq!(workers.items[3].state, "errored");
let stale_detail = registry.worker("remote:primary", "worker-stale").unwrap(); let stale_detail = registry.worker("remote:primary", "worker-stale").unwrap();
assert!(!stale_detail.capabilities.can_accept_input); assert!(!stale_detail.capabilities.can_accept_input);
assert!(!stale_detail.capabilities.can_stop); assert!(!stale_detail.capabilities.can_stop);
assert_eq!(stale_detail.status, "stale"); assert_eq!(stale_detail.state, "stale");
server.join().expect("mock remote server finished"); server.join().expect("mock remote server finished");
} }

View File

@ -1583,7 +1583,7 @@ fn build_runtime_cleanup_plan(
let live_running_worker_ids: HashSet<String> = workers let live_running_worker_ids: HashSet<String> = workers
.items .items
.iter() .iter()
.filter(|worker| worker.status == "running" || worker.state == "running") .filter(|worker| worker.state == "running")
.map(|worker| backend_worker_id(worker.runtime_id.as_str(), worker.worker_id.as_str())) .map(|worker| backend_worker_id(worker.runtime_id.as_str(), worker.worker_id.as_str()))
.collect(); .collect();
let (workdir_summaries, mut diagnostics) = let (workdir_summaries, mut diagnostics) =
@ -3939,7 +3939,6 @@ fn worker_summary_from_registry(record: &WorkerRegistryRecord) -> WorkerSummary
host_id: "backend-registry".to_string(), host_id: "backend-registry".to_string(),
role: None, role: None,
label: record.display_name.clone(), label: record.display_name.clone(),
status: "archived".to_string(),
state: "archived".to_string(), state: "archived".to_string(),
last_seen_at: Some(record.updated_at.clone()), last_seen_at: Some(record.updated_at.clone()),
pinned: record.retention_state == "pinned", pinned: record.retention_state == "pinned",
@ -4820,7 +4819,7 @@ mod tests {
let projected = merge_worker_registry_projection(None, &worker, vec![link], &[workdir]); let projected = merge_worker_registry_projection(None, &worker, vec![link], &[workdir]);
assert_eq!(projected.status, "archived"); assert_eq!(projected.state, "archived");
assert_eq!(projected.state, "archived"); assert_eq!(projected.state, "archived");
assert_eq!( assert_eq!(
projected.working_directory.as_ref().unwrap().status, projected.working_directory.as_ref().unwrap().status,
@ -6891,7 +6890,7 @@ mod tests {
.runtime .runtime
.worker("embedded-worker-runtime", &worker_id) .worker("embedded-worker-runtime", &worker_id)
.expect("worker detail"); .expect("worker detail");
if detail.status == "idle" { if detail.state == "idle" {
break; break;
} }
assert!( assert!(
@ -6913,7 +6912,7 @@ mod tests {
.runtime .runtime
.worker("embedded-worker-runtime", &worker_id) .worker("embedded-worker-runtime", &worker_id)
.expect("restored worker"); .expect("restored worker");
assert_eq!(restored_worker.status, "stale"); assert_eq!(restored_worker.state, "stale");
assert!(!restored_worker.capabilities.can_accept_input); assert!(!restored_worker.capabilities.can_accept_input);
assert!(!restored_worker.capabilities.can_stop); assert!(!restored_worker.capabilities.can_stop);
assert!( assert!(

View File

@ -106,7 +106,7 @@
<span class="worker-task-title">-</span> <span class="worker-task-title">-</span>
</span> </span>
<span class="item-meta"> <span class="item-meta">
{worker.role ? `${worker.role} · ` : ''}{worker.state} · {worker.status} · 🖥 {worker.host_id} {worker.role ? `${worker.role} · ` : ''}{worker.state} · 🖥 {worker.host_id}
{worker.working_directory ? ` · wd:${worker.working_directory.repository_id}@${worker.working_directory.resolved_commit.slice(0, 8)}` : ''} {worker.working_directory ? ` · wd:${worker.working_directory.repository_id}@${worker.working_directory.resolved_commit.slice(0, 8)}` : ''}
</span> </span>
</a> </a>

View File

@ -84,7 +84,6 @@ export type Worker = {
profile?: string | null; profile?: string | null;
workspace: { visibility: string; identity: string }; workspace: { visibility: string; identity: string };
state: string; state: string;
status: string;
pinned?: boolean; pinned?: boolean;
retention_state?: string; retention_state?: string;
last_seen_at?: string | null; last_seen_at?: string | null;

View File

@ -324,7 +324,7 @@
</div> </div>
<div class="console-header-actions"> <div class="console-header-actions">
<div class="console-status-pill" class:warn={streamState !== 'open'}> <div class="console-status-pill" class:warn={streamState !== 'open'}>
{worker?.state ?? 'unknown'} · {worker?.status ?? 'loading'} · stream {streamState} {worker?.state ?? 'loading'} · stream {streamState}
</div> </div>
<button type="button" class="secondary-button" aria-expanded={workerDetailsOpen} onclick={() => workerDetailsOpen = !workerDetailsOpen}> <button type="button" class="secondary-button" aria-expanded={workerDetailsOpen} onclick={() => workerDetailsOpen = !workerDetailsOpen}>
Details Details

View File

@ -27,7 +27,7 @@
} }
function workerStatus(worker: Worker): string { function workerStatus(worker: Worker): string {
return `${worker.state} · ${worker.status}`; return worker.state;
} }
function workerProfile(worker: Worker): string { function workerProfile(worker: Worker): string {