Files
turnstone/tests/test_storage_deferred_create.py
T
Patrick Buckley 480a1426b3 Fail-closed history-commit handoff (#1005)
* fix(session): fail-closed history-commit handoff (#981)

The deleted-workstream discovery is now a terminal, ws_id-keyed latch:
keyed conversation commits refuse admission once the durable parent is
gone (convergence finalizers and force-abandon are exempt), history
handoff refuses to mint a proof token so /history fails closed with a
503 instead of silently wiping the pane, and the SSE stream carries a
workstream_gone resync reason. Discarded commits leave a forensic log
of commit keys and roles, never content.

Conversation rows gain a commit_key (migration 071): keyed saves are
idempotent under retry, validated against the full commit identity, and
refused when they would cross a workstream deletion. The prune orphan
category now requires a NULL alias plus a two-hour updated grace, with
cutoffs computed at discovery time and carried into both dialects'
rechecks.

The mid-turn interjection queue is owner-partitioned with no per-site
mode flags: pops take the acting principal's and unowned rows, other
participants' rows are structurally retained, and enforcement lives at
queue admission plus the shared before_spawn gates. The retraction
ledger is bounded by open pop windows: pops open a window atomically
with the queue delete, restores close their ids atomically with the
ledger consume, every other exit closes through one helper, and misses
for unheld ids record nothing. The workstream-gone latch refuses
unattended wakes at all three gates (watcher spawn, claim, delivery
pre-pop), and the retry dispatcher regained its pre-envelope
cancel/error convergence net.

Persistence-state reporting derives through the session bound to each
UI instead of a registry lookup by id that failed open to healthy
during tombstone retention. The dashboard roster no longer re-inserts
ghost entries from trailing activity events, the history tool-outcome
scan tolerates interleaved non-turn rows, and the shared
handoff-deadline handle owns its own retirement.

Single-sourced across call sites: keyed-commit row values, attachment
save wrappers, tail-truncation and conflict-resolution bodies for both
storage dialects; worker-slot lifecycle field sets; the direct-commit
admission frame; queued-row layout accessors; the string-aware comment
stripper shared by every JS harness suite.

Refs #981 #964

* fix(session): sweep handoff fixes to their sibling surfaces

The interactive replay loop treated a system row as a tool-batch
boundary, so every tool result after an interleaved row vanished from
that pane while the coordinator rendered the same history correctly.
Only a conversational turn ends the batch window now, matching the
shared outcome index.

Accepted user turns clear the composer's attachment chips on the same
viewer policy that settles optimistic bubbles rather than on having
matched a local bubble, so a workstream created with an upload no
longer keeps a chip for an attachment the create dispatch already
consumed. The coordinator's raced-Stop arm emits the stream-end hook it
inherits alongside the idle state, leaving no unfinalized bubble or
unflushed tool output. Ending a session surfaces a failure toast when
the request never lands or answers with a non-JSON body.

The per-second persistence reconcile now probes each session without
blocking: a workstream whose generation and handoff locks are held is
skipped until the next pass instead of contending the locks every
commit needs. The one-shot repair that gates workstream creation at
capacity keeps a definite probe — it has no next pass, and the sessions
likeliest to be contended are the ones whose unresolved journals
emptied its candidate list.

Single-sourced: the attachment lane builds its conversation row through
the shared commit-identity builder; the ordinary worker exit releases
its slot through the lifecycle owner; both operator surfaces snapshot
their counters through one non-consuming helper; the replay preamble
loses its per-kind wrappers and its config hook; the browser harness
suites share one brace walker; and each in-flight history attempt is
one record carrying both its abort controller and its deadline.

Refs #981 #964
2026-08-11 04:18:36 -07:00

681 lines
24 KiB
Python

"""Backend and manager regressions for durable deferred-create publication."""
from __future__ import annotations
from contextlib import nullcontext
from typing import Any
import pytest
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from tests.test_session_manager import FakeAdapter
from turnstone.core.session_manager import SessionManager
from turnstone.core.storage import ForkCloneExpectation, ForkDestinationConflictError
from turnstone.core.storage._postgresql import PostgreSQLBackend
from turnstone.core.storage._protocol import FORK_RESERVATION_CONFIG_KEY
from turnstone.core.storage._schema import workstream_config, workstreams
def _row_ids(rows: list[Any]) -> set[str]:
return {str(row._mapping["ws_id"] if hasattr(row, "_mapping") else row[0]) for row in rows}
def _raw_config(backend: Any, ws_id: str) -> dict[str, str]:
with backend._conn() as conn:
rows = conn.execute(
sa.select(workstream_config.c.key, workstream_config.c.value).where(
workstream_config.c.ws_id == ws_id
)
).all()
return {str(key): str(value) for key, value in rows}
def _force_updated(backend: Any, ws_ids: list[str], updated: str) -> None:
with backend._engine.connect() as conn:
conn.execute(
sa.update(workstreams).where(workstreams.c.ws_id.in_(ws_ids)).values(updated=updated)
)
conn.commit()
class _UnknownRowcountResult:
"""Successful PostgreSQL DML result from a driver without sane rowcount."""
rowcount = -1
def __init__(
self,
*,
row: tuple[Any, ...] | None = None,
rows: list[tuple[Any, ...]] | None = None,
) -> None:
self._row = row
self._rows = rows or []
def fetchone(self) -> tuple[Any, ...] | None:
return self._row
def fetchall(self) -> list[tuple[Any, ...]]:
return self._rows
class _ScriptedPostgresConnection:
def __init__(self, *results: _UnknownRowcountResult) -> None:
self._results = list(results)
self.statements: list[Any] = []
self.commits = 0
self.rollbacks = 0
def execute(self, statement: Any, *_args: Any, **_kwargs: Any) -> _UnknownRowcountResult:
self.statements.append(statement)
if not self._results:
raise AssertionError("unexpected PostgreSQL execute")
return self._results.pop(0)
def commit(self) -> None:
self.commits += 1
def rollback(self) -> None:
self.rollbacks += 1
def assert_consumed(self) -> None:
assert self._results == []
def _scripted_postgres_backend(
*results: _UnknownRowcountResult,
) -> tuple[PostgreSQLBackend, _ScriptedPostgresConnection]:
backend = PostgreSQLBackend.__new__(PostgreSQLBackend)
conn = _ScriptedPostgresConnection(*results)
backend._conn = lambda: nullcontext(conn) # type: ignore[method-assign]
return backend, conn
def _register_creating(
backend: Any,
ws_id: str,
token: str,
*,
alias: str | None = None,
) -> None:
assert (
backend.register_workstream(
ws_id,
node_id="node-a",
name="hidden create",
state="creating",
user_id="alice",
alias=alias,
kind="interactive",
fork_reservation_token=token,
)
is True
)
def _seed_visible_and_creating(backend: Any) -> tuple[str, str, str]:
visible_id = "visible-row-1234"
creating_id = "creating-row-5678"
token = "history-incarnation"
assert (
backend.register_workstream(
visible_id,
node_id="node-a",
name="published control",
state="idle",
user_id="alice",
kind="interactive",
)
is True
)
_register_creating(backend, creating_id, token)
backend.save_message(visible_id, "user", "deferredvisibilityneedle published")
backend.save_message(creating_id, "user", "deferredvisibilityneedle hidden")
return visible_id, creating_id, token
def test_creating_row_is_hidden_from_ordinary_storage_discovery(storage_backend: Any) -> None:
backend = storage_backend
ws_id = "creating-row-1234"
token = "creating-incarnation"
_register_creating(backend, ws_id, token, alias="hidden-alias")
backend.save_message(ws_id, "user", "history must not make this visible")
# Raw identity reads remain available to reservation owners and cleanup.
raw = backend.get_workstream(ws_id)
assert raw is not None
assert raw["state"] == "creating"
assert "fork_reservation_token" not in raw
assert backend.load_workstream_config(ws_id) == {}
assert backend.get_workstream_reservation_token(ws_id) == token
assert _raw_config(backend, ws_id) == {FORK_RESERVATION_CONFIG_KEY: token}
# User-facing discovery never exposes a half-constructed durable row,
# even when it already has an alias and conversation history.
assert ws_id not in _row_ids(backend.list_workstreams(user_id="alice"))
assert ws_id not in _row_ids(backend.list_workstreams_with_history(user_id="alice"))
assert backend.resolve_workstream(ws_id) is None
assert backend.resolve_workstream("creating-row") is None
assert backend.resolve_workstream("hidden-alias") is None
def test_stale_creating_reaper_hard_deletes_dependents_and_attachment_refs(
storage_backend: Any,
) -> None:
backend = storage_backend
ws_id = "abandoned-create-1234"
token = "abandoned-incarnation"
attachment_id = "a" * 64
_register_creating(backend, ws_id, token)
message_id = backend.save_message(ws_id, "user", "private cloned content")
backend.save_attachment(
attachment_id,
"private.txt",
"text/plain",
7,
"text",
b"private",
)
backend.set_message_attachments(ws_id, message_id, [attachment_id])
assert backend.finalize_deferred_create(
ws_id,
token,
alias="reclaimable-alias",
config={"model_alias": "private-model"},
node_id="stable-node",
)
_force_updated(backend, [ws_id], "2020-01-01T00:00:00")
deleted = backend.delete_stale_creating_reservations(
"interactive",
"2024-01-01T00:00:00",
[],
live_node_ids=["stable-node"],
local_node_id="stable-node",
)
assert deleted == [ws_id]
assert backend.get_workstream(ws_id) is None
assert backend.load_message_turns(ws_id) == []
assert _raw_config(backend, ws_id) == {}
assert backend.get_attachment(attachment_id) is None
assert ws_id not in {row["ws_id"] for row in backend.list_workstream_overrides()}
assert (
backend.register_workstream(
ws_id,
alias="reclaimable-alias",
state="idle",
kind="interactive",
)
is True
)
def test_stale_creating_reaper_fences_state_age_owner_token_and_loaded_ids(
storage_backend: Any,
caplog: pytest.LogCaptureFixture,
) -> None:
backend = storage_backend
stale_ids = [
"same-node-abandoned",
"same-node-loaded",
"dead-peer-abandoned",
"live-peer-protected",
"published-protected",
"tokenless-protected",
]
for ws_id, node_id, token in [
("same-node-abandoned", "stable-node", "same-token"),
("same-node-loaded", "stable-node", "loaded-token"),
("dead-peer-abandoned", "dead-peer", "dead-token"),
("live-peer-protected", "live-peer", "live-token"),
("published-protected", "dead-peer", "published-token"),
("tokenless-protected", "dead-peer", ""),
]:
assert (
backend.register_workstream(
ws_id,
node_id=node_id,
state="creating",
kind="interactive",
fork_reservation_token=token,
)
is True
)
assert backend.publish_deferred_create("published-protected", "published-token") is True
_force_updated(backend, stale_ids, "2020-01-01T00:00:00")
_register_creating(backend, "fresh-protected", "fresh-token")
deleted = backend.delete_stale_creating_reservations(
"interactive",
"2024-01-01T00:00:00",
["same-node-loaded"],
live_node_ids=["stable-node", "live-peer"],
local_node_id="stable-node",
)
assert set(deleted) == {
"same-node-abandoned",
"dead-peer-abandoned",
"tokenless-protected",
}
assert "storage.stale_create_tokenless_reaped" in caplog.text
for ws_id in [
"same-node-loaded",
"live-peer-protected",
"published-protected",
"fresh-protected",
]:
assert backend.get_workstream(ws_id) is not None
assert backend.get_workstream("published-protected")["state"] == "idle"
# The public protocol requires an authoritative liveness result. Backends
# still fail closed if a non-conforming caller passes uncertainty through.
assert (
backend.delete_stale_creating_reservations(
"interactive",
"2024-01-01T00:00:00",
[],
live_node_ids=None, # type: ignore[arg-type]
local_node_id="stable-node",
)
== []
)
def test_retention_prune_leaves_stale_creating_for_complete_reaper(
storage_backend: Any,
) -> None:
backend = storage_backend
ws_id = "creating-owned-by-reaper"
_register_creating(backend, ws_id, "retention-incarnation")
backend.save_message(ws_id, "user", "cloned history with dependent data")
_force_updated(backend, [ws_id], "2020-01-01T00:00:00")
orphans, stale = backend.prune_workstreams(retention_days=30)
assert (orphans, stale) == (0, 0)
row = backend.get_workstream(ws_id)
assert row is not None
assert row["state"] == "creating"
def test_history_child_count_excludes_creating_until_publication(storage_backend: Any) -> None:
backend = storage_backend
parent_id = "published-parent-1234"
child_id = "creating-child-1234"
token = "child-incarnation"
assert (
backend.register_workstream(
parent_id,
name="published parent",
state="idle",
user_id="alice",
kind="coordinator",
)
is True
)
backend.save_message(parent_id, "user", "make the parent listable")
assert (
backend.register_workstream(
child_id,
name="hidden child",
state="creating",
user_id="alice",
kind="interactive",
parent_ws_id=parent_id,
fork_reservation_token=token,
)
is True
)
rows = backend.list_workstreams_with_history(kind="coordinator", user_id="alice")
assert len(rows) == 1
assert rows[0][0] == parent_id
assert rows[0][12] == 0
assert backend.publish_deferred_create(child_id, token) is True
rows = backend.list_workstreams_with_history(kind="coordinator", user_id="alice")
assert len(rows) == 1
assert rows[0][0] == parent_id
assert rows[0][12] == 1
def test_history_apis_exclude_creating_until_publication(storage_backend: Any) -> None:
backend = storage_backend
visible_id, creating_id, token = _seed_visible_and_creating(backend)
assert _row_ids(backend.list_workstreams_with_history(user_id="alice")) == {visible_id}
assert {str(row[1]) for row in backend.search_history("deferredvisibilityneedle")} == {
visible_id
}
assert {str(row[1]) for row in backend.search_history_recent(limit=20)} == {visible_id}
assert backend.publish_deferred_create(creating_id, token) is True
expected = {visible_id, creating_id}
assert _row_ids(backend.list_workstreams_with_history(user_id="alice")) == expected
assert {str(row[1]) for row in backend.search_history("deferredvisibilityneedle")} == expected
assert {str(row[1]) for row in backend.search_history_recent(limit=20)} == expected
def test_workstream_counts_exclude_creating_until_publication(storage_backend: Any) -> None:
backend = storage_backend
_visible_id, creating_id, token = _seed_visible_and_creating(backend)
since = "1970-01-01T00:00:00"
assert backend.count_workstreams_by_state(user_id="alice") == {"idle": 1}
assert backend.count_workstreams_since(since, user_id="alice") == 1
assert backend.publish_deferred_create(creating_id, token) is True
assert backend.count_workstreams_by_state(user_id="alice") == {"idle": 2}
assert backend.count_workstreams_since(since, user_id="alice") == 2
def test_publish_deferred_create_is_exact_token_cas_and_exposes_idle_row(
storage_backend: Any,
) -> None:
backend = storage_backend
ws_id = "publish-row-1234"
token = "publish-incarnation"
_register_creating(backend, ws_id, token, alias="published-alias")
backend.save_message(ws_id, "user", "visible only after publication")
before = backend.get_workstream(ws_id)
before_config = _raw_config(backend, ws_id)
assert backend.publish_deferred_create(ws_id, "wrong-incarnation") is False
assert backend.get_workstream(ws_id) == before
assert backend.get_workstream_reservation_token(ws_id) == token
assert _raw_config(backend, ws_id) == before_config
assert backend.resolve_workstream(ws_id) is None
assert backend.publish_deferred_create(ws_id, token) is True
published = backend.get_workstream(ws_id)
assert published is not None
assert published["state"] == "idle"
# Publication consumes the creating marker, not the private incarnation
# fence. Rollback and clone authorization still compare this exact token.
assert backend.get_workstream_reservation_token(ws_id) == token
assert _raw_config(backend, ws_id) == {FORK_RESERVATION_CONFIG_KEY: token}
assert ws_id in _row_ids(backend.list_workstreams(user_id="alice"))
assert ws_id in _row_ids(backend.list_workstreams_with_history(user_id="alice"))
assert backend.resolve_workstream(ws_id) == ws_id
assert backend.resolve_workstream("published-alias") == ws_id
# State is part of the CAS. A duplicate publication is a refusal and must
# leave the already-visible incarnation unchanged.
published_config = _raw_config(backend, ws_id)
assert backend.publish_deferred_create(ws_id, token) is False
assert backend.get_workstream(ws_id) == published
assert _raw_config(backend, ws_id) == published_config
def test_published_destination_cannot_reuse_retained_token_for_clone(
storage_backend: Any,
) -> None:
backend = storage_backend
token = "destination-incarnation"
assert backend.register_workstream("source", user_id="alice", kind="interactive") is True
backend.save_message("source", "user", "must not copy after publication")
source_snapshot = backend.ensure_workstream_incarnation_snapshot("source")
assert source_snapshot is not None
_register_creating(backend, "destination", token)
assert backend.publish_deferred_create("destination", token) is True
expectation = ForkCloneExpectation(
persona_config=(),
project_id="",
project_name="",
project_writable=False,
destination_reservation_token=token,
source_reservation_token=source_snapshot["fork_reservation_token"],
)
with pytest.raises(ForkDestinationConflictError, match="destination is not available"):
backend.clone_workstream(
"source",
"destination",
principal_id="alice",
expected_session=expectation,
)
destination = backend.get_workstream("destination")
assert destination is not None
assert destination["state"] == "idle"
assert backend.load_message_turns("destination") == []
assert backend.get_workstream_reservation_token("destination") == token
assert _raw_config(backend, "destination") == {FORK_RESERVATION_CONFIG_KEY: token}
def test_other_manager_cannot_open_until_exact_create_publication(storage_backend: Any) -> None:
backend = storage_backend
creator_adapter = FakeAdapter()
observer_adapter = FakeAdapter()
state_at_emit: list[str | None] = []
original_emit_created = creator_adapter.emit_created
def _record_durable_state_at_emit(ws: Any) -> None:
row = backend.get_workstream(ws.id)
state_at_emit.append(None if row is None else str(row["state"]))
original_emit_created(ws)
creator_adapter.emit_created = _record_durable_state_at_emit # type: ignore[method-assign]
creator = SessionManager(
creator_adapter,
storage=backend,
max_active=2,
node_id="creator-node",
event_emitter=creator_adapter,
)
observer = SessionManager(
observer_adapter,
storage=backend,
max_active=2,
node_id="observer-node",
event_emitter=observer_adapter,
)
ws_id = "manager-publication-1234"
pending = creator.create(
ws_id=ws_id,
user_id="alice",
name="manager publication",
defer_emit_created=True,
)
token = pending._fork_reservation_token
assert token
raw = backend.get_workstream(ws_id)
assert raw is not None
assert raw["state"] == "creating"
assert observer.open(ws_id) is None
assert observer_adapter.events == []
assert creator.commit_create(pending) is True
assert state_at_emit == ["idle"]
published = backend.get_workstream(ws_id)
assert published is not None
assert published["state"] == "idle"
assert _raw_config(backend, ws_id)[FORK_RESERVATION_CONFIG_KEY] == token
reopened = observer.open(ws_id)
assert reopened is not None
assert reopened.id == ws_id
assert [event.kind for event in observer_adapter.events] == ["rehydrated"]
def test_postgresql_register_uses_returning_when_driver_rowcount_is_unknown() -> None:
"""A successful insert is not a collision merely because rowcount is -1."""
ws_id = "postgres-register-returning"
token = "postgres-register-incarnation"
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(row=(ws_id,)),
_UnknownRowcountResult(),
)
assert (
backend.register_workstream(
ws_id,
state="creating",
fork_reservation_token=token,
)
is True
)
conn.assert_consumed()
assert conn.commits == 1
assert conn.rollbacks == 0
def test_postgresql_publish_uses_returning_when_driver_rowcount_is_unknown() -> None:
"""A successful creating-to-idle CAS is recognized through RETURNING."""
ws_id = "postgres-publish-returning"
token = "postgres-publish-incarnation"
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(row=("creating",)),
_UnknownRowcountResult(row=(token,)),
_UnknownRowcountResult(row=(ws_id,)),
)
assert backend.publish_deferred_create(ws_id, token) is True
conn.assert_consumed()
assert conn.commits == 1
assert conn.rollbacks == 0
def test_postgresql_conditional_delete_uses_returning_when_rowcount_is_unknown() -> None:
"""Exact-token deletion recognizes a successful final DELETE via RETURNING."""
ws_id = "postgres-delete-returning"
token = "postgres-delete-incarnation"
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(row=(ws_id,)),
_UnknownRowcountResult(row=(token,)),
_UnknownRowcountResult(rows=[]),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(row=(ws_id,)),
)
assert backend.delete_workstream_if_fork_reserved(ws_id, token) is True
conn.assert_consumed()
assert conn.commits == 1
assert conn.rollbacks == 0
def test_postgresql_stale_creating_reaper_locks_state_age_and_exact_incarnation() -> None:
ws_id = "postgres-stale-create"
token = "postgres-stale-incarnation"
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(rows=[(ws_id,)]),
_UnknownRowcountResult(row=(token,)),
_UnknownRowcountResult(row=(ws_id,)),
_UnknownRowcountResult(rows=[]),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(row=(ws_id,)),
)
assert backend.delete_stale_creating_reservations(
"interactive",
"2024-01-01T00:00:00",
[],
live_node_ids=["stable-node", "live-peer"],
local_node_id="stable-node",
) == [ws_id]
conn.assert_consumed()
assert conn.commits == 1
assert conn.rollbacks == 0
candidate_sql = str(conn.statements[0].compile(dialect=postgresql.dialect())).lower()
assert "workstreams.state" in candidate_sql
assert "workstreams.updated" in candidate_sql
assert "for update skip locked" in candidate_sql
token_sql = str(conn.statements[1].compile(dialect=postgresql.dialect())).lower()
assert "workstream_config" in token_sql
assert "for update" in token_sql
exact_sql = str(conn.statements[2].compile(dialect=postgresql.dialect())).lower()
assert "workstreams.state" in exact_sql
assert "workstreams.updated" in exact_sql
assert "workstream_config.value" in exact_sql
def test_postgresql_stale_creating_reaper_recovers_tokenless_locked_row(
caplog: pytest.LogCaptureFixture,
) -> None:
ws_id = "postgres-tokenless-stale-create"
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(rows=[(ws_id,)]),
_UnknownRowcountResult(),
_UnknownRowcountResult(row=(ws_id,)),
_UnknownRowcountResult(rows=[]),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(),
_UnknownRowcountResult(row=(ws_id,)),
)
assert backend.delete_stale_creating_reservations(
"interactive",
"2024-01-01T00:00:00",
[],
live_node_ids=[],
local_node_id="stable-node",
) == [ws_id]
conn.assert_consumed()
assert conn.commits == 1
exact_sql = str(conn.statements[2].compile(dialect=postgresql.dialect())).lower()
assert "workstreams.state" in exact_sql
assert "workstreams.updated" in exact_sql
assert "workstream_config.value" not in exact_sql
assert "storage.stale_create_tokenless_reaped" in caplog.text
def test_postgresql_retention_prune_excludes_creating_rows() -> None:
"""Both candidate discoveries exclude provisional rows, and take no locks.
Discovery moved out of the deleting transaction when prune became one
bounded transaction per candidate: it is a plain read now, with no
``FOR UPDATE SKIP LOCKED`` and nothing to commit. That lock rides each
candidate's own transaction instead — see
``test_postgresql_prune_candidate_locks_rechecks_and_commits_alone`` in
tests/test_storage_prune_commit_races.py. The predicates themselves are
unchanged, which is what this test pins.
"""
backend, conn = _scripted_postgres_backend(
_UnknownRowcountResult(rows=[]),
_UnknownRowcountResult(rows=[]),
)
assert backend.prune_workstreams(retention_days=30) == (0, 0)
conn.assert_consumed()
assert conn.commits == 0
orphan_select_sql = str(
conn.statements[0].compile(
dialect=postgresql.dialect(),
compile_kwargs={"literal_binds": True},
)
).lower()
stale_select_sql = str(
conn.statements[1].compile(
dialect=postgresql.dialect(),
compile_kwargs={"literal_binds": True},
)
).lower()
for candidate_sql in (orphan_select_sql, stale_select_sql):
assert "workstreams.state" in candidate_sql
assert "creating" in candidate_sql
assert "for update" not in candidate_sql
assert "not (exists" in orphan_select_sql
# Round-3 review guards: the orphan category excludes named workstreams
# (explicit user intent) and rows younger than the grace (a user
# mid-first-turn whose rows may still be journal-held on another node).
assert "workstreams.alias is null" in orphan_select_sql
assert "workstreams.updated" in orphan_select_sql
assert "workstreams.updated" in stale_select_sql