Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "headlesscode",
"version": "1.9.7",
"version": "1.9.8",
"description": "Coding-agent harness with CLI and HTTP interfaces, parallel Git worktree orchestration, and bounded recursive self-improvement (RSI).",
"license": "Apache-2.0",
"repository": {
Expand Down
58 changes: 58 additions & 0 deletions src/rsi/__tests__/operations-monitor.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import assert from "node:assert/strict"
import { EventEmitter } from "node:events"
import { syncBuiltinESMExports } from "node:module"
import fsPromises from "node:fs/promises"
import test from "node:test"
import { spawn, type ChildProcess } from "node:child_process"
import * as fs from "node:fs/promises"
Expand Down Expand Up @@ -204,6 +206,62 @@ test("monitor writes an atomic heartbeat and refuses a concurrent process lock",
await fs.rm(stateDirectory, { recursive: true, force: true })
})

test("monitor lock files project only process identity and scope fields", async () => {
const stateDirectory = await fs.mkdtemp(path.join(os.tmpdir(), "headlesscode-rsi-monitor-lock-projection-"))
await fs.chmod(stateDirectory, 0o700)
const fixture = fixturePool()
const sentinel = "postgres://monitor-lock-secret:sentinel-password@127.0.0.1/private?token=sentinel-token"
Object.assign(fixture.pool, { connectionString: sentinel, privatePoolOption: "must-not-serialize" })
const injectedOptions = Object.assign({
...statusOptions, pool: fixture.pool, stateDirectory, pollMs: 1000, stallMs: 2000, maxRuntimeMs: 10_000,
}, { connectionString: sentinel, additionalRuntimeOption: "must-not-serialize" }) as RsiMonitorOptions
const originalOpen = fsPromises.open
const captured: Record<string, string> = {}
const patchedOpen: typeof fsPromises.open = async (...args) => {
const handle = await originalOpen(...args)
const filename = String(args[0])
if (!filename.endsWith("/monitor.lock") && !filename.endsWith("/monitor.lock.bootstrap")) return handle
return new Proxy(handle, {
get(target, property) {
if (property === "writeFile") return async (...writeArgs: Parameters<typeof handle.writeFile>) => {
await Reflect.apply(handle.writeFile.bind(handle), handle, writeArgs)
captured[path.basename(filename)] = await fs.readFile(filename, "utf8")
return undefined
}
const value = Reflect.get(target, property, target)
return typeof value === "function" ? value.bind(target) : value
},
})
}
const controller = new AbortController()
try {
fsPromises.open = patchedOpen
syncBuiltinESMExports()
const exitCode = await runRsiMonitor({ ...injectedOptions, signal: controller.signal, stdout: () => controller.abort() })
assert.equal(exitCode, 0)
const persistent = JSON.parse(captured["monitor.lock"] ?? "null") as Record<string, unknown> | null
const bootstrap = JSON.parse(captured["monitor.lock.bootstrap"] ?? "null") as Record<string, unknown> | null
assert.ok(persistent, "read the persistent lock bytes after the file write")
assert.ok(bootstrap, "capture the bootstrap lock bytes during its write")
const allowedPersistent = ["schemaVersion", "pid", "startTicks", "bootId", "queueName", "campaignId", "startedAt"]
const allowedBootstrap = ["schemaVersion", "pid", "startTicks", "bootId", "queueName", "campaignId", "nonce"]
assert.deepEqual(Object.keys(persistent).sort(), allowedPersistent.sort())
assert.deepEqual(Object.keys(bootstrap).sort(), allowedBootstrap.sort())
assert.equal(persistent.queueName, statusOptions.queueName)
assert.equal(persistent.campaignId, statusOptions.campaignId)
assert.equal(bootstrap.queueName, statusOptions.queueName)
assert.equal(bootstrap.campaignId, statusOptions.campaignId)
assert.ok(!captured["monitor.lock"].includes(sentinel))
assert.ok(!captured["monitor.lock.bootstrap"].includes(sentinel))
assert.ok(!captured["monitor.lock"].includes("must-not-serialize"))
assert.ok(!captured["monitor.lock.bootstrap"].includes("must-not-serialize"))
} finally {
fsPromises.open = originalOpen
syncBuiltinESMExports()
await fs.rm(stateDirectory, { recursive: true, force: true })
}
})

