6.1.2 Epic-5 predicates — custom-field (per-type), label, and component conditions via the documented join contracts
Estimate: 28m · Depends on: 6.1.1, 5.3.1, 5.4.1
The registry + compiler extension consuming the contracts 5.3.1 / 5.4.1 documented for this story.
Custom fields — registry entries are DYNAMIC per project (the field list is data): each definition contributes a field entry keyed cf:<fieldId> with the operator set of its type (select → enum semantics over its options incl. archived ones for historical matching; user → enum over members; number/date/text → their type sets). Compilation = the documented indexed JOIN per condition (custom_field_value on [fieldId, valueOptionId|valueNumber|valueDate|valueUserId]; is empty = NOT EXISTS); multiple CF conditions compose under the combinator with one join apiece (aliased — no join collision; bounded by the 20-row cap).
Labels / components — lbl/cmp field entries with enum semantics compiling to EXISTS/NOT-EXISTS over work_item_label/work_item_component (the 5.4.1 indexed joins); is empty = no join rows.
Stale-referent rule: a condition referencing a deleted field/option/label/component id (a shared or saved URL outliving the data) resolves to the typed "unknown value" condition — matches nothing, surfaces a per-row notice, never errors the query (the durable behaviour 6.2 saved filters depend on).
Acceptance criteria
- Every CF type filters correctly through its indexed join (EXPLAIN spot-checks on the large seed: index scans); select matching includes archived-option values;
is emptysemantics verified per type; multi-CF + label + component conditions compose under both combinators without join collisions. - Label/component conditions match the 5.4 join data incl. negation + empty; the project's dynamic field entries appear/disappear with definitions (registry totality preserved — the enumeration test covers the dynamic entries).
- Stale referents degrade to unknown-value (match-nothing + notice), asserted for field/option/label/component deletion each; injection fuzz extended over the dynamic ids.
pnpm test:coverage≥90% on the extension.
Context refs
- The 5.3.1 predicate contract (typed-EAV columns +
[fieldId, value*]indexes + the JOIN sketch) and the 5.4.1 label/component join contract — written for this subtask - 6.1.1 registry/compiler (the extension points)
customFieldsServicereads (5.3.2/5.3.3) for definitions/options;labelsService/componentsServicereads (5.4.2/5.4.3) for values- The stale-referent rule in the Story 6.1 description (the 6.2 dependency)