mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
* fix(remote): stop a disclosure list latching the mirror completeness gate `hostScope.omittedHostIds` was doing two jobs with opposite requirements. As disclosure it must over-name: `omitted-host-scope-selectors.ts` deliberately keeps ids for servers that are no longer paired so a caller can still see the gap, and `docs/reference/ssh-execution-boundary.md` requires a listing to name what it did not cover. As a completeness gate it must name only coverage that was owed and not delivered, or it latches. It latched. `workspaceSessionsByHostId` keeps a partition for every runtime a machine has ever paired with and nothing prunes it, and a mirrored `remote:` row names its peer too — so any client that has ever paired outward publishes a permanently non-empty `omittedHostIds`. `probeHostLiveTerminals` read that as `unverifiable`, `markHostSessionMirrorHydrated` never fired, and panes parked on `parkUntilHostSessionMirrorHydrates` never drained. `hostScopeCensusIsComplete` gives the gate its own answer and leaves the disclosure list alone. A `runtime:` host is never owed coverage by the runtime answering: a paired runtime is a peer with its own control plane reached with `--environment`, and there is no paired-runtime PTY provider for this runtime to have queried. Two other branches stay load-bearing — an absent scope is a host too old to claim one, and a listing that covered no host proves nothing. No wire change: the host publishes byte-identical content and only the client's reading moves, so this reaches the reporter by updating their client alone rather than waiting for their remote. That also avoids a new field's fallback rule, where "absent means complete" would recreate the bug with the polarity flipped. `queried-host-kinds.test.ts` pins the invariant the predicate rests on at its source, because the consolidation moving the SSH path onto orcad is the change most likely to introduce a runtime-backed PTY provider and quietly invalidate it. Fixes #18595 * test(remote): pin the orphan-recovery host-scope gate and narrow the invariant claim The readiness review found the second gate unpinned: reverting `web-session-terminal-orphan-recovery-inventory.ts` alone to the pre-PR expression left the whole renderer suite green, because every existing fixture passes `omittedHostIds: []`. The commit claimed two gates and proved one. Four cases now drive `resolveTerminalOrphanInventory` through a non-empty scope. Reverting that gate alone fails the peer-runtime case. Note the absent-scope case deletes the key rather than passing `undefined`, because `listResult` substitutes its default for `undefined` — routing through the fixture there silently tests the default instead. `queried-host-kinds.test.ts` also claimed more than it caught: a runtime-backed transport registered under an SSH connection id reports as `ssh:` and passes, which is the shape the orcad consolidation is expected to take. It pins the spelling this function emits, which is what the gate keys on, and now says so. * fix(remote): require a legible covered host before believing a census CodeRabbit found a real asymmetry: the predicate refused an omitted host id it could not parse, but accepted an unparseable *covered* id as proof of coverage. `isTerminalListResult` validates only that `hostIds` is an array, so `{hostIds: ['runtime:'], omittedHostIds: ['runtime:env-7']}` was `unverifiable` before this PR and would have become `complete` after it. Taken as "at least one legible covered host" rather than the suggested "every id parses". A host that later gains a kind this client cannot parse would otherwise report an incomplete census forever — which is this bug in a new coat, and the failure mode the predicate exists to prevent. The check exposed four tests publishing `hostIds: ['remote-runtime']`, a bare environment id that `parseExecutionHostId` rejects. No host emits that: a runtime answering `terminal.list` names the execution hosts it covered, which is `local` — verified against a live paired runtime. Those fixtures are corrected to the shape the wire actually carries, which is why the assertions move.
82 lines
3.1 KiB
TypeScript
82 lines
3.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { hostScopeCensusIsComplete } from './runtime-listing-host-scope'
|
|
|
|
/**
|
|
* The gate and the disclosure list answer different questions off the same field. These pin the
|
|
* cases where they disagree — which is every case that mattered in #18595.
|
|
*/
|
|
describe('hostScopeCensusIsComplete', () => {
|
|
it('reads a peer runtime as disclosure, not as coverage this host owed', () => {
|
|
expect(
|
|
hostScopeCensusIsComplete({ hostIds: ['local'], omittedHostIds: ['runtime:env-7'] })
|
|
).toBe(true)
|
|
})
|
|
|
|
it('still reads an SSH host as a gap, because this runtime does query those', () => {
|
|
expect(hostScopeCensusIsComplete({ hostIds: ['local'], omittedHostIds: ['ssh:box-1'] })).toBe(
|
|
false
|
|
)
|
|
})
|
|
|
|
it('reads a mixed omission as incomplete on the strength of the SSH host alone', () => {
|
|
expect(
|
|
hostScopeCensusIsComplete({
|
|
hostIds: ['local'],
|
|
omittedHostIds: ['runtime:env-7', 'ssh:box-1']
|
|
})
|
|
).toBe(false)
|
|
})
|
|
|
|
it('calls a clean census complete', () => {
|
|
expect(hostScopeCensusIsComplete({ hostIds: ['local', 'ssh:box-1'], omittedHostIds: [] })).toBe(
|
|
true
|
|
)
|
|
})
|
|
|
|
// Defence in depth: `listKnownExecutionHostIds` always seeds `local`, so a real scope that
|
|
// covered nothing also omits `local` and is refused by the runtime-only rule anyway. This
|
|
// branch is what stops a scope that answered for no host from ever reading complete if that
|
|
// ever stops holding.
|
|
it('refuses a listing that covered no host at all', () => {
|
|
expect(hostScopeCensusIsComplete({ hostIds: [], omittedHostIds: ['runtime:env-7'] })).toBe(
|
|
false
|
|
)
|
|
expect(hostScopeCensusIsComplete({ hostIds: [], omittedHostIds: [] })).toBe(false)
|
|
})
|
|
|
|
// Why: `hostScope` shipped in v1.4.187. An older host cannot say what it covered, and absence
|
|
// of the claim is never the claim — this must stay the first branch.
|
|
it('refuses a host too old to publish a scope', () => {
|
|
expect(hostScopeCensusIsComplete(undefined)).toBe(false)
|
|
})
|
|
|
|
// Why: without this the runtime-only rule trusts a coverage claim it cannot read — the shape
|
|
// `{hostIds: ['runtime:'], omittedHostIds: ['runtime:env-7']}` was `unverifiable` before the
|
|
// gate changed and must not become `complete` on the strength of an unparseable id.
|
|
it('refuses a coverage claim with no legible host in it', () => {
|
|
expect(
|
|
hostScopeCensusIsComplete({
|
|
hostIds: ['runtime:' as never],
|
|
omittedHostIds: ['runtime:env-7']
|
|
})
|
|
).toBe(false)
|
|
})
|
|
|
|
// Why "at least one legible" and not "all legible": a host that later gains a kind this client
|
|
// cannot parse must not report an incomplete census forever — that is this bug in a new coat.
|
|
it('accepts a coverage claim carrying one legible host beside an unreadable one', () => {
|
|
expect(
|
|
hostScopeCensusIsComplete({ hostIds: ['local', 'newkind:x' as never], omittedHostIds: [] })
|
|
).toBe(true)
|
|
})
|
|
|
|
it('refuses an unparseable host id rather than discounting it', () => {
|
|
expect(
|
|
hostScopeCensusIsComplete({
|
|
hostIds: ['local'],
|
|
omittedHostIds: ['runtime:' as never]
|
|
})
|
|
).toBe(false)
|
|
})
|
|
})
|