mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-10-21 05:06:37 +00:00
Aggregate compaction fragments before reactive SDK reduction while advancing revision fences immediately and preserving native terminal and snapshot authority. Keep task-tool shells keyed across payload updates and rescan bounded membership so removals and replacements cannot leave phantom tools. Isolate SSE callbacks and decode/dispatch diagnostics. Subscriber-local teardown no longer destroys the healthy shared native client. Install HTTP cancellation before preflight and fence late continuations without replaying or interrupting already-admitted mutations. Preserve ownership and environment admission checks. Move HTTP password derivation to async scrypt with serialized password changes and login-authority fencing. Yield cooperatively in both structural-index phases without changing snapshot/digest protocols; an individual SQLite step stays sync. Add isolated red/green regressions, bounded browser/native qualification scripts, independent reviews, source fingerprints and performance evidence for issue #824. Synchronize the Git focus assertion with its async contract and make the opt-in trace self-contained instead of serializing a tsx helper into the browser. Validation includes 793 passing server tests and 6 skips after replay, UI/server/ Electron typechecks, UI/server/plugin builds, and private Windows native 2.0.21 fixtures. Renderer fixture median main-thread cost is 324.57 to 16.94 ms. The latest full browser run remains 358 pass, 1 fail, 1 skip: its trace failure was subsequently reproduced and corrected with a minimal Chromium check, but the full suite has not been rerun. Store assertions use force-exit; natural cleanup and Linux Electron to Windows LAN/HTTP with 2.0.19 remain unqualified. Publish as a draft for review, not a universal resolution or issue-closing fix. Refs #824.
93 lines
5.2 KiB
JavaScript
93 lines
5.2 KiB
JavaScript
// Called only by the isolated location fixture. Native events and the shared
|
|
// SDK subscription are real; one recipient's ownership I/O is held deliberately.
|
|
import assert from "node:assert/strict"
|
|
import { setTimeout as delay } from "node:timers/promises"
|
|
import { tsImport } from "tsx/esm/api"
|
|
|
|
export async function testNativeEventRelay({ client, location, service }) {
|
|
const { EventBus } = await tsImport("../packages/server/src/events/bus.ts", import.meta.url)
|
|
const { InstanceEventBridge } = await tsImport("../packages/server/src/workspaces/instance-events.ts", import.meta.url)
|
|
const controller = new AbortController()
|
|
let release
|
|
const slow = new Promise(resolve => { release = resolve })
|
|
const records = ["fast", "slow"].map(id => ({ id, path: location.directory }))
|
|
const owns = async (id, directory) => directory === location.directory && (id === "slow" ? slow : true)
|
|
const bus = new EventBus(), routed = [], native = [], sessions = []
|
|
let connected = false, nativeConnected = false
|
|
const manager = {
|
|
list: () => records,
|
|
ownsDirectory: owns,
|
|
ownsLocation: (id, ref) => owns(id, ref.directory),
|
|
getSharedServiceClient: () => service ? service.client() : Promise.resolve(client),
|
|
subscribeToSharedService: signal => service ? service.subscribe({ signal }) : client.event.subscribe({ signal }),
|
|
invalidateWorktrees() {},
|
|
}
|
|
bus.on("instance.eventStatus", event => { if (event.status === "connected") connected = true })
|
|
bus.on("instance.event", event => routed.push(event))
|
|
const bridge = new InstanceEventBridge({ workspaceManager: manager, eventBus: bus, logger: { debug() {}, warn() {} } })
|
|
const subscriber = (async () => {
|
|
for await (const event of client.event.subscribe({ signal: controller.signal })) {
|
|
if (event.type === "server.connected") nativeConnected = true
|
|
native.push(event)
|
|
}
|
|
})()
|
|
// Keep the async subscriber's rejection handled even if an earlier assertion fails.
|
|
void subscriber.catch(() => {})
|
|
const until = async predicate => {
|
|
const deadline = Date.now() + 10_000
|
|
while (!predicate()) {
|
|
assert.ok(Date.now() < deadline, "native relay stalled behind another recipient")
|
|
await delay(10)
|
|
}
|
|
}
|
|
try {
|
|
bus.publish({ type: "workspace.started", workspace: records[0] })
|
|
await until(() => connected && nativeConnected)
|
|
if (service) {
|
|
for (const mode of ["abort", "return", "throw"]) {
|
|
const local = new AbortController()
|
|
const wrapped = (await service.subscribe({ signal: local.signal }))[Symbol.asyncIterator]()
|
|
try {
|
|
assert.equal((await wrapped.next()).value.type, "server.connected")
|
|
if (mode === "abort") {
|
|
const next = wrapped.next()
|
|
local.abort()
|
|
assert.equal((await next).done, true)
|
|
} else if (mode === "throw") {
|
|
const failure = new Error("isolated subscriber failure")
|
|
await assert.rejects(wrapped.throw(failure), error => error === failure)
|
|
} else await wrapped.return()
|
|
await client.server.info()
|
|
assert.equal((await service.acquire()).client, client, `${mode} must retain the shared native client`)
|
|
} finally { local.abort(); await wrapped.return() }
|
|
}
|
|
console.log("PASS: native service subscriber abort/return/throw retain the healthy shared connection")
|
|
}
|
|
const session = await client.session.create({ location: { directory: location.directory } })
|
|
sessions.push(session.id)
|
|
const titles = Array.from({ length: 8 }, (_, index) => `relay-fixture-${index}`)
|
|
for (const title of titles) await client.session.update({ sessionID: session.id, title })
|
|
const renames = events => events.filter(event => event.type === "session.renamed" && event.data.sessionID === session.id).map(event => event.data.title)
|
|
await until(() => renames(native).length === titles.length && renames(routed.filter(x => x.instanceId === "fast").map(x => x.event)).length === titles.length)
|
|
assert.deepEqual(renames(native), titles, "another subscriber on the same SDK client must keep receiving")
|
|
assert.deepEqual(renames(routed.filter(x => x.instanceId === "fast").map(x => x.event)), titles)
|
|
assert.equal(renames(routed.filter(x => x.instanceId === "slow").map(x => x.event)).length, 0)
|
|
release(true)
|
|
await until(() => renames(routed.filter(x => x.instanceId === "slow").map(x => x.event)).length === titles.length)
|
|
assert.deepEqual(renames(routed.filter(x => x.instanceId === "slow").map(x => x.event)), titles)
|
|
console.log("PASS: native relay isolates slow recipients, preserves session ordering and does not block another shared SDK subscriber")
|
|
if (service) {
|
|
bridge.shutdown()
|
|
await client.session.update({ sessionID: session.id, title: "after-relay-shutdown" })
|
|
await until(() => renames(native).includes("after-relay-shutdown"))
|
|
assert.equal((await service.acquire()).client, client)
|
|
console.log("PASS: relay shutdown leaves another native subscriber and shared client requests usable")
|
|
}
|
|
} finally {
|
|
release(false)
|
|
bridge.shutdown()
|
|
controller.abort()
|
|
await subscriber.catch(() => {})
|
|
await Promise.allSettled(sessions.map(sessionID => client.session.remove({ sessionID })))
|
|
}
|
|
}
|