Problem
Workspace lifecycle commands acquire the filesystem lock, then WorkspaceLockStore::register_acquired() writes directly through $wpdb->insert(). On a Markdown Database / SQLite site under concurrent WP-CLI load, that insert blocks for minutes and eventually returns the generic workspace_lock_db_insert_failed 500.
DMC already owns bounded SQLite contention behavior in Storage\SqliteBusyRetry, and WorktreeInventoryRepository uses it, but the DB-visible workspace lock store does not. This makes the lifecycle control plane unavailable exactly when concurrent agents need deterministic lock behavior.
Production evidence
Installed DMC: bd6c751 / v0.51.4.
Command:
studio wp datamachine-code workspace worktree add blocks-engine release/php-transformer-0.4.7 --from=origin/trunk
Observed after 300 seconds:
Error: Failed to record workspace lock ownership in the database.
No worktree was created. git worktree list confirmed the primary and existing worktrees were unchanged.
At failure time, direct evidence showed:
- active SQLite index: 1,950,507,008 bytes
- WAL: 255,238,152 bytes
- multiple WP-CLI processes holding the DB/WAL/SHM
- unrelated
datamachine-code workspace worktree get calls stuck for 7–13 minutes
workspace worktree locks --format=json also timed out after 180 seconds
Root cause
WorkspaceLockStore::register_acquired() and release() call $wpdb->insert() / $wpdb->update() directly. They do not use DataMachineCode\Storage\SqliteBusyRetry, unlike WorktreeInventoryRepository. The resulting error also discards the contention-specific 503/retry metadata that DMC already defines.
Acceptance criteria
- DB-visible lock registration and release use the shared bounded SQLite contention primitive.
- SQLite busy/locked failures return deterministic
workspace_sqlite_lock_contention diagnostics with retry metadata rather than a generic 500.
- The filesystem lock is always released when DB registration fails.
- Add deterministic coverage for busy-then-success and exhausted contention paths.
- Verify worktree add remains fail-closed: no lifecycle mutation occurs when required lock ownership cannot be recorded.
Problem
Workspace lifecycle commands acquire the filesystem lock, then
WorkspaceLockStore::register_acquired()writes directly through$wpdb->insert(). On a Markdown Database / SQLite site under concurrent WP-CLI load, that insert blocks for minutes and eventually returns the genericworkspace_lock_db_insert_failed500.DMC already owns bounded SQLite contention behavior in
Storage\SqliteBusyRetry, andWorktreeInventoryRepositoryuses it, but the DB-visible workspace lock store does not. This makes the lifecycle control plane unavailable exactly when concurrent agents need deterministic lock behavior.Production evidence
Installed DMC:
bd6c751/ v0.51.4.Command:
Observed after 300 seconds:
No worktree was created.
git worktree listconfirmed the primary and existing worktrees were unchanged.At failure time, direct evidence showed:
datamachine-code workspace worktree getcalls stuck for 7–13 minutesworkspace worktree locks --format=jsonalso timed out after 180 secondsRoot cause
WorkspaceLockStore::register_acquired()andrelease()call$wpdb->insert()/$wpdb->update()directly. They do not useDataMachineCode\Storage\SqliteBusyRetry, unlikeWorktreeInventoryRepository. The resulting error also discards the contention-specific 503/retry metadata that DMC already defines.Acceptance criteria
workspace_sqlite_lock_contentiondiagnostics with retry metadata rather than a generic 500.