mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 00:04:01 +00:00
fix(orchestration): decide queued mail by batch membership, not sequence
The queued-mail probe asked whether an unread row existed with a sequence above the outstanding Delivery's highest. Mailbox routing moves rows with `UPDATE ... SET to_handle` and never rewrites `sequence`, so mail released from a settled Dispatch, or from a deferred direct handle, enters the Run mailbox carrying an older sequence. Such a row is unread, not a member of the replayed batch, and genuinely queued behind it -- but the probe reported `queuedMatchingMessages: false`, which renders as no warning at all. A coordinator waiting on a `worker_done` saw a replayed batch and no reason to suspect the message it was waiting for was one ack away. Test membership against the batch's own message ids instead. That is sequence-independent and therefore routing-independent. Both `EXPLAIN QUERY PLAN`s remain indexed SEARCHes, and the id list is bounded by the 50-row batch cap. An empty batch now reports any unread matching mail as queued rather than asserting `false`. Also: - `formatDeliveryAction` renders silence only for an observed `false`; every other value renders "unavailable", matching `formatDeliveryStatus`'s polarity so an off-contract value cannot read as "nothing is queued". - Queued mail is not necessarily newer, so say "Other messages" rather than "Newer messages" in the CLI output, the skill guide, the command spec, and the reliability gate. The old wording restated the assumption that caused the defect.
This commit is contained in:
@@ -3333,7 +3333,7 @@
|
||||
"durationSeconds": 1.5,
|
||||
"summary": "175/175 at the relocated paths on the unified tool authority, replacing the 2026-08-27 record of the same command at 174/174. That run killed twelve of fourteen mutants as sole deltas — dropping the document branch from the one authority door, removing either browsing-registration refusal or the mint-side refusal that is its converse, deleting the registration notification or widening it to the worktree-wide and any-tab waits, disposing revoked state by grant instead of by page, dropping the hosting-renderer or destroyed-contents check, rebuilding the renderer tool target from the grant, and deleting the teardown identity check under a re-mint — and reported two as ill-posed rather than as kills. The relocation changed no file it names except their directory."
|
||||
},
|
||||
{
|
||||
{
|
||||
"date": "2026-08-27",
|
||||
"runner": "local",
|
||||
"platform": "macos",
|
||||
@@ -3378,7 +3378,7 @@
|
||||
"durationSeconds": 0.17,
|
||||
"summary": "22/22 on the candidate that stops a previewed document writing into this desktop's Downloads folder. The hole was read out of the shipping path, not guessed: the preview partition took the shared browser partition policies whole, including will-download, and a preview guest joins no browser-page registry, so handleGuestWillDownload resolved no owner context, routeBrowserClientDownload answered local for a non-client-hosted contents, and the item got a reserved Downloads name with no prompt and no tab to attribute it to. Downloads are now the one policy the preview partition does not inherit. Red-green with each mutant as the sole delta: making the installer ignore the deny option routes the preview partition's download to the router again, and making the preview protocol installer stop asking for the deny leaves the option unset. The absence half is paired with a presence precondition in the same run — an ordinary browsing partition installed beside the preview one in one test still reaches the download router, so a deny that fenced everything, or a download path that had been removed entirely, would fail rather than pass quietly."
|
||||
},
|
||||
{
|
||||
{
|
||||
"date": "2026-08-27",
|
||||
"runner": "local",
|
||||
"platform": "macos",
|
||||
@@ -3441,7 +3441,7 @@
|
||||
"durationSeconds": 0.36,
|
||||
"summary": "The four surfaces the trusted-click route is built from passed 63/63: the preload's click policy over a real document, including an untrusted dispatched click, an untrusted middle click, an SVG animated href resolved against the document so a relative, rooted or fragment SVG link behaves exactly like the identical HTML anchor, fragment and percent-encoded fragment targets and a trusted middle click; the guest policy's deny-only sinks, its refusal of a navigation that arrives before a document has bound the guest to a grant, and its report gate for an unfocused guest, an unregistered sender, a missing or revoked grant and non-web URLs; will-attach-webview pinning the preview preload in both directions; and the click channel handing main its own sender without a trusted-renderer check."
|
||||
},
|
||||
{
|
||||
{
|
||||
"date": "2026-08-26",
|
||||
"runner": "local",
|
||||
"platform": "macos",
|
||||
@@ -3468,7 +3468,7 @@
|
||||
"durationSeconds": 66,
|
||||
"summary": "The journey passed 3/3 again under --repeat-each=3 on the candidate that clears grants on every fresh shell document and gates the mint channel on the trusted renderer, so neither change disturbs a live preview: the document still rendered, both browser counts held at baseline, and the target=_blank press still routed out as an Orca browser tab."
|
||||
},
|
||||
{
|
||||
{
|
||||
"date": "2026-08-26",
|
||||
"runner": "local",
|
||||
"platform": "macos",
|
||||
@@ -12293,7 +12293,7 @@
|
||||
"https://github.com/stablyai/orca/issues/14522",
|
||||
"internal incident evidence: improve-vps-setup, 2026-08-10"
|
||||
],
|
||||
"invariant": "Each message has one stable row ID and authoritative recipient; coordinator-addressed current-delivery inserts are atomically owned by run:<id>. Pointer staging may set delivered_at but never consumes mail. Each Run consumer generation has at most one outstanding Delivery with a fixed ID and fixed message IDs; ordinary checks label and replay it until an explicit matching acknowledgment marks exactly those rows read. Newer mail remains unseen and unread while a bounded indexed probe reports whether queued rows match the waiter's requested types. Rebinding fences the old generation, notification types/counts correspond to unread rows retrievable under the same authority, and federation replay imports each stable message identity once without re-waking an already-read duplicate.",
|
||||
"invariant": "Each message has one stable row ID and authoritative recipient; coordinator-addressed current-delivery inserts are atomically owned by run:<id>. Pointer staging may set delivered_at but never consumes mail. Each Run consumer generation has at most one outstanding Delivery with a fixed ID and fixed message IDs; ordinary checks label and replay it until an explicit matching acknowledgment marks exactly those rows read. Mail queued behind the batch remains unseen and unread while a bounded indexed probe reports, by batch membership rather than by sequence, whether queued rows match the waiter's requested types. Rebinding fences the old generation, notification types/counts correspond to unread rows retrievable under the same authority, and federation replay imports each stable message identity once without re-waking an already-read duplicate.",
|
||||
"oracle": "Seed status, dispatch, question, escalation, and worker_done rows across direct-handle and canonical Run recipients in an isolated DB. Compare pointer count, RPC and built-CLI check output, direct SQLite rows, unread/peek/all/type filters, concurrent pollers, fixed Delivery IDs, explicit and wrong acknowledgment, bare-ack rejection, restart, filtered check --wait, queued matching-mail signaling, concurrent send during acknowledgment, and coordinator remint. Route a 125-row old-handle backlog, inject a commit without notification, and require startup repair. Exercise duplicate Run/Dispatch owners, stale panes, 50-row pages, cancellation, lifecycle fencing, and absent PTYs. Drop a federation ACK, reconnect/restart v1/v2 peers, and require stable import plus no duplicate read-row wake. Hold a healthy SSH write past five seconds but below the 60-second settlement deadline, then separately exceed the bound and require retryable undelivered state.",
|
||||
"commands": [
|
||||
"pnpm run build:cli && pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orchestration-message-delivery-identity.test.ts --reporter=dot --testTimeout=5000",
|
||||
@@ -12338,7 +12338,7 @@
|
||||
"notification count equals the concurrently replayed fixed Delivery batch",
|
||||
"unread, peek, all, and type filters preserve explicit acknowledgment semantics",
|
||||
"restart replays one outstanding Delivery ID without inserting another Delivery row",
|
||||
"a replay explicitly reports its fixed Delivery ID and whether newer filter-matching mail is queued without exposing or consuming it",
|
||||
"a replay explicitly reports its fixed Delivery ID and whether other filter-matching mail is queued without exposing or consuming it, including mail routed in at a lower sequence",
|
||||
"a filtered check --wait wakes once without a duplicate terminal pointer",
|
||||
"a 125-row old-handle backlog is atomically rebound before coordinator identity changes",
|
||||
"committed coordinator mail is canonicalized without relying on notification delivery",
|
||||
|
||||
@@ -137,7 +137,7 @@ Rules:
|
||||
|
||||
- Omit `--from` unless impersonating another terminal; Orca auto-resolves it from the current terminal.
|
||||
- A coordinator `check` returns the bound Run's oldest FIFO Delivery (up to 50 messages) and replays that exact batch until `--ack <delivery_id>`. Human output labels the Delivery as new or an unacknowledged replay; JSON includes `deliveryId`, `replayed`, and `queuedMatchingMessages`. Process every message before acknowledging; `check --ack <id> --wait` acknowledges, checks, and waits in one operation. Bare `--ack` is invalid.
|
||||
- When an outstanding Delivery blocks newer mail, `queuedMatchingMessages: true` means at least one still-unseen row matches the requested `--types`. An omitted value from an older runtime is unknown and human output labels it unavailable. The replay remains the same exact batch: acknowledge it before checking or waiting for the queued mail, and never infer that the queued rows were consumed or included; the printed acknowledgment command retains the exact `--run` scope.
|
||||
- When an outstanding Delivery blocks other mail, `queuedMatchingMessages: true` means at least one still-unseen row matches the requested `--types`. Queued mail is not necessarily newer: routing moves a message between mailboxes without renumbering it, so mail released from a settled Dispatch can queue up behind the batch carrying an older sequence. An omitted value from an older runtime is unknown and human output labels it unavailable. The replay remains the same exact batch: acknowledge it before checking or waiting for the queued mail, and never infer that the queued rows were consumed or included; the printed acknowledgment command retains the exact `--run` scope.
|
||||
- Use `--peek` and `--all` only for read-only history/debugging. Type filters decide when a waiter wakes; the returned actionable Delivery is still the oldest full batch.
|
||||
- Use `dispatch:<id>` for coordinator guidance to one supervised worker. Orca routes that stable address locally or through the connected-server relay; do not substitute a remote terminal handle.
|
||||
- Terminal handles remain appropriate for low-level pre-Dispatch messaging. Prefer `agentTerminalHandle` from the create response, fall back to `startupTerminal.handle` for older runtimes, then re-resolve with `orca terminal list --worktree ... --json` if missing or stale. Continue with the replacement handle only; never dual-send to old and new handles.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -109,7 +109,7 @@ export const ORCHESTRATION_COMMAND_SPECS: CommandSpec[] = [
|
||||
'On Windows PowerShell, quote comma-separated type filters, e.g. --types "worker_done,escalation".',
|
||||
'--format renders the returned rows as local text only; it never writes to another terminal.',
|
||||
'A bound Run replays the same Delivery until --ack; process every message before acknowledging.',
|
||||
'Human output labels new versus replayed Deliveries. JSON also reports queuedMatchingMessages when newer filter-matching mail is blocked behind the fixed batch.'
|
||||
'Human output labels new versus replayed Deliveries. JSON also reports queuedMatchingMessages when other filter-matching mail is blocked behind the fixed batch.'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import type { MessageRow, MessageType } from '../../types'
|
||||
import type { OrchestrationDb } from '../orchestration-db'
|
||||
|
||||
// Why: mailbox routing moves rows with `UPDATE ... SET to_handle` and never rewrites
|
||||
// `sequence`, so a sequence watermark cannot stand in for batch membership — mail can
|
||||
// land in the Run mailbox behind an outstanding batch carrying an older sequence.
|
||||
export function hasQueuedMatchingRunMessages(
|
||||
this: OrchestrationDb,
|
||||
runId: string,
|
||||
deliveryMessages: MessageRow[],
|
||||
wakeTypes?: MessageType[]
|
||||
matchTypes?: MessageType[]
|
||||
): boolean {
|
||||
const lastSequence = deliveryMessages.at(-1)?.sequence
|
||||
if (lastSequence === undefined) {
|
||||
return false
|
||||
const conditions: string[] = []
|
||||
const params: (string | number)[] = [runId, `run:${runId}`]
|
||||
if (matchTypes?.length) {
|
||||
conditions.push(`type IN (${matchTypes.map(() => '?').join(',')})`)
|
||||
params.push(...matchTypes)
|
||||
}
|
||||
const address = `run:${runId}`
|
||||
if (wakeTypes?.length) {
|
||||
const placeholders = wakeTypes.map(() => '?').join(',')
|
||||
return Boolean(
|
||||
this.db
|
||||
.prepare(
|
||||
`SELECT 1 FROM messages INDEXED BY idx_messages_unread_current_run_type
|
||||
WHERE run_id = ? AND to_handle = ? AND read = 0
|
||||
AND delivery_contract = 'current_delivery' AND sequence > ?
|
||||
AND type IN (${placeholders}) LIMIT 1`
|
||||
)
|
||||
.get(runId, address, lastSequence, ...wakeTypes)
|
||||
)
|
||||
const deliveredIds = deliveryMessages.map((message) => message.id)
|
||||
if (deliveredIds.length > 0) {
|
||||
conditions.push(`id NOT IN (${deliveredIds.map(() => '?').join(',')})`)
|
||||
params.push(...deliveredIds)
|
||||
}
|
||||
const index = matchTypes?.length
|
||||
? 'idx_messages_unread_current_run_type'
|
||||
: 'idx_messages_unread_current_inbox'
|
||||
return Boolean(
|
||||
this.db
|
||||
.prepare(
|
||||
`SELECT 1 FROM messages INDEXED BY idx_messages_unread_current_inbox
|
||||
`SELECT 1 FROM messages INDEXED BY ${index}
|
||||
WHERE run_id = ? AND to_handle = ? AND read = 0
|
||||
AND delivery_contract = 'current_delivery' AND sequence > ? LIMIT 1`
|
||||
AND delivery_contract = 'current_delivery'
|
||||
${conditions.map((condition) => `AND ${condition}`).join(' ')} LIMIT 1`
|
||||
)
|
||||
.get(runId, address, lastSequence)
|
||||
.get(...params)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { OrchestrationDb } from './db'
|
||||
|
||||
describe('queued-mail probe at the 50-id batch boundary', () => {
|
||||
let db: OrchestrationDb | undefined
|
||||
afterEach(() => db?.close())
|
||||
|
||||
function seed() {
|
||||
db = new OrchestrationDb(':memory:')
|
||||
const run = db.createRun({
|
||||
objective: 'boundary',
|
||||
coordinatorHandle: 'term_coord',
|
||||
coordinatorPaneKey: 'tab_coord:11111111-1111-4111-8111-111111111111'
|
||||
})
|
||||
return { d: db, run }
|
||||
}
|
||||
|
||||
it('binds a FULL 50-member batch plus filters without exceeding SQLite variable limits', () => {
|
||||
const { d, run } = seed()
|
||||
// 60 rows straight into the run mailbox -> batch is the first 50.
|
||||
for (let i = 0; i < 60; i++) {
|
||||
d.insertMessage({ from: 'w', to: `run:${run.id}`, subject: `m${i}`, runId: run.id })
|
||||
}
|
||||
const first = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
queuedTypes: ['status', 'worker_done', 'escalation', 'question', 'heartbeat']
|
||||
})!
|
||||
expect(first.messages).toHaveLength(50)
|
||||
// 50 ids + runId + address + 5 types = 57 bound params.
|
||||
expect(first.queuedMatchingMessages).toBe(true)
|
||||
})
|
||||
|
||||
it('with a FULL batch, still sees an OLDER routed-in message that is not a member', () => {
|
||||
const { d, run } = seed()
|
||||
const parked = d.insertMessage({
|
||||
from: 'w',
|
||||
to: 'dispatch:disp_full',
|
||||
subject: 'parked worker_done',
|
||||
type: 'worker_done',
|
||||
runId: run.id
|
||||
})
|
||||
for (let i = 0; i < 50; i++) {
|
||||
d.insertMessage({ from: 'w', to: `run:${run.id}`, subject: `m${i}`, runId: run.id })
|
||||
}
|
||||
const first = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
expect(first.messages).toHaveLength(50)
|
||||
expect(first.messages.map((m) => m.id)).not.toContain(parked.id)
|
||||
|
||||
d.routeUnreadDispatchMailboxToRunMailbox('disp_full', run.id)
|
||||
const replay = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
queuedTypes: ['worker_done']
|
||||
})!
|
||||
expect(replay.replayed).toBe(true)
|
||||
expect(replay.queuedMatchingMessages).toBe(true)
|
||||
|
||||
// ground truth: acking releases the older parked row first (lowest sequence)
|
||||
d.acknowledgeRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
deliveryId: first.delivery.id
|
||||
})
|
||||
expect(
|
||||
d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!.messages[0].id
|
||||
).toBe(parked.id)
|
||||
})
|
||||
|
||||
it('does not report a batch member as queued behind itself', () => {
|
||||
const { d, run } = seed()
|
||||
d.insertMessage({ from: 'w', to: `run:${run.id}`, subject: 'only', runId: run.id })
|
||||
const first = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
expect(first.messages).toHaveLength(1)
|
||||
expect(first.queuedMatchingMessages).toBe(false)
|
||||
const replay = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
expect(replay.replayed).toBe(true)
|
||||
expect(replay.queuedMatchingMessages).toBe(false)
|
||||
})
|
||||
|
||||
it('a type filter matching nothing queued still reports false', () => {
|
||||
const { d, run } = seed()
|
||||
d.insertMessage({ from: 'w', to: `run:${run.id}`, subject: 'head', runId: run.id })
|
||||
d.getOrCreateRunDelivery({ runId: run.id, consumerGeneration: run.consumer_generation })
|
||||
d.insertMessage({
|
||||
from: 'w',
|
||||
to: `run:${run.id}`,
|
||||
subject: 'beat',
|
||||
type: 'heartbeat',
|
||||
runId: run.id
|
||||
})
|
||||
const replay = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
queuedTypes: ['worker_done']
|
||||
})!
|
||||
expect(replay.queuedMatchingMessages).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -178,6 +178,114 @@ describe('OrchestrationDb Run state', () => {
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
// Why: routing rewrites to_handle but never sequence, so batch membership -- not a
|
||||
// sequence watermark -- decides what is still queued behind an outstanding Delivery.
|
||||
it('reports queued mail that reaches the Run mailbox with an older sequence', () => {
|
||||
const d = createDb()
|
||||
const run = createBoundRun(d)
|
||||
const held = d.insertMessage({
|
||||
from: 'term_peer',
|
||||
to: 'term_worker',
|
||||
subject: 'worker finished',
|
||||
type: 'worker_done',
|
||||
runId: run.id
|
||||
})
|
||||
const status = d.insertMessage({
|
||||
from: 'term_worker',
|
||||
to: `run:${run.id}`,
|
||||
subject: 'status',
|
||||
runId: run.id
|
||||
})
|
||||
expect(d.getMessageById(held.id)!.sequence).toBeLessThan(
|
||||
d.getMessageById(status.id)!.sequence
|
||||
)
|
||||
|
||||
const first = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
expect(first.messages.map((message) => message.id)).toEqual([status.id])
|
||||
|
||||
d.routeUnreadDirectMessagesToRunMailbox(run.id, 'term_worker')
|
||||
expect(d.getMessageById(held.id)!.to_handle).toBe(`run:${run.id}`)
|
||||
expect(d.getMessageById(held.id)!.read).toBe(0)
|
||||
|
||||
const replay = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
queuedTypes: ['worker_done']
|
||||
})!
|
||||
expect(replay.replayed).toBe(true)
|
||||
expect(replay.delivery.id).toBe(first.delivery.id)
|
||||
expect(replay.messages.map((message) => message.id)).toEqual([status.id])
|
||||
expect(replay.queuedMatchingMessages).toBe(true)
|
||||
|
||||
d.acknowledgeRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
deliveryId: first.delivery.id
|
||||
})
|
||||
expect(
|
||||
d
|
||||
.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
.messages.map((message) => message.id)
|
||||
).toEqual([held.id])
|
||||
})
|
||||
|
||||
// The other routing entry point: mail released when a Dispatch settles.
|
||||
it('reports queued mail released from a settled Dispatch mailbox', () => {
|
||||
const d = createDb()
|
||||
const run = createBoundRun(d)
|
||||
const parked = d.insertMessage({
|
||||
from: 'term_worker',
|
||||
to: 'dispatch:disp_1',
|
||||
subject: 'worker finished',
|
||||
type: 'worker_done',
|
||||
runId: run.id
|
||||
})
|
||||
const later = d.insertMessage({
|
||||
from: 'term_other',
|
||||
to: `run:${run.id}`,
|
||||
subject: 'later status',
|
||||
runId: run.id
|
||||
})
|
||||
expect(parked.sequence).toBeLessThan(later.sequence)
|
||||
|
||||
const first = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
expect(first.messages.map((message) => message.id)).toEqual([later.id])
|
||||
|
||||
expect(d.routeUnreadDispatchMailboxToRunMailbox('disp_1', run.id).routedCount).toBe(1)
|
||||
|
||||
const replay = d.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
queuedTypes: ['worker_done']
|
||||
})!
|
||||
expect(replay.replayed).toBe(true)
|
||||
expect(replay.messages.map((message) => message.id)).toEqual([later.id])
|
||||
expect(replay.queuedMatchingMessages).toBe(true)
|
||||
|
||||
d.acknowledgeRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation,
|
||||
deliveryId: first.delivery.id
|
||||
})
|
||||
expect(
|
||||
d
|
||||
.getOrCreateRunDelivery({
|
||||
runId: run.id,
|
||||
consumerGeneration: run.consumer_generation
|
||||
})!
|
||||
.messages.map((message) => message.id)
|
||||
).toEqual([parked.id])
|
||||
})
|
||||
|
||||
it('fences an outstanding batch when the Run consumer changes', () => {
|
||||
const d = createDb()
|
||||
const run = createBoundRun(d)
|
||||
|
||||
@@ -66,7 +66,7 @@ describe('formatOrchestrationCheckText', () => {
|
||||
)
|
||||
|
||||
expect(output).toContain('Delivery delivery_1 [replay: unacknowledged]')
|
||||
expect(output).toContain('Newer messages matching this check are queued behind this Delivery.')
|
||||
expect(output).toContain('Other messages matching this check are queued behind this Delivery.')
|
||||
expect(output).toContain('orchestration check --run run_1 --ack delivery_1')
|
||||
})
|
||||
|
||||
@@ -100,4 +100,40 @@ describe('formatOrchestrationCheckText', () => {
|
||||
'Queued matching-message status is unavailable from this runtime.'
|
||||
)
|
||||
})
|
||||
|
||||
// Why: the SSH path casts the payload without validating, so an off-contract value
|
||||
// must not read as a positively-established "nothing is queued".
|
||||
it('treats an off-contract queued value as unavailable rather than silence', () => {
|
||||
const output = formatOrchestrationCheckText(
|
||||
{
|
||||
count: 1,
|
||||
deliveryId: 'delivery_bad',
|
||||
replayed: true,
|
||||
queuedMatchingMessages: null as unknown as boolean,
|
||||
messages: [],
|
||||
formatted: 'formatted message'
|
||||
},
|
||||
'term_coord'
|
||||
)
|
||||
|
||||
expect(output).toContain('Queued matching-message status is unavailable from this runtime.')
|
||||
expect(output).not.toContain('Other messages matching this check are queued')
|
||||
})
|
||||
|
||||
it('stays silent about queued mail only when the runtime observed none', () => {
|
||||
const output = formatOrchestrationCheckText(
|
||||
{
|
||||
count: 1,
|
||||
deliveryId: 'delivery_clear',
|
||||
replayed: true,
|
||||
queuedMatchingMessages: false,
|
||||
messages: [],
|
||||
formatted: 'formatted message'
|
||||
},
|
||||
'term_coord'
|
||||
)
|
||||
|
||||
expect(output).not.toContain('Queued matching-message status is unavailable')
|
||||
expect(output).not.toContain('Other messages matching this check are queued')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -128,12 +128,13 @@ function formatDeliveryAction(result: OrchestrationCheckOutput): string {
|
||||
if (!result.deliveryId) {
|
||||
return ''
|
||||
}
|
||||
// Why: only an observed `false` may render as silence; every other value is unestablished.
|
||||
const queued =
|
||||
result.queuedMatchingMessages === true
|
||||
? '\nNewer messages matching this check are queued behind this Delivery.'
|
||||
: result.queuedMatchingMessages === undefined
|
||||
? '\nQueued matching-message status is unavailable from this runtime.'
|
||||
: ''
|
||||
? '\nOther messages matching this check are queued behind this Delivery.'
|
||||
: result.queuedMatchingMessages === false
|
||||
? ''
|
||||
: '\nQueued matching-message status is unavailable from this runtime.'
|
||||
const runFlag = result.runId ? ` --run ${result.runId}` : ''
|
||||
return `${queued}\nAfter processing every message, acknowledge this exact batch with \`orca orchestration check${runFlag} --ack ${result.deliveryId}\`.\n`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user