docs: document subagent registry persistence tests

This commit is contained in:
Peter Steinberger
2026-06-04 15:55:31 -04:00
parent ec4a871f91
commit e7de27f8b0
6 changed files with 26 additions and 0 deletions
@@ -1,3 +1,5 @@
// Subagent registry persistence tests cover JSON registry restore, child
// session timing writes, and restart cleanup behavior.
import fsSync from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
@@ -123,6 +125,8 @@ describe("subagent registry persistence", () => {
persisted: Record<string, unknown>,
opts?: { seedChildSessions?: boolean },
) => {
// Each persisted-registry fixture gets its own state dir so session stores
// and registry files are tested through the same paths production resolves.
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-subagent-"));
process.env.OPENCLAW_STATE_DIR = tempStateDir;
const registryPath = path.join(tempStateDir, "subagents", "runs.json");
@@ -187,6 +191,8 @@ describe("subagent registry persistence", () => {
};
const fastPersistSubagentRunsToDisk = (runs: Map<string, SubagentRunRecord>) => {
// Most tests assert restore semantics, not async writer behavior, so this
// synchronous writer keeps registry state immediately observable.
const registryPath = tempStateDir
? path.join(tempStateDir, "subagents", "runs.json")
: resolveSubagentRegistryPath();
@@ -1,3 +1,5 @@
// Subagent registry steer-restart tests cover replacing child runs after steer
// commands while preserving lifecycle hooks and completion delivery.
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { ContextEngine } from "../context-engine/types.js";
@@ -195,6 +197,8 @@ describe("subagent registry steer restarts", () => {
};
const createDeferredAnnounceResolver = (): ((value: boolean) => void) => {
// Deferred announce lets tests observe registry state while delivery is
// still in flight, then release the promise deterministically.
let resolveAnnounce: ((value: boolean) => void) | undefined;
announceSpy.mockImplementationOnce(
() =>
@@ -1,3 +1,5 @@
// Subagent registry SQLite store tests cover whole-snapshot persistence and
// one-time import from the legacy JSON registry file.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -107,6 +109,8 @@ describe("subagent registry sqlite store", () => {
});
it("imports the legacy json registry when sqlite has no runs", async () => {
// Import deletes the JSON source after the first successful migration so
// later loads treat SQLite as canonical state.
const legacyRun = createRun({
runId: "legacy-run",
childSessionKey: "agent:main:subagent:legacy",
@@ -1,3 +1,5 @@
// Subagent registry test helpers expose the in-memory run map for small unit
// tests that do not need persistence, lifecycle hooks, or gateway mocks.
import { subagentRuns } from "./subagent-registry-memory.js";
import type { SubagentRunRecord } from "./subagent-registry.types.js";
+4
View File
@@ -1,3 +1,5 @@
// Subagent run liveness tests cover stale-unended detection and child-link
// retention windows for registry list/read paths.
import { describe, expect, it, vi } from "vitest";
import {
isLiveUnendedSubagentRun,
@@ -54,6 +56,8 @@ describe("subagent run liveness", () => {
});
it("ignores non-real fixture timestamps as unknown instead of stale", () => {
// Small fixture timestamps appear in tests and old synthetic records; they
// should not be interpreted as Unix epoch production runs.
const entry = {
createdAt: 100,
};
@@ -1,3 +1,5 @@
// Subagent spawn context tests cover isolated, forked, lightweight, and
// thread-bound bootstrap context preparation for child sessions.
import path from "node:path";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -42,6 +44,8 @@ describe("sessions_spawn context modes", () => {
});
function usePersistentStoreMock(store: SessionStore) {
// The spawn path mutates the session store in-place; this mock keeps that
// contract visible without touching disk.
updateSessionStoreMock.mockImplementation(async (_storePath: unknown, mutator: unknown) => {
if (typeof mutator !== "function") {
throw new Error("missing session store mutator");
@@ -198,6 +202,8 @@ describe("sessions_spawn context modes", () => {
});
it("falls back to isolated context when requested fork is too large", async () => {
// Forking very large transcripts would create expensive child context, so
// the accepted run records the downgrade in its note.
const store: SessionStore = {
main: {
sessionId: "parent-session-id",