Skip to content

Workspace lock ownership writes bypass SQLite contention handling #955

Description

@chubes4

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions