Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 0 additions & 295 deletions dev/plans/260723-everyday-query-hot-paths.md

This file was deleted.

10 changes: 3 additions & 7 deletions dev/plans/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ Each program is ordered internally. Promote one numbered delivery slice at a
time into its own executor plan and independently reviewable change;
evidence-gated slices receive an executor plan only after their gate passes.

1. [Everyday query hot paths](260723-everyday-query-hot-paths.md) — fix broad
entry selection first, then reduce repeated search hydration and summary
work, add compatible keyset continuation, and measure later planner/startup
candidates.
2. [Indexing hot paths](260723-indexing-hot-paths.md) — measure discovery and
1. [Indexing hot paths](260723-indexing-hot-paths.md) — measure discovery and
replacement work, remove avoidable provider lookup/serialization and
statement-per-content costs, then gate deeper transaction or WAL changes.
3. [Doctor and maintenance hot paths](260723-doctor-maintenance-hot-paths.md) —
2. [Doctor and maintenance hot paths](260723-doctor-maintenance-hot-paths.md) —
make exact FTS verification memory-bounded, partition oversized terms, page
only orphan candidates, and gate any compact-proof optimization separately.
4. [Verified bounded session reads](260723-verified-bounded-session-reads.md) —
3. [Verified bounded session reads](260723-verified-bounded-session-reads.md) —
stream complete validation and the existing public-document digest while
retaining only the requested bounded `show` or `export` selection.
11 changes: 11 additions & 0 deletions docs/architecture-memo.md
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,17 @@ facets, deterministic comparison/timelines, tokenizer phrase search, smaller
search/entries titles, exact locator interning, and Markdown presentation remain
unsequenced until evidence gives them priority.

Cursor format convergence is also deferred. List and entries currently emit
anchored v2 continuations while accepting v1 offset continuations once; search
still emits v1. Promote a retirement plan only after a measured, exact search
keyset design justifies v2 search, every command has stopped emitting v1, and a
declared compatibility boundary permits removal. That plan must first preserve
v1 decoding during the emission transition, prove complete v2 traversal and
existing stale/query-mismatch failures, then remove the v1 decoder and legacy
offset paths together. Opaque cursors remain continuation tokens rather than
durable bookmarks, but their removal is still an explicit compatibility
decision.

