Jump to…
snowinitial commitqoxwzsukwmkx1mo
1# Revset semantics — notes for the §8 subset
2
3Spec §8 requires a deliberately small revset subset (`author()`, `description()`,
4`conflicted()`, `bookmarks()`, `open()`, plus `&`, `|`, `~`) parsed into SQL, and warns:
5
6> Do not attempt to implement jj's full revset language against a Git-backed index; it will not
7> be faithful, and a subtly wrong revset is worse than an honestly limited one.
8
9These are behaviours verified against jj 0.43.0 that a naive SQL translation gets wrong.
10
11## `description()` is an EXACT match, not a substring match
12
13This is the trap. Verified directly:
14
15```
16$ jj log -r 'description("merge base")' # commit described exactly "merge base"
17(empty result)
18
19$ jj log -r 'description(substring:"base")'
20mmnulkozlxru merge base
21
22$ jj log -r 'subject("merge base")'
23mmnulkozlxru merge base
24```
25
26The obvious implementation — `WHERE description ILIKE '%' || $1 || '%'` — is **wrong**, and
27wrong in the most damaging direction: it silently returns *more* than the CLI would, so a
28reviewer filtering a change list sees results their terminal does not. That is precisely the
29"subtly wrong revset" the spec says is worse than no revset.
30
31Correct mapping for the v1 subset:
32
33| revset | SQL |
34|---|---|
35| `description("x")` | `description = 'x'` — exact, including jj's trailing newline handling |
36| `description(substring:"x")` | `description ILIKE '%x%'` |
37| `subject("x")` | exact match against the **first line** of the description |
38
39If only one form is implemented in v1, implement `description(substring:)`, because it is the
40one users actually want — but then **do not accept the bare `description("x")` form at all**.
41Reject it with the "unsupported expression" message rather than aliasing it to substring.
42Accepting it with different semantics than the CLI is the failure mode to avoid.
43
44Note also that jj descriptions carry a trailing newline. Normalise on ingest (store without
45it) so exact matching does not depend on invisible whitespace.
46
47## Prefix matching
48
49Ambiguity handling matters. jj resolves the shortest unique prefix and errors on ambiguity;
50spec §7 requires Dogfood render a disambiguation page rather than guess. The index has
51`changes_prefix_idx (repo_id, change_id text_pattern_ops)` for this — use
52`change_id LIKE $1 || '%'` and count results before choosing a page.
53
54## Functions deliberately NOT in the v1 subset
55
56`heads()`, `roots()`, `ancestors()`, `descendants()`, `::`, `..`, `latest()`, `merges()`,
57`file()`, `diff_contains()` — all require graph traversal or content search that the SQL index
58cannot answer faithfully. The parser must reject these by name with a clear message naming the
59unsupported function, not fail to parse with a generic syntax error.
60
61## `mine()` / `author()`
62
63`author()` in jj matches against the author *email and name* as a substring. Dogfood stores
64`revisions.author_email` and `author_name`; match against both, and be explicit in the UI that
65this is a substring match so it is not confused with `description()`'s exact semantics.

65 lines · Markdown