Remove final AppDatabase pass-through methods with ESLint guard (C1 part 3/3)

Migrate all remaining pass-through call sites (social, skills, budget,
entityCrud, documents, knowledge, automation, wakeup, backup, threads,
settings, snapshot, connectors, workspaces, activity) to their owning
domain modules. `AppDatabase` now carries only three methods:

  - createHireRequest (multi-module composite: agents + approvalsMod)
  - rollbackConfigRevision (multi-module composite: documents + entityCrud)
  - queryAll (raw-SQL escape hatch, @internal)

The vault/env-binding infrastructure previously passed argument-by-
argument into `entityCrud.saveSecret`/`resolveSecretEnv` now binds at
module construction, letting callers invoke `db.entityCrud.saveSecret({...})`
without carrying vault plumbing.

Structural types that narrowed AppDatabase to a bag of flat methods
(`ConnectorModelPolicyDeps` callers, `CapabilityMatchDb`, test mocks in
budget-enforcement / budget-incidents / task-quality-gates /
failure-escalation / task-quality-gates-sweep) are reshaped to the new
namespace. `connectorPolicyDepsFromDb` replaces the old pattern of
handing the whole AppDatabase to `validateConnectorModelSelection`.

A new ESLint rule in eslint.config.mjs blocks new top-level methods on
AppDatabase so the pass-through layer cannot silently grow back.
`AppDatabase.ts` dropped from 193 lines to 58; `AppDatabaseBase` lost
the 270-line trailing pass-through block.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-20 13:31:39 -04:00
1 parent a69fbb053b
commit 118e3d8795
120 files changed
+838 -933

No files matched your search