Semantic search, an external plugin ABI, cloud/team indexes, native binaries,
Homebrew, TUI/watch mode, orchestration integrations, opt-in automated changes,
raw provider backup, destination-provider delivery, and automatic project edits
Expand Down
33 changes: 22 additions & 11 deletions docs/contributing/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ forget / data repair-orphans / data compact / data clear
-> src/infrastructure/sqlite/index-maintenance.ts
```

The composition root is the only production module that imports both a concrete
adapter and infrastructure. It resolves Cursor and Codex lazily: help, version,
list, search, entries, manifest, show, export, forget, data repair-orphans, data
compact, and data clear do not resolve provider configuration.
Index, paths, and doctor resolve registered sources. Implicit indexing skips
only valid unavailable sources; explicit selection and all other probe failures
remain strict.
The composition root is the only production module that selects both concrete
adapters and infrastructure. CLI grammar stays static, while providers,
lifecycle, maintenance, diagnostics, indexing, and command services load through
memoized callback-local imports. Help and version therefore load none of those
capabilities. List, search, entries, manifest, show, export, forget, data
repair-orphans, data compact, and data clear load their provider-free services
without resolving provider configuration. Index, paths, and doctor resolve
registered sources. Implicit indexing skips only valid unavailable sources;
explicit selection and all other probe failures remain strict.

## Ownership

Expand Down Expand Up @@ -308,7 +310,11 @@ FTS damage. List/search/manifest read the stored digest directly and do not
reconstruct every document. None resolve or
reopen a provider, so retained content remains usable after provider disappearance.
The guard changes neither the SQLite schema nor physical read cost.
Query cursors bind the query plus library identity/writer generation. An explicit
Query cursors bind the query plus library identity/writer generation. List and
entry continuations use v2 provider-neutral numeric anchors for indexed keyset
continuation while retaining the cumulative offset and accepting existing v1
offset tokens; search remains on the compatible v1 offset format. No cursor
contains a raw provider identity. An explicit
leased index writer can rebuild FTS-only damage from canonical content. Doctor
stays read-only and reports canonical integrity, content reachability,
projection health, and the global capture aggregate separately. Canonical health
Expand Down Expand Up @@ -370,10 +376,15 @@ fallback, bounded context assembly, query-wide counts, and cursor encoding.
The shared capture-scope reader uses registered-source and tracking columns only,
reports applicable source coverage even for a no-hit page, and names canonical
metadata, entry, and text filters it cannot assess for unindexed sessions.
Search ranks compact coordinates first, keeps the extra rank-only row used for
pagination, and hydrates text, digest, and snippets only for the selected page.
List, search, and entries carry compact canonical session IDs through page
selection and hydrate the selected retained summaries in one bounded,
identity-checked batch. Search ranks compact coordinates first, keeps the extra
rank-only row used for pagination, and hydrates text, digest, and snippets in one
selected-page statement. Context link discovery is page-wide; physical context
coordinates are deduplicated and their bodies are read in fixed-size chunks.
Snippet markers are checked against those selected canonical texts and retried
on collision, so search does not scan or hydrate the rest of the library.
for the complete selected page on collision, so search does not scan or hydrate
unselected text.
`any` mode derives exact per-hit terms with candidate-local probes after page
selection. One query-scoped root resolver serves support plus list/search/entries
attribution. Support remains exact and query-wide rather than being inferred from the page.
Expand Down
48 changes: 36 additions & 12 deletions docs/contributing/entries.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,35 @@ The public behavior is defined by the
1. The domain validates and freezes shared session filters, exact entry filters,
selection, page limit, and cursor. Defaults are `all` and 50; the maximum page
is 200 entries.
2. SQLite selects compact entry coordinates through source, tracking, canonical
session, and entry rows. It does not use FTS or reconstruct session documents.
2. SQLite selects compact entry coordinates through an explicit
source→tracking→canonical→entry traversal. `CROSS JOIN` boundaries keep that
loop order stable so SQLite can stop after the requested page instead of
scanning the entry table and sorting the complete result. It does not use FTS
or reconstruct session documents.
3. `all` keeps every qualifying entry. `first` or `last` keeps the lowest or
highest canonical ordinal per session after all filters are applied.
4. Origin qualifies through retained segments, including omitted content. An
empty entry cannot match an origin. Tool name or namespace selects observed
`tool-call` entries only.
5. After page selection, SQLite loads exact segment counts and at most one text
preview per entry. An origin-filtered query previews only text with that
origin; an omitted-only match has no preview.
preview per entry. It deduplicates selected sessions and loads their retained
summaries in one identity-checked batch of at most 200 requests. An
origin-filtered query previews only text with that origin; an omitted-only
match has no preview.
6. The same immutable snapshot supplies one page-level capture scope from
registered sources and tracking state. Entry and canonical metadata filters
are named as unassessed for tracking-only sessions.
7. One query-scoped lineage resolver returns the known retained root or
`unknown` for each result session.
8. A next cursor binds the full query, library identity, writer generation, and
offset. It is a continuation token, not a durable bookmark.
8. A next cursor binds the full query, library identity, writer generation,
cumulative offset, and the last selected numeric session/entry coordinate.
Continued pages strictly resolve that coordinate under the same filters and
selection, recover its binary identity order, and continue after it without
`OFFSET`. The token contains no raw provider identity.
9. Existing v1 offset cursors remain accepted. They use the offset path once and
emit a v2 anchored continuation. A missing or nonqualifying matching-revision
anchor is invalid; a different library or writer generation is stale. Cursors
remain opaque continuation tokens, not durable bookmarks.

## Order and evidence

Expand All @@ -44,13 +56,25 @@ match or non-match.

## Cost

The query scans matching entry coordinates in stable key order and hydrates text
only for the selected page. `first` and `last` use a per-session ordinal lookup
after filtering. Origin filters probe retained segment rows. Root resolution
reads retained lineage once per nonempty query and reuses results within it.
The query walks matching entry coordinates in stable source and identity index
order, stops after `limit + 1`, and hydrates text only for the selected page.
`first` and `last` use a per-session ordinal lookup after filtering. Origin
filters probe retained segment rows. Root resolution reads retained lineage once
per nonempty query and reuses results within it.

The current schema and indexes are sufficient for the measured generic corpus.
Any later durable index needs separate size and query evidence.
The generated measure uses an on-disk skewed corpus with thousands of sessions,
hundreds of thousands of mostly textless entries, and one session with tens of
thousands of entries. It warms and repeats broad and filtered `all`, `first`,
`last`, origin, tool, early-page, and deep-page reads. The report separates
coordinate selection from full hydration, proves repeated result equality, and
normalizes `EXPLAIN QUERY PLAN` into the outer access, indexes used, and
temporary-ordering presence. It also reports whether the production statement
uses keyset continuation or `OFFSET`; new and v2 entry pages must have no
`OFFSET`. Elapsed time is report-only; semantic equality and the
source-first/no-full-sort bounded plan shape are the structural proof.

The current schema and indexes are sufficient for this traversal. Any later
durable index needs separate size and query evidence.

## Code and proof

Expand Down
29 changes: 24 additions & 5 deletions docs/contributing/search.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ The public behavior is defined by the [CLI contract](../reference/cli-contract.m
4. SQLite ranks each entry by its best FTS5 BM25 score. Ties use session activity,
source identity, and entry ordinal in a fixed order. The query keeps one extra
rank row only to decide whether a next page exists.
5. After selecting the page, SQLite loads full text, its digest, and the FTS
snippet only for selected content IDs. `any` mode probes each selected entry
for its exact matched terms; `all` reuses the unique query terms.
5. After selecting the page, one page-bounded SQLite statement loads full text,
its digest, and the FTS snippet for the distinct selected content IDs. Snippet
marker collisions retry that whole selected page deterministically. `any`
mode probes each selected entry for its exact matched terms; `all` reuses the
unique query terms. Distinct selected sessions load their retained summaries
in one identity-checked batch of at most 200 requests.
6. The same immutable snapshot supplies one page-level capture scope from
registered sources and tracking state. Source/tracking filters can narrow that
aggregate; canonical metadata, entry, and search-text filters are named as
Expand All @@ -25,7 +28,9 @@ The public behavior is defined by the [CLI contract](../reference/cli-contract.m
`unknown`.
8. Search verifies each selected content hash, bounds snippets and context to 512
UTF-8 bytes, and adds requested neighboring entries plus direct tool-call and
tool-result links.
tool-result links. One page-level query discovers direct links, then selected
physical context coordinates are deduplicated and hydrated in fixed-size
chunks before each hit's flags and order are rebuilt.
9. Support is calculated over the complete filtered retained result, before page slicing:
matching occurrences, distinct content, known roots, and sessions with unknown
lineage.
Expand Down Expand Up @@ -57,9 +62,23 @@ and lineage counts still inspect the full qualifying result, so broad searches c
still take longer on large libraries. The design favors exact evidence over
approximate counts or ranking.

Selected-content, summary, and linked-context query counts are page-bounded
instead of growing once per hit. Context body hydration grows with fixed-size
chunks of distinct selected physical entries, so overlapping hit neighborhoods
share the same read. These batching steps do not change ranking or query-wide
support work.

The exact query-wide support, identity, and rank passes intentionally remain
separate. A generated `MATERIALIZED` one-pass prototype proved one qualifying FTS
scan and exact result parity, but was about 15% slower across broad profiles
instead of meeting the 20% improvement gate. Its selective regression and peak
memory stayed within bounds, so performance—not correctness—closed that
candidate and no prototype runtime path is retained.

`any` mode adds at most one candidate-local FTS probe per unique term for the
selected page. Activity bounds reuse canonical timestamps and add no storage
index. The repeatable measurement covers both term modes; elapsed time remains
index. The repeatable measurement covers small and maximum-size pages, with and
without neighboring context, in both term modes; elapsed time remains
report-only.

## Retrieve an exact span
Expand Down
28 changes: 28 additions & 0 deletions docs/contributing/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,34 @@ set-based query shape from N+1 drift. It constructs no provider adapter, prints
only aggregate counts and timings, has no timed threshold, and stays outside
`pnpm check`.

`pnpm measure:query-planner-statistics` is an opt-in, provider-free experiment
for SQLite planner statistics. It builds one skewed generic library, closes it,
then makes byte-exact control, `ANALYZE`, and forced `PRAGMA optimize` clones.
Only the two experiment clones receive statistics mutations. The command
compares normalized representative plans and alternating warm elapsed
aggregates for broad and narrow entries, identity and activity list filters,
broad and selective `all`/`any` search, and manifest. Production query results
must remain exactly equal across all clones. The report also includes
statistics-table row counts, statistics payload bytes, mutation time, database
growth, clone verification, and final temporary-root cleanup. The experiment
has no elapsed threshold and does not define or invoke a runtime refresh policy.
The full corpus stays outside `pnpm check`; a small `-- --contract` run in the
test suite checks mutation isolation, semantic equality, report shape, and
cleanup. Current generated evidence leaves runtime statistics disabled: entry
plans stayed unchanged while several narrow, list, and search profiles regressed.
Any future policy proposal must rerun this experiment against the then-current
queries and separately design certified writer mutation and refresh semantics.

`pnpm measure:cli-startup` is the compiled, provider-free startup measure. Run
`pnpm build` first. It rotates bare Node, version, top-level help, command help,
and one uninitialized local read across warm-up and measured rounds using only a
mode-0700 temporary data root. It checks exact success/output shapes, reports
median and p95 elapsed aggregates plus overhead against bare Node, and removes
the temporary root before emitting its report. Lazy CLI composition is a
candidate only when version, top help, and command help each cost at least 25 ms
over bare Node and at least 2× bare Node. These are implementation decision
thresholds, not CI performance budgets; the command stays outside `pnpm check`.

`pnpm measure:indexing:codex -- --allow-provider-read` is the Codex local
provider-read measurement. It is macOS/Linux-only and fails before provider
resolution elsewhere. It uses the production Codex adapter, exhausts its full
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@
"format:docs:check": "oxfmt --check \"**/*.md\"",
"lint": "oxlint -c .oxlintrc.json src scripts test vitest.config.ts",
"lint:fix": "oxlint -c .oxlintrc.json --fix src scripts test vitest.config.ts",
"measure:cli-startup": "node scripts/measure-cli-startup.ts",
"measure:content-storage": "node scripts/measure-content-storage.ts",
"measure:entry-query": "node scripts/measure-entry-query.ts",
"measure:indexing": "node scripts/measure-indexing.ts",
"measure:indexing:codex": "node scripts/measure-codex-indexing.ts",
"measure:indexing:cursor": "node scripts/measure-cursor-indexing.ts",
"measure:manifest": "node scripts/measure-manifest.ts",
"measure:query-lineage": "node scripts/measure-query-lineage.ts",
"measure:query-planner-statistics": "node scripts/measure-query-planner-statistics.ts",
"measure:search-query": "node scripts/measure-search-query.ts",
"hooks:install": "simple-git-hooks",
"prepack": "pnpm build",
Expand Down
Loading