# Agent Note: 统一会话查询服务

Status: implemented

[English](2026-07-23-unified-session-query-service.md) | 中文

## 问题

精确读取、语义过滤、关系追踪与全文搜索都作用于同一个实时源优先的会话语料库。将全文搜索暴露在第二个上下文键下，会让消费方与应用组合把同一项查询功能视为两个服务，尽管只有 SQLite 实现是后端特有的部分。

接口包已经拥有共享的记录、过滤、追踪、搜索请求、游标与错误契约。提供方注册表或协调器会引入运行时选择语义，而目前没有任何消费方支持这种语义。

## 决策

`SessionQueryService` 是注册为 `ctx.sessionQuery` 的唯一抽象服务。它通过后端无关的 `SessionCorpus` 具体实现列表查询、标题与事件读取、表层读取、过滤和关系追踪。仅有 `searchSessions()` 与 `searchEvents()` 两个方法为抽象方法。

`SessionQuerySqlite` 扩展该服务，并且是唯一的具体后端。因此，一个挂载实例便可通过 `ctx.sessionQuery` 暴露全部操作；其继承的精确操作使用共享的语料库实现，而由 SQLite 管理的生命周期负责观察数据源、对齐派生 FTS 索引、对匹配项排序并管理游标代际。接口包不提供独立的具体插件、搜索提供方注册表或第二个上下文键。

后端配置除了自身的索引路径、日志模式、分页限制与文本片段长度上限外，还包含继承的 `readWindowMax` 设置。需要会话查询的第一方应用挂载 SQLite 后端，并将其可丢弃索引放在已配置的持久化根目录旁。

这一服务拓扑取代了[精确查询决策](../feature/2026-07-10-session-query-service.md)和 [SQLite 搜索决策](../feature/2026-07-10-sqlite-session-query-provider.md)中关于分离上下文键的部分；其中关于语料库、查询、分词器、对齐与安全性的决策仍然有效。

## 已考虑的替代方案

- **保留相互独立的 `ctx.sessionQuery` 与 `ctx.sessionSearch`**：不予采纳，因为二者都针对同一逻辑语料库提供操作，迫使消费方识别两个键，还可能让应用误挂载一组不完整的查询接口。
- **保留具体的基础服务，再由 SQLite 插件注册或修改两个搜索方法**：不予采纳，因为方法是否可用将取决于插件顺序与资源释放时机，而且该服务需要为唯一的实现定义一套提供方注册协议。
- **将所有查询实现移入 SQLite 包**：不予采纳，因为精确读取、过滤与追踪不需要索引，并且都属于应与提供方无关契约放在一起的共享行为。

## 后果

消费方只需注入一个服务，无需再次查找其他功能，便可组合精确操作与全文操作。生产环境的组合必须选择一个具体后端，即使当前某个消费方只调用继承的精确方法；如果后端行为不在测试范围内，测试可以使用最小子类。

统一后的对象有意保留两种内部观察策略：精确操作在每次调用时读取权威的实时源或持久化源，全文操作则使可丢弃索引与数据源对齐。共用上下文键不会让派生索引成为权威来源，也不会使精确读取的可用性依赖 FTS 查询。

单元测试在同一个键上同时固定继承实现与抽象方法的契约，SQLite 测试在具体后端上覆盖两类操作，真实 Loader 路径则验证单个导出的插件能够注册组合后的服务。
