mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 16:02:03 +00:00
fix(orchestration): give the per-pane attention verdict the full liveness subject
The attention context passed no workerStage and no resource releaseState to projectLiveness, so a released worker's pane could classify live from a stale agent status while worker-list called the same dispatch exited.
This commit is contained in:
+12
-3
@@ -18,10 +18,13 @@ export type WorkerAttentionFacts = {
|
||||
terminationReason: TerminalExitCause['kind'] | null
|
||||
isRoot: boolean
|
||||
workerState: WorkerDispatchState | null
|
||||
workerStage: string | null
|
||||
dispatchStatus: DispatchStatus
|
||||
/** Execution host of the worker's terminal resource; a remote row with no connection id is
|
||||
* unverifiable. `undefined` when no resource was ever materialized. */
|
||||
hostScope?: string | null
|
||||
/** A released resource is an execution-host confirmation that the terminal is gone. */
|
||||
releaseState?: string | null
|
||||
}
|
||||
|
||||
export function getWorkerAttentionFactsForDispatches(
|
||||
@@ -37,8 +40,9 @@ export function getWorkerAttentionFactsForDispatches(
|
||||
const rows = this.db
|
||||
.prepare(
|
||||
`SELECT d.id AS dispatch_id, d.task_id, d.status AS dispatch_status,
|
||||
d.termination_reason, w.state AS worker_state, t.parent_id AS parent_task_id,
|
||||
r.id AS resource_id, r.host_scope,
|
||||
d.termination_reason, w.state AS worker_state, w.stage AS worker_stage,
|
||||
t.parent_id AS parent_task_id,
|
||||
r.id AS resource_id, r.host_scope, r.release_state,
|
||||
EXISTS (
|
||||
SELECT 1 FROM question_threads q
|
||||
WHERE q.dispatch_id = d.id AND q.status = 'pending'
|
||||
@@ -65,9 +69,11 @@ export function getWorkerAttentionFactsForDispatches(
|
||||
dispatch_status: DispatchStatus
|
||||
termination_reason: TerminalExitCause['kind'] | null
|
||||
worker_state: WorkerDispatchState | null
|
||||
worker_stage: string | null
|
||||
parent_task_id: string | null
|
||||
resource_id: string | null
|
||||
host_scope: string | null
|
||||
release_state: string | null
|
||||
pending_input: number
|
||||
pending_approval: number
|
||||
pending_guidance: number
|
||||
@@ -105,8 +111,11 @@ export function getWorkerAttentionFactsForDispatches(
|
||||
terminationReason: row.termination_reason,
|
||||
isRoot: row.parent_task_id === null,
|
||||
workerState: row.worker_state,
|
||||
workerStage: row.worker_stage,
|
||||
dispatchStatus: row.dispatch_status,
|
||||
...(row.resource_id === null ? {} : { hostScope: row.host_scope })
|
||||
...(row.resource_id === null
|
||||
? {}
|
||||
: { hostScope: row.host_scope, releaseState: row.release_state })
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ function facts(overrides: Partial<WorkerAttentionFacts> = {}): WorkerAttentionFa
|
||||
terminationReason: null,
|
||||
isRoot: false,
|
||||
workerState: 'ready',
|
||||
workerStage: 'prompt_delivered',
|
||||
dispatchStatus: 'dispatched',
|
||||
...overrides
|
||||
}
|
||||
@@ -68,6 +69,37 @@ describe('worker attention liveness', () => {
|
||||
expect(attention).toEqual({ categories: [], requiresAction: false })
|
||||
})
|
||||
|
||||
it('reads a released resource as exited, not as a stale live pane', () => {
|
||||
const attention = projectWorkerAttentionContext({
|
||||
// worker-list called the same dispatch exited while this pane classified from a status.
|
||||
facts: facts({
|
||||
outcome: 'outcome_unknown',
|
||||
hostScope: '{"kind":"local","hostId":"local"}',
|
||||
releaseState: 'released'
|
||||
}),
|
||||
isRoot: false,
|
||||
status: status({ evidenceObservedAt: NOW - AGENT_STATUS_STALE_AFTER_MS - 60_000 }),
|
||||
now: NOW
|
||||
})
|
||||
|
||||
expect(attention).toEqual({ categories: [], requiresAction: false })
|
||||
})
|
||||
|
||||
it('reads a released worker stage as exited, not as a stale live pane', () => {
|
||||
const attention = projectWorkerAttentionContext({
|
||||
facts: facts({
|
||||
outcome: 'outcome_unknown',
|
||||
workerStage: 'released',
|
||||
hostScope: '{"kind":"local","hostId":"local"}'
|
||||
}),
|
||||
isRoot: false,
|
||||
status: status({ evidenceObservedAt: NOW - AGENT_STATUS_STALE_AFTER_MS - 60_000 }),
|
||||
now: NOW
|
||||
})
|
||||
|
||||
expect(attention).toEqual({ categories: [], requiresAction: false })
|
||||
})
|
||||
|
||||
it('treats a settled worker stop as exited rather than unverifiable', () => {
|
||||
const attention = projectWorkerAttentionContext({
|
||||
facts: facts({ workerState: 'stopped', outcome: 'in_progress' }),
|
||||
|
||||
@@ -52,8 +52,12 @@ export function projectWorkerAttentionContext(args: {
|
||||
liveness: projectLiveness(
|
||||
{
|
||||
workerState: args.facts.workerState,
|
||||
workerStage: args.facts.workerStage,
|
||||
terminationReason: args.facts.terminationReason,
|
||||
resource: args.facts.hostScope === undefined ? null : { hostScope: args.facts.hostScope }
|
||||
resource:
|
||||
args.facts.hostScope === undefined
|
||||
? null
|
||||
: { hostScope: args.facts.hostScope, releaseState: args.facts.releaseState }
|
||||
},
|
||||
args.status,
|
||||
args.now
|
||||
|
||||
Reference in New Issue
Block a user