From f10bfca9d970af340c3a71094b32cbdfd80b03d7 Mon Sep 17 00:00:00 2001 From: Rohit C Prasad Date: Sun, 16 Aug 2026 18:20:44 -0700 Subject: [PATCH] Workers see the claimable pool (drill-caught) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Worker list_items was slice-only, so an unassigned external worker saw an empty board — a pull queue nobody can see. Open+unassigned items are now visible to workers while claims are open; hidden again under lead-only. --- coworker/teams/store.py | 16 +++++++++++++++- tests/test_team_board.py | 5 +++++ tests/test_team_open_surface.py | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/coworker/teams/store.py b/coworker/teams/store.py index d8fe935b..af0e8b1f 100644 --- a/coworker/teams/store.py +++ b/coworker/teams/store.py @@ -495,7 +495,21 @@ class TeamStore: items = [_row_to_item(row) for row in rows] if actor.role == Role.WORKER: visible = self._worker_slice(space, actor.id) - items = [item for item in items if item["id"] in visible] + # On an open-claims board the claimable pool is visible too — a + # pull queue nobody can see is not a queue (drill-caught: an + # external worker with no assignment saw an empty board). Under + # lead-only policy workers can't act on it, so it stays hidden. + claims_open = self.policy(space)["claims"] == "open" + items = [ + item + for item in items + if item["id"] in visible + or ( + claims_open + and item["state"] == ItemState.OPEN.value + and not item["assignee"] + ) + ] for item in items: item["links"] = self._links_of(space, item["id"]) return items diff --git a/tests/test_team_board.py b/tests/test_team_board.py index abcd1c56..42ce7e2d 100644 --- a/tests/test_team_board.py +++ b/tests/test_team_board.py @@ -47,6 +47,11 @@ def test_workers_file_items_open_and_unassigned(store): assert filed["id"] in visible with pytest.raises(AuthorityError): store.assign(SPACE, WORKER, filed["id"], "worker-1") + # open + unassigned = claimable, so OTHER sees it in the pool (open-claims + # default); under lead-only policy the strict slice rule returns + other_worker = {item["id"] for item in store.list_items(SPACE, OTHER)} + assert filed["id"] in other_worker + store.set_policy(SPACE, LEAD, claims="lead-only") other_worker = {item["id"] for item in store.list_items(SPACE, OTHER)} assert filed["id"] not in other_worker diff --git a/tests/test_team_open_surface.py b/tests/test_team_open_surface.py index 4246bc6f..04a36d91 100644 --- a/tests/test_team_open_surface.py +++ b/tests/test_team_open_surface.py @@ -102,6 +102,27 @@ def test_claim_feeds_journal_grants_like_assignment(store): assert "case-alpha" in store.journal.cases(NIA) +def test_workers_see_the_claimable_pool(store): + """A pull queue nobody can see is not a queue (drill-caught 2026-08-16): + an unassigned worker must be able to DISCOVER open items to claim them.""" + item = seed(store) + mine = store.create_item("proj", NIA, title="Mine", criteria="c") + # WEBB sees every open unassigned item — including NIA's filing (claimable) + assert {i["id"] for i in store.list_items("proj", WEBB)} == { + item["id"], + mine["id"], + } + # …but only while claims are open; under lead-only the slice rule stands + store.set_policy("proj", LEAD, claims="lead-only") + assert store.list_items("proj", WEBB) == [] + # own filings stay visible regardless of policy + assert {i["id"] for i in store.list_items("proj", NIA)} == {mine["id"]} + # a claimed item leaves the pool for everyone else + store.set_policy("proj", LEAD, claims="open") + store.claim("proj", NIA, item["id"]) + assert {i["id"] for i in store.list_items("proj", WEBB)} == {mine["id"]} + + # ------------------------------------------------------------------ dialects