rag-your-code 1.4.2__tar.gz → 1.4.3__tar.gz
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.
- {rag_your_code-1.4.2/src/rag_your_code.egg-info → rag_your_code-1.4.3}/PKG-INFO +136 -136
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/README.md +135 -135
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/pyproject.toml +1 -1
- {rag_your_code-1.4.2 → rag_your_code-1.4.3/src/rag_your_code.egg-info}/PKG-INFO +136 -136
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/__init__.py +1 -1
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/LICENSE +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/setup.cfg +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/rag_your_code.egg-info/SOURCES.txt +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/rag_your_code.egg-info/dependency_links.txt +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/rag_your_code.egg-info/entry_points.txt +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/rag_your_code.egg-info/requires.txt +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/rag_your_code.egg-info/top_level.txt +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/agentic.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/annotate.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/cli.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/config.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/descriptions.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/document.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/embeddings.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/graph.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/indexer.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/models.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/parser.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/providers.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/py.typed +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/search.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/src/ragyourcode/workflow.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_absent_queries.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_agent_protocol.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_agentic.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_config.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_descriptions.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_doc_comments.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_document.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_e2e_cli.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_evidence.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_golden.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_graph_incremental.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_language_fixtures.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_large_repo.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_local_model.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_metadata.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_multilanguage.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_parser_edges.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_providers.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_ragyourcode.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_ranking.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_repo_queries.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_resilience.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_retrieval_correctness.py +0 -0
- {rag_your_code-1.4.2 → rag_your_code-1.4.3}/tests/test_workflow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rag-your-code
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.3
|
|
4
4
|
Summary: A local, explainable RAG index for codebases and coding agents
|
|
5
5
|
Author: rag-your-code contributors
|
|
6
6
|
License-Expression: MIT
|
|
@@ -61,11 +61,10 @@ grep for. **Reading whole files** is thorough and blows the context budget:
|
|
|
61
61
|
five files of a real repository is tens of thousands of tokens, most of them
|
|
62
62
|
irrelevant.
|
|
63
63
|
|
|
64
|
-
Retrieval sits in between
|
|
65
|
-
|
|
64
|
+
Retrieval sits in between, and brings a third problem the first two do not
|
|
65
|
+
have. Grep can tell you it found nothing. **A ranking cannot.** It always
|
|
66
66
|
produces a least-bad candidate and returns it with a score and a rank that read
|
|
67
|
-
exactly like an answer, whether or not the repository
|
|
68
|
-
relevant. That is the failure this project spent its last two releases on.
|
|
67
|
+
exactly like an answer, whether or not the repository holds anything relevant.
|
|
69
68
|
|
|
70
69
|
## 2 · What it does
|
|
71
70
|
|
|
@@ -79,9 +78,9 @@ relevant. That is the failure this project spent its last two releases on.
|
|
|
79
78
|
| **Serve** | A CLI, and a JSON-lines protocol for a long-lived agent subprocess. |
|
|
80
79
|
|
|
81
80
|
**Scope.** Retrieval over source declarations. Not a code-understanding model,
|
|
82
|
-
not a generation step, not an IDE index. Questions are answered in
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
not a generation step, not an IDE index. Questions are answered in vocabulary
|
|
82
|
+
somebody wrote down: in the code, its documentation, or a description an agent
|
|
83
|
+
added.
|
|
85
84
|
|
|
86
85
|
## 3 · What is actually hard here
|
|
87
86
|
|
|
@@ -89,11 +88,11 @@ Three things, and all three are measured rather than argued.
|
|
|
89
88
|
|
|
90
89
|
### 3.1 · Ranking cannot say "no answer"
|
|
91
90
|
|
|
92
|
-
Eight releases measured how well retrieval *finds* the answer. None could
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
implements — settled it in
|
|
96
|
-
|
|
91
|
+
Eight releases measured how well retrieval *finds* the answer. None could see
|
|
92
|
+
what it does when there is none, because every question graded had one. A
|
|
93
|
+
fourth ruler — thirty questions about subjects neither graded repository
|
|
94
|
+
implements — settled it in one run: **all thirty answered**, both languages,
|
|
95
|
+
both repositories.
|
|
97
96
|
|
|
98
97
|
| asked of a repository containing no such code | answered with | on the evidence of |
|
|
99
98
|
|---|---|---|
|
|
@@ -101,8 +100,8 @@ languages, on both repositories.
|
|
|
101
100
|
| `准入控制为什么会拒绝没有资源限额的容器组` | the UTF-8 console setup | `拒绝` `控制` `没有` |
|
|
102
101
|
| `how is the OAuth refresh token rotated` | a description-store method | `before` `is` `refresh` `the` |
|
|
103
102
|
|
|
104
|
-
Not a Chinese problem and not a ranking problem — a **missing question
|
|
105
|
-
|
|
103
|
+
Not a Chinese problem and not a ranking problem — a **missing question**: nothing
|
|
104
|
+
in the pipeline ever asked *is any of this evidence*.
|
|
106
105
|
|
|
107
106
|
Retrieval now asks two questions that ranking cannot:
|
|
108
107
|
|
|
@@ -115,28 +114,26 @@ until you notice which half.
|
|
|
115
114
|
**Concentration** — what share of the query's *rarity* lands inside a single
|
|
116
115
|
declaration. Coverage alone asks whether each word occurs somewhere, which a
|
|
117
116
|
question about a subject nothing here implements can satisfy entirely out of
|
|
118
|
-
unrelated units: four of six words
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
better evidence than one holding the rare word the question is about.
|
|
117
|
+
unrelated units: four of six words in four declarations with nothing to do with
|
|
118
|
+
the question or with one another. Rarity-weighted rather than counted, because
|
|
119
|
+
two ordinary words are not better evidence than the rare word asked about.
|
|
122
120
|
|
|
123
|
-
Both are **ratios inside the query**, never thresholds on a score
|
|
124
|
-
threshold is tied to whatever scale the ranking
|
|
125
|
-
|
|
126
|
-
the scale.
|
|
121
|
+
Both are **ratios inside the query**, never thresholds on a score: a score
|
|
122
|
+
threshold is tied to whatever scale the ranking produces, and this project has
|
|
123
|
+
already had one silently stop existing the moment BM25F changed that scale.
|
|
127
124
|
|
|
128
125
|
### 3.2 · The vector was carrying nothing, and here is why
|
|
129
126
|
|
|
130
127
|
The default embedder is a signed feature hash. Ablating it entirely moves the
|
|
131
128
|
three positive rulers by **±1 question in either direction** while the vectors
|
|
132
|
-
occupy **
|
|
129
|
+
occupy **72.1%** of the index. That was known since 0.6.0 and left unexplained.
|
|
133
130
|
The explanation, measured here:
|
|
134
131
|
|
|
135
|
-
- **Not saturation.** Median 56 distinct tokens per unit into 384 buckets
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
- **Not redundancy.** Its cosine correlates only **+0.45** with
|
|
139
|
-
|
|
132
|
+
- **Not saturation.** Median 56 distinct tokens per unit into 384 buckets, 0.4%
|
|
133
|
+
of units over the width; widening to 16,384 raises fidelity from r=0.40 to
|
|
134
|
+
r=0.56 and buys no ranking.
|
|
135
|
+
- **Not redundancy.** Its cosine correlates only **+0.45** with BM25F over
|
|
136
|
+
26,490 scored candidates, so it does carry variance of its own.
|
|
140
137
|
- **The variance is the wrong variance.** A signed hash counts every token
|
|
141
138
|
equally. The independent part of what it measures is therefore precisely the
|
|
142
139
|
contribution of words that are everywhere — the part rarity weighting exists
|
|
@@ -145,20 +142,19 @@ The explanation, measured here:
|
|
|
145
142
|
vector cannot make anything retrievable. Six of thirty-five foreign-ruler
|
|
146
143
|
questions have an accepted answer sharing **no token at all** with the query.
|
|
147
144
|
|
|
148
|
-
Eight replacement schemes were
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
now an installable option, and measured below.
|
|
145
|
+
Eight replacement schemes were measured across releases — character n-grams,
|
|
146
|
+
random indexing, truncated SVD, posting-list signatures, a rarity-weighted
|
|
147
|
+
hash, call-graph diffusion, postings expansion, authored-fields-only. None beat
|
|
148
|
+
using no vector: **a vector computed from the same words cannot know anything
|
|
149
|
+
the words do not already say.** Making it useful takes a model, which is an
|
|
150
|
+
installable option and is measured below.
|
|
155
151
|
|
|
156
152
|
### 3.3 · Retrieval reaches only what somebody wrote down
|
|
157
153
|
|
|
158
154
|
`retry_charge` tokenizes to one opaque term, not to *retry* and *charge*.
|
|
159
|
-
Splitting identifiers was
|
|
160
|
-
|
|
161
|
-
`
|
|
155
|
+
Splitting identifiers was measured with query and stored vectors rebuilt
|
|
156
|
+
together: equal or worse on every ruler, because the pieces are `get`, `find`,
|
|
157
|
+
`check`, `test`, which rarity weighting discounts.
|
|
162
158
|
|
|
163
159
|
So the vocabulary ladder is the answer, cheapest rung first:
|
|
164
160
|
|
|
@@ -171,6 +167,9 @@ So the vocabulary ladder is the answer, cheapest rung first:
|
|
|
171
167
|
|
|
172
168
|
## 4 · How it works
|
|
173
169
|
|
|
170
|
+
The same pipeline drawn out, with the refusal path and the three surfaces:
|
|
171
|
+
**[docs/FLOW.md](docs/FLOW.md)**.
|
|
172
|
+
|
|
174
173
|
```
|
|
175
174
|
your repository
|
|
176
175
|
→ walk source files configurable ignores, suffixes, size cap
|
|
@@ -192,19 +191,18 @@ qualified names, call lists and spans are exact. Every other language goes
|
|
|
192
191
|
through three separated layers: a scanner reading one line at a time, a rule
|
|
193
192
|
table per language, and a span closer following brace depth, Ruby's `end`, or
|
|
194
193
|
the next declaration. Because a pattern never sees a second line, a reported
|
|
195
|
-
line number **is** the
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
line number **is** the loop index and cannot drift, and no declaration can
|
|
195
|
+
swallow the ones after it. A 530-byte JavaScript file that took 12.6 s to parse
|
|
196
|
+
now takes 0.37 ms.
|
|
198
197
|
|
|
199
|
-
Qualified names come from the spans the closer already produced
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
Qualified names come from the spans the closer already produced: nested inside
|
|
199
|
+
another's span *is* nested in it, whatever the braces did on the way. One
|
|
200
|
+
mechanism, so there is no second one to disagree with it.
|
|
202
201
|
|
|
203
|
-
**Ranking.** BM25F with per-field length normalisation
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
its penalty for being long.
|
|
202
|
+
**Ranking.** BM25F with per-field length normalisation, which is the part that
|
|
203
|
+
matters: against one length for the whole unit, a body repeating a word forty
|
|
204
|
+
times still beat the declaration named after it, because its raw-count
|
|
205
|
+
advantage cancelled its length penalty.
|
|
208
206
|
|
|
209
207
|
| field | weight | why |
|
|
210
208
|
|---|---|---|
|
|
@@ -218,26 +216,33 @@ its penalty for being long.
|
|
|
218
216
|
their low weight the same way a Chinese bigram does — by being everywhere — so
|
|
219
217
|
it works in a language nobody anticipated and no list has to be maintained.
|
|
220
218
|
|
|
221
|
-
**Safety.** A repository
|
|
222
|
-
`.rag-your-code/index.json` it ships
|
|
223
|
-
path to act on: superseded vector sidecars are enumerated from the
|
|
224
|
-
|
|
225
|
-
|
|
219
|
+
**Safety.** A scanned repository is untrusted input, including any
|
|
220
|
+
`.rag-your-code/index.json` it ships, so nothing read out of an index may name
|
|
221
|
+
a path to act on: superseded vector sidecars are enumerated from the writer's
|
|
222
|
+
own naming scheme. A crafted index once made `index` delete an arbitrary
|
|
223
|
+
in-tree file and report success.
|
|
226
224
|
|
|
227
225
|
## 5 · Before and after
|
|
228
226
|
|
|
229
227
|
A question with no lexical shortcut, asked of this repository:
|
|
230
228
|
|
|
231
|
-
|
|
229
|
+
````console
|
|
232
230
|
$ rag-your-code search "where does it decide whether to answer at all" --limit 1
|
|
233
|
-
[src/ragyourcode/search.py:
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
[src/ragyourcode/search.py:117:Evidence] score=0.446
|
|
232
|
+
The verdict on whether a question reached this index at all, kept separate from
|
|
233
|
+
how results rank. ... 中文:判定一个提问究竟有没有够到索引的结论。...
|
|
234
|
+
```python
|
|
235
|
+
class Evidence:
|
|
236
|
+
"""Whether a query reached this index at all, kept apart from ..."""
|
|
236
237
|
```
|
|
238
|
+
````
|
|
237
239
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
There is no string here to grep for: *decide* occurs nowhere in that
|
|
241
|
+
declaration and matched nothing. What ranked it first is ordinary words —
|
|
242
|
+
*answer*, *whether*, *where* — weighted against this corpus, where they are
|
|
243
|
+
rare enough to tell declarations apart. What the agent-written description adds
|
|
244
|
+
is the other language: 「在哪里判定一个提问有没有答案」 returns the same
|
|
245
|
+
declaration first, at 0.392, sharing not one character with its source.
|
|
241
246
|
|
|
242
247
|
Now the case that motivated 1.0.0 and 1.1.0 — a question this repository has no
|
|
243
248
|
answer to at all:
|
|
@@ -261,15 +266,15 @@ it happens to use elsewhere.
|
|
|
261
266
|
"matched_terms": ["job","leave","print"],
|
|
262
267
|
"ubiquitous_terms": ["a","does","the","why"],
|
|
263
268
|
"coverage": 0.5, "min_coverage": 0.4,
|
|
264
|
-
"concentration": 0.
|
|
269
|
+
"concentration": 0.1691, "min_concentration": 0.28,
|
|
265
270
|
"applied_min_coverage": 0.4, "applied_min_concentration": 0.28,
|
|
266
271
|
"hint": "..."}}
|
|
267
272
|
```
|
|
268
273
|
|
|
269
|
-
Read `coverage: 0.5` against `concentration: 0.
|
|
270
|
-
words are here — `job`, `leave`, `print` — and
|
|
271
|
-
|
|
272
|
-
back with a confident-looking result.
|
|
274
|
+
Read `coverage: 0.5` against `concentration: 0.1691`. Half the distinctive
|
|
275
|
+
words are here — `job`, `leave`, `print` — and spread thin enough that no
|
|
276
|
+
declaration holds a fifth of what was asked, against a bar of 0.28. Before
|
|
277
|
+
1.1.0 that question came back with a confident-looking result.
|
|
273
278
|
|
|
274
279
|
Four reasons, because each is recovered by a different move:
|
|
275
280
|
|
|
@@ -283,7 +288,7 @@ Four reasons, because each is recovered by a different move:
|
|
|
283
288
|
## 6 · Benchmark dashboard
|
|
284
289
|
|
|
285
290
|
Four rulers, 135 distinct questions in English and Chinese, graded 235 times —
|
|
286
|
-
|
|
291
|
+
one of them runs against both repositories. Three grade whether the answer is
|
|
287
292
|
**found**; the fourth grades whether silence is **kept**. Every report
|
|
288
293
|
carries a fingerprint of the corpus it graded, because between two runs of an
|
|
289
294
|
unchanged `search.py` the foreign ruler moved 0.257 → 0.229 purely because that
|
|
@@ -321,7 +326,7 @@ Foreign silence fell from 0.933 to 0.833 when the subject changed, and the
|
|
|
321
326
|
cause is a limit of the design rather than a defect. A word counts as evidence
|
|
322
327
|
unless it occurs in more than 5% of units — a stopword list derived from the
|
|
323
328
|
corpus, so that it needs no list and works in any language. Here `how`, `when`,
|
|
324
|
-
`does` and `are` are everywhere, because
|
|
329
|
+
`does` and `are` are everywhere, because 301 units carry written English prose.
|
|
325
330
|
Across 1,572 units of mostly short, undocumented methods they occur in 1–5% of
|
|
326
331
|
them and start counting as evidence. Five English questions about subjects
|
|
327
332
|
Flask does not implement get through on exactly that.
|
|
@@ -335,8 +340,9 @@ Flask does not implement get through on exactly that.
|
|
|
335
340
|
| concentration only | 0.200/0.286/0.238 | 0.314/0.471/0.383 | 0.443/0.614/0.509 | 0.967 / 0.800 |
|
|
336
341
|
| **both (1.1.0)** | **0.200/0.286/0.238** | **0.314/0.471/0.383** | 0.443/0.614/0.509 | **0.967 / 0.833** |
|
|
337
342
|
|
|
338
|
-
Ruler A is **unmoved by either bar
|
|
339
|
-
|
|
343
|
+
Ruler A is **unmoved by either bar**; B loses one hit@3 question to either bar
|
|
344
|
+
alone and nothing further when both apply. The rest of the cost is three of
|
|
345
|
+
seventy at hit@1 on the warmest ruler, and six at hit@3.
|
|
340
346
|
|
|
341
347
|
Through 1.3.0 this section said concentration subsumes coverage. **On a corpus
|
|
342
348
|
this project did not choose, it does not.** Both bars together silence 0.833 of
|
|
@@ -425,7 +431,7 @@ framework reversed it. The honest claim is narrower than either table alone:
|
|
|
425
431
|
|
|
426
432
|
**Once the vocabulary exists, it is not close.**
|
|
427
433
|
|
|
428
|
-
| this repository · 70 questions · 584 units `c9df00350cbd` ·
|
|
434
|
+
| this repository · 70 questions · 584 units `c9df00350cbd` · 301 described | Grep loop | rag-your-code |
|
|
429
435
|
|---|---|---|
|
|
430
436
|
| right file first | 22.9% | **58.6%** |
|
|
431
437
|
| right file in top 3 | 54.3% | **77.1%** |
|
|
@@ -434,28 +440,26 @@ framework reversed it. The honest claim is narrower than either table alone:
|
|
|
434
440
|
| questions it answers | **61** | 60 |
|
|
435
441
|
|
|
436
442
|
Those two tables are the whole argument of section 3.3, measured against a real
|
|
437
|
-
baseline instead of asserted. A cold index retrieves against a
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
and long identifiers, the same cold index lost to Grep by the same margin.
|
|
443
|
+
baseline instead of asserted. A cold index retrieves against a generated
|
|
444
|
+
sentence plus whatever docstrings the author wrote, so how it fares against Grep
|
|
445
|
+
is decided by how much prose the repository already has. Flask documents most
|
|
446
|
+
public methods and the cold index beats Grep there with no description added; on
|
|
447
|
+
the previous subject, terse comments and long identifiers, it lost by the same
|
|
448
|
+
margin.
|
|
444
449
|
|
|
445
450
|
What does not depend on the subject is what descriptions buy: on this
|
|
446
451
|
repository first-place accuracy goes to **more than double** Grep's, and the
|
|
447
452
|
payload comes back ranked, spanned, and roughly half the size.
|
|
448
453
|
|
|
449
|
-
**Both tables come from `python -m benchmarks.grep_baseline`**,
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
was always a call into shipped code, and the baseline never was.
|
|
454
|
+
**Both tables come from `python -m benchmarks.grep_baseline`**, new in 1.3.0.
|
|
455
|
+
Until then this section — the strongest claim the project makes — came from a
|
|
456
|
+
script that was never committed, so nothing here could be checked and "Grep
|
|
457
|
+
loop" had no precise meaning. The committed version defines it: take the
|
|
458
|
+
query's words, drop the ones the corpus itself shows are everywhere, run one
|
|
459
|
+
substring search per remaining word over exactly the files the index was built
|
|
460
|
+
from, rank each file by how many distinct words hit it, break ties on path.
|
|
461
|
+
Reconstructing it reproduced this side's figures exactly and moved Grep's —
|
|
462
|
+
the expected shape, since the ranked arm was always a call into shipped code.
|
|
459
463
|
|
|
460
464
|
Four qualifications, because the table would otherwise flatter both sides:
|
|
461
465
|
|
|
@@ -490,16 +494,14 @@ the time to describe.
|
|
|
490
494
|
|
|
491
495
|
**Build the ruler before reshaping the thing measured.** Four candidate scoring
|
|
492
496
|
changes once landed between five and six correct over an eight-question set —
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
one of them.
|
|
497
|
+
the instrument's resolution limit, not a ranking. There are 135 questions now
|
|
498
|
+
across four rulers, and every claim here is a number from one of them.
|
|
496
499
|
|
|
497
500
|
**Measure somewhere it can fail.** Every ruler this project had once graded a
|
|
498
|
-
repository its own authors wrote
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
35 hit@3.
|
|
501
|
+
repository its own authors wrote; cold against a foreign one the same code
|
|
502
|
+
scored 0.086 hit@1 against a self-reported 0.457. Ruler A exists so that can
|
|
503
|
+
never be comfortable again — and stemming, which helps both own-repo rulers,
|
|
504
|
+
was rejected on it: 3 of 35 hit@3 on the foreign one.
|
|
503
505
|
|
|
504
506
|
**Make the error structurally impossible rather than checking for it.** A line
|
|
505
507
|
number that *is* the loop index cannot drift. A description keyed by a digest
|
|
@@ -509,18 +511,16 @@ of its own code cannot outlive it.
|
|
|
509
511
|
ratios do not.
|
|
510
512
|
|
|
511
513
|
**Derive figures from data; a hand-maintained number is a claim nobody checks.**
|
|
512
|
-
The
|
|
513
|
-
|
|
514
|
-
behind before that test existed.
|
|
514
|
+
The settings table in this README is asserted against `config.py` in both
|
|
515
|
+
directions — it had drifted nine settings behind before that test existed.
|
|
515
516
|
|
|
516
|
-
**The contract does not move.** `CodeUnit`, index schema 2
|
|
517
|
+
**The contract does not move.** `CodeUnit`, index schema 2 and the JSON-lines
|
|
517
518
|
protocol are unchanged across every release; new information arrives in new
|
|
518
|
-
fields
|
|
519
|
+
fields, never by widening an enumeration callers branch on.
|
|
519
520
|
|
|
520
|
-
**Publish what was measured and rejected.** Twelve changes
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
and it cost 3 of 35" is worth more than an unexplored idea.
|
|
521
|
+
**Publish what was measured and rejected.** Twelve changes were implemented,
|
|
522
|
+
measured and dropped, with their numbers, in [docs/ROADMAP.md](docs/ROADMAP.md)
|
|
523
|
+
— "we tried that and it cost 3 of 35" beats an unexplored idea.
|
|
524
524
|
|
|
525
525
|
## 9 · Bringing your own model
|
|
526
526
|
|
|
@@ -633,10 +633,9 @@ Four commands and one skill. No hooks, no agents, no MCP server:
|
|
|
633
633
|
|
|
634
634
|
Measured with `claude plugin details` on an installed copy: **~249 tokens added
|
|
635
635
|
to every session** (skill ~30, each command ~50–60), and 590–2,400 only when
|
|
636
|
-
one
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
install the Python package on first use.
|
|
636
|
+
one fires. Up from ~39 in 1.1.0, and the increase is the price of being
|
|
637
|
+
findable: a skill fires only when a model decides it should, which left the
|
|
638
|
+
plugin with no entry point a person could discover.
|
|
640
639
|
|
|
641
640
|
**As a CLI:**
|
|
642
641
|
|
|
@@ -648,14 +647,13 @@ rag-your-code describe status # description coverage
|
|
|
648
647
|
rag-your-code describe promote | git apply # move descriptions into the code
|
|
649
648
|
```
|
|
650
649
|
|
|
651
|
-
`bootstrap` exists because indexing is not the same as being searchable
|
|
652
|
-
fresh index retrieves against
|
|
653
|
-
|
|
654
|
-
|
|
650
|
+
`bootstrap` exists because indexing is not the same as being searchable: a
|
|
651
|
+
fresh index retrieves against a generated sentence that adds no word the source
|
|
652
|
+
did not have. It reports which rung the repository is on and hands over that
|
|
653
|
+
rung's work; run it again after each round.
|
|
655
654
|
|
|
656
655
|
The index is written under `.rag-your-code/`; **your source files are never
|
|
657
|
-
modified**. `describe promote` emits a diff
|
|
658
|
-
writes source itself.
|
|
656
|
+
modified**. `describe promote` emits a diff to review — it never writes source.
|
|
659
657
|
|
|
660
658
|
### Configuration
|
|
661
659
|
|
|
@@ -711,35 +709,37 @@ than following the console codepage.
|
|
|
711
709
|
|
|
712
710
|
Named because they are measured, not because they are excuses.
|
|
713
711
|
|
|
714
|
-
**One English question in fifteen
|
|
715
|
-
`how is a hostname resolved when the
|
|
716
|
-
`resolved` and `times` genuinely
|
|
717
|
-
|
|
718
|
-
real answer. Chinese sits at 1.000 silence on both.
|
|
712
|
+
**One English question in fifteen is answered when it should not be** on this
|
|
713
|
+
repository, and five in fifteen on Flask. `how is a hostname resolved when the
|
|
714
|
+
nameserver times out` finds `hostname`, `resolved` and `times` genuinely
|
|
715
|
+
co-occurring in one unrelated declaration. No lexical rule separates a real
|
|
716
|
+
vocabulary collision from a real answer. Chinese sits at 1.000 silence on both.
|
|
719
717
|
|
|
720
718
|
**Chinese cold-start hit@1 is 0.000** on rulers A and B. Chinese reaches a
|
|
721
719
|
repository through descriptions or not at all: the code contains no Chinese, so
|
|
722
720
|
a cold index has no Chinese vocabulary to match. `describe` is the fix and it
|
|
723
|
-
works — ruler C is 0.
|
|
721
|
+
works — ruler C is 0.250 on its twelve Chinese questions — but there is no free
|
|
722
|
+
rung of the ladder for it. A Grep loop scores 0.000 there too, on the same
|
|
723
|
+
questions: it is the corpus's limit, not this tool's.
|
|
724
724
|
|
|
725
725
|
**There is no stemming.** `catastrophic backtracking` does not reach
|
|
726
726
|
`backtracks catastrophically`. A light suffix stripper was implemented and
|
|
727
727
|
measured on all four rulers: it improves both own-repository rulers and costs
|
|
728
728
|
the foreign one 3 of 35 hit@3, so it was rejected.
|
|
729
729
|
|
|
730
|
-
**A test declaration sometimes outranks real code** —
|
|
731
|
-
three rulers,
|
|
732
|
-
The long-standing explanation, that a test outranks the
|
|
733
|
-
wrong: of the
|
|
734
|
-
prose. A callee-before-caller rerank fires on zero questions and the `name`
|
|
735
|
-
field weight moves nothing
|
|
730
|
+
**A test declaration sometimes outranks real code** — 9 of 175 questions across
|
|
731
|
+
three rulers, a test at rank 1 displacing an accepted answer at rank 2–3, and
|
|
732
|
+
none of them on Flask. The long-standing explanation, that a test outranks the
|
|
733
|
+
code it *tests*, is wrong: five of the nine are unrelated tests winning on
|
|
734
|
+
prose. A callee-before-caller rerank fires on zero questions, and the `name`
|
|
735
|
+
field weight moves nothing because an underscored test name is one token.
|
|
736
736
|
|
|
737
|
-
**The vectors are
|
|
738
|
-
embedder.
|
|
739
|
-
and the schema stays one shape.
|
|
737
|
+
**The vectors are 72.1% of the index and earn ±1 question** under the default
|
|
738
|
+
embedder. Kept: the same storage is what makes an optional model work.
|
|
740
739
|
|
|
741
|
-
**`search.vector_recall` scans every vector per query
|
|
742
|
-
|
|
740
|
+
**`search.vector_recall` scans every vector per query** — under a semantic
|
|
741
|
+
embedder. The default hash never widens at all. Affordable at the measured
|
|
742
|
+
envelope, and exactly the work an ANN index would replace.
|
|
743
743
|
|
|
744
744
|
**Tree-sitter parsing and a SQLite/ANN storage layer are not here.** Both would
|
|
745
745
|
need a dependency, and the policy for those is settled: they follow the
|
|
@@ -765,9 +765,9 @@ pytest -q
|
|
|
765
765
|
|
|
766
766
|
Per-release test counts are in [CHANGELOG.md](CHANGELOG.md); a bare figure in a
|
|
767
767
|
living document is a claim that rots. CI runs Python 3.10–3.13 on Linux and
|
|
768
|
-
Windows,
|
|
769
|
-
|
|
770
|
-
line verbatim.
|
|
768
|
+
Windows, installs the built wheel into a clean environment and runs the
|
|
769
|
+
documented CLI end to end — `bootstrap` through `describe promote` — plus the
|
|
770
|
+
skill's own install line verbatim.
|
|
771
771
|
|
|
772
772
|
- [docs/FLOW.md](docs/FLOW.md) — the whole thing in four diagrams
|
|
773
773
|
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — how each stage works and why
|