Skip to content

Commit 4570c11

Browse files
Lukas Geigerclaude
andcommitted
feat(find): restrict a search to one observe-source
Source sizes differ by three orders of magnitude -- on the reporting machine codex-sessions holds 260,623 transcript lines against 518 in usmc-working, out of 290,902 observed entries. BM25 hands the whole first page to the transcripts, so a subject-matter search comes back looking empty and the index appears not to contain the entry at all. find() now takes --source <id>[,<id>] (and find(source=...)), a WHERE condition on the observed/<source-id>/ namespace applied before the ranking -- in all three stages, because wiring it into the exact FTS pass alone would drop the filter silently on any multi-word query. Without a query the flag lists the source, since FTS5 has nothing to match on. --type and --limit are passed through from the CLI as well; find() already accepted them. The find command parses its own flags now: the CLI has no argparse and joined everything after `find` into the query, so --source would have become a search word. Read-only: no schema migration, no new index, recall() untouched, and the new parameter is appended with a None default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BoFKxJmj9pU5Q8a6yN8HBn
1 parent 67d148a commit 4570c11

11 files changed

Lines changed: 583 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,44 @@
11
# Changelog
22

3+
## 2026-08-13
4+
5+
`find()` can be restricted to one observe-source, so a small source is no
6+
longer buried by a large one.
7+
8+
- **`--source <id>[,<id>]` / `find(source=...)`** filters on the
9+
`observed/<source-id>/…` namespace as a `WHERE` condition -- before the
10+
ranking, and in all three stages of `find()`: exact FTS, the multi-word OR
11+
fallback, and the LIKE fallback. Wiring it into only the first stage would
12+
have dropped the filter silently on any multi-word query.
13+
- Why it was needed: source sizes differ by three orders of magnitude. On
14+
the reporting machine `codex-sessions` holds 260,623 transcript lines
15+
against 518 in `usmc-working`, out of 290,902 `observed` entries total.
16+
BM25 hands the entire first page to the transcripts, so a subject-matter
17+
search returns nothing usable and reads as "not in the index".
18+
- A source id matches a whole path segment, so `--source usmc` does not
19+
pull in `usmc-working`. A leading `observed/` is optional, several ids
20+
are OR-ed, and `_`/`%` in an id are escaped instead of acting as LIKE
21+
wildcards.
22+
- **`--source` without a query lists the source**, newest first. FTS5 needs a
23+
term to match; "show me everything from this source" has none, so that case
24+
takes a plain `WHERE`/`ORDER BY updated` path instead of returning nothing.
25+
- **`--type` and `--limit` are now reachable from the CLI.** `find()` already
26+
accepted both; only the command line did not pass them through.
27+
- **The `find` command parses its own flags.** The CLI has no argparse and
28+
joined everything after `find` into the query, so `--source` would have
29+
become a search word. `_parse_find_args()` splits options from search terms,
30+
accepts `--flag value` and `--flag=value`, and reports unknown options and
31+
missing values instead of silently searching for them.
32+
- Documented in `README.md` and `README_de.md`, including the pre-existing
33+
workaround for older versions (pass the source id as a search word -- entry
34+
names are in the full-text index) and the boundary against `extra_tags`,
35+
which labels a source at registration time rather than narrowing one search.
36+
- Test suite grew from 86 to 108 tests.
37+
38+
Read-only change: no schema migration, no new index, `recall()` untouched, and
39+
existing `find()` callers keep their behaviour (the new parameter is appended
40+
and defaults to `None`).
41+
342
## 2026-08-05
443

544
Fixed: the never-index list missed Windows paths on non-Windows hosts.

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,44 @@ af.observe_source_add("usmc-lessons", "sqlite_table",
278278
"tags": "category"})
279279
```
280280

281+
### Searching one source instead of all of them
282+
283+
Sources differ in size by three orders of magnitude. On this machine
284+
`codex-sessions` holds 260,000 transcript lines while `usmc-working` holds
285+
518 notes — so BM25 hands the whole first page to the transcripts, and a
286+
subject-matter search comes back looking empty. `find()` therefore takes a
287+
source filter:
288+
289+
```bash
290+
gardener find --source usmc-working store welle
291+
gardener find --source usmc-working,usmc-facts store
292+
gardener find --source usmc-working # no query: list the source
293+
gardener find --type memory --limit 5 store # also exposed: type, limit
294+
```
295+
296+
```python
297+
af.find("store welle", source="usmc-working")
298+
af.find("store", source=["usmc-working", "usmc-facts"])
299+
af.find("", source="usmc-working", limit=50) # list, newest first
300+
```
301+
302+
The filter is a `WHERE` condition on the `observed/<source-id>/…` namespace
303+
and runs **before** the ranking, in all three stages of `find()` (exact FTS,
304+
multi-word OR fallback, LIKE fallback). A source id matches the whole path
305+
segment, so `--source usmc` does not pull in `usmc-working`; a leading
306+
`observed/` may be written or omitted. `--source` and the `source` field in a
307+
result are different things — the field names the database (`user`/`system`).
308+
309+
> [!NOTE]
310+
> **Older versions without `--source`:** pass the source id as a search word,
311+
> `gardener find usmc-working store`. Entry names are part of the full-text
312+
> index, so this works — it just ranks weaker than a real filter, because the
313+
> id competes with the query terms instead of restricting the candidate set.
314+
315+
This is the query-time counterpart to `extra_tags` below: `extra_tags` labels a
316+
source when it is registered, for consumers that group several sources under one
317+
name; `--source` narrows a single search to a named source and needs no foresight.
318+
281319
### What a source can never index
282320

283321
A source config points an adapter at whatever glob it likes, so the

README_de.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,45 @@ af.observe_source_add("gemini-archive", "agent_transcripts",
280280
zip_inner="*/.system_generated/logs/transcript.jsonl")
281281
```
282282

283+
### Eine Quelle suchen statt alle
284+
285+
Quellen unterscheiden sich um drei Grössenordnungen: Auf dieser Maschine hält
286+
`codex-sessions` 260.000 Transkriptzeilen, `usmc-working` 518 Notizen — BM25 gibt
287+
die ganze erste Seite also den Transkripten, und eine Fachsuche sieht aus, als
288+
gäbe es nichts. `find()` nimmt deshalb einen Quellenfilter entgegen:
289+
290+
```bash
291+
gardener find --source usmc-working store welle
292+
gardener find --source usmc-working,usmc-facts store
293+
gardener find --source usmc-working # ohne Suchbegriff: Quelle auflisten
294+
gardener find --type memory --limit 5 store # ebenfalls neu durchgereicht
295+
```
296+
297+
```python
298+
af.find("store welle", source="usmc-working")
299+
af.find("store", source=["usmc-working", "usmc-facts"])
300+
af.find("", source="usmc-working", limit=50) # auflisten, neueste zuerst
301+
```
302+
303+
Der Filter ist eine `WHERE`-Bedingung auf den Namensraum `observed/<quell-id>/…`
304+
und wirkt **vor** dem Ranking, in allen drei Stufen von `find()` (exakte
305+
FTS-Suche, Mehrwort-ODER-Fallback, LIKE-Fallback). Eine Quell-ID matcht das ganze
306+
Pfadsegment, `--source usmc` zieht also nicht `usmc-working` mit; ein
307+
vorangestelltes `observed/` darf man schreiben oder weglassen. `--source` und das
308+
Feld `source` im Ergebnis sind zweierlei — das Feld benennt die Datenbank
309+
(`user`/`system`).
310+
311+
> [!NOTE]
312+
> **Ältere Versionen ohne `--source`:** die Quell-ID als Suchwort mitgeben,
313+
> `gardener find usmc-working store`. Eintragsnamen stehen im Volltextindex, das
314+
> funktioniert also — es rankt nur schwächer als ein echter Filter, weil die ID
315+
> mit den Suchbegriffen konkurriert, statt die Kandidatenmenge einzuschränken.
316+
317+
Das ist das Gegenstück zur Abfragezeit zu `extra_tags` weiter unten: `extra_tags`
318+
etikettiert eine Quelle bei der Registrierung, für Konsumenten, die mehrere
319+
Quellen unter einem Namen bündeln; `--source` verengt eine einzelne Suche auf
320+
eine benannte Quelle und braucht keine Vorausplanung.
321+
283322
### Was eine Quelle niemals indexieren kann
284323

285324
Eine Quellen-Konfiguration richtet den Adapter auf einen beliebigen Glob —

ROADMAP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
**🇩🇪 [Deutsche Version](ROADMAP_de.md)**
44

5-
> Updated: 2026-08-01
6-
> Current release: v0.3.1 (prototype)
5+
> Updated: 2026-08-13
6+
> Current release: v0.4.0 (prototype)
77
88
## Prototype (v0.1) — DONE
99

ROADMAP_de.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
**🇬🇧 [English Version](ROADMAP.md)**
44

5-
> Aktualisiert: 2026-08-01
6-
> Aktuelle Version: v0.3.1 (Prototyp)
5+
> Aktualisiert: 2026-08-13
6+
> Aktuelle Version: v0.4.0 (Prototyp)
77
88
## Prototyp (v0.1) — ERLEDIGT
99

0 commit comments

Comments
 (0)