--- id: STORE-15 family: GR-STORE level: extended profiles: [storage-api, editor-client] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/gr-store/store-15 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # STORE-15 — Searching the workflow list matches a literal substring of the name *GR-STORE (Part I) · level: extended · profiles: storage-api, editor-client · added in 1.0* The term is text to find, not a pattern to interpret, so a name containing a percent sign is found by searching for a percent sign. ## The rule > **Normative.** This is the rule. > > 1. A list request may carry a search term, which filters the list to workflows whose name contains it, compared without regard to case and matched anywhere in the name. > > 2. The term is matched literally and carries no pattern syntax: `%` and `_` match themselves and nothing else. > > 3. The same filter applies to the count, so the reported total describes the filtered set rather than the collection (API-6). > > 4. A term that matches nothing answers an empty page with a coherent pagination block, not a refusal and not a not-found. > > 5. A term of `0` is an ordinary search term. > > 6. A search parameter that is not a single scalar value is refused with `400`. ## What it means A search term is text to find, never a pattern to interpret. That matters because the family of characters a pattern language treats specially — `%` and `_`, in the pattern syntax this rule explicitly rules out — are ordinary characters in a workflow name, and a caller who names a workflow `100% coverage` has to be able to find it by searching for the percent sign literally, not by learning to escape it first. A term that matches nothing is not a refusal and not a not-found: it is an ordinary page, empty, with a pagination block that still reports correctly on zero rows. And the filter and the count agree with each other — the reported total describes the filtered set the caller is looking at, not the whole collection behind it (API-6). ## Example ```http title="A search matching two workflows by a case-different substring" verdict="200 paginated" GET /api/flowdrop/workflows?search=INVOICE {"success": true, "data": [ … ], "pagination": {"total": 2, "limit": 50, "offset": 0, "has_more": false}} ``` ```http title="A percent sign, matched literally rather than read as a wildcard" verdict="200 paginated" GET /api/flowdrop/workflows?search=%25 {"success": true, "data": [ … ], "pagination": {"total": 1, "limit": 50, "offset": 0, "has_more": false}} ``` ```http title="A term no name contains" verdict="200 paginated" GET /api/flowdrop/workflows?search=nothing+here {"success": true, "data": [], "pagination": {"total": 0, "limit": 50, "offset": 0, "has_more": false}} ``` A wildcard reading of `_nvoice` would match a name containing `Invoice`; a literal one, which is what this rule requires, matches nothing — the same empty, coherent answer as any other term nothing contains. ## Why Recorded under OPEN-19. ## Related rules - Names: API-6, STORE-14 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.