Skip to content

Allow one THOTH process per local workspace; repeated state changes write nothing - #14

Merged
hyperdrivebeep merged 1 commit into
mainfrom
public-20261018
Oct 18, 2026
Merged

hyperdrivebeep merged 1 commit into
mainfrom
public-20261018

Conversation

@hyperdrivebeep

Copy link
Copy Markdown
Owner

Two THOTH processes writing the same workspace could create duplicate
record versions. Opening a local workspace's database now takes an
exclusive lock on /runtime.lock before any migration or
startup work. The operating system releases it when the process ends,
however it ends, so a leftover file never blocks a restart. Runtimes
inside one process share the lock.

  • serve and desktop take the lock before listening, so a second server
    is refused at start; a server started without the CLI answers 503
    WORKSPACE_IN_USE on its first request.
  • shell, run, rpc, events and run-pack are refused with one Korean and
    one English line and exit code 3. Commands that do not open the
    database (workspace, doctor, source-stage, git-snapshot, auth-*) still
    run next to a running THOTH.
  • The process id and path in the refusal come from a hint in the lock
    file and are never stored. A refused start writes nothing to the
    first workspace.
  • Hosted review mode is not locked. Shared, synced and network folders
    are outside this protection (docs/KNOWN_LIMITATIONS.md).

Repeating a state change that is already in effect now answers with the
current state (unchanged=true and a reason) and writes no new record and
no notification. Before, each repeat with a new request key wrote
another revision and another notification.

  • Threads: pause, resume and stop. Investigations: pause and stop; a
    stop on an ended investigation no longer overwrites CONVERGED with
    STOPPED.
  • Closure decide and reopen, legacy baseline approval of the current
    baseline, and a repeated authorization vote while it is pending.
  • Research pause and resume. A resume is treated as a repeat only while
    the attempt is running under a lease whose worker is confirmed alive;
    a dead, unknown or expired worker still takes the recovery path.
  • A different decision, scope or request is still recorded as before.

Tests pin the behavior before and after both changes, and how a request
behaves when its process is killed mid-command (it stays RUNNING for the
same key and nothing is written twice).

Verification: the full local check (Python 5120 tests, web tests, lint,
typecheck, build, architecture and module budget, README smoke) passed
except one browser rendering test that fails only under heavy machine
load. Its cause is pre-existing and unrelated to this change: closing the
headless browser can exceed a 2 second limit and discard an already
captured page. That fix follows separately. The test passes when rerun.

…rite nothing

Two THOTH processes writing the same workspace could create duplicate
record versions. Opening a local workspace's database now takes an
exclusive lock on <workspace>/runtime.lock before any migration or
startup work. The operating system releases it when the process ends,
however it ends, so a leftover file never blocks a restart. Runtimes
inside one process share the lock.

- serve and desktop take the lock before listening, so a second server
  is refused at start; a server started without the CLI answers 503
  WORKSPACE_IN_USE on its first request.
- shell, run, rpc, events and run-pack are refused with one Korean and
  one English line and exit code 3. Commands that do not open the
  database (workspace, doctor, source-stage, git-snapshot, auth-*) still
  run next to a running THOTH.
- The process id and path in the refusal come from a hint in the lock
  file and are never stored. A refused start writes nothing to the
  first workspace.
- Hosted review mode is not locked. Shared, synced and network folders
  are outside this protection (docs/KNOWN_LIMITATIONS.md).

Repeating a state change that is already in effect now answers with the
current state (unchanged=true and a reason) and writes no new record and
no notification. Before, each repeat with a new request key wrote
another revision and another notification.

- Threads: pause, resume and stop. Investigations: pause and stop; a
  stop on an ended investigation no longer overwrites CONVERGED with
  STOPPED.
- Closure decide and reopen, legacy baseline approval of the current
  baseline, and a repeated authorization vote while it is pending.
- Research pause and resume. A resume is treated as a repeat only while
  the attempt is running under a lease whose worker is confirmed alive;
  a dead, unknown or expired worker still takes the recovery path.
- A different decision, scope or request is still recorded as before.

Tests pin the behavior before and after both changes, and how a request
behaves when its process is killed mid-command (it stays RUNNING for the
same key and nothing is written twice).

Verification: the full local check (Python 5120 tests, web tests, lint,
typecheck, build, architecture and module budget, README smoke) passed
except one browser rendering test that fails only under heavy machine
load. Its cause is pre-existing and unrelated to this change: closing the
headless browser can exceed a 2 second limit and discard an already
captured page. That fix follows separately. The test passes when rerun.
@hyperdrivebeep
hyperdrivebeep merged commit 5d4d263 into main Oct 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant