Q108: deliverables under review are held until approved instead of written first

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-08 17:45:39 -04:00
1 parent 4765683b86
commit 34c5557a32
13 files changed
+325 -87

No files matched your search

@@ -0,0 +1,27 @@
export const heldDeliverablesSchema = `
create table if not exists held_deliverables (
id text primary key,
org_id text not null references organizations(id) on delete cascade,
approval_id text not null,
kind text not null check (kind in ('file', 'document_create', 'document_update')),
agent_id text,
task_id text,
goal_id text,
project_id text,
workspace_root text,
relative_path text,
document_id text,
base_version integer,
title text,
doc_type text,
reason text,
content text not null,
state text not null check (state in ('held', 'published', 'declined')),
created_at text not null
);
create index if not exists held_deliverables_task on held_deliverables(task_id, state);
create index if not exists held_deliverables_goal on held_deliverables(goal_id, state);
insert into schema_migrations(version, name, applied_at)
values (86, 'held_deliverables', datetime('now'));
`;
+2
View File
@@ -84,6 +84,7 @@ import { connectorPendingAccountSchema } from "./migrations/082-connector-pendin
import { connectorAccountLabelsSchema } from "./migrations/083-connector-account-labels";
import { connectorGrantLimitsSchema } from "./migrations/084-connector-grant-limits";
import { approvalSubjectSnapshotSchema } from "./migrations/085-approval-subject-snapshot";
import { heldDeliverablesSchema } from "./migrations/086-held-deliverables";
interface Migration {
version: number;
@@ -177,6 +178,7 @@ const MIGRATIONS: Migration[] = [
{ version: 83, name: "connector_account_labels", sql: connectorAccountLabelsSchema },
{ version: 84, name: "connector_grant_limits", sql: connectorGrantLimitsSchema },
{ version: 85, name: "approval_subject_snapshot", sql: approvalSubjectSnapshotSchema },
{ version: 86, name: "held_deliverables", sql: heldDeliverablesSchema },
];
const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
+37 -43
View File
@@ -1,4 +1,7 @@
import { RISK_LEVEL } from "../../shared/domain";
import { createId } from "../../shared/ids";
import { withSavepoint } from "../database/connection";
import { holdDeliverable, reviewsDeliverables, type HeldTarget } from "./held-deliverables";
import { ApprovalService } from "./approval-service";
import { writeDeliverable } from "./deliverable-writer";
import { DocumentService } from "./document-service";
@@ -7,10 +10,16 @@ import { requireString } from "./agent-tool-args";
import type { AgentToolContext, AgentToolDeps } from "./agent-tools";
import type { JsonRecord } from "./provider-http";
const REVIEW_EXCERPT_CHARS = 4000;
export function writeDeliverableTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string {
if (!ctx.workspace) throw new Error("No workspace is bound to this task; cannot write deliverables.");
const path = requireString(args.path, "path");
const content = requireString(args.content, "content");
if (reviewsDeliverables(deps.db, ctx.orgId)) {
holdForReview(deps, ctx, { kind: "file", workspaceRoot: ctx.workspace.localPath, relativePath: path }, content, `Review deliverable: ${path}`);
return `Deliverable ${path} (${content.length} chars) is held for board review in Approvals. It is not written until approved, so no one can use it yet.`;
}
const written = writeDeliverable({ workspaceRoot: ctx.workspace.localPath, relativePath: path, content });
const fileId = recordWorkspaceFile(deps.db, {
orgId: ctx.orgId,
@@ -19,21 +28,18 @@ export function writeDeliverableTool(deps: AgentToolDeps, ctx: AgentToolContext,
workspaceRoot: ctx.workspace.localPath,
relativePath: written,
});
const review = requestDeliverableReview(deps, ctx, {
title: `Review deliverable: ${written}`,
details: `Deliverable ${written} (${content.length} chars) produced by an agent run.`,
sourceEntityType: "file",
sourceEntityId: fileId,
});
return `Wrote deliverable ${written} (file_id=${fileId}, chars=${content.length}).${review ? " It is queued for board review in Approvals." : ""}`;
return `Wrote deliverable ${written} (file_id=${fileId}, chars=${content.length}).`;
}
export function createDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string {
const title = requireString(args.title, "title");
const docType = requireString(args.doc_type, "doc_type");
const content = requireString(args.content, "content");
const documentService = new DocumentService(deps.db);
const docId = documentService.create({
if (reviewsDeliverables(deps.db, ctx.orgId)) {
holdForReview(deps, ctx, { kind: "document_create", title, docType }, content, `Review ${docType}: ${title}`);
return `Document "${title}" (${docType}, ${content.length} chars) is held for board review in Approvals. It is not created until approved, so no one can use it yet.`;
}
const docId = new DocumentService(deps.db).create({
orgId: ctx.orgId,
title,
docType,
@@ -44,40 +50,28 @@ export function createDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, a
goalId: ctx.taskGoalId,
taskId: ctx.taskId,
});
const review = requestDeliverableReview(deps, ctx, {
title: `Review ${docType}: ${title}`,
details: `Document "${title}" (${docType}, ${content.length} chars) authored by an agent run.`,
sourceEntityType: "document",
sourceEntityId: docId,
});
return `Created document "${title}" (doc_id=${docId}, type=${docType}, chars=${content.length}).${review ? " It is queued for board review in Approvals." : ""}`;
return `Created document "${title}" (doc_id=${docId}, type=${docType}, chars=${content.length}).`;
}
/**
* In AI Co-Founder mode the operator reviews what the company produces, so
* every deliverable and document lands in the Approvals queue. AI CEO mode
* ships without review — that autonomy is the mode's contract.
*/
export function requestDeliverableReview(
deps: AgentToolDeps,
ctx: AgentToolContext,
input: { title: string; details: string; sourceEntityType: "file" | "document"; sourceEntityId: string },
): boolean {
const org = deps.db.prepare("select review_deliverables from organizations where id = ?")
.get(ctx.orgId) as { review_deliverables: number } | undefined;
if (!org) throw new Error("Organization was not found.");
if (org.review_deliverables !== 1) return false;
new ApprovalService(deps.db).create(
{
orgId: ctx.orgId,
kind: "deliverable_review",
title: input.title,
details: input.details,
risk: RISK_LEVEL.LOW,
requestedByType: "agent",
requestedById: ctx.agent.id,
},
{ sourceEntityType: input.sourceEntityType, sourceEntityId: input.sourceEntityId },
);
return true;
/** In AI Co-Founder mode the board reviews what the company produces before it exists; AI CEO mode ships without review. */
export function holdForReview(deps: AgentToolDeps, ctx: AgentToolContext, target: HeldTarget, content: string, title: string): void {
const excerpt = content.length > REVIEW_EXCERPT_CHARS ? `${content.slice(0, REVIEW_EXCERPT_CHARS)}\n[... ${content.length - REVIEW_EXCERPT_CHARS} more chars]` : content;
withSavepoint(deps.db, "hold_deliverable", () => {
const heldId = createId("hld");
const approvalId = new ApprovalService(deps.db).create(
{
orgId: ctx.orgId,
kind: "deliverable_review",
title,
details: `Produced by an agent run (${content.length} chars). Approving writes it; declining discards it.\n\n${excerpt}`,
risk: RISK_LEVEL.LOW,
requestedByType: "agent",
requestedById: ctx.agent.id,
},
{ sourceEntityType: "held_deliverable", sourceEntityId: heldId },
);
holdDeliverable(deps.db, {
id: heldId, approvalId, orgId: ctx.orgId, agentId: ctx.agent.id, taskId: ctx.taskId, goalId: ctx.taskGoalId, projectId: ctx.taskProjectId, target, content,
});
});
}
+9 -10
View File
@@ -1,5 +1,6 @@
import { optionalEnum, optionalLimit, optionalText, requireString } from "./agent-tool-args";
import { requestDeliverableReview } from "./agent-deliverable-tools";
import { holdForReview } from "./agent-deliverable-tools";
import { reviewsDeliverables } from "./held-deliverables";
import type { AgentToolContext, AgentToolDeps } from "./agent-tools";
import { DocumentService } from "./document-service";
import type { JsonRecord } from "./provider-http";
@@ -108,22 +109,20 @@ export function readDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, arg
export function updateDocumentTool(deps: AgentToolDeps, ctx: AgentToolContext, args: JsonRecord): string {
const id = requireString(args.doc_id, "doc_id");
const doc = deps.db.prepare("select title, doc_type, status from documents where id = ? and org_id = ?")
.get(id, ctx.orgId) as { title: string; doc_type: string; status: string } | undefined;
const doc = deps.db.prepare("select title, doc_type, status, version from documents where id = ? and org_id = ?")
.get(id, ctx.orgId) as { title: string; doc_type: string; status: string; version: number } | undefined;
if (!doc) throw new Error(`No document with doc_id "${id}".`);
const content = requireString(args.content, "content");
const title = optionalText(args.title, "title") ?? doc.title;
const reason = requireString(args.reason, "reason");
if (reviewsDeliverables(deps.db, ctx.orgId)) {
holdForReview(deps, ctx, { kind: "document_update", documentId: id, baseVersion: doc.version, title, reason }, content, `Review ${doc.doc_type} update: ${title}`);
return `The update to "${title}" is held for board review in Approvals. The document keeps its current version until the update is approved.`;
}
const version = new DocumentService(deps.db).update({
orgId: ctx.orgId, documentId: id, title, content, status: doc.status, reason, changedByType: "agent", changedById: ctx.agent.id,
});
const review = requestDeliverableReview(deps, ctx, {
title: `Review ${doc.doc_type} update: ${title}`,
details: `Document "${title}" v${version} was updated by an agent run (${content.length} chars). Reason: ${reason}`,
sourceEntityType: "document",
sourceEntityId: id,
});
return `Updated document "${title}" to v${version} (doc_id=${id}).${review ? " The update is queued for board review in Approvals." : ""}`;
return `Updated document "${title}" to v${version} (doc_id=${id}).`;
}
function producedBy(row: DocumentRow): string {
+9
View File
@@ -7,6 +7,7 @@ import type { JsonRecord } from "./provider-http";
import type { ProviderService } from "./provider-service";
import { unreadableArguments, type AgentTurnMessage, type ToolCall, type ToolDefinition } from "./provider-tool-turn";
import { MAX_TOOL_CALLS_PER_TURN, throwIfRunStopped, untilStopped } from "./run-control";
import { heldWorkTitles } from "./held-deliverables";
const AUDIT_MAX_ITERATIONS = 6;
const STATUS_TASK_LINES = 8;
@@ -78,6 +79,7 @@ export async function completeGoalTool(args: GoalCompletionArgs): Promise<string
return "ERROR: Only the CEO or the goal's owner can complete a goal. Report your evidence to them instead.";
}
if (goal.status !== "active") return `Goal "${goal.title}" is already ${goal.status}.`;
if (heldWorkTitles(deps.db, { goalId: goal.id }).length > 0) return heldGoalRefusal(deps, goal);
const evidence = requireString(call.arguments.evidence, "evidence");
const verdict = await auditGoalCompletion(args, goal, evidence);
@@ -85,6 +87,8 @@ export async function completeGoalTool(args: GoalCompletionArgs): Promise<string
return `The independent audit rejected closing the goal: ${verdict.reason} The goal stays active — close that gap or create the tasks that will.`;
}
throwIfRunStopped();
// Work held for review while the audit ran keeps the goal open too.
if (heldWorkTitles(deps.db, { goalId: goal.id }).length > 0) return heldGoalRefusal(deps, goal);
deps.db.prepare("update goals set status = 'achieved', stalled_reason = null, updated_at = ? where id = ? and org_id = ?")
.run(new Date().toISOString(), goal.id, ctx.orgId);
new AuditService(deps.db).record({
@@ -102,6 +106,11 @@ export async function completeGoalTool(args: GoalCompletionArgs): Promise<string
}
}
function heldGoalRefusal(deps: GoalCompletionArgs["deps"], goal: { id: string; title: string }): string {
const held = heldWorkTitles(deps.db, { goalId: goal.id });
return `ERROR: Goal "${goal.title}" has work awaiting board review (${held.join(", ")}); it is not written yet, so the goal cannot be achieved.`;
}
interface AuditVerdict {
approved: boolean;
reason: string;
+5
View File
@@ -4,6 +4,7 @@ import { APPROVAL_STATE, ROLE_KEY } from "../../shared/domain";
import { createId } from "../../shared/ids";
import { AuditService } from "./audit-service";
import { settleHire } from "./agent-admission";
import { settleHeldDeliverable } from "./held-deliverables";
import { IdentityAccessService } from "./identity-access-service";
import { OrgGovernanceService } from "./org-governance-service";
@@ -101,6 +102,10 @@ export class ApprovalService {
action: input.state,
payload: { decidedAt: now },
});
// Last, so nothing after it can fail once a file is on disk.
if (approval.source_entity_type === "held_deliverable" && approval.source_entity_id) {
settleHeldDeliverable(this.db, approval.source_entity_id, input.state === APPROVAL_STATE.APPROVED);
}
}
private assertRequesterBelongsToOrg(input: CreateApprovalInput): void {
+14 -20
View File
@@ -5,6 +5,7 @@ import type { DatabaseSync } from "node:sqlite";
import { FILE_SCAN_STATE, type FileScanState } from "../../../shared/domain";
import { createId } from "../../../shared/ids";
import { resolveWorkspacePath } from "./workspace-path";
import { withSavepoint } from "../../database/connection";
export interface FileScanResult {
state: FileScanState;
@@ -155,26 +156,19 @@ export function recordWorkspaceFile(db: DatabaseSync, input: {
const name = basename(input.relativePath);
const scan = scanFileContent(name, bytes);
const now = new Date().toISOString();
db.exec("begin immediate");
try {
const id = upsertFileObject(db, {
orgId: input.orgId,
name,
kind: fileKind(name),
sizeBytes: bytes.byteLength,
sha256: createHash("sha256").update(bytes).digest("hex"),
storagePath: absolute,
ownerType: input.ownerType,
ownerId: input.ownerId,
scan,
now,
});
db.exec("commit");
return id;
} catch (error) {
db.exec("rollback");
throw error;
}
// A savepoint, not a transaction: an approved deliverable is recorded inside the approval's own transaction.
return withSavepoint(db, "record_workspace_file", () => upsertFileObject(db, {
orgId: input.orgId,
name,
kind: fileKind(name),
sizeBytes: bytes.byteLength,
sha256: createHash("sha256").update(bytes).digest("hex"),
storagePath: absolute,
ownerType: input.ownerType,
ownerId: input.ownerId,
scan,
now,
}));
}
function grantWorkspaceAccess(db: DatabaseSync, orgId: string, fileId: string, now: string): void {
+117
View File
@@ -0,0 +1,117 @@
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import type { DatabaseSync } from "node:sqlite";
import { writeDeliverable } from "./deliverable-writer";
import { DocumentService } from "./document-service";
import { recordWorkspaceFile } from "./files/file-object-store";
import { resolveWorkspacePath } from "./files/workspace-path";
/** What a held deliverable will become once approved. */
export type HeldTarget =
| { kind: "file"; workspaceRoot: string; relativePath: string }
| { kind: "document_create"; title: string; docType: string }
| { kind: "document_update"; documentId: string; baseVersion: number; title: string; reason: string };
interface HeldRow {
id: string;
org_id: string;
kind: HeldTarget["kind"];
agent_id: string | null;
task_id: string | null;
goal_id: string | null;
project_id: string | null;
workspace_root: string | null;
relative_path: string | null;
document_id: string | null;
base_version: number | null;
title: string | null;
doc_type: string | null;
reason: string | null;
content: string;
}
/** Whether this org's board reviews deliverables before they are written. */
export function reviewsDeliverables(db: DatabaseSync, orgId: string): boolean {
const org = db.prepare("select review_deliverables from organizations where id = ?").get(orgId) as { review_deliverables: number } | undefined;
if (!org) throw new Error("Organization was not found.");
return org.review_deliverables === 1;
}
/** Keeps a deliverable out of the workspace and library until its review is approved. */
export function holdDeliverable(
db: DatabaseSync,
input: { id: string; approvalId: string; orgId: string; agentId: string; taskId: string | null; goalId: string | null; projectId: string | null; target: HeldTarget; content: string },
): void {
const target = input.target;
// A file path that could never be written is refused now, not at approval.
if (target.kind === "file") resolveWorkspacePath(target.workspaceRoot, target.relativePath);
db.prepare(`
insert into held_deliverables(
id, org_id, approval_id, kind, agent_id, task_id, goal_id, project_id, workspace_root, relative_path,
document_id, base_version, title, doc_type, reason, content, state, created_at
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'held', ?)
`).run(
input.id, input.orgId, input.approvalId, target.kind, input.agentId, input.taskId, input.goalId, input.projectId,
target.kind === "file" ? target.workspaceRoot : null,
target.kind === "file" ? target.relativePath : null,
target.kind === "document_update" ? target.documentId : null,
target.kind === "document_update" ? target.baseVersion : null,
target.kind === "file" ? null : target.title,
target.kind === "document_create" ? target.docType : null,
target.kind === "document_update" ? target.reason : null,
input.content,
new Date().toISOString(),
);
console.info(`[deliverables] held ${target.kind} ${input.id} for review ${input.approvalId}`);
}
/** Writes an approved deliverable where it was meant to go; a declined one is never written. */
export function settleHeldDeliverable(db: DatabaseSync, heldId: string, approved: boolean): void {
const row = db.prepare("select * from held_deliverables where id = ? and state = 'held'").get(heldId) as HeldRow | undefined;
if (!row) throw new Error("The held deliverable of this review was not found.");
db.prepare("update held_deliverables set state = ? where id = ?").run(approved ? "published" : "declined", heldId);
// Publication is the last write, so a file reaches disk only once every database change before it has succeeded.
if (approved) publish(db, row);
console.info(`[deliverables] ${row.kind} ${heldId} ${approved ? "published" : "declined"}`);
}
function publish(db: DatabaseSync, row: HeldRow): void {
if (row.kind === "file") {
const { absolute } = resolveWorkspacePath(row.workspace_root!, row.relative_path!);
const previous = existsSync(absolute) ? readFileSync(absolute) : null;
try {
const written = writeDeliverable({ workspaceRoot: row.workspace_root!, relativePath: row.relative_path!, content: row.content });
recordWorkspaceFile(db, { orgId: row.org_id, ownerType: "agent", ownerId: row.agent_id, workspaceRoot: row.workspace_root!, relativePath: written });
} catch (error) {
// A publication that fails leaves the workspace as it was: the old file back, or none.
if (previous) writeFileSync(absolute, previous);
else rmSync(absolute, { force: true });
throw error;
}
return;
}
const documents = new DocumentService(db);
if (row.kind === "document_create") {
documents.create({
orgId: row.org_id, title: row.title!, docType: row.doc_type!, content: row.content, authorAgentId: row.agent_id,
reviewerAgentId: null, projectId: row.project_id, goalId: row.goal_id, taskId: row.task_id,
});
return;
}
const current = db.prepare("select version, status from documents where id = ? and org_id = ?").get(row.document_id, row.org_id) as { version: number; status: string } | undefined;
if (!current) throw new Error("The document this update was for has been deleted; decline the review.");
if (current.version !== row.base_version) {
throw new Error(`The document moved from v${row.base_version} to v${current.version} after this draft was held; decline the review and ask for a fresh draft.`);
}
documents.update({
orgId: row.org_id, documentId: row.document_id!, title: row.title!, content: row.content, status: current.status,
reason: row.reason!, changedByType: "agent", changedById: row.agent_id!,
});
}
/** Held work of a task or goal still waiting for review, by title; done and achieved wait for it. */
export function heldWorkTitles(db: DatabaseSync, scope: { taskId: string } | { goalId: string }): string[] {
const rows = "taskId" in scope
? db.prepare("select coalesce(title, relative_path) as name from held_deliverables where task_id = ? and state = 'held'").all(scope.taskId)
: db.prepare("select coalesce(title, relative_path) as name from held_deliverables where goal_id = ? and state = 'held'").all(scope.goalId);
return (rows as Array<{ name: string }>).map((row) => row.name);
}
+3
View File
@@ -3,6 +3,7 @@ import { RISK_LEVEL, TASK_STATUS, type TaskPriority } from "../../shared/domain"
import type { CreateTaskInput, DeleteTaskInput, UpdateTaskInput } from "../../shared/commands";
import { AuditService } from "./audit-service";
import { withSavepoint } from "../database/connection";
import { heldWorkTitles } from "./held-deliverables";
type StatusActor = { type: "system" } | { type: "agent"; id: string };
@@ -98,6 +99,8 @@ export class TaskMutations {
const assignee = task.assignee_agent_id ? (this.db.prepare("select name from agents where id = ?").get(task.assignee_agent_id) as { name: string }).name : "the CEO";
throw new Error(`Only ${assignee}, their managers or the open reviewer can change "${task.title}".`);
}
const held = input.status === TASK_STATUS.DONE ? heldWorkTitles(this.db, { taskId: task.id }) : [];
if (held.length > 0) throw new Error(`"${task.title}" has work awaiting board review (${held.join(", ")}); it is not written yet, so the task cannot be done.`);
const finishing = input.status === TASK_STATUS.DONE || input.status === TASK_STATUS.REVIEW;
if (finishing && !input.evidence) {
throw new Error('"evidence" is required to move work to review or done: say what was produced and where (file_ids, document ids, test results).');
+7 -5
View File
@@ -91,12 +91,14 @@ describe("agent document tools", () => {
h.connection.close();
});
test("in review mode an update goes to Approvals", () => {
const h = harness(true);
test("in review mode an update is held in Approvals and the document keeps its version", () => {
const h = harness(false);
const docId = /doc_id=(doc_\w+)/.exec(h.run("create_document", { title: "Policy", doc_type: "policy", content: "v1" }))![1];
expect(h.run("update_document", { doc_id: docId, content: "v2", reason: "Tighter wording" })).toContain("queued for board review");
const approvals = h.connection.db.prepare("select title from approvals where org_id = ? and kind = 'deliverable_review' order by created_at").all(h.orgId);
expect(approvals).toEqual([{ title: "Review policy: Policy" }, { title: "Review policy update: Policy" }]);
h.connection.db.prepare("update organizations set review_deliverables = 1 where id = ?").run(h.orgId);
expect(h.run("update_document", { doc_id: docId, content: "v2", reason: "Tighter wording" })).toContain("held for board review");
const approvals = h.connection.db.prepare("select title from approvals where org_id = ? and kind = 'deliverable_review'").all(h.orgId);
expect(approvals).toEqual([{ title: "Review policy update: Policy" }]);
expect(h.connection.db.prepare("select version, content from documents where id = ?").get(docId)).toEqual({ version: 1, content: "v1" });
h.connection.close();
});
});
+16
View File
@@ -117,6 +117,22 @@ describe("complete_goal with independent audit", () => {
h.connection.close();
});
test("work held for board review keeps the goal open, even when held while the audit runs", async () => {
const h = createHarness();
const hold = () => h.connection.db.prepare(`
insert into held_deliverables(id, org_id, approval_id, kind, goal_id, title, doc_type, content, state, created_at)
values (?, ?, 'app_x', 'document_create', ?, 'Launch memo', 'memo', 'draft', 'held', ?)
`).run(`hld_${randomUUID()}`, h.orgId, h.goalId, new Date().toISOString());
const auditor = async (): Promise<AuditorTurn> => {
hold();
return turnOf("<approved/>");
};
const output = await completeGoalTool(argsFor(h, h.ceoId, auditor, call({ evidence: "src/index.ts works" })));
expect(output).toBe('ERROR: Goal "Ship it" has work awaiting board review (Launch memo); it is not written yet, so the goal cannot be achieved.');
expect(goalStatus(h)).toBe("active");
h.connection.close();
});
test("no explicit approval means not achieved", async () => {
const h = createHarness();
const auditor = async (): Promise<AuditorTurn> => turnOf("Looks plausible I guess.");
+1 -1
View File
@@ -24,7 +24,7 @@ describe("domain services", () => {
const connection = createConnection();
const rows = connection.db.prepare("select version from schema_migrations order by version asc").all() as Array<{ version: number }>;
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85]);
expect(rows.map((row) => row.version)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86]);
connection.close();
});
+78 -8
View File
@@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import { mkdirSync } from "node:fs";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
@@ -71,17 +71,87 @@ function pendingApprovals(h: Harness, kind: string): Array<{ state: string; sour
}
describe("execution modes", () => {
test("AI Co-Founder mode queues every deliverable and document for board review", () => {
test("AI Co-Founder mode holds every deliverable and document until the board approves it", () => {
const h = harness("ai_cofounder");
const db = h.connection.db;
const root = h.ctx.workspace!.localPath;
const wrote = dispatchAgentTool(h.deps, h.ctx, call("write_deliverable", { path: "plan/business-plan.md", content: "# Plan" }));
expect(wrote).toContain("queued for board review");
expect(wrote).toContain("held for board review");
const doc = dispatchAgentTool(h.deps, h.ctx, call("create_document", { title: "Launch memo", doc_type: "memo", content: "Ship it." }));
expect(doc).toContain("queued for board review");
expect(doc).toContain("held for board review");
// Nothing exists for anyone to use while the reviews wait.
expect(existsSync(join(root, "plan", "business-plan.md"))).toBe(false);
expect(db.prepare("select count(*) as n from documents where org_id = ?").get(h.orgId)).toEqual({ n: 0 });
const reviews = pendingApprovals(h, "deliverable_review");
expect(reviews).toHaveLength(2);
expect(reviews.every((review) => review.state === "pending")).toBe(true);
expect(reviews.map((review) => review.source_entity_type).sort()).toEqual(["document", "file"]);
const reviews = db.prepare("select id, state, source_entity_type, details from approvals where org_id = ? and kind = 'deliverable_review' order by rowid").all(h.orgId) as Array<{ id: string; state: string; source_entity_type: string; details: string }>;
expect(reviews.map((review) => [review.state, review.source_entity_type])).toEqual([["pending", "held_deliverable"], ["pending", "held_deliverable"]]);
expect(reviews[0].details).toContain("# Plan");
expect(reviews[1].details).toContain("Ship it.");
const employeeId = (db.prepare("select id from employees where org_id = ?").get(h.orgId) as { id: string }).id;
for (const review of reviews) {
h.connection.transaction(() => new ApprovalService(db).decide({ orgId: h.orgId, approvalId: review.id, state: "approved", decidedByEmployeeId: employeeId }));
}
expect(readFileSync(join(root, "plan", "business-plan.md"), "utf8")).toBe("# Plan");
expect(db.prepare("select title, content from documents where org_id = ?").all(h.orgId)).toEqual([{ title: "Launch memo", content: "Ship it." }]);
});
test("a declined deliverable is never written, and held work keeps its task open", () => {
const h = harness("ai_cofounder");
const db = h.connection.db;
const employeeId = (db.prepare("select id from employees where org_id = ?").get(h.orgId) as { id: string }).id;
const taskId = h.connection.transaction(() => h.deps.organization.createTask({
orgId: h.orgId, title: "Write the plan", description: "d", status: "in_progress", assigneeAgentId: h.ceoId, risk: "low",
projectId: null, goalId: null, workspaceId: null, priority: TASK_PRIORITY.NORMAL, requiresFilesystem: false,
}));
const ctx = { ...h.ctx, taskId };
dispatchAgentTool(h.deps, ctx, call("write_deliverable", { path: "plan.md", content: "draft" }));
const finish = () => h.deps.organization.agentSetTaskStatus({ orgId: h.orgId, taskId, status: "done", agentId: h.ceoId, evidence: "plan.md" });
expect(finish).toThrow('"Write the plan" has work awaiting board review (plan.md); it is not written yet, so the task cannot be done.');
const review = (db.prepare("select id from approvals where org_id = ? and kind = 'deliverable_review'").get(h.orgId) as { id: string }).id;
h.connection.transaction(() => new ApprovalService(db).decide({ orgId: h.orgId, approvalId: review, state: "declined", decidedByEmployeeId: employeeId }));
expect(existsSync(join(h.ctx.workspace!.localPath, "plan.md"))).toBe(false);
expect(db.prepare("select state from held_deliverables").get()).toEqual({ state: "declined" });
finish();
});
test("an approved file whose registration fails leaves the workspace as it was", () => {
const h = harness("ai_cofounder");
const db = h.connection.db;
const root = h.ctx.workspace!.localPath;
writeFileSync(join(root, "kept.md"), "old");
dispatchAgentTool(h.deps, h.ctx, call("write_deliverable", { path: "kept.md", content: "new" }));
dispatchAgentTool(h.deps, h.ctx, call("write_deliverable", { path: "fresh.md", content: "new" }));
db.exec("create trigger registry_down before insert on file_objects begin select raise(abort, 'registry down'); end;");
const employeeId = (db.prepare("select id from employees where org_id = ?").get(h.orgId) as { id: string }).id;
for (const review of db.prepare("select id from approvals where kind = 'deliverable_review'").all() as Array<{ id: string }>) {
expect(() => h.connection.transaction(() => new ApprovalService(db).decide({ orgId: h.orgId, approvalId: review.id, state: "approved", decidedByEmployeeId: employeeId })))
.toThrow("registry down");
}
expect(readFileSync(join(root, "kept.md"), "utf8")).toBe("old");
expect(existsSync(join(root, "fresh.md"))).toBe(false);
expect(db.prepare("select state from held_deliverables order by rowid").all()).toEqual([{ state: "held" }, { state: "held" }]);
// A failing state change is caught before anything is written.
db.exec("drop trigger registry_down; create trigger held_down before update on held_deliverables begin select raise(abort, 'held store down'); end;");
const first = (db.prepare("select id from approvals where kind = 'deliverable_review' order by rowid").get() as { id: string }).id;
expect(() => h.connection.transaction(() => new ApprovalService(db).decide({ orgId: h.orgId, approvalId: first, state: "approved", decidedByEmployeeId: employeeId })))
.toThrow("held store down");
expect(readFileSync(join(root, "kept.md"), "utf8")).toBe("old");
});
test("a held document update is refused at approval if the document moved on meanwhile", () => {
const h = harness("ai_ceo");
const db = h.connection.db;
const created = dispatchAgentTool(h.deps, h.ctx, call("create_document", { title: "Memo", doc_type: "memo", content: "v1" }));
const docId = /doc_id=([^,]+)/.exec(created)![1];
db.prepare("update organizations set review_deliverables = 1 where id = ?").run(h.orgId);
expect(dispatchAgentTool(h.deps, h.ctx, call("update_document", { doc_id: docId, content: "v2 draft", reason: "tighten" }))).toContain("held for board review");
expect(db.prepare("select version, content from documents where id = ?").get(docId)).toEqual({ version: 1, content: "v1" });
db.prepare("update documents set version = 2 where id = ?").run(docId);
const employeeId = (db.prepare("select id from employees where org_id = ?").get(h.orgId) as { id: string }).id;
const review = (db.prepare("select id from approvals where org_id = ? and kind = 'deliverable_review'").get(h.orgId) as { id: string }).id;
expect(() => h.connection.transaction(() => new ApprovalService(db).decide({ orgId: h.orgId, approvalId: review, state: "approved", decidedByEmployeeId: employeeId })))
.toThrow("The document moved from v1 to v2 after this draft was held; decline the review and ask for a fresh draft.");
expect(db.prepare("select state from approvals where id = ?").get(review)).toEqual({ state: "pending" });
});
test("AI CEO mode ships deliverables without review", () => {