aboutsummaryrefslogtreecommitdiff
path: root/patterns/label-matches-behavior.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-05 00:55:21 -0500
committerCraig Jennings <c@cjennings.net>2026-06-05 00:55:21 -0500
commit83bf3cb50c88f91730656a2242141567551063ac (patch)
tree069f0d9d52ac6ffe9c4a97a770be460b01e75cd5 /patterns/label-matches-behavior.org
parent3eed2895b2d23d1d8e468aee6f3dfd8122012fe4 (diff)
downloadrulesets-83bf3cb50c88f91730656a2242141567551063ac.tar.gz
rulesets-83bf3cb50c88f91730656a2242141567551063ac.zip
feat(patterns): add cross-project pattern catalog (six seed patterns)
A good interaction-design pattern surfaces in one project, then gets lost, so the next project re-derives it. Pearl shipped six worked examples and the principle they share, but they sat as four raw notes in docs/design/ with nothing making them reusable. I added a patterns/ directory, one file per pattern, each with frontmatter (name, principle, problem, tags, source, examples) and a Problem / Do / Anti-pattern / Applicability / Related body. The six seeds: one-prompt-picker-typed-prefix, transient-state-buttons, no-empty-input-as-meaningful, label-matches-behavior, default-most-common-friction-proportional, collapse-orthogonal-prompts. Patterns 3-6 cross-link as facets of one root principle: the choices the user has should all be on screen, accurately labeled, ordered by what they'll most often want, with friction sized to the cost of being wrong. The catalog lives in rulesets because every project's agent already pulls from here. A thin claude-rules/patterns.md pointer tells the agent the catalog exists and when to consult it, so it reads one pattern on demand instead of carrying all of them. The pointer auto-installs via the Makefile RULES glob. README.org holds the root principle, the frontmatter contract, and the capture-on-landing/promote-on-review intake cadence. The patterns are .org files with #+KEYWORD frontmatter. The pointer stays .md because the rules layer and the Makefile glob require it. Seed patterns keep their concrete Elisp examples. Generalize on the second caller, not up front.
Diffstat (limited to 'patterns/label-matches-behavior.org')
-rw-r--r--patterns/label-matches-behavior.org32
1 files changed, 32 insertions, 0 deletions
diff --git a/patterns/label-matches-behavior.org b/patterns/label-matches-behavior.org
new file mode 100644
index 0000000..0883abc
--- /dev/null
+++ b/patterns/label-matches-behavior.org
@@ -0,0 +1,32 @@
+#+TITLE: The label matches what the prompt does
+#+SLUG: label-matches-behavior
+#+PRINCIPLE: A visible choice's label has to match what picking it does; visibility without accuracy still leaves the user with the wrong model.
+#+PROBLEM: A uniform sentinel label ("none") used across prompts that mean different things (one means "any", another means "cancel") misdescribes what the choice does.
+#+TAGS: completing-read prompts labels sentinel
+#+SOURCE: pearl commit 505e707 (filter vs saved-query prompts), handoff note 2026-05-28
+#+EXAMPLES: pearl filter dimensions ([ Any. ]) vs pick prompts ([ Cancel. ])
+
+* Problem
+
+Once "no value" is a visible candidate (see [[file:no-empty-input-as-meaningful.org][no-empty-input-as-meaningful]]), the next trap is a label that doesn't match behavior. Pearl used =[ None. ]= uniformly, but it meant two different things. For a filter dimension, picking it meant "no constraint, every value matches," which is any, not none. For a pick-an-existing-thing prompt (delete, run), it meant "don't act on anything," which is cancel. A label that says "none" when the behavior is "any" leaves the user holding the wrong model, no better than the invisible empty-input idiom it replaced.
+
+* Do
+
+Give each behavior a sentinel whose label states what picking it does:
+
+- =[ Any. ]= for a filter dimension (no constraint, everything matches)
+- =[ Cancel. ]= for a pick-an-existing-thing prompt (act on nothing)
+
+A generic =with-sentinel SENTINEL CANDIDATES= helper lets each call site choose the label that fits. One opt-out predicate recognizes any sentinel (and nil/empty) so downstream logic stays uniform.
+
+* Anti-pattern
+
+One sentinel label reused across prompts whose semantics differ. Visibility without accuracy is its own failure: the user sees the choice, but its name describes the wrong outcome.
+
+* Applicability
+
+Anywhere a sentinel or "special" choice appears in more than one prompt with different meanings. The fix is per-call-site labels over a shared predicate, not a single label stretched to cover both.
+
+* Related
+
+The accuracy half of the root principle. Sharpens [[file:no-empty-input-as-meaningful.org][no-empty-input-as-meaningful]]: visible and accurately labeled.