test("monitor rejects a pre-existing lock and malformed history instead of taking ownership", async () => {
const stateDirectory = await fs.mkdtemp(path.join(os.tmpdir(), "headlesscode-rsi-monitor-lock-"))
await fs.chmod(stateDirectory, 0o700)
Expand Down
148 changes: 134 additions & 14 deletions src/rsi/benchmark/__tests__/runner.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import assert from "node:assert/strict"
import { execFileSync } from "node:child_process"
import * as fs from "node:fs/promises"
import * as os from "node:os"
import * as path from "node:path"
import { FileRsiArtifactStore } from "../../artifact-store.js"
import { freezeBenchmarkProtocol, loadBenchmark, runBenchmark } from "../runner.js"
Expand All @@ -11,14 +10,116 @@ import { OpenShellBenchmarkAgent } from "../openshell-agent.js"

const fixtureRoot = path.resolve("fixtures/rsi-benchmark/smoke")
const loaded = await loadBenchmark(fixtureRoot)
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "rsi-benchmark-runner-test-"))
const scratchRoot = path.resolve(".headlesscode/scratch")
await fs.mkdir(scratchRoot, { recursive: true })
const tempRoot = await fs.mkdtemp(path.join(scratchRoot, "rsi-benchmark-runner-test-"))
const outputRoot = path.join(tempRoot, "results")
const harnessCommit = "a".repeat(40)
let agentCalls = 0
let fakeCodingGuestActive = false
let lastCodingGuestWorkspace = ""
let activeSplit: "development" | "confirmation" = "development"
const confirmationTexts = new Set(loaded.manifest.tasks.filter((task) => task.split === "confirmation").map((task) => task.task))
const ownedFakeAgentFixtures = new Set<string>()
const MAX_FIXTURE_REMOVE_ATTEMPTS = 5
const fixtureGitEnv = {
...process.env,
GIT_CONFIG_COUNT: "3",
GIT_CONFIG_KEY_0: "gc.auto",
GIT_CONFIG_VALUE_0: "0",
GIT_CONFIG_KEY_1: "maintenance.auto",
GIT_CONFIG_VALUE_1: "false",
GIT_CONFIG_KEY_2: "maintenance.autoDetach",
GIT_CONFIG_VALUE_2: "false",
}
const fixtureGitLocalConfigEnv = { ...fixtureGitEnv, GIT_CONFIG_COUNT: "0" }

async function createOwnedFakeAgentFixture(): Promise<string> {
const parent = path.join(tempRoot, "fake-agent-fixtures")
await fs.mkdir(parent, { recursive: true })
const candidate = await fs.mkdtemp(path.join(parent, "rsi-benchmark-fake-agent-"))
ownedFakeAgentFixtures.add(candidate)
return candidate
}

async function removeOwnedFakeAgentFixture(
candidate: string,
options: {
remove?: (target: string) => Promise<void>
wait?: (milliseconds: number) => Promise<void>
} = {},
): Promise<void> {
if (!ownedFakeAgentFixtures.has(candidate)) throw new Error("refusing to remove an unowned fake-agent fixture")
const remove = options.remove ?? (async (target: string) => fs.rm(target, { recursive: true, force: true }))
const wait = options.wait ?? ((milliseconds: number) => new Promise<void>((resolve) => setTimeout(resolve, milliseconds)))
let lastError: NodeJS.ErrnoException | undefined
let attempts = 0
for (let attempt = 1; attempt <= MAX_FIXTURE_REMOVE_ATTEMPTS; attempt += 1) {
attempts = attempt
try {
await remove(candidate)
ownedFakeAgentFixtures.delete(candidate)
return
} catch (error) {
lastError = error as NodeJS.ErrnoException
if (lastError.code !== "ENOTEMPTY" || attempt === MAX_FIXTURE_REMOVE_ATTEMPTS) break
await wait(attempt * 20)
}
}
const failure = new Error(`could not remove owned fake-agent fixture after ${attempts} attempt${attempts === 1 ? "" : "s"}`, { cause: lastError }) as NodeJS.ErrnoException
failure.code = lastError?.code
throw failure
}

async function removeRemainingOwnedFakeAgentFixtures(): Promise<void> {
for (const fixture of ownedFakeAgentFixtures) await removeOwnedFakeAgentFixture(fixture)
}

