Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions openspec/changes/add-work-queue/proposal.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@ additive: one page, one menu entry, one relocation.

The base filter is `{"assignee": "IS NULL", "isFinalStatus": false}`.

`assignee: "IS NULL"` is the literal sentinel `MariaDbSearchHandler::applyNullCheck`
matches. The documented `assignee_isnull=true` spelling does **not** work over HTTP:
`SearchQueryHandler::cleanQuery` tests the value with `=== true`, and a query string
can only ever deliver the string `"true"`, so the operator silently degrades to
`IS NOT NULL` and the page renders empty. Verified against a live instance: 17
unassigned cases with the sentinel, 20 assigned, 2 unassigned and open.
`assignee: "IS NULL"` is the literal sentinel every OpenRegister condition builder
matches by value. Verified against a live instance: 17 unassigned cases with the
sentinel, 20 assigned, 2 unassigned and open.

The suffix spelling `assignee_isnull=true` was dead when this page shipped, and the
reason is deeper than it first looked: the only code mentioning the operator had no
production callers, and `isnull` was absent from
`MagicSearchHandler::COMPARISON_OPERATORS`, so the filter contributed no condition at
all rather than an inverted one. Fixed in openregister `isnull-filter-operator`. The
sentinel is kept here because it also works on instances that do not yet carry that
change, and the two are two spellings of one predicate.

`isFinalStatus` is a real boolean on every case row (measured: 37 of 37 carry it, none
absent), so plain equality reaches it and no derived predicate is needed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ dossiq SHALL provide a Queue page at `/queue`, an index over the `case` schema
filtered to cases with no `assignee` and `isFinalStatus` false. It SHALL sit first in
the My work group, above Assigned to me.

The base filter SHALL be `assignee: "IS NULL"` and `isFinalStatus: false`. The
`assignee_isnull=true` spelling SHALL NOT be used: OpenRegister's
`SearchQueryHandler::cleanQuery` compares the value with `=== true`, so a query string
degrades it to `IS NOT NULL` and the page renders empty with no error.
The base filter SHALL be `assignee: "IS NULL"` and `isFinalStatus: false`.
`assignee: "IS NULL"` is the literal sentinel every OpenRegister condition builder
matches by value, and it SHALL be preferred over the `assignee_isnull=true` suffix,
which was unimplemented when this page shipped and works only on instances carrying
openregister `isnull-filter-operator`.

#### Scenario: The queue holds unassigned open cases

Expand Down
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@
"route": "/queue",
"type": "index",
"title": "Queue",
"_note": "The one queue: every case that is open and that nobody has picked up. It is a FILTER over `case`, not a collection of its own, so this is a plain type:index rather than a bespoke view. `assignee: \"IS NULL\"` is the literal sentinel MariaDbSearchHandler::applyNullCheck matches; the documented `assignee_isnull=true` spelling does NOT survive a query string, because SearchQueryHandler::cleanQuery compares the value with `=== true` and degrades it to IS NOT NULL, which renders an empty page with no error. `isFinalStatus: false` keeps closed cases out; it is a real boolean on every case row, not a derived one, so plain equality reaches it. Assigning a case removes it from here and puts it on that person's Assigned to me; All cases shows it either way. The caseType folder sidebar is the same control the Cases index uses, so the queue narrows by case type without a second page. WHY THIS IS A PAGE AND NOT A `menu[].query` PRESET, which is what gate-68 (ADR-097 Decision 5) proposes for a second index over an already-indexed schema: a preset is only a link into the target page, where the query filters and the reader's own facet filters share one map, so a facet interaction can widen the queue back to every case. A base filter on the page itself cannot be cleared by the person reading it, and that is the property that makes the queue trustworthy. Assigned to me is a page for the same reason.",
"_note": "The one queue: every case that is open and that nobody has picked up. It is a FILTER over `case`, not a collection of its own, so this is a plain type:index rather than a bespoke view. `assignee: \"IS NULL\"` is the literal sentinel every OpenRegister condition builder matches by value. The suffix spelling `assignee_isnull=true` was dead when this page shipped: the only code that mentioned it had no callers, and `isnull` was missing from MagicSearchHandler::COMPARISON_OPERATORS, so the filter contributed no condition at all. Fixed in openregister `isnull-filter-operator`; the sentinel is kept because it also works on instances that do not yet carry that change. `isFinalStatus: false` keeps closed cases out; it is a real boolean on every case row, not a derived one, so plain equality reaches it. Assigning a case removes it from here and puts it on that person's Assigned to me; All cases shows it either way. The caseType folder sidebar is the same control the Cases index uses, so the queue narrows by case type without a second page. WHY THIS IS A PAGE AND NOT A `menu[].query` PRESET, which is what gate-68 (ADR-097 Decision 5) proposes for a second index over an already-indexed schema: a preset is only a link into the target page, where the query filters and the reader's own facet filters share one map, so a facet interaction can widen the queue back to every case. A base filter on the page itself cannot be cleared by the person reading it, and that is the property that makes the queue trustworthy. Assigned to me is a page for the same reason.",
"config": {
"register": "dossiq",
"schema": "case",
Expand Down
Loading