thurview 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thurview",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "Guided, evidence-anchored reviews of agent-written code. A coding agent authors the review; you read, ask, comment and decide in the browser.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,19 +32,9 @@
32
32
  "@toon-format/toon": "2.3.1",
33
33
  "axi-sdk-js": "0.1.11",
34
34
  "diff": "9.0.0",
35
- "graphology": "0.26.0",
36
- "graphology-communities-louvain": "2.0.2",
37
35
  "markdown-it": "15.0.1",
38
36
  "open": "11.0.2",
39
37
  "shiki": "4.4.3",
40
- "tree-sitter-elixir": "0.3.5",
41
- "tree-sitter-go": "0.25.0",
42
- "tree-sitter-java": "0.23.5",
43
- "tree-sitter-javascript": "0.25.0",
44
- "tree-sitter-python": "0.25.0",
45
- "tree-sitter-rust": "0.24.0",
46
- "tree-sitter-typescript": "0.23.2",
47
- "web-tree-sitter": "0.27.0",
48
38
  "yaml": "2.9.0",
49
39
  "zod": "4.5.4"
50
40
  },
@@ -52,7 +42,6 @@
52
42
  "@types/diff": "8.0.0",
53
43
  "@types/node": "26.4.1",
54
44
  "esbuild": "0.28.2",
55
- "graphology-types": "0.24.8",
56
45
  "prettier": "3.9.6",
57
46
  "tsx": "4.23.13",
58
47
  "typescript": "7.0.2",
@@ -133,37 +133,32 @@ cold, and the walkthrough is what makes it so.
133
133
  ### 3. Study the change
134
134
 
135
135
  Read the whole diff once (`git diff <base> <head>`). The diff tells you what
136
- changed. The code graph tells you what it means, which is what the review is
137
- for. thurview builds it from the pinned commits with tree-sitter and the
138
- definitions-and-references query each grammar ships, so ask it rather than
139
- re-deriving structure from hunks:
136
+ changed; what it means is in the code it does not show - who calls what the
137
+ change moved, which tests reach it, what imports the module it touched. Find
138
+ those yourself, at the pinned commits, with the recipes in
139
+ [Searching the code](references/searching.md):
140
140
 
141
141
  ```sh
142
- thurview graph interfaces --review <id> # what the change added to, changed in or removed from the visible surface
143
- thurview graph impact --review <id> # symbols touched, edges added and removed, what reaches them, what tests cover them
144
- thurview graph callers <symbol> --review <id> # used, or speculative? (--graph base for the old side)
145
- thurview graph tests-for <symbol> --review <id>
146
- thurview graph architecture --review <id> # file clusters with their hubs, the edges between them, the file-level diff
142
+ git grep -n -E -e '\bname *\(' <head> -- # who calls it now
143
+ git grep -n -E -e '\bname *\(' <base> -- # who called it before: a removed symbol's callers are only here
144
+ git grep -n -E -e '\bname\b' <head> -- '*test*' # what tests name it
147
145
  ```
148
146
 
149
- The graph covers TypeScript, JavaScript, Python, Go, Rust, Java and Elixir; other
150
- files are absent from it, not empty. References resolve by name, so treat
151
- `unresolved` as the size of what it could not place, and `<module>` as code
152
- outside any definition. If `truncated` is true (`truncated.base` and
153
- `truncated.head` for impact and architecture, which look at both commits; a
154
- plain `truncated` for callers and tests-for, which look at one), the repo has
155
- more supported files than the graph could parse, and that answer is a partial
156
- view: say so rather than treating an empty result as "nothing there".
157
-
158
- Read `graph interfaces` first: it is the reader's own first question, and its
159
- `verdict` is what the browser shows above your document. A `removed` entry is
160
- the most review-worthy thing the change can contain; `No interface moved`
161
- means the change is internal, and the document should say why the refactor was
162
- worth making rather than dress it up as a feature. Do not repeat the entries
163
- in prose - the panel already lists them. Explain the ones that need it,
164
- in `data.yaml` (see below).
165
-
166
- Spend the rest of the review on what the other queries answer: what the change
147
+ Start with the interfaces: what the change added to, changed in or removed
148
+ from what other code, a user or another system reaches - an exported function,
149
+ a CLI flag, an HTTP route, a config key, a file format. It is the reader's own
150
+ first question, and the list you declare in `data.yaml` (step 5) is what the
151
+ browser shows above your document. A removed or changed one is the most
152
+ review-worthy thing a change can contain, so search for its callers at both
153
+ pins. A change that moves none is internal, and the document should say why the
154
+ refactor was worth making rather than dress it up as a feature. Do not repeat
155
+ the entries in prose - the panel already lists them.
156
+
157
+ A search finds names, not meaning, so open each hit before you count it, and
158
+ state the search beside any claim that rests on one - "no other caller" is
159
+ worth exactly the line that found none.
160
+
161
+ Spend the rest of the review on what the searches answer: what the change
167
162
  reaches that the diff does not show, which boundaries it crosses, what now
168
163
  depends on what, what it left untested. Then compare the stated intent (commit
169
164
  messages, PR description, the user's own words) with what the code does. The
@@ -205,9 +200,11 @@ Source worktree: <worktree>
205
200
  Base commit: <base>
206
201
  Head commit: <head>
207
202
 
208
- Seed the structure from `thurview graph architecture --review <id>` rather
209
- than guessing it: communities and their hubs become nodes, its edges the
210
- edges, and its diff the difference between base and head.
203
+ Seed the structure from the code rather than guessing it: the directories at
204
+ each pin (`git ls-tree -d -r --name-only <commit>`) become candidate nodes, and
205
+ the importers of each one (the recipes in the thurview skill's
206
+ references/searching.md) the edges. What differs between base and head is the
207
+ diff the map shows.
211
208
 
212
209
  Author <dir>/map.yaml: the head structure under nodes/edges and the base
213
210
  structure under base. Do not edit review.md or data.yaml. Do not publish.
@@ -225,10 +222,11 @@ Edit `review.md` and `data.yaml` in the review directory following
225
222
  Default to anchor links for evidence; use an inline peek only when the reader
226
223
  must see the code to follow the main claim.
227
224
 
228
- In `data.yaml`, add an `interfaces` entry for each interface change a
229
- consumer would not understand from its declaration alone, and for the ones
230
- the graph cannot see - a CLI flag, an HTTP route, a config key, a file
231
- format. See [Components](references/components.md) for the shape and
225
+ In `data.yaml`, add an `interfaces` entry for each interface the change added,
226
+ changed or removed - an exported function, a CLI flag, an HTTP route, a config
227
+ key, a file format - anchored on the lines that moved it. Publish refuses an
228
+ anchor that sits on no added or deleted line, so an entry cannot outlive the
229
+ code. See [Components](references/components.md) for the shape and
232
230
  [Document authoring](references/document-authoring.md) for what earns an
233
231
  entry. Never write one for a capability the change did not deliver.
234
232
 
@@ -79,10 +79,7 @@ stores:
79
79
  body: { type: text }
80
80
 
81
81
  interfaces:
82
- spawnPty: # annotate a derived entry
83
- symbol: src/pty.ts:spawnPty # an id from `thurview graph interfaces`
84
- capability: Callers get a sized PTY without knowing the fallback.
85
- dryRun: # declare one the graph cannot see
82
+ dryRun: # one per interface the change moved
86
83
  name: thurview publish --dry-run # what a consumer types or calls
87
84
  change: added # added | changed | removed
88
85
  capability: Validate a review without sealing a revision.
@@ -91,33 +88,38 @@ interfaces:
91
88
  security: # a review only; omit until you have looked
92
89
  - boundary: The --shell flag reaches execFile's argv unquoted.
93
90
  anchor: spawn # a head anchor, with a peek
91
+
92
+ searches: # an explainer only
93
+ spawnCallers:
94
+ pattern: '\bspawnPty *\(' # git grep -E, re-run at the pinned commit
95
+ paths: ["src/"] # optional git pathspecs; the whole commit when left out
96
+ why: who opens a PTY # optional; the question it answered
94
97
  ```
95
98
 
96
99
  An anchor without `peek` can label a map node but cannot open code.
97
100
 
98
101
  ## interfaces
99
102
 
100
- The browser shows the interface delta above the document. thurview derives it
101
- at `publish` from the code graph at both pinned commits - every symbol the
102
- diff touched that is visible outside its own file, split into added, changed
103
- and removed - so the list itself is never authored and never goes stale.
103
+ The browser shows the interface delta above the document: what the change
104
+ added to, changed in or removed from the surfaces something outside it reaches.
105
+ You declare each entry; thurview checks it.
104
106
 
105
- Each entry in `interfaces` does one of two things, and never both:
107
+ Every entry has `name`, `change`, `capability` and `anchor`:
106
108
 
107
- - **`symbol`** annotates a derived entry with `capability`, one sentence in a
108
- consumer's terms. `publish` fails when the change did not move that symbol,
109
- so an annotation cannot outlive the entry it explains. Take the id verbatim
110
- from `thurview graph interfaces`.
111
- - **`name`** declares an interface the graph cannot see: a CLI subcommand or
112
- flag, an HTTP route, an event kind, a config key, a file format. It needs
113
- `change` and an `anchor`. `publish` checks the anchor against the pinned
114
- diff - a `removed` entry needs a `graph: base` anchor covering a deleted
115
- line, `added` and `changed` need a head anchor covering an added line - so a
116
- declared interface is evidence, not a claim.
109
+ - **`name`** is what a consumer types or calls: an exported function, a CLI
110
+ subcommand or flag, an HTTP route, an event kind, a config key, a file
111
+ format.
112
+ - **`change`** is `added`, `changed` or `removed`.
113
+ - **`anchor`** proves it. `publish` checks it against the pinned diff - a
114
+ `removed` entry needs a `graph: base` anchor covering a deleted line, `added`
115
+ and `changed` need a head anchor covering an added line - so an entry is
116
+ evidence, not a claim, and cannot outlive the code that moved it.
117
+ - **`capability`** is what a consumer can now do, or can no longer do. Write
118
+ "`thurview publish` gains `--dry-run`", not "added a boolean to
119
+ PublishOptions".
117
120
 
118
- `capability` is what a consumer can now do, or can no longer do. Write
119
- "`thurview publish` gains `--dry-run`", not "added a boolean to
120
- PublishOptions".
121
+ An entry written with `symbol:` named a row thurview used to derive. It derives
122
+ none now, and `publish` refuses the key with how to write the entry instead.
121
123
 
122
124
  ## security
123
125
 
@@ -153,6 +155,27 @@ severity that exists belongs to the findings in `thurview-fix`, not to this
153
155
  document. An explainer and a design are pinned to one commit and have no change,
154
156
  so `publish` refuses the key on either.
155
157
 
158
+ ## searches
159
+
160
+ An explainer's record of what it searched: the callers, tests and importers
161
+ it looked for while reading the code. `publish` re-runs each one with
162
+ `git grep -I -E` at the pinned commit, so what it matched is the commit's and
163
+ not the worktree's, and the Coverage tab counts every file in scope it matched
164
+ and nothing anchored or placed as _matched by a search_. A search that matched
165
+ nothing is listed too, since that zero is what a claim of absence rests on.
166
+
167
+ - **`pattern`** is a POSIX extended regular expression, as `git grep -E` reads
168
+ it. One git refuses fails the publish with git's own message.
169
+ - **`paths`** are git pathspecs to search under, read exactly as your own
170
+ `git grep` reads them, so `*test*` reaches into every directory; the whole
171
+ commit when left out.
172
+ Coverage counts only the files inside the explainer's scope either way.
173
+ - **`why`** is the question the search answered, in a sentence.
174
+
175
+ A review or a design has no Coverage tab, so `publish` refuses `searches` there:
176
+ put the search beside the claim it supports, in the prose. The recipes are in
177
+ [Searching the code](searching.md).
178
+
156
179
  ## Anchor link
157
180
 
158
181
  ```markdown
@@ -66,33 +66,28 @@ Progressive disclosure: every `##` heading is a section the reader can fold.
66
66
  ## Interface delta
67
67
 
68
68
  The reader's first question is what the change lets them do that they could
69
- not before, and what it cost. thurview answers it from the code graph rather
70
- than from your prose: every symbol the diff touched that is visible outside
71
- its own file, as added, changed or removed, above your document. Read it with
72
- `thurview graph interfaces` before you write, and let it shape the document:
69
+ not before, and what it cost. You answer it in `data.yaml` under `interfaces`
70
+ (see [Components](components.md)), one entry per interface the change added,
71
+ changed or removed - an exported function, a CLI subcommand or flag, an HTTP
72
+ route, an event kind, a config key, a file format - and the browser lists them
73
+ above your document. Each entry carries an anchor on the lines the diff moved;
74
+ publish refuses one that sits on none, so the list cannot claim what the change
75
+ did not do. Let it shape the document:
73
76
 
74
77
  - **A removed entry is the change's most review-worthy fact.** Say what
75
- depended on it (`thurview graph callers <name> --graph base`) and what
76
- replaces it. Never let a removal read as a rearrangement.
77
- - **`No interface moved` is a finding, not an empty result.** The change is
78
- internal. Write about why it was worth making - the bug it fixes, the
79
- duplication it folds - and do not dress it up as a capability.
80
- - **Do not restate the entries in prose.** The panel lists them, with the
81
- declaration and a link into the file. Your sentences are for what it cannot
82
- derive: why the surface has this shape, what a consumer does with it, what
83
- a removal breaks.
84
-
85
- Add an `interfaces` entry in `data.yaml` (see [Components](components.md))
86
- only when one of these holds:
87
-
88
- 1. A derived entry's declaration does not tell a consumer what it is for. The
89
- `capability` line says what they can now do, in their words.
90
- 2. The change moves an interface the graph cannot see - a CLI subcommand or
91
- flag, an HTTP route, an event kind, a config key, a file format. Declare
92
- it, with an anchor on the line the diff moved.
93
-
94
- Anything else is noise: the entry is already there, or there is nothing to
95
- add. An interface the change did not deliver is never an entry.
78
+ depended on it - search for its callers at the base pin, as
79
+ [Searching the code](searching.md) shows - and what replaces it. Never let a
80
+ removal read as a rearrangement.
81
+ - **No entry is a finding, not an empty result.** The change is internal.
82
+ Write about why it was worth making - the bug it fixes, the duplication it
83
+ folds - and do not dress it up as a capability.
84
+ - **Do not restate the entries in prose.** The panel lists them, with a link
85
+ into the file. Your sentences are for what it cannot hold: why the surface
86
+ has this shape, what a consumer does with it, what a removal breaks.
87
+
88
+ What earns an entry is a surface something outside the change reaches. A
89
+ private helper is not one, however much it moved, and an interface the change
90
+ did not deliver is never an entry.
96
91
 
97
92
  ## Trust boundaries
98
93
 
@@ -101,7 +96,8 @@ Every review answers where the change lets input cross a trust boundary, in
101
96
  it under the interface delta, one line per place with the anchor the reader
102
97
  opens.
103
98
 
104
- Answer it after you have read the diff and the graph, and answer it either way.
99
+ Answer it after you have read the diff and searched what it reaches, and answer
100
+ it either way.
105
101
  `security: none` is the whole answer for a change that crosses none, and writing
106
102
  it is what makes the panel worth reading on the review where it is not none. A
107
103
  review that leaves the key out publishes as "not assessed", which is honest for
@@ -0,0 +1,74 @@
1
+ # Searching the code
2
+
3
+ thurview builds no index of the code. Who calls a symbol, which tests touch a
4
+ file and what imports a module are answered by your own search, at the pinned
5
+ commit, and every answer you state comes with the search behind it so the
6
+ reader can run it again. Every skill that asks one of these questions uses the
7
+ recipes here.
8
+
9
+ ## Search the pinned commit, not the worktree
10
+
11
+ `git grep` reads a commit directly, so its answer is the one your anchors are
12
+ pinned to however far the worktree has moved:
13
+
14
+ ```sh
15
+ git grep -n -E -e '<pattern>' <commit> -- '<path glob>'
16
+ ```
17
+
18
+ `<commit>` is `head` for what the change made, `base` for what it replaced.
19
+ Each hit prints as `<commit>:<path>:<line>:<text>`; the `<path>:<line>` part is
20
+ what an anchor's `peek` takes. `rg` gives the same answer, faster, only when
21
+ `git rev-parse HEAD` in the worktree is the pinned commit and the tree is
22
+ clean; when either is not true, use `git grep`.
23
+
24
+ ## Recipes
25
+
26
+ Swap the name in; each one is a starting point, so read the hits before you
27
+ trust the count.
28
+
29
+ | Question | Search |
30
+ | --------------------------- | -------------------------------------------------------------------------- |
31
+ | callers of a function | `git grep -n -E -e '\bname *\(' <commit> --` |
32
+ | every reference to a symbol | `git grep -n -E -e '\bname\b' <commit> --` |
33
+ | callers before the change | the same at `<base>`: a removed symbol has no callers left at head |
34
+ | importers of a module | `git grep -n -E -e "['\"][./]*path/to/module(\.[a-z]+)?['\"]" <commit> --` |
35
+ | tests that touch a file | `git grep -l -E -e '\bexportedName\b' <commit> -- '*test*' '*spec*'` |
36
+ | tests that name a symbol | `git grep -n -E -e '\bname\b' <commit> -- '*test*' '*spec*'` |
37
+ | the directories in a scope | `git ls-tree -d -r --name-only <commit> -- <scope>` |
38
+ | the files in a scope | `git ls-tree -r --name-only <commit> -- <scope>` |
39
+
40
+ Every recipe is one `-E` pattern, with `\b` for a word boundary rather than
41
+ `-w`, so an explainer can record it under `searches` exactly as you ran it -
42
+ publish re-runs it with `-E` and nothing else. `\b` is a GNU extension: check
43
+ it on the platform once (`git grep -c -E -e '\bname\b' <commit> --` must match
44
+ what `-w -e name` matches) and use `[[:<:]]name[[:>:]]` where git's regex
45
+ library reads that instead.
46
+
47
+ The import recipe is written for JavaScript and TypeScript. Use the language's
48
+ own form elsewhere: `^import .*module` in Python and Go, `use crate::module` in
49
+ Rust, `alias|import|use Module` in Elixir. Test files are named per project;
50
+ check one before you rely on `*test*`.
51
+
52
+ ## What a search can and cannot tell you
53
+
54
+ A text search finds names, not meaning. It misses a call made through a
55
+ variable, a re-export, a string-built name or reflection, and it matches a
56
+ comment or a different symbol with the same name. So:
57
+
58
+ - **A hit is a lead.** Open it before you call it a caller.
59
+ - **No hit is a finding about the search, not the code.** "Nothing calls
60
+ `audit`" is true only of the forms you searched for; say which.
61
+ - **Name the search with the claim.** A sentence like "no other caller" carries
62
+ the line that found none, so the reader can run it.
63
+
64
+ ## Record what you searched
65
+
66
+ How it is recorded depends on the document:
67
+
68
+ - **An explainer** lists its searches under `searches` in `data.yaml`. Publish
69
+ re-runs each one with `git grep -E` at the pinned commit and the Coverage tab
70
+ counts the files it matched; see [Components](components.md). Record the ones
71
+ that shaped what you wrote, a zero-hit one included.
72
+ - **A review or a design** has no Coverage tab. Put the search in the prose
73
+ beside the claim it supports, as inline code.
74
+ - **A fix pass** puts it in the evidence column of its report.
@@ -103,19 +103,19 @@ passed as `--review <id>`; that flag names a document, whichever kind it is.
103
103
  ### 2. Study what the design has to fit
104
104
 
105
105
  The design is an argument about a system, so read the system before proposing
106
- anything. The code graph is the fastest way in, and it is the same graph the
107
- reader can re-derive:
106
+ anything. Search it yourself at the pinned commit, with the recipes in the
107
+ `thurview` skill's Searching the code reference, so what you find is what the
108
+ reader can re-run:
108
109
 
109
110
  ```sh
110
- thurview graph architecture --review <id> # clusters in the scope, their hubs, the edges between them
111
- thurview graph callers <symbol> --review <id> # who depends on what you plan to change
112
- thurview graph tests-for <symbol> --review <id> # what would have to move with it
111
+ git ls-tree -d -r --name-only <commit> -- <scope> # the parts the design has to fit
112
+ git grep -n -E -e '\bname *\(' <commit> -- # who depends on what you plan to change
113
+ git grep -n -E -e '\bname\b' <commit> -- '*test*' # what tests would have to move with it
113
114
  ```
114
115
 
115
- `graph interfaces` and `graph impact` compare two commits and are refused here:
116
- there is one. The graph covers TypeScript, JavaScript, Python, Go, Rust, Java
117
- and Elixir; other files are absent from it, not empty, and `truncated` means
118
- the answer is partial.
116
+ A search finds names, not meaning: open each hit before you count it, and put
117
+ the search beside any claim that rests on it - a design has no Coverage tab to
118
+ carry it, so `searches` in `data.yaml` is refused here.
119
119
 
120
120
  Read every range you intend to anchor from the pinned commit itself —
121
121
  `git show <commit>:<path>` — not from the working tree.
@@ -144,8 +144,7 @@ interfaces:
144
144
  a restatement of the signature.
145
145
  - `anchor` is the **site**: real code at the pinned commit that this proposal
146
146
  lands in, replaces or plugs into. It must resolve and it must have a `peek`.
147
- - A `symbol:` entry is refused. That shape annotates a row the code graph
148
- derived from a diff, and a design has none.
147
+ - A `symbol:` entry is refused: every entry names its own interface.
149
148
  - **A design with no entry here is refused.** A document that proposes nothing
150
149
  is an explainer; write one of those instead.
151
150
 
@@ -164,8 +163,9 @@ finishes is a design nobody decided on. A shape that works:
164
163
  fence. This is what makes a design arguable rather than assertible.
165
164
  3. **What to build** — the proposals in step 3, with the reasoning the panel
166
165
  cannot carry.
167
- 4. **What it costs** — what has to move, what breaks, what is left out. Use
168
- `thurview graph callers` for the blast radius rather than guessing it.
166
+ 4. **What it costs** — what has to move, what breaks, what is left out. Search
167
+ for the callers to count the blast radius rather than guessing it, and give
168
+ the search with the count.
169
169
  5. **What was considered and dropped**, with the reason. This is the section
170
170
  readers send a design back for missing.
171
171
 
@@ -205,7 +205,10 @@ The Map tab is where a design shows structure. Put the structure it
205
205
  part, and publish does not warn about it.
206
206
  - A node under `base` may not. It is a claim about today, and publish warns
207
207
  when its globs match nothing at the pinned commit.
208
- - Seed `base` from `thurview graph architecture --review <id>`.
208
+ - Seed `base` from the code: the directories at the pinned commit
209
+ (`git ls-tree -d -r --name-only <commit>`) and what imports what between
210
+ them, found with the `git grep` recipes in the `thurview` skill's Searching
211
+ the code reference.
209
212
 
210
213
  A design that changes one part in place does not raise the question: leave
211
214
  `nodes: []` and say so in the handover.
@@ -23,12 +23,12 @@ to nothing would put that question on every other anchor in the document.
23
23
 
24
24
  ## What this buys, concretely
25
25
 
26
- | The design says | How it is carried | What the reader can do |
27
- | ---------------------------------------------- | ---------------------------------------------------- | --------------------------------------------- |
28
- | "today the router picks a handler in a switch" | anchor with a `peek` | open the switch |
29
- | "we would add `Router.register`" | proposal, `change: added`, anchored at the switch | open the code it replaces |
30
- | "it would look roughly like this" | plain fenced code block in `review.md` | read it as a sketch, because it is not a peek |
31
- | "these fourteen callers move" | anchor per caller, or the count from `graph callers` | check the count |
26
+ | The design says | How it is carried | What the reader can do |
27
+ | ---------------------------------------------- | ------------------------------------------------------------ | --------------------------------------------- |
28
+ | "today the router picks a handler in a switch" | anchor with a `peek` | open the switch |
29
+ | "we would add `Router.register`" | proposal, `change: added`, anchored at the switch | open the code it replaces |
30
+ | "it would look roughly like this" | plain fenced code block in `review.md` | read it as a sketch, because it is not a peek |
31
+ | "these fourteen callers move" | anchor per caller, or the count and the `git grep` behind it | run the search and check the count |
32
32
 
33
33
  ## The refusals, and why each one is there
34
34
 
@@ -37,9 +37,11 @@ why; these are the reasons behind them.
37
37
 
38
38
  - **`graph: base` on an anchor.** A design has one pinned commit. A base-graph
39
39
  anchor would resolve against a commit the document never named.
40
- - **A `symbol:` interface entry.** That shape annotates a row the code graph
41
- derived from a diff. A design has no diff, so there is no derived row, and an
42
- annotation with nothing under it is an assertion wearing a badge.
40
+ - **A `symbol:` interface entry.** That shape annotated a row derived from a
41
+ diff. A design has no diff, and an annotation with nothing under it is an
42
+ assertion wearing a badge; a proposal names its own interface.
43
+ - **`searches` in `data.yaml`.** Those feed an explainer's Coverage tab, which a
44
+ design has none of. Give the search in the prose, beside the count it backs.
43
45
  - **A design that proposes nothing.** A document with no `interfaces` entry is
44
46
  prose about the code as it stands. That is an explainer, and it should be one
45
47
  — the reader of a design is being asked to approve something.