async function assertFixtureCleanupContract(): Promise<void> {
const transient = await createOwnedFakeAgentFixture()
let attempts = 0
await removeOwnedFakeAgentFixture(transient, {
remove: async () => {
attempts += 1
if (attempts < 3) throw Object.assign(new Error("simulated concurrent Git metadata write"), { code: "ENOTEMPTY" })
await fs.rm(transient, { recursive: true, force: true })
},
wait: async () => undefined,
})
assert.equal(attempts, 3, "owned fixture cleanup retries transient ENOTEMPTY and then succeeds")
assert.equal(ownedFakeAgentFixtures.has(transient), false, "successful cleanup releases fixture ownership")

const persistent = await createOwnedFakeAgentFixture()
attempts = 0
await assert.rejects(removeOwnedFakeAgentFixture(persistent, {
remove: async () => {
attempts += 1
throw Object.assign(new Error("simulated persistent Git metadata write"), { code: "ENOTEMPTY" })
},
wait: async () => undefined,
}), (error: NodeJS.ErrnoException) => error.code === "ENOTEMPTY")
assert.equal(attempts, MAX_FIXTURE_REMOVE_ATTEMPTS, "persistent ENOTEMPTY stops at the configured retry bound")
assert.equal(ownedFakeAgentFixtures.has(persistent), true, "failed cleanup retains ownership for final teardown")
await removeOwnedFakeAgentFixture(persistent)

const unexpected = await createOwnedFakeAgentFixture()
attempts = 0
await assert.rejects(removeOwnedFakeAgentFixture(unexpected, {
remove: async () => {
attempts += 1
throw Object.assign(new Error("simulated unexpected cleanup failure"), { code: "EACCES" })
},
wait: async () => undefined,
}), (error: NodeJS.ErrnoException) => error.code === "EACCES")
assert.equal(attempts, 1, "non-ENOTEMPTY cleanup errors are not retried")
await removeOwnedFakeAgentFixture(unexpected)

let removedUnowned = false
await assert.rejects(removeOwnedFakeAgentFixture(path.join(tempRoot, "not-owned"), {
remove: async () => { removedUnowned = true },
}), /unowned fake-agent fixture/)
assert.equal(removedUnowned, false, "unowned paths are never passed to the remover")
}

const agent: BenchmarkAgent = {
provider: "fake-model",
Expand All @@ -36,24 +137,38 @@ const agent: BenchmarkAgent = {
}
const task = requestTask
const oracle = JSON.parse(await fs.readFile(path.join(fixtureRoot, task.knownGoodPath!), "utf8")) as { files: Record<string, string> }
const candidate = await fs.mkdtemp(path.join(os.tmpdir(), "rsi-benchmark-fake-agent-"))
await fs.rm(candidate, { recursive: true, force: true })
execFileSync("git", ["clone", "--quiet", "--no-hardlinks", "--shared", request.workspace, candidate], { stdio: ["ignore", "pipe", "pipe"] })
const candidate = await createOwnedFakeAgentFixture()
let operationError: unknown
try {
execFileSync("git", ["config", "user.name", "RSI Benchmark Test"], { cwd: candidate })
execFileSync("git", ["config", "user.email", "rsi-benchmark-test@invalid.example"], { cwd: candidate })
execFileSync("git", ["clone", "--quiet", "--no-hardlinks", "--shared", "--config", "gc.auto=0", "--config", "maintenance.auto=false", request.workspace, candidate], { stdio: ["ignore", "pipe", "pipe"], env: fixtureGitEnv })
assert.equal(execFileSync("git", ["config", "--local", "--get", "gc.auto"], { cwd: candidate, encoding: "utf8", env: fixtureGitLocalConfigEnv }).trim(), "0")
assert.equal(execFileSync("git", ["config", "--local", "--get", "maintenance.auto"], { cwd: candidate, encoding: "utf8", env: fixtureGitLocalConfigEnv }).trim(), "false")
execFileSync("git", ["config", "gc.auto", "0"], { cwd: candidate, env: fixtureGitEnv })
execFileSync("git", ["config", "maintenance.auto", "false"], { cwd: candidate, env: fixtureGitEnv })
execFileSync("git", ["config", "maintenance.autoDetach", "false"], { cwd: candidate, env: fixtureGitEnv })
execFileSync("git", ["config", "user.name", "RSI Benchmark Test"], { cwd: candidate, env: fixtureGitEnv })
execFileSync("git", ["config", "user.email", "rsi-benchmark-test@invalid.example"], { cwd: candidate, env: fixtureGitEnv })
for (const [relative, content] of Object.entries(oracle.files)) {
const target = path.join(candidate, relative)
await fs.mkdir(path.dirname(target), { recursive: true })
await fs.writeFile(target, content)
}
execFileSync("git", ["add", "--all"], { cwd: candidate, stdio: "ignore" })
execFileSync("git", ["-c", "core.hooksPath=/dev/null", "commit", "--quiet", "-m", "fake model patch"], { cwd: candidate, stdio: "ignore" })
const base = execFileSync("git", ["rev-parse", "HEAD~1"], { cwd: candidate, encoding: "utf8" }).trim()
const patch = execFileSync("git", ["diff", "--binary", "--no-ext-diff", `${base}...HEAD`], { cwd: candidate, encoding: "buffer" })
execFileSync("git", ["add", "--all"], { cwd: candidate, stdio: "ignore", env: fixtureGitEnv })
execFileSync("git", ["-c", "core.hooksPath=/dev/null", "commit", "--quiet", "-m", "fake model patch"], { cwd: candidate, stdio: "ignore", env: fixtureGitEnv })
const base = execFileSync("git", ["rev-parse", "HEAD~1"], { cwd: candidate, encoding: "utf8", env: fixtureGitEnv }).trim()
const patch = execFileSync("git", ["diff", "--binary", "--no-ext-diff", `${base}...HEAD`], { cwd: candidate, encoding: "buffer", env: fixtureGitEnv })
return { validity: "valid", patch, stdout: "fake model completed", stderr: "", calls: 1, tokens: 22, wallTimeMs: 25, stopReason: "fake-complete" }
} catch (error) {
operationError = error
throw error
} finally {
await fs.rm(candidate, { recursive: true, force: true })
try {
await removeOwnedFakeAgentFixture(candidate)
} catch (cleanupError) {
fakeCodingGuestActive = false
if (operationError !== undefined) throw new AggregateError([operationError, cleanupError], "fake-agent operation and fixture cleanup both failed")
throw cleanupError
}
fakeCodingGuestActive = false
}
},
Expand All @@ -73,6 +188,7 @@ const verifier: BenchmarkVerifier = {
}

