mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
* fix(orchestration): complete worker tasks and improve coordinator UX
* Fix orchestration lifecycle sender resolution and peek/check compat hand
- Lifecycle sends (worker_done/heartbeat) now use ORCA_TERMINAL_HANDLE
verbatim, skipping the liveness probe and pane remint that could
block delivery during restarts or mismatch stale-runtime assignee
handles.
- --peek now round-trips as {peek:true, unread:false} so older runtimes
that strip unknown params degrade to non-destructive "all" instead of
mark-read, with client-side filtering to restore peek semantics and a
clear error when --peek --wait can't be honored.
- Reject combined read-mode flags (--unread/--peek/--all) before calling
the runtime.
- Distinguish suppressed (already-consumed) lifecycle messages from
ignored ones so send doesn't wake --wait waiters for stale heartbeats.
- Fix task summary truncation to avoid splitting UTF-16 surrogate pairs
and to not misreport whitespace normalization as truncation.
* Add shared helper to abbreviate orchestration task specs for brief listi
- Normalizes whitespace and caps spec length at 160 chars, flagging
truncation separately from whitespace-only changes
- Truncates on UTF-16 code point boundaries to avoid splitting
surrogate pairs and emitting malformed strings
* Add pane-key identity to worker_done/heartbeat reconciliation and server
- Records the sender's pane key on messages and dispatch contexts so
worker_done/heartbeat ownership can be verified by the remint-stable
pane leaf instead of the terminal handle, which is reissued across
restarts.
- Rejects lifecycle messages from a genuinely foreign pane while still
tolerating handle remints, tab break-outs, and older CLIs that lack
pane identity.
- Moves task-spec abbreviation server-side (orchestration.taskList
--brief) so full specs no longer cross SSH/relay transports, with a
client-side fallback for older runtimes; consolidates the shared
abbreviation helper under src/shared.
- Adds a stderr warning when a pre-peek runtime's --peek response hits
the 100-row cap, since older unread messages may be missing.
* Isolate ORCA_PANE_KEY in CLI test beforeEach to fix leaked senderPaneKey
Co-authored-by: Orca <help@stably.ai>
* Fix pane-key remint bypassing dispatch mutual-exclusion lock
- Dispatch locking only matched on assignee_handle, so a reminted
terminal handle (tab break-out) could open a second concurrent
dispatch on the same pane.
- Add leaf-UUID-based pane key comparison (parsePaneKey) as a
secondary lock, falling back to exact handle match for legacy
rows without pane keys.
* Update orchestration skill docs for lifecycle authority and CLI flag add
- Clarify that dispatch lifecycle is tied to taskId+dispatchId verified against
the dispatched pane, not the terminal handle, since handles can be reminted
after restart
- Document new `check --peek`/`--all` and `task-list --brief` flags, with
fallback guidance for older CLIs that reject them
- Note that a valid worker_done auto-completes the task/dispatch, so workers
shouldn't also call task-update manually
---------
Co-authored-by: Orca <help@stably.ai>
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { abbreviateOrchestrationTasks } from './orchestration-task-summary'
|
|
|
|
describe('abbreviateOrchestrationTasks', () => {
|
|
it('collapses whitespace and caps long task specs', () => {
|
|
const [task] = abbreviateOrchestrationTasks([
|
|
{ id: 'task_1', spec: `First line\n\n${'detail '.repeat(40)}` }
|
|
])
|
|
|
|
expect(task.id).toBe('task_1')
|
|
expect(task.spec).not.toContain('\n')
|
|
expect(task.spec).toHaveLength(160)
|
|
expect(task.spec.endsWith('…')).toBe(true)
|
|
expect(task.spec_truncated).toBe(true)
|
|
})
|
|
|
|
it('preserves a short one-line spec', () => {
|
|
const [task] = abbreviateOrchestrationTasks([{ spec: 'Short task' }])
|
|
|
|
expect(task).toEqual({ spec: 'Short task', spec_truncated: false })
|
|
})
|
|
|
|
it('does not report whitespace normalization as truncation', () => {
|
|
const [task] = abbreviateOrchestrationTasks([{ spec: 'Short\n\n task' }])
|
|
|
|
expect(task).toEqual({ spec: 'Short task', spec_truncated: false })
|
|
})
|
|
|
|
it('does not split a surrogate pair at the truncation boundary', () => {
|
|
// 158 chars + an astral emoji spanning UTF-16 units 158-159: a naive
|
|
// slice(0, 159) would cut the pair and leave a lone high surrogate.
|
|
const [task] = abbreviateOrchestrationTasks([{ spec: `${'a'.repeat(158)}😀${'b'.repeat(40)}` }])
|
|
|
|
expect(task.spec_truncated).toBe(true)
|
|
expect(task.spec.isWellFormed()).toBe(true)
|
|
expect(task.spec.endsWith('…')).toBe(true)
|
|
})
|
|
})
|