Skip to content

feat: the people filter answers in two tiers, and the bar fits on one row - #309

Merged
Sawtaytoes merged 3 commits into
mainfrom
queue-filter-sections
Sep 5, 2026
Merged

feat: the people filter answers in two tiers, and the bar fits on one row#309
Sawtaytoes merged 3 commits into
mainfrom
queue-filter-sections

Conversation

@Sawtaytoes

@Sawtaytoes Sawtaytoes commented Sep 5, 2026

Copy link
Copy Markdown
Owner

What changes

Two things, both from the same report: the people filter answered with one word when it needed
two, and the bar it lives on had grown to three rows.

1. The filter answers in two tiers

Ticking one person now finds the queues that person is on, not only the queues that need
nobody else.

  • Exact — every ticked person is on the queue, and every required person is ticked. This is
    the rule that shipped on 2026-08-26, unchanged, and it is still the rule the SERVER picks on.
  • Also in — every ticked person is on the queue, but the queue also wants somebody who is
    not ticked. Drawn under a rule that names who, up to three people then a count.

A queue where a ticked person is not on the roster at all is still not shown. That is the one
thing the second tier does not relax.

Chip counts cover both tiers. Counting only exact matches is why somebody who never has a queue
to herself read 0 while her queues were plainly on the screen under Anyone.

2. The bar is quick picks plus a dropdown

  • The first four of the roster are chips, plus every ticked person wherever they sit.
    The rest go behind one + N more — a Charcuterie Combobox isMultiple with a search field.
  • The provider filter is a multi-select (?only= is a comma list) and its pills sit on the
    right of the same row. Every address the single-select era wrote still parses.
  • A person the selection shares no queue with is not offered: the chip disappears, the
    dropdown row is disabled. A ticked person is never hidden either way — clicking a ticked
    chip is the way out of a selection that shows nothing.

Before / after

The bar, unfiltered, nine people. Three rows become one.

Before After
before after

?people=sven — Sven is on four queues and has none of her own. Before: one card, and her
chip says 1. After: the exact match, a rule, and the four queues she is on.

Before After
before after

?people=grace,linus — the queue that names exactly those two is an exact match; the family
queue that also wants the adults is under the rule.

twokids

?people=omar — Omar shares no queue with Hedy, Alan or Priya, so their rows are disabled
and their chips are gone. Nadia is on shorts with him and stays live.

deadend

Narrow View, 390px. Wraps, does not pan.

narrow

Two things that bite

  • The dead-end test cannot be a count of zero. A queue nobody is filed on passes every
    people filter — that is the 2026-08-26 rule and it is right — so the count for two people who
    share nothing is however many unfiled queues the house owns, which is at least one. The test
    is hasQueueFor, which asks only about queues that carry a roster. A count-based test would
    never have fired once.
  • and do not render in this app. Both are outside the Latin subset of Outfit that
    vite.config.ts preloads, and ⚙ Edit people had been painting a tofu box on the live
    landing. Both are inline SVGs now.

Checks

  • yarn workspace queuepilot-web test — 24 files, 344 tests, all pass (11 new).
  • tsc --noEmit clean in web/ and e2e/. biome check adds no finding; the 74 warnings are
    pre-existing useExhaustiveDependencies in files this branch does not touch.
  • e2e/shot-queue-filter.ts run on main and on the branch. It prints what it measured:
    3 rows → 1 row, ?people=sven 1 shelf and no rule → 6 rows with a rule.

Screenshots are fixture data

The cast is the landing fixture's Ada, Grace and Linus plus six invented people the harness
adds — Sven, Hedy, Alan, Nadia, Omar and Priya. Nine, because a filter that does not scale
cannot be shown with three. AGENTS.md names them so the next harness reuses them.

Decisions

  • docs/decisions/2026-09-05-the-people-filter-answers-in-two-tiers-exact-then-also-in.md
  • docs/decisions/2026-09-05-the-filter-bar-is-quick-picks-plus-a-dropdown-and-a-dead-end-is-not-offered.md

🤖 Generated with Claude Code

Ticking one person now finds the queues that person is on, not only the
queues that need nobody else. The strict rule is unchanged and is still
what `exact` means; the queues it used to DROP are drawn under a rule
instead of thrown away.

- `peopleMatch()` answers `exact` / `also` / `none` and reports how many
  required people the selection is short of. `membersMatchPeople()` is
  now `tier === "exact"`, so the server's pick rule and its browser
  mirror did not move.
- `splitByMatch()` orders the also-in tier by that distance, stable, so
  the near misses read first and the file order survives inside a tier.
- `AlsoInDivider` names who the queues below it still want, up to three
  people then a count. It renders nothing when there is nothing below it.
- Chip counts cover BOTH tiers. Counting only exact matches is why a
  person who never has a queue to herself read `0` while her queues were
  on the screen under Anyone.
- The provider filter is a MULTI-SELECT: `?only=` is a comma list, and
  `?only=kavita` / `?only=all` — every address the single-select era
  wrote — still parse. Its pills join the people's wrapping flow after a
  hairline rather than owning a row of their own.
- Two dropdown layouts sit behind `?layout=combos|compact` as a PREVIEW,
  so the chip row can be compared against the two multi-select
  comboboxes the owner proposed. Two of the three go when he picks.
…s not offered

Three rows became one at nine people, and the bar stops offering
combinations that cannot exist.

- The first FOUR of the roster are chips, plus every ticked person
  wherever they sit in it. The rest go behind `+ N more` — a Charcuterie
  `Combobox isMultiple` with a search field, a face, a name and a count
  per row. Quick-pick membership is ROSTER ORDER, not a usage ranking: a
  control that reorders itself as you use it cannot be learned.
- The provider pills stay pills, on the right of the same row. They take
  their own line only in the Narrow View.
- A person the selection shares NO QUEUE with is not offered: the chip
  disappears, the dropdown row is disabled. A ticked person is never
  hidden and never disabled — clicking a ticked chip is the way out of a
  selection that has filtered the page to nothing.
- ⚠️ The dead-end test is `hasQueueFor`, not a count of zero. A queue
  nobody is filed on passes every people filter by design, so the count
  for two people who share nothing is at least 1 and a count-based test
  would never have fired once.
- `⚙` and `▾` are outside Outfit's Latin subset and were painting a tofu
  box on the live landing. Both are inline SVGs now, the route
  `SchemeIcons.tsx` already took.

The three-layout preview switch and `?layout=` are deleted; the owner
picked from a served build.
`shot-queue-filter.ts` boots the server on the landing fixtures, adds
the six invented EXTENDED CAST people over the API and writes the queue
trays, then takes five frames. The trays are written rather than seeded
from group claims because the shape the frames need — one adult with
queues of her own, a partner with none, and a queue naming two specific
children — is not one a group claim can express.

Each frame prints what it measured, so the harness reports the claim
rather than only illustrating it: the bar is 3 rows on main and 1 on the
branch, `?people=sven` is 1 shelf and no rule on main and 6 rows with a
rule on the branch, and `?people=omar` has no +N more control on main.

The seven PR images are committed under docs/images/, and AGENTS.md now
names the extended cast so the next harness that needs a household-sized
roster reuses it rather than inventing a seventh set of names.
@Sawtaytoes
Sawtaytoes merged commit c95e98f into main Sep 5, 2026
2 checks passed
@Sawtaytoes
Sawtaytoes deleted the queue-filter-sections branch September 5, 2026 07:29
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