try {
await assertFixtureCleanupContract()
assert.equal(loaded.manifest.tasks.length, 32)
assert.equal(loaded.manifest.tasks.filter((task) => task.split === "development").length, 16)
assert.equal(loaded.manifest.tasks.filter((task) => task.split === "confirmation").length, 16)
Expand Down Expand Up @@ -195,7 +311,11 @@ try {
}), /does not match requested commit/)
assert.equal(imageIdentityReads, 1, "mismatched identity must come from the deterministic resolver without Docker")
assert.deepEqual(await fs.readdir(path.join(identityRoot, "attempts")).catch(() => []), [], "wrong image identity must abort without a scored attempt")
console.log("All 18 RSI benchmark runner integration assertions passed")
console.log("All RSI benchmark runner integration assertions passed")
} finally {
await fs.rm(tempRoot, { recursive: true, force: true })
try {
await removeRemainingOwnedFakeAgentFixtures()
} finally {
await fs.rm(tempRoot, { recursive: true, force: true })
}
}
4 changes: 2 additions & 2 deletions src/rsi/operations-monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,8 @@ async function acquireMonitorLock(directory: string, scope: { queueName: string;
const lockPath = path.join(directory, "monitor.lock")
const bootstrapPath = path.join(directory, "monitor.lock.bootstrap")
const identity = await monitorProcessIdentity()
const contents = `${JSON.stringify({ schemaVersion: 1, ...identity, ...scope, startedAt: new Date().toISOString() })}\n`
const bootstrapContents = `${JSON.stringify({ schemaVersion: 1, ...identity, ...scope, nonce: randomUUID() })}\n`
const contents = `${JSON.stringify({ schemaVersion: 1, pid: identity.pid, startTicks: identity.startTicks, bootId: identity.bootId, queueName: scope.queueName, campaignId: scope.campaignId, startedAt: new Date().toISOString() })}\n`
const bootstrapContents = `${JSON.stringify({ schemaVersion: 1, pid: identity.pid, startTicks: identity.startTicks, bootId: identity.bootId, queueName: scope.queueName, campaignId: scope.campaignId, nonce: randomUUID() })}\n`
let bootstrap
try { bootstrap = await fs.open(bootstrapPath, "wx", 0o600) }
catch (error) {
Expand Down
Loading