+6 -6
View File
@@ -27,14 +27,14 @@ describe("agent budget policy synchronization", () => {
description: "Budget sync regression coverage",
status: "active",
});
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
version: "test",
lastError: null,
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -57,7 +57,7 @@ describe("agent budget policy synchronization", () => {
department: "engineering",
});
const firstPolicyId = db.saveBudgetPolicy({
const firstPolicyId = db.budget.saveBudgetPolicy({
companyId,
scopeType: "agent",
scopeId: agentId,
@@ -86,7 +86,7 @@ describe("agent budget policy synchronization", () => {
department: "engineering",
});
const secondPolicyId = db.saveBudgetPolicy({
const secondPolicyId = db.budget.saveBudgetPolicy({
companyId,
scopeType: "agent",
scopeId: agentId,
@@ -99,13 +99,13 @@ describe("agent budget policy synchronization", () => {
isActive: true,
});
const agentPolicies = db.listBudgetPolicies(companyId).filter(
const agentPolicies = db.budget.listBudgetPolicies(companyId).filter(
(policy) => policy.scopeType === "agent" && policy.scopeId === agentId,
);
expect(secondPolicyId).toBe(firstPolicyId);
expect(agentPolicies).toHaveLength(1);
expect(agentPolicies[0]?.amount).toBe(25_000);
expect(db.getActivePoliciesForRun(companyId, agentId, null).map((policy) => policy.amount)).toEqual([25_000]);
expect(db.budget.getActivePoliciesForRun(companyId, agentId, null).map((policy) => policy.amount)).toEqual([25_000]);
db.close();
});
+2 -2
View File
@@ -28,14 +28,14 @@ describe("hire routing guards", () => {
description: "Hire routing regression coverage",
status: "active",
});
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
version: "test",
lastError: null,
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
+3 -3
View File
@@ -35,7 +35,7 @@ describe("canManageOrganization", () => {
description: "Tests recursive org authority",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -105,7 +105,7 @@ describe("canManageOrganization", () => {
description: "Tests permission-based org authority",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -159,7 +159,7 @@ describe("canManageOrganization", () => {
description: "Tests that branch growth does not unlock org-wide admin powers",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
+2 -2
View File
@@ -23,7 +23,7 @@ describe("hire approval routing", () => {
const db = new AppDatabase(profileDir);
db.init();
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
@@ -36,7 +36,7 @@ describe("hire approval routing", () => {
description: "Tests recursive hire wake routing",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -23,7 +23,7 @@ describe("deliverable review feedback writeback", () => {
const db = new AppDatabase(profileDir);
db.init();
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
@@ -36,7 +36,7 @@ describe("deliverable review feedback writeback", () => {
description: "Tests review feedback knowledge writeback",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -67,7 +67,7 @@ describe("deliverable review feedback writeback", () => {
priority: "high",
status: "in_review",
});
const documentId = db.saveDocument({
const documentId = db.documentsMod.saveDocument({
companyId,
type: "knowledge_article",
title: "Market report",
@@ -107,7 +107,7 @@ describe("deliverable review feedback writeback", () => {
trackTimer: vi.fn(),
}, approvalId, companyId, "revision_requested");
const knowledgeEntries = db.listSnapshot().knowledgeBase.filter((entry) => entry.companyId === companyId);
const knowledgeEntries = db.snap.listSnapshot().knowledgeBase.filter((entry) => entry.companyId === companyId);
expect(knowledgeEntries).toHaveLength(1);
expect(knowledgeEntries[0]?.category).toBe("lesson_learned");
expect(knowledgeEntries[0]?.importance).toBe("high");
@@ -117,7 +117,7 @@ describe("deliverable review feedback writeback", () => {
expect(knowledgeEntries[0]?.content).toContain("stronger competitor evidence");
expect(wakeAgentIfPossible).toHaveBeenCalledWith(agentId, companyId, "revision_needed");
expect(db.entityCrud.getTask(taskId).status).toBe("in_progress");
const document = db.listSnapshot().documents.find((entry) => entry.id === documentId);
const document = db.snap.listSnapshot().documents.find((entry) => entry.id === documentId);
expect(document?.status).toBe("draft");
db.close();
+2 -2
View File
@@ -36,7 +36,7 @@ function createTestCompany(db: AppDatabase): string {
}
function createTestConnector(db: AppDatabase): void {
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "",
@@ -45,7 +45,7 @@ function createTestConnector(db: AppDatabase): void {
}
function createTestWorkspace(db: AppDatabase, companyId: string): string {
return db.saveWorkspace({
return db.workspacesMod.saveWorkspace({
companyId,
name: "Test Workspace",
localPath: "/tmp/test-workspace",
+19 -21
View File
@@ -84,10 +84,7 @@ function createMockDb() {
createdAt: string;
}> = [];
return {
policies,
costEntries,
const budget = {
saveBudgetPolicy(input: Partial<BudgetPolicyRecord> & { companyId: string; scopeType: string; scopeId: string; amount: number }) {
const id = input.id ?? crypto.randomUUID();
const existing = policies.findIndex((p) => p.id === id);
@@ -150,6 +147,7 @@ function createMockDb() {
return computeSpentCents(filtered);
},
};
return { policies, costEntries, budget };
}
// ======================================================================
@@ -164,7 +162,7 @@ describe("Budget Policy CRUD", () => {
});
it("saveBudgetPolicy creates new policy and returns its ID", () => {
const id = db.saveBudgetPolicy({
const id = db.budget.saveBudgetPolicy({
companyId: "c1",
scopeType: "company",
scopeId: "c1",
@@ -177,13 +175,13 @@ describe("Budget Policy CRUD", () => {
});
it("saveBudgetPolicy updates existing policy when ID provided", () => {
const id = db.saveBudgetPolicy({
const id = db.budget.saveBudgetPolicy({
companyId: "c1",
scopeType: "company",
scopeId: "c1",
amount: 10000,
});
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
id,
companyId: "c1",
scopeType: "company",
@@ -195,14 +193,14 @@ describe("Budget Policy CRUD", () => {
});
it("deleteBudgetPolicy removes policy by ID", () => {
const id = db.saveBudgetPolicy({
const id = db.budget.saveBudgetPolicy({
companyId: "c1",
scopeType: "company",
scopeId: "c1",
amount: 10000,
});
expect(db.policies).toHaveLength(1);
db.deleteBudgetPolicy("c1", id);
db.budget.deleteBudgetPolicy("c1", id);
expect(db.policies).toHaveLength(0);
});
});
@@ -215,27 +213,27 @@ describe("getActivePoliciesForRun", () => {
});
it("returns all active policies matching company+agent+project scopes", () => {
db.saveBudgetPolicy({ companyId: "c1", scopeType: "company", scopeId: "c1", amount: 50000 });
db.saveBudgetPolicy({ companyId: "c1", scopeType: "agent", scopeId: "a1", amount: 10000 });
db.saveBudgetPolicy({ companyId: "c1", scopeType: "project", scopeId: "p1", amount: 20000 });
db.budget.saveBudgetPolicy({ companyId: "c1", scopeType: "company", scopeId: "c1", amount: 50000 });
db.budget.saveBudgetPolicy({ companyId: "c1", scopeType: "agent", scopeId: "a1", amount: 10000 });
db.budget.saveBudgetPolicy({ companyId: "c1", scopeType: "project", scopeId: "p1", amount: 20000 });
// Different company — should not match
db.saveBudgetPolicy({ companyId: "c2", scopeType: "company", scopeId: "c2", amount: 99999 });
db.budget.saveBudgetPolicy({ companyId: "c2", scopeType: "company", scopeId: "c2", amount: 99999 });
const result = db.getActivePoliciesForRun("c1", "a1", "p1");
const result = db.budget.getActivePoliciesForRun("c1", "a1", "p1");
expect(result).toHaveLength(3);
expect(result.map((p) => p.scopeType).sort()).toEqual(["agent", "company", "project"]);
});
it("returns empty array when no policies exist (D-02: no policy = unlimited)", () => {
const result = db.getActivePoliciesForRun("c1", "a1", null);
const result = db.budget.getActivePoliciesForRun("c1", "a1", null);
expect(result).toEqual([]);
});
it("excludes project scope when projectId is null", () => {
db.saveBudgetPolicy({ companyId: "c1", scopeType: "company", scopeId: "c1", amount: 50000 });
db.saveBudgetPolicy({ companyId: "c1", scopeType: "project", scopeId: "p1", amount: 20000 });
db.budget.saveBudgetPolicy({ companyId: "c1", scopeType: "company", scopeId: "c1", amount: 50000 });
db.budget.saveBudgetPolicy({ companyId: "c1", scopeType: "project", scopeId: "p1", amount: 20000 });
const result = db.getActivePoliciesForRun("c1", "a1", null);
const result = db.budget.getActivePoliciesForRun("c1", "a1", null);
expect(result).toHaveLength(1);
expect(result[0]!.scopeType).toBe("company");
});
@@ -261,7 +259,7 @@ describe("getSpentInWindow", () => {
amount: 100000, warnPercent: 80, hardStopEnabled: true, notifyEnabled: true,
isActive: true, createdAt: now.toISOString(), updatedAt: now.toISOString(),
};
const spent = db.getSpentInWindow(policy);
const spent = db.budget.getSpentInWindow(policy);
expect(spent).toBe(380); // (1.50 + 2.30) * 100 = 380 cents
});
@@ -278,7 +276,7 @@ describe("getSpentInWindow", () => {
amount: 100000, warnPercent: 80, hardStopEnabled: true, notifyEnabled: true,
isActive: true, createdAt: now.toISOString(), updatedAt: now.toISOString(),
};
const spent = db.getSpentInWindow(policy);
const spent = db.budget.getSpentInWindow(policy);
expect(spent).toBe(500); // Only a1's $5.00 = 500 cents
});
@@ -295,7 +293,7 @@ describe("getSpentInWindow", () => {
amount: 100000, warnPercent: 80, hardStopEnabled: true, notifyEnabled: true,
isActive: true, createdAt: now.toISOString(), updatedAt: now.toISOString(),
};
const spent = db.getSpentInWindow(policy);
const spent = db.budget.getSpentInWindow(policy);
expect(spent).toBe(750); // Only p1's $7.50 = 750 cents
});
});
+29 -29
View File
@@ -23,8 +23,7 @@ function createMockIncidentDb() {
return { start, end };
}
return {
incidents,
const budget = {
getCalendarMonthWindow,
upsertBudgetIncident(
@@ -132,6 +131,7 @@ function createMockIncidentDb() {
return true;
},
};
return { incidents, budget };
}
function makePolicy(overrides: Partial<BudgetPolicyRecord> = {}): BudgetPolicyRecord {
@@ -166,7 +166,7 @@ describe("upsertBudgetIncident", () => {
it("creates new incident when none exists for policy+window+threshold_type", () => {
const policy = makePolicy();
const id = db.upsertBudgetIncident(policy, "warn_threshold", 8500);
const id = db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
expect(id).toBeTruthy();
expect(db.incidents).toHaveLength(1);
expect(db.incidents[0]!.thresholdType).toBe("warn_threshold");
@@ -176,8 +176,8 @@ describe("upsertBudgetIncident", () => {
it("updates amount_observed when open incident already exists (D-08 dedup)", () => {
const policy = makePolicy();
const id1 = db.upsertBudgetIncident(policy, "warn_threshold", 8500);
const id2 = db.upsertBudgetIncident(policy, "warn_threshold", 9200);
const id1 = db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
const id2 = db.budget.upsertBudgetIncident(policy, "warn_threshold", 9200);
expect(id1).toBe(id2); // Same incident, not a new one
expect(db.incidents).toHaveLength(1); // Still just one
expect(db.incidents[0]!.amountObserved).toBe(9200); // Updated
@@ -185,8 +185,8 @@ describe("upsertBudgetIncident", () => {
it("creates separate incidents for different threshold types", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
expect(db.incidents).toHaveLength(2);
expect(db.incidents[0]!.thresholdType).toBe("warn_threshold");
expect(db.incidents[1]!.thresholdType).toBe("hard_stop");
@@ -202,10 +202,10 @@ describe("resolveIncidentsForPolicy", () => {
it("sets status to provided resolution reason for all open incidents", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
const count = db.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
const count = db.budget.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
expect(count).toBe(2);
expect(db.incidents[0]!.status).toBe("auto_resolved_limit_increase");
expect(db.incidents[1]!.status).toBe("auto_resolved_limit_increase");
@@ -214,10 +214,10 @@ describe("resolveIncidentsForPolicy", () => {
it("does not affect already-resolved incidents", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.resolveIncidentsForPolicy("pol-1", "resolved");
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.resolveIncidentsForPolicy("pol-1", "resolved");
// Now try to resolve again
const count = db.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
const count = db.budget.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
expect(count).toBe(0);
expect(db.incidents[0]!.status).toBe("resolved"); // Unchanged
});
@@ -252,7 +252,7 @@ describe("autoCloseExpiredIncidents", () => {
updatedAt: "2025-01-15T00:00:00.000Z",
});
const count = db.autoCloseExpiredIncidents("c1");
const count = db.budget.autoCloseExpiredIncidents("c1");
expect(count).toBe(1);
expect(db.incidents[0]!.status).toBe("auto_closed");
expect(db.incidents[0]!.resolvedAt).toBeTruthy();
@@ -260,10 +260,10 @@ describe("autoCloseExpiredIncidents", () => {
it("does not close incidents whose window_end is in the future", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
// The auto-created incident has window_end in the future (end of current month)
const count = db.autoCloseExpiredIncidents("c1");
const count = db.budget.autoCloseExpiredIncidents("c1");
expect(count).toBe(0);
expect(db.incidents[0]!.status).toBe("open");
});
@@ -278,22 +278,22 @@ describe("listBudgetIncidents", () => {
it("returns all incidents for a company when status is 'all'", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.resolveIncidentsForPolicy("pol-1", "resolved");
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.resolveIncidentsForPolicy("pol-1", "resolved");
const all = db.listBudgetIncidents("c1", "all");
const all = db.budget.listBudgetIncidents("c1", "all");
expect(all).toHaveLength(2);
});
it("filters by status when specified", () => {
const policy = makePolicy();
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
// Resolve only warn
db.resolveWarnIncidentsForPolicy("pol-1", "resolved");
db.budget.resolveWarnIncidentsForPolicy("pol-1", "resolved");
const open = db.listBudgetIncidents("c1", "open");
const open = db.budget.listBudgetIncidents("c1", "open");
expect(open).toHaveLength(1);
expect(open[0]!.thresholdType).toBe("hard_stop");
});
@@ -308,7 +308,7 @@ describe("checkAutoResolve (D-06)", () => {
it("auto-resolves incidents when policy limit increases above observed amount", () => {
const policy = makePolicy({ amount: 10000 });
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
expect(db.incidents[0]!.status).toBe("open");
// Simulate limit increase: now checking if spent < new limit
@@ -316,7 +316,7 @@ describe("checkAutoResolve (D-06)", () => {
const spent = 10500;
const newAmount = 20000;
if (spent < newAmount) {
db.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
db.budget.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
}
expect(db.incidents[0]!.status).toBe("auto_resolved_limit_increase");
@@ -324,14 +324,14 @@ describe("checkAutoResolve (D-06)", () => {
it("auto-resolves only warn incidents when below warn threshold but above hard stop", () => {
const policy = makePolicy({ amount: 10000, warnPercent: 80 });
db.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.upsertBudgetIncident(policy, "hard_stop", 10500);
db.budget.upsertBudgetIncident(policy, "warn_threshold", 8500);
db.budget.upsertBudgetIncident(policy, "hard_stop", 10500);
// Spent is now 7500 (below warn threshold of 8000 = 10000*80/100)
const spent = 7500;
const _warnAmount = Math.floor((policy.amount * policy.warnPercent) / 100);
if (spent < policy.amount) {
db.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
db.budget.resolveIncidentsForPolicy("pol-1", "auto_resolved_limit_increase");
}
// Both resolved since spent < policy.amount
expect(db.incidents.every((i) => i.status === "auto_resolved_limit_increase")).toBe(true);
+5 -5
View File
@@ -32,7 +32,7 @@ describe("company mode switching", () => {
const db = new AppDatabase(profileDir);
db.init();
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
@@ -48,7 +48,7 @@ describe("company mode switching", () => {
autoApproveHires: false,
reviewDeliverables: true,
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -112,7 +112,7 @@ describe("company mode switching", () => {
});
threadIntegration.onApprovalCreated(approvalId, companyId, taskId, "deliverable_review", "Review deliverable");
expect(db.listThreadWaitStates(companyId).length).toBeGreaterThan(0);
expect(db.threads.listThreadWaitStates(companyId).length).toBeGreaterThan(0);
expect(db.entityCrud.getTask(taskId).requiresUserReview).toBe(true);
expect(db.approvalsMod.getApprovalRecord(approvalId).state).toBe("pending");
@@ -122,7 +122,7 @@ describe("company mode switching", () => {
handlers.set(channel, handler);
},
db,
ensureCompanyExists: (id) => (db.hasCompany(id) ? null : { ok: false, error: { code: "COMPANY_NOT_FOUND", message: "missing" } }),
ensureCompanyExists: (id) => (db.settings.hasCompany(id) ? null : { ok: false, error: { code: "COMPANY_NOT_FOUND", message: "missing" } }),
publishDomainChanged: vi.fn(),
handleApprovalResolved: (resolvedApprovalId, resolvedCompanyId, decision) => {
threadIntegration.onApprovalResolved(resolvedApprovalId, resolvedCompanyId, decision);
@@ -148,7 +148,7 @@ describe("company mode switching", () => {
expect(result.ok).toBe(true);
expect(db.company.getCompanyExecutionMode(companyId)).toBe("ai_ceo");
expect(db.listThreadWaitStates(companyId)).toHaveLength(0);
expect(db.threads.listThreadWaitStates(companyId)).toHaveLength(0);
expect(db.entityCrud.getTask(taskId).requiresUserReview).toBe(false);
expect(db.approvalsMod.getApprovalRecord(approvalId).state).toBe("approved");
+35 -35
View File
@@ -39,7 +39,7 @@ describe("AppDatabase", () => {
description: "Operator company",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary Workspace",
localPath: "/tmp/northline",
@@ -60,14 +60,14 @@ describe("AppDatabase", () => {
capabilities: "Directs execution",
budgetMonthlyUsd: 250,
});
const goalId = db.saveGoal({
const goalId = db.entityCrud.saveGoal({
companyId,
title: "Ship the desktop product",
description: "Stabilize the local operator console.",
ownerAgentId: agentId,
status: "active",
});
const projectId = db.saveProject({
const projectId = db.entityCrud.saveProject({
companyId,
goalId,
name: "Desktop Rebuild",
@@ -88,20 +88,20 @@ describe("AppDatabase", () => {
status: "todo",
});
db.saveSecret({
db.entityCrud.saveSecret({
companyId,
name: "vault-openai",
description: "OpenAI API token",
value: "sk-test-secret",
});
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "OPENAI_API_KEY=vault-openai",
notes: "Primary coding connector",
});
const snapshot = db.listSnapshot();
const snapshot = db.snap.listSnapshot();
expect(snapshot.currentCompanyId).toBe(companyId);
expect(snapshot.workspaces[0]?.id).toBe(workspaceId);
@@ -109,7 +109,7 @@ describe("AppDatabase", () => {
expect(snapshot.goals[0]?.id).toBe(goalId);
expect(snapshot.projects[0]?.id).toBe(projectId);
expect(snapshot.tasks[0]?.id).toBe(taskId);
expect(db.resolveSecretEnv("OPENAI_API_KEY=vault-openai", companyId)).toEqual({
expect(db.entityCrud.resolveSecretEnv("OPENAI_API_KEY=vault-openai", companyId)).toEqual({
OPENAI_API_KEY: "sk-test-secret",
});
});
@@ -122,7 +122,7 @@ describe("AppDatabase", () => {
});
const backupDir = await mkdtemp(join(tmpdir(), "agentcompany-backup-"));
await db.exportBackup(backupDir);
await db.backupMod.exportBackup(backupDir);
db.company.saveCompany({
id: companyId,
name: "Mutated Company",
@@ -130,9 +130,9 @@ describe("AppDatabase", () => {
status: "paused",
});
await db.restoreFromBackup(backupDir);
await db.backupMod.restoreFromBackup(backupDir);
const snapshot = db.listSnapshot();
const snapshot = db.snap.listSnapshot();
expect(snapshot.companies[0]?.name).toBe("Backup Test Co");
await rm(backupDir, { recursive: true, force: true });
@@ -150,19 +150,19 @@ describe("AppDatabase", () => {
status: "active",
});
db.saveSecret({
db.entityCrud.saveSecret({
companyId: alphaCompanyId,
name: "shared-secret-name",
description: "Alpha secret",
value: "alpha-secret",
});
expect(db.resolveSecretEnv("API_KEY=shared-secret-name", alphaCompanyId)).toEqual({
expect(db.entityCrud.resolveSecretEnv("API_KEY=shared-secret-name", alphaCompanyId)).toEqual({
API_KEY: "alpha-secret",
});
// Beta company has no secret named "shared-secret-name", so resolveSecretEnv
// falls back to using the raw value literally (allows direct env bindings).
expect(db.resolveSecretEnv("API_KEY=shared-secret-name", betaCompanyId)).toEqual({
expect(db.entityCrud.resolveSecretEnv("API_KEY=shared-secret-name", betaCompanyId)).toEqual({
API_KEY: "shared-secret-name",
});
});
@@ -173,7 +173,7 @@ describe("AppDatabase", () => {
description: "Atomic checkout validation",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Execution Workspace",
localPath: "/tmp/checkout",
@@ -194,7 +194,7 @@ describe("AppDatabase", () => {
capabilities: "Leads",
budgetMonthlyUsd: 100,
});
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "",
@@ -238,7 +238,7 @@ describe("AppDatabase", () => {
description: "Budget hard stop validation",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Budget Workspace",
localPath: "/tmp/budget",
@@ -395,7 +395,7 @@ describe("AppDatabase", () => {
it("runs forward-only migrations and creates schema_migrations table", () => {
// The migration system runs during init() — verify the tracking table exists
const snapshot = db.listSnapshot();
const snapshot = db.snap.listSnapshot();
expect(snapshot).toBeTruthy();
// Verify we can re-init without errors (migrations are idempotent)
@@ -403,7 +403,7 @@ describe("AppDatabase", () => {
db = new AppDatabase(tempDir);
db.init();
const snapshot2 = db.listSnapshot();
const snapshot2 = db.snap.listSnapshot();
expect(snapshot2).toBeTruthy();
});
@@ -413,7 +413,7 @@ describe("AppDatabase", () => {
description: "Workspace lock test",
status: "active",
});
const wsId = db.saveWorkspace({
const wsId = db.workspacesMod.saveWorkspace({
companyId,
name: "Lockable WS",
localPath: "/tmp/lock-test",
@@ -423,24 +423,24 @@ describe("AppDatabase", () => {
});
// Acquire lock for run-1
expect(db.acquireWorkspaceLock(wsId, "run-1")).toBe(true);
let ws = db.getWorkspace(wsId);
expect(db.workspacesMod.acquireWorkspaceLock(wsId, "run-1")).toBe(true);
let ws = db.workspacesMod.getWorkspace(wsId);
expect(ws?.state).toBe("busy");
// Same run can re-acquire (idempotent)
expect(db.acquireWorkspaceLock(wsId, "run-1")).toBe(true);
expect(db.workspacesMod.acquireWorkspaceLock(wsId, "run-1")).toBe(true);
// Different run cannot acquire while run-1 holds the lock
expect(db.acquireWorkspaceLock(wsId, "run-2")).toBe(false);
expect(db.workspacesMod.acquireWorkspaceLock(wsId, "run-2")).toBe(false);
// Release lock
db.releaseWorkspaceLock(wsId, "run-1");
ws = db.getWorkspace(wsId);
db.workspacesMod.releaseWorkspaceLock(wsId, "run-1");
ws = db.workspacesMod.getWorkspace(wsId);
expect(ws?.state).toBe("ready");
// Now run-2 can acquire
expect(db.acquireWorkspaceLock(wsId, "run-2")).toBe(true);
db.releaseWorkspaceLock(wsId, "run-2");
expect(db.workspacesMod.acquireWorkspaceLock(wsId, "run-2")).toBe(true);
db.workspacesMod.releaseWorkspaceLock(wsId, "run-2");
});
it("releases all workspace locks on crash recovery", () => {
@@ -449,7 +449,7 @@ describe("AppDatabase", () => {
description: "Lock recovery test",
status: "active",
});
const wsId = db.saveWorkspace({
const wsId = db.workspacesMod.saveWorkspace({
companyId,
name: "Recovery WS",
localPath: "/tmp/recovery-test",
@@ -458,11 +458,11 @@ describe("AppDatabase", () => {
isPrimary: true,
});
db.acquireWorkspaceLock(wsId, "stale-run");
expect(db.getWorkspace(wsId)?.state).toBe("busy");
db.workspacesMod.acquireWorkspaceLock(wsId, "stale-run");
expect(db.workspacesMod.getWorkspace(wsId)?.state).toBe("busy");
db.releaseAllWorkspaceLocks();
expect(db.getWorkspace(wsId)?.state).toBe("ready");
db.workspacesMod.releaseAllWorkspaceLocks();
expect(db.workspacesMod.getWorkspace(wsId)?.state).toBe("ready");
});
it("purges expired run logs based on retention setting", async () => {
@@ -471,7 +471,7 @@ describe("AppDatabase", () => {
description: "Log purge test",
status: "active",
});
const wsId = db.saveWorkspace({
const wsId = db.workspacesMod.saveWorkspace({
companyId,
name: "PurgeWS",
localPath: "/tmp/purge",
@@ -521,7 +521,7 @@ describe("AppDatabase", () => {
expect(db.runs.readRunLog(run.id)).toContain("test log line");
// Set retention to 1 day and manually backdate the run's finished_at
db.updateSettings({ logRetentionDays: 1 });
db.settings.updateSettings({ logRetentionDays: 1 });
// Backdate finished_at to 10 days ago
const tenDaysAgo = new Date(Date.now() - 10 * 86_400_000).toISOString();
// Direct SQL update for test only
@@ -529,7 +529,7 @@ describe("AppDatabase", () => {
.prepare("update runs set finished_at = ? where id = ?")
.run(tenDaysAgo, run.id);
const purged = db.purgeExpiredRunLogs();
const purged = db.settings.purgeExpiredRunLogs();
expect(purged).toBe(1);
// Log should be gone after purge
+11 -11
View File
@@ -25,13 +25,13 @@ function scaffold(db: AppDatabase) {
description: "Budget exhaustion mid-run edge case tests (D-05.2)",
status: "active",
});
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "gemini-cli",
model: "gemini-pro",
envBindingText: "",
notes: "Test connector",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: "/tmp/budget-edge-test",
@@ -52,14 +52,14 @@ function scaffold(db: AppDatabase) {
capabilities: "Executes tasks",
budgetMonthlyUsd: 100,
});
const goalId = db.saveGoal({
const goalId = db.entityCrud.saveGoal({
companyId,
title: "Ship feature",
description: "Build budget edge case test",
ownerAgentId: agentId,
status: "active",
});
const projectId = db.saveProject({
const projectId = db.entityCrud.saveProject({
companyId,
goalId,
name: "Budget Project",
@@ -119,7 +119,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Create company budget policy: 500 cents ($5), hard stop enabled
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
@@ -205,7 +205,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Create company budget policy: 500 cents ($5)
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
@@ -253,7 +253,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Create company budget policy with known ID
const policyId = db.saveBudgetPolicy({
const policyId = db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
@@ -301,7 +301,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Company-level: plenty of room (10000 cents = $100)
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
@@ -310,7 +310,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Agent-level: tight budget (100 cents = $1)
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "agent",
scopeId: agentId,
@@ -358,7 +358,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Create policy with 300 cents ($3) budget
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
@@ -408,7 +408,7 @@ describe("Edge Case: Budget Exhaustion Mid-Run (D-05.2)", () => {
});
// Create tight budget
db.saveBudgetPolicy({
db.budget.saveBudgetPolicy({
companyId,
scopeType: "company",
scopeId: companyId,
+2 -2
View File
@@ -36,7 +36,7 @@ function createTestCompany(db: AppDatabase): string {
}
function createTestConnector(db: AppDatabase): void {
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "gemini-cli",
model: "gemini-pro",
envBindingText: "",
@@ -45,7 +45,7 @@ function createTestConnector(db: AppDatabase): void {
}
function createTestWorkspace(db: AppDatabase, companyId: string): string {
return db.saveWorkspace({
return db.workspacesMod.saveWorkspace({
companyId,
name: "Test Workspace",
localPath: "/tmp/concurrent-test",
+4 -4
View File
@@ -28,14 +28,14 @@ function scaffold(db: AppDatabase, connectorId: ConnectorId = "gemini-cli") {
});
// Always save gemini-cli (needed for most tests)
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "gemini-cli",
model: "gemini-pro",
envBindingText: "",
notes: "Test connector - no native context management",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: "/tmp/session-edge-test",
@@ -56,14 +56,14 @@ function scaffold(db: AppDatabase, connectorId: ConnectorId = "gemini-cli") {
capabilities: "Executes tasks",
budgetMonthlyUsd: 100,
});
const goalId = db.saveGoal({
const goalId = db.entityCrud.saveGoal({
companyId,
title: "Ship feature",
description: "Build session rotation edge case test",
ownerAgentId: agentId,
status: "active",
});
const projectId = db.saveProject({
const projectId = db.entityCrud.saveProject({
companyId,
goalId,
name: "Session Project",
+4 -4
View File
@@ -31,7 +31,7 @@ describe("ipc-core-agent-graph-handlers model enforcement", () => {
const db = new AppDatabase(profileDir);
db.init();
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
@@ -43,8 +43,8 @@ describe("ipc-core-agent-graph-handlers model enforcement", () => {
description: "Tests saveAgent model validation",
status: "active",
});
db.setDisabledModels(companyId, "openai-codex", [{ id: "gpt-5.4", label: "gpt-5.4" }]);
const workspaceId = db.saveWorkspace({
db.settings.setDisabledModels(companyId, "openai-codex", [{ id: "gpt-5.4", label: "gpt-5.4" }]);
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: profileDir,
@@ -72,7 +72,7 @@ describe("ipc-core-agent-graph-handlers model enforcement", () => {
handlers.set(channel, handler);
},
db,
ensureCompanyExists: (id) => (db.hasCompany(id) ? null : { ok: false, error: { code: "COMPANY_NOT_FOUND", message: "missing" } }),
ensureCompanyExists: (id) => (db.settings.hasCompany(id) ? null : { ok: false, error: { code: "COMPANY_NOT_FOUND", message: "missing" } }),
findInvalidReference: () => null,
publishDomainChanged: vi.fn(),
handleApprovalResolved: vi.fn(),
+1 -1
View File
@@ -63,7 +63,7 @@ describe("ipc-core-admin-handlers connector saves", () => {
}) as { ok: boolean; error?: { code: string; message: string } };
expect(result.ok).toBe(true);
expect(db.getConnector("anthropic").model).toBe(anthropicModel);
expect(db.connectorsCrud.getConnector("anthropic").model).toBe(anthropicModel);
db.close();
});
+2 -2
View File
@@ -28,7 +28,7 @@ describe("knowledge provenance", () => {
status: "active",
});
const knowledgeId = db.saveKnowledgeEntry({
const knowledgeId = db.knowledgeMod.saveKnowledgeEntry({
companyId,
category: "lesson_learned",
topic: "Original lesson",
@@ -37,7 +37,7 @@ describe("knowledge provenance", () => {
sourceRunId: null,
});
db.saveKnowledgeEntry({
db.knowledgeMod.saveKnowledgeEntry({
id: knowledgeId,
companyId,
category: "lesson_learned",
+8 -8
View File
@@ -19,7 +19,7 @@ afterEach(async () => {
});
function createScaffold(db: AppDatabase) {
db.updateConnectorHealth({
db.connectorsCrud.updateConnectorHealth({
id: "openai-codex",
status: "ready",
authState: "authenticated",
@@ -33,7 +33,7 @@ function createScaffold(db: AppDatabase) {
status: "active",
executionMode: "ai_cofounder",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: "/tmp/message-dispatch",
@@ -282,7 +282,7 @@ describe("message dispatch", () => {
});
threadIntegration.onTaskCreated(taskId, companyId);
const thread = db.listThreads({
const thread = db.threads.listThreads({
companyId,
type: "task",
relatedEntityType: "task",
@@ -294,21 +294,21 @@ describe("message dispatch", () => {
throw new Error("Expected task thread to exist.");
}
const replyWait = db.setThreadWaitState({
const replyWait = db.threads.setThreadWaitState({
threadId: thread.id,
companyId,
waitingFor: "user_reply",
relatedApprovalId: null,
reason: "Reply needed",
});
const reviewWait = db.setThreadWaitState({
const reviewWait = db.threads.setThreadWaitState({
threadId: thread.id,
companyId,
waitingFor: "user_review",
relatedApprovalId: null,
reason: "Review needed",
});
const approvalWait = db.setThreadWaitState({
const approvalWait = db.threads.setThreadWaitState({
threadId: thread.id,
companyId,
waitingFor: "user_approval",
@@ -328,7 +328,7 @@ describe("message dispatch", () => {
body: "Board-wide update",
});
let unresolved = db.listThreadWaitStates(companyId);
let unresolved = db.threads.listThreadWaitStates(companyId);
expect(unresolved.some((entry) => entry.id === replyWait.id)).toBe(false);
expect(unresolved.some((entry) => entry.id === reviewWait.id)).toBe(true);
@@ -346,7 +346,7 @@ describe("message dispatch", () => {
body: "Specific reply for the thread",
});
unresolved = db.listThreadWaitStates(companyId);
unresolved = db.threads.listThreadWaitStates(companyId);
expect(unresolved.some((entry) => entry.id === reviewWait.id)).toBe(false);
expect(unresolved.some((entry) => entry.id === approvalWait.id)).toBe(true);
+5 -5
View File
@@ -32,13 +32,13 @@ function seedCompany(db: AppDatabase) {
description: "Regression fixture",
status: "active",
});
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "",
notes: "fixture",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Default",
localPath: "/tmp/fixture",
@@ -91,13 +91,13 @@ describe("resolveWorkspaceWithLockMode", () => {
it("project-bound workspace → exclusive (single writer per repo)", () => {
const { companyId } = seedCompany(db);
const projectId = db.saveProject({
const projectId = db.entityCrud.saveProject({
companyId,
name: "Platform",
description: "",
status: "active",
});
db.saveWorkspace({
db.workspacesMod.saveWorkspace({
companyId,
name: "Project repo",
localPath: "/tmp/project-ws",
@@ -131,7 +131,7 @@ describe("resolveWorkspaceWithLockMode", () => {
it("task workspace wins over agent workspace even when both are set", () => {
const { companyId, workspaceId: agentWsId } = seedCompany(db);
const taskWsId = db.saveWorkspace({
const taskWsId = db.workspacesMod.saveWorkspace({
companyId,
name: "Task-only",
localPath: "/tmp/task-ws",
+3 -3
View File
@@ -26,7 +26,7 @@ function scaffold(db: AppDatabase) {
description: "Testing session management",
status: "active",
});
const workspaceId = db.saveWorkspace({
const workspaceId = db.workspacesMod.saveWorkspace({
companyId,
name: "Primary",
localPath: "/tmp/session-test",
@@ -47,14 +47,14 @@ function scaffold(db: AppDatabase) {
capabilities: "Writes code",
budgetMonthlyUsd: 100,
});
const goalId = db.saveGoal({
const goalId = db.entityCrud.saveGoal({
companyId,
title: "Ship feature",
description: "Build session management",
ownerAgentId: agentId,
status: "active",
});
const projectId = db.saveProject({
const projectId = db.entityCrud.saveProject({
companyId,
goalId,
name: "Session Project",
+4 -2
View File
@@ -154,8 +154,10 @@ describe("checkCapabilityMatch", () => {
entityCrud: {
getAgent: (_id: string) => agent,
},
listAgentSkillAssignments: (_id: string) => skillAssignments,
getCompanySkill: (_companyId: string, skillId: string) => skills[skillId] ?? null,
skills: {
listAgentSkillAssignments: (_id: string) => skillAssignments,
getCompanySkill: (_companyId: string, skillId: string) => skills[skillId] ?? null,
},
};
}
+2 -2
View File
@@ -35,7 +35,7 @@ function createTestCompany(db: AppDatabase): string {
}
function createTestConnector(db: AppDatabase): void {
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "",
@@ -44,7 +44,7 @@ function createTestConnector(db: AppDatabase): void {
}
function createTestWorkspace(db: AppDatabase, companyId: string): string {
return db.saveWorkspace({
return db.workspacesMod.saveWorkspace({
companyId,
name: "Phase Workspace",
localPath: "/tmp/phase-workspace",
+11 -11
View File
@@ -27,7 +27,7 @@ function createTestCompany(db: AppDatabase): string {
}
function createTestConnector(db: AppDatabase): void {
db.saveConnector({
db.connectorsCrud.saveConnector({
id: "openai-codex",
model: "gpt-5",
envBindingText: "",
@@ -36,7 +36,7 @@ function createTestConnector(db: AppDatabase): void {
}
function createTestWorkspace(db: AppDatabase, companyId: string): string {
return db.saveWorkspace({
return db.workspacesMod.saveWorkspace({
companyId,
name: "Wakeup Workspace",
localPath: "/tmp/wakeup-workspace",
@@ -87,9 +87,9 @@ describe("wakeup lifecycle", () => {
const workspaceId = createTestWorkspace(db, companyId);
const agentId = createTestAgent(db, companyId, workspaceId);
db.enqueueWakeupRequest(companyId, agentId, "task.created", "New task assigned");
db.wakeup.enqueueWakeupRequest(companyId, agentId, "task.created", "New task assigned");
const wakes = db.listWakeupRequests(companyId);
const wakes = db.wakeup.listWakeupRequests(companyId);
expect(wakes.length).toBe(1);
expect(wakes[0].agentId).toBe(agentId);
expect(wakes[0].status).toBe("queued");
@@ -107,10 +107,10 @@ describe("wakeup lifecycle", () => {
const workspaceId = createTestWorkspace(db, companyId);
const agentId = createTestAgent(db, companyId, workspaceId);
db.enqueueWakeupRequest(companyId, agentId, "task.created", "First task");
db.enqueueWakeupRequest(companyId, agentId, "task.status_changed", "Second trigger");
db.wakeup.enqueueWakeupRequest(companyId, agentId, "task.created", "First task");
db.wakeup.enqueueWakeupRequest(companyId, agentId, "task.status_changed", "Second trigger");
const wakes = db.listWakeupRequests(companyId);
const wakes = db.wakeup.listWakeupRequests(companyId);
// D-07: Per-agent scope -- only one wakeup row should exist
expect(wakes.length).toBe(1);
expect(wakes[0].coalescedCount).toBe(1);
@@ -128,15 +128,15 @@ describe("wakeup lifecycle", () => {
const agent1Id = createTestAgent(db, companyId, workspaceId, "Agent1");
const agent2Id = createTestAgent(db, companyId, workspaceId, "Agent2");
db.enqueueWakeupRequest(companyId, agent1Id, "task.created", "Agent1 task");
db.enqueueWakeupRequest(companyId, agent2Id, "task.created", "Agent2 task");
db.wakeup.enqueueWakeupRequest(companyId, agent1Id, "task.created", "Agent1 task");
db.wakeup.enqueueWakeupRequest(companyId, agent2Id, "task.created", "Agent2 task");
// List all for company
const allWakes = db.listWakeupRequests(companyId);
const allWakes = db.wakeup.listWakeupRequests(companyId);
expect(allWakes.length).toBe(2);
// Filter by agentId
const agent1Wakes = db.listWakeupRequests(companyId, { agentId: agent1Id });
const agent1Wakes = db.wakeup.listWakeupRequests(companyId, { agentId: agent1Id });
expect(agent1Wakes.length).toBe(1);
expect(agent1Wakes[0].agentId).toBe(agent1Id);
});