Rewrite resolveWorkspace to per-task lockMode inference; drop company_fallback silent share (B4-adjacent)
Old resolver: task → agent → project → any company workspace, all
marked exclusive. That fourth step folded every runnable agent in a
multi-agent company onto a single workspace row and serialised the
C-suite (four agents, one exclusive lock, three starved).
New resolver: lockMode='exclusive' is now an opt-in decision inferred
per task. Three rules:
1. task.workspaceId set → exclusive on that workspace (explicit).
2. filesystem signal (task.requiresFilesystem OR agent in a
coding role/engineering department) → exclusive on
agent.workspaceId / project primary; throws if neither exists.
3. otherwise → none / null. Pure cognitive work runs with no
workspace lock and fully in parallel.
Removed:
- company_fallback silent-share path. Filesystem-touching runs
with no legitimate binding now throw WorkspaceConfigurationError
at resolve time so the caller decides recovery rather than the
resolver picking a random shared workspace.
- workspacesMod.getAnyCompanyWorkspace (now dead code).
Invariants now enforced by types:
- lockMode='exclusive' ⇒ workspace is a live WorkspaceRecord.
- lockMode='none' ⇒ workspace is null.
Tests updated to cover the new decision table and the four-non-
coding-agents parallel case that was the original bug.
This commit is contained in:
1 parent
7829acc7f0
commit
28cdf7c56f
4 files changed
+252
-80
No files matched your search
@@ -68,15 +68,6 @@ export function buildWorkspaceMethods(
|
||||
return rows.map((r) => r.localPath).filter(Boolean);
|
||||
},
|
||||
|
||||
getAnyCompanyWorkspace(companyId: string): WorkspaceRecord | null {
|
||||
const row = getDb()
|
||||
.prepare(
|
||||
"select id, company_id as companyId, name, local_path as localPath, repo_url as repoUrl, repo_ref as repoRef, project_id as projectId, state, is_primary as isPrimary, created_at as createdAt, updated_at as updatedAt from workspaces where company_id = ? order by is_primary desc, created_at asc limit 1",
|
||||
)
|
||||
.get(companyId) as WorkspaceRecord | undefined;
|
||||
return row ? { ...row, isPrimary: toBoolean(row.isPrimary) } : null;
|
||||
},
|
||||
|
||||
deleteWorkspace(id: string, companyId: string) {
|
||||
transaction(() => {
|
||||
getDb().prepare("update agents set workspace_id = null where workspace_id = ? and company_id = ?").run(id, companyId);
|
||||
|
||||
Reference in new issue
Block a user