# Revset semantics — notes for the §8 subset

Spec §8 requires a deliberately small revset subset (`author()`, `description()`,
`conflicted()`, `bookmarks()`, `open()`, plus `&`, `|`, `~`) parsed into SQL, and warns:

> Do not attempt to implement jj's full revset language against a Git-backed index; it will not
> be faithful, and a subtly wrong revset is worse than an honestly limited one.

These are behaviours verified against jj 0.43.0 that a naive SQL translation gets wrong.

## `description()` is an EXACT match, not a substring match

This is the trap. Verified directly:

```
$ jj log -r 'description("merge base")'          # commit described exactly "merge base"
(empty result)

$ jj log -r 'description(substring:"base")'
mmnulkozlxru  merge base

$ jj log -r 'subject("merge base")'
mmnulkozlxru  merge base
```

The obvious implementation — `WHERE description ILIKE '%' || $1 || '%'` — is **wrong**, and
wrong in the most damaging direction: it silently returns *more* than the CLI would, so a
reviewer filtering a change list sees results their terminal does not. That is precisely the
"subtly wrong revset" the spec says is worse than no revset.

Correct mapping for the v1 subset:

| revset | SQL |
|---|---|
| `description("x")` | `description = 'x'` — exact, including jj's trailing newline handling |
| `description(substring:"x")` | `description ILIKE '%x%'` |
| `subject("x")` | exact match against the **first line** of the description |

If only one form is implemented in v1, implement `description(substring:)`, because it is the
one users actually want — but then **do not accept the bare `description("x")` form at all**.
Reject it with the "unsupported expression" message rather than aliasing it to substring.
Accepting it with different semantics than the CLI is the failure mode to avoid.

Note also that jj descriptions carry a trailing newline. Normalise on ingest (store without
it) so exact matching does not depend on invisible whitespace.

## Prefix matching

Ambiguity handling matters. jj resolves the shortest unique prefix and errors on ambiguity;
spec §7 requires Dogfood render a disambiguation page rather than guess. The index has
`changes_prefix_idx (repo_id, change_id text_pattern_ops)` for this — use
`change_id LIKE $1 || '%'` and count results before choosing a page.

## Functions deliberately NOT in the v1 subset

`heads()`, `roots()`, `ancestors()`, `descendants()`, `::`, `..`, `latest()`, `merges()`,
`file()`, `diff_contains()` — all require graph traversal or content search that the SQL index
cannot answer faithfully. The parser must reject these by name with a clear message naming the
unsupported function, not fail to parse with a generic syntax error.

## `mine()` / `author()`

`author()` in jj matches against the author *email and name* as a substring. Dogfood stores
`revisions.author_email` and `author_name`; match against both, and be explicit in the UI that
this is a substring match so it is not confused with `description()`'s exact semantics.
