Skip to content

fix(wiki-favicon): 修复 negentropy-wiki 站点 favicon.ico 不生效(单分辨率畸形 × 非方形源图) - #423

Merged
ThreeFish-AI merged 1 commit into
feature/1.x.xfrom
ThreeFish-AI/fix-wiki-favicon
Apr 27, 2026
Merged

fix(wiki-favicon): 修复 negentropy-wiki 站点 favicon.ico 不生效(单分辨率畸形 × 非方形源图)#423
ThreeFish-AI merged 1 commit into
feature/1.x.xfrom
ThreeFish-AI/fix-wiki-favicon

Conversation

@ThreeFish-AI

Copy link
Copy Markdown
Owner

背景

用户在浏览器访问已发布的 Negentropy Wiki 站点(apps/negentropy-wiki)时,标签页未显示品牌图标,回落为浏览器默认地球图标,影响品牌识别。

缺图标的 tab

根因(双重畸形叠加)

通过 file(1) 与 ICO 二进制头部检验:

维度 当前 wiki 站点(异常) 兄弟应用 negentropy-ui(正常参考)
file 输出 1 icon, 256x-1, 32 bits/pixel 9 icons, 16x16 ... 32 bits/pixel
文件体积 269,342 字节 191KB
ICO 目录条目 width=0x00(=256),height=0xFF(=255) 多档标准方形条目
内嵌 BMP DIB 256×510(即 256×255 单图) 多档标准方形条目
  • 源图 apps/negentropy-wiki/public/logo.png800×798 非方形 PNG
  • 历史转换工具未做 padding/裁切便直接外裹 ICO 头,吐出单分辨率 + 非方形 + 高度字段错误的畸形 ICO;
  • 现代浏览器(Chrome / Firefox / Safari)拒绝解析此类畸形 ICO,按规范回退默认图标。

已排除的伪因(避免下次走同样弯路)

  • ✗ 中间件 / 代理拦截(next.config.ts 仅 rewrites /api/:path*);
  • ✗ 顶层动态路由 [pubSlug]/page.tsx 拦截(App Router 元数据文件优先级高于 dynamic segment,本机 curl 已验证);
  • ✗ standalone 构建产物缺失(pnpm build.next/standalone/.next/server/app/favicon.ico/route.js + .body + .meta 完整);
  • layout.tsx 元数据冲突(metadata.icons.apple = "/logo.png" 仅追加 <link rel=\"apple-touch-icon\">,不影响 <link rel=\"icon\"> 自动注入)。

修复方案(最小干预 + 复用驱动)

仅替换 apps/negentropy-wiki/src/app/favicon.ico 文件本身,不动 layout.tsx / next.config.ts / start-production.mjs,保留 App Router metadata 自动注入路径:

uv run --with 'pillow>=11' --no-project python - <<'PY'
from PIL import Image, ImageOps
from pathlib import Path

src = Path(\"apps/negentropy-wiki/public/logo.png\")
dst = Path(\"apps/negentropy-wiki/src/app/favicon.ico\")

im = Image.open(src).convert(\"RGBA\")
side = max(im.size)  # 800x798 -> 800x800 居中透明 padding
im = ImageOps.pad(im, (side, side), color=(0, 0, 0, 0), centering=(0.5, 0.5))

sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
im.save(dst, format=\"ICO\", sizes=sizes)
PY

结果:6 档多分辨率 ICO,体积 269KB → 118KB。

自证(端到端验证)

1. 静态层

$ file apps/negentropy-wiki/src/app/favicon.ico
MS Windows icon resource - 6 icons, 16x16 with PNG image data, ... 32x32 ... 32 bits/pixel

ICO 头部十六进制确认 6 条目(16/32/48/64/128/256),全部 PNG 编码:

00000000: 0000 0100 0600 1010 0000 0000 2000 5203
00000010: 0000 6600 0000 2020 0000 0000 2000 f209
00000020: 0000 b803 0000 3030 0000 0000 2000 2e13
00000030: 0000 aa0d 0000 4040 0000 0000 2000 081f
00000040: 0000 d820 0000 8080 0000 0000 2000 f460
00000050: 0000 e03f 0000 0000 0000 0000 2000 dc2c
00000060: 0100 d4a0 0000 8950 4e47 0d0a 1a0a 0000  ← PNG 签名

2. 构建层(standalone 产物)

$ pnpm build  # 编译成功,无新增 warnings
$ ls .next/standalone/.next/server/app/favicon.ico*
.next/standalone/.next/server/app/favicon.ico/route.js
.next/standalone/.next/server/app/favicon.ico/route.js.nft.json
.next/standalone/.next/server/app/favicon.ico.body   # 6 icons ICO ✓
.next/standalone/.next/server/app/favicon.ico.meta   # content-type: image/x-icon ✓

3. 运行层

$ pnpm start &
$ curl -sI http://localhost:3092/favicon.ico
HTTP/1.1 200 OK
content-type: image/x-icon
cache-control: public, max-age=0, must-revalidate
x-nextjs-cache: HIT

$ curl -s http://localhost:3092/ | grep -oE '<link[^>]*rel=\"icon\"[^>]*>'
<link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\" sizes=\"16x16\"/>

4. 路由优先级回归

$ curl -sI http://localhost:3092/favicon.ico        # → image/x-icon ✓
$ curl -sI http://localhost:3092/some-random-slug   # → text/html ✓([pubSlug] 接管)

证明 [pubSlug] dynamic route 不会误命中 favicon.ico

Test Plan

  • file apps/negentropy-wiki/src/app/favicon.ico 输出 6 icons, 16x16 ... 256x256 PNG image data
  • pnpm build 通过且 .next/standalone/.next/server/app/favicon.ico.body 同样为 6 档 ICO;
  • 本机 pnpm startcurl -I /favicon.ico 返回 200 / image/x-icon / 118192 bytes
  • 首页 HTML 包含 <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">(自动注入);
  • [pubSlug] 动态路由不会拦截 /favicon.ico
  • 用户在 Chrome / Firefox / Safari 隐身模式访问发布站点,确认 tab 显示 Negentropy 品牌图标。

防范沉淀

docs/issue.md 追加 ISSUE-027,沉淀以下工程约束:

  1. ICO 必须方形 + 多分辨率(至少 16×16 / 32×32 两档),入库前 file 自检;
  2. 优先复用 Pillow ImageOps.pad + save(format=\"ICO\", sizes=[…]) 流水线模板;
  3. 涉及品牌资产的 PR 必须附「替换前 / 替换后浏览器 tab 截图」+ file 输出;
  4. 同类影响:未来 apps/*/src/app/icon.{png,svg}apple-icon.pngopengraph-image.{png,jpg} 均需走 padding+多档生成流程。

影响范围

  • apps/negentropy-wiki 站点用户感知;
  • 不影响后端 / 其它 app;
  • 不引入新依赖(构建/运行时仍为 Next.js + Pillow 仅在本地一次性生成);
  • 二进制变更已通过 git diff --stat 体现:1 个 ICO 文件 + 1 个文档条目。

🤖 Generated with Claude Code

…球图标;

- 根因:apps/negentropy-wiki/src/app/favicon.ico 是单分辨率畸形 ICO(file 输出 256x-1,高度字节 0xFF),且源图 logo.png 为非方形 800x798,导致 Chrome/Firefox/Safari 解析失败、tab 回落默认地球图标;
- 修复:用 Pillow 对 logo.png 做透明 padding 至 800x800 方形,再生成多分辨率 ICO(16/32/48/64/128/256 共六档)覆盖原文件;体积从 269KB 降至 118KB;
- 验证:file 输出 6 icons; pnpm build 后 .next/standalone 内 favicon route + body + meta 完整;pnpm start 后 curl /favicon.ico 返回 200 image/x-icon,HTML 自动注入 <link rel="icon">;
- 防范:docs/issue.md 追加 ISSUE-027,沉淀「ICO 必须方形 + 多分辨率」工程约束与 Pillow 流水线模板,禁止「原图直裹 ICO 头」反模式;
- 不动:layout.tsx / next.config.ts / start-production.mjs,保留 App Router metadata 自动注入路径,最小干预。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit f166f39 into feature/1.x.x Apr 27, 2026
ThreeFish-AI added a commit that referenced this pull request Apr 27, 2026
…res;

合并 #423(修复 negentropy-wiki 站点 favicon.ico 单分辨率畸形),保持本分支与 base 同步。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI deleted the ThreeFish-AI/fix-wiki-favicon branch April 27, 2026 06:51
ThreeFish-AI added a commit that referenced this pull request May 5, 2026
…at 双气泡终结 + YAML 配置统一 (#462)

* feat(agent-defs): 主 Agent 入库 + 按 DB 读 instruction + 模型选择回退 (#420)

* fix(agent-defs): 修复 Agent 加载路径 + 主 Agent 纳入 Interface Sync + 运行时按 DB 读 instruction;

- cli.py: --reload_agents 改用 Path(__file__) 推导的绝对路径,杜绝 cwd 依赖导致的「src/negentropy/negentropy」双重段错误;
- subagent_presets: 新增 NegentropyEngine root payload(adk_config.kind="root"),Sync 后 DB 出现主 Agent 行;
- sync API: 循环写入 config.kind,末尾调 invalidate_cache(prefix="subagent:") 批量失效;
- SubAgentResponse: 新增顶层 kind 字段(root/subagent),供前端置顶 + 徽章;
- model_resolver: 抽取 _load_subagent_row 共用单行查询,新增 resolve_subagent_instruction;
- _dynamic_instruction: 新增 InstructionProvider 工厂,root + 5 子 Agent 的 instruction 接入运行时 DB 读取;
- 测试: 更新 test_subagent_presets 覆盖 root payload + kind 断言;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-llm): 修复无 Session 时模型选择回退 + SubAgents 列表 Root 置顶徽章;

- home-body: 新增 pendingLlmRef,改写 handleSelectedLlmModelChange 与 Effect 1,
  使「无 session 选模型→建 session→自动发送」全流程保持选择不丢失;
- SubAgents page: 按 kind="root" 置顶排序,Sync 按钮文案从「Sync Negentropy 5」改为「Sync Negentropy」;
- SubAgentCard: Root Agent 显示 violet 色 Root 徽章;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(model-resolver): SubAgent 行缺失/未启用补回 60s TTL 负命中缓存;

回归点:重构 `_resolve_subagent_row` 时把空占位写入移到了 `loaded is None`
判断之后,导致禁用 Faculty 与未 Sync 环境下每次 LLM 请求都触发一次 DB 查询。
本次在 `loaded is None` 分支补 `_cache[cache_key] = ("", {"i": ""}, now)`,
让负命中同样落入 60s TTL,避免重复 DB 压力。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-llm): pending 模型选择仅对 startNewSession 新 id 消费;

回归点:Effect 1 的 pending 转移分支会在「首次进入既有 session」时触发,
把无 session 阶段的 pending 模型写入该 session 的 perThreadLlmRef,
并让 Effect 2 跳过 snapshot 初始化,导致服务器端记忆模型被静默替换。

修复方式:
- 新增 `pendingLlmTargetIdRef` 仅记录 startNewSession 返回的新 id;
- 通过 `startNewSessionWithLlmTarget` 包装内联调用与 `onNewSession` 两条路径;
- Effect 1 仅在 `sessionId === pendingLlmTargetIdRef.current` 时转移 pending,
  其余进入既有 session 的分支主动丢弃 pending,让 snapshot 正常生效。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): 修复 KB Retrieve 全屏空白(前端聚合 rejection × 后端 hybrid/rrf 降级 × 502 上游错误码 × 诊断仪器化) (#421)

* fix(knowledge): 修复 Knowledge Base Retrieve 全屏空白(前端聚合 rejection + 后端 hybrid/rrf 降级 + 502 错误码 + 诊断日志);

双层 Bug 同因联修(详见 docs/issue.md ISSUE-026):
1. 前端 searchAcrossCorpora 旧实现以 Promise.allSettled 仅取 fulfilled,rejected 静默丢失,导致全部 Corpus 失败时返回 {count:0,items:[]} 走"成功路径"使 UI 空白且无任何提示——本次改为聚合三态(全成功/部分失败/全失败),SearchResults 类型扩展 errors[],handleRetrieve 对部分失败 toast.warning 透出原因;
2. 后端 service.search hybrid/rrf 旧实现未捕获 EmbeddingFailed,外部 Embedding 上游故障直接 500,丧失"keyword 仍可用"的优雅降级——本次 hybrid 失败回退 keyword-only、rrf 失败走与 not embedding_fn 等价的回退路径,semantic 仍传播以保留显式失败语义;
3. api.py _map_exception_to_http 拆分 EmbeddingFailed 分支映射到 502 Bad Gateway(保留 EMBEDDING_FAILED code),与 SearchError 自身错误的 500 区分,便于前端识别"上游修复后再试"语义;
4. embedding.py 调用 litellm 前后增加结构化诊断日志:api_base_host(脱敏 path/credentials 仅留 host)+ input_count + text_preview + kwargs_keys;失败附 upstream_response_text(沿异常链 __cause__/__context__ 提取 MaskedHTTPStatusError.text,已被 litellm 脱敏 URL,限长 500 字节);
5. 测试锁定:tests/unit_tests/knowledge/test_search_resilience.py 5 例(hybrid/rrf 降级 + semantic 传播 + EmbeddingFailed→502 + SearchError→500)+ tests/unit/knowledge/searchAcrossCorpora.test.ts 3 例(allSettled 三态);
6. docs/issue.md 追加 ISSUE-026,含后续防范(Promise.allSettled 必须聚合 rejection / vendor 失败必须 502 / hybrid 必须有降级路径 / vendor 调用必须 host+upstream_text 双信号)与同类问题影响清单。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): searchAcrossCorpora 聚合保留 KnowledgeError code 并修正 _map_exception_to_http docstring;

Review #1(前端契约): SearchResultError 仅透 message 会丢弃 KnowledgeError.code(如 EMBEDDING_FAILED),削弱本次 502/500 拆分对前端"上游修复 vs 自身错误"的可分流价值——本次扩展 SearchResultError 增加可选 code,rejection instanceof KnowledgeError 时回填;全失败分支由 throw new Error 改为 throw new KnowledgeError(aggregatedCode, msg, {errors}),code 一致时透传原 code、混合时退化为 AGGREGATED_SEARCH_ERRORS,既保留分流能力又携带逐条失败明细;新增 1 例同 code 透传 + 1 例混合 code 退化的单测,全部 4 例通过。

Review #2(后端文档): api._map_exception_to_http docstring 仍只列 400/404/409/500,与新增 EmbeddingFailed→502 分支不一致;本次补 "502: 上游服务错误(vendor / Embedding 等外部依赖)" 一行,避免后续维护者按旧映射加分支。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(wiki-favicon): 修复 negentropy-wiki 站点 favicon.ico 单分辨率畸形导致浏览器回落默认地球图标; (#423)

- 根因:apps/negentropy-wiki/src/app/favicon.ico 是单分辨率畸形 ICO(file 输出 256x-1,高度字节 0xFF),且源图 logo.png 为非方形 800x798,导致 Chrome/Firefox/Safari 解析失败、tab 回落默认地球图标;
- 修复:用 Pillow 对 logo.png 做透明 padding 至 800x800 方形,再生成多分辨率 ICO(16/32/48/64/128/256 共六档)覆盖原文件;体积从 269KB 降至 118KB;
- 验证:file 输出 6 icons; pnpm build 后 .next/standalone 内 favicon route + body + meta 完整;pnpm start 后 curl /favicon.ico 返回 200 image/x-icon,HTML 自动注入 <link rel="icon">;
- 防范:docs/issue.md 追加 ISSUE-027,沉淀「ICO 必须方形 + 多分辨率」工程约束与 Pillow 流水线模板,禁止「原图直裹 ICO 头」反模式;
- 不动:layout.tsx / next.config.ts / start-production.mjs,保留 App Router metadata 自动注入路径,最小干预。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(mcp-resources): 接入 Resource Templates 并贯通 PDF 图片到 Wiki Markdown (#422)

* feat(mcp-client): 接入 MCP Resource Templates 与同会话动态资源拉取;

新增 McpResourceTemplate 模型与 Alembic migration 0012,扩展 McpClientService 在
连接发现阶段并发调用 list_resource_templates(旧 server 不支持时静默兜底,不
阻断 tools 发现),新增 call_tool_and_resolve_resources:在同一 ClientSession 内
完成工具调用与所有 resource_link URI 的并发拉取(Semaphore 限流 4,return_exceptions
保证单条失败不击穿主流程)。这是接入 Negentropy Perceives 动态 FileResource
(perceives://pdf/<job_id>/<filename>)的协议层基石——动态实例的生命周期与工具
会话强绑定,必须在 session 关闭前完成 resources/read 才能避免事后失链。

Interface API 同步:load_mcp_server_tools 端点扩展为 capability 全量同步(tools
+ resource_templates,软删除已下线的 templates),LoadToolsResponse 新增
resource_templates 字段(向后兼容),新增 GET /mcp/servers/{id}/resource-templates
端点;list_mcp_servers 拆解为分段计数避免 JOIN 笛卡尔积;McpServerResponse 暴露
resource_template_count 给前端展示。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(perceives-resources): PDF 图片资源端到端贯通到 GCS 与 Wiki Markdown;

把 Perceives MCP 工具调用返回的 ResourceLink 接入既有提取流水线(Ingest 与
Re-Parse from GCS),让 PDF 图片资源在主仓 ↔ Perceives 之间通过 MCP 协议
完整贯通:

- 提取层(extraction.py):新增 _extract_resource_link_assets 把 ResourceLink
  与同会话 read_resource 拉取的 base64 配对为 ExtractionAsset;_call_tool_with_plan
  改用 resolve_resource_links=True 路径,确保动态 URI 不会因会话关闭失链;
  _build_success_result 接收 resolved_resources / resource_errors,按 "warn +
  占位" 容错策略合并 assets 并标记 partial_failure 不阻断主入库;新增
  _rewrite_markdown_image_links 在 Markdown 写入 GCS 之前把相对路径图片引用
  重写为 /api/documents/{doc_id}/assets/{filename},重写采用 capture group 偏移
  以避免 alt 文本含同名 src 时误替换。

- Knowledge API:新增 GET /knowledge/wiki/documents/{document_id}/assets/{filename}
  公开端点,filename 严格白名单 ^[A-Za-z0-9._-]+$ 与 180 字符上限;鉴权策略与
  既有 wiki entry content 端点对齐——仅放通至少被一条 WikiPublicationEntry
  引用的 document,避免持任意 doc_id 拖走未发布文档资产。

- 前端 MCP 卡片(negentropy-ui):新增 Resource Templates 折叠区与 ResourceDetailPanel,
  视觉与 Tools 区完全镜像;page.tsx 在 tools:load 响应中同步消费
  resource_templates 段,状态合并到 ServerWithTools;动态实例(带 job_id)
  按设计不入卡片。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(mcp-client): Resource Templates 同步加 capability flag,避免静默兜底误清空模板表;

`_discover_on_transport` 对 `list_resource_templates` 的所有异常都会静默兜底返回空列表(兼容旧 server 与瞬态错误),但 `load_mcp_server_tools` 会把空列表当作权威结果裁剪 stale 行,导致一次网络抖动或 server bug 即抹掉全部模板;同时与 tools 同步"只增量更新、不裁剪"的语义不对称。

- `McpConnectionResult` 新增 `resource_templates_listed: bool`,仅在 `list_resource_templates` 成功返回时为 True;
- `load_mcp_server_tools` 仅在该 flag 为 True(权威空列表)时才裁剪 stale 模板,未支持/错误场景保留既有 DB 行;
- 单元测试覆盖 flag 在权威空列表与异常兜底两种路径下的取值。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(mcp-card): 单测 server fixture 补 resource_template_count 修 UI Type Checks;

`McpServer` 类型新增的必填字段 `resource_template_count` 未同步到 `McpServerCard.test.tsx` 的 server 固件,导致 ui-quality / UI Type Checks 在 5 处 `<McpServerCard server={...}>` 调用上报 TS2741。

- 在 server 固件加 `resource_template_count: 0`,spread 派生用例自动获得新字段。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): 查询时 honor Corpus 自配 embedding 模型,修复 query/index 模型不一致 (ISSUE-028) (#424)

search() 原直接使用实例化时锁定的 self._embedding_fn(全局默认 gemini/text-embedding-004),
未读 corpus.config.models.embedding_config_id;而 _attach_embeddings 索引侧已按 corpus pin 走
专属 fn。两侧不对称导致:用户在 Corpus Settings 已切到 openai/text-embedding-3-small(1536 维),
索引按 OpenAI 生成,查询仍走 Gemini 全局默认经 localhost:3392 翻译代理报 400。

修复:
- 新增 _resolve_embedding_fn(corpus_config) 助手,corpus pin 优先 → 退回 service 默认 fn;
- search() 入口加载 corpus_config + embedding_fn 本地变量,rrf/hybrid/semantic 三分支替换;
- ISSUE-026 keyword 兜底 + 502 映射 + 诊断日志原样保留,零回归;
- 新增 5 例单元测试覆盖 corpus pin 命中/落空/兜底/rrf/semantic 上抛,577 全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError (#425)

* fix(docs): 同步文档启动命令与 cli.py 修复,消除 Home Send 500 复发路径;

cli.py 的 agents_dir 已在 35204ff 从 src/negentropy 修正为 src,
但 README / docs 下 4 个文件 7 处仍写 --reload_agents src/negentropy,
用户照文档启动复现 ValueError: Agent not found 500。
统一替换为 uv run negentropy serve(SSOT),
追加 ISSUE-029(文档漂移)与 ISSUE-030(SubAgents root Agent 防回归)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError;

DynamicRootLiteLlm/DynamicSubagentLiteLlm 在 ContextVar 或 sub_agents.model
为空时直接返回 None,回退到构造时无 api_key 的硬编码实例,绕过了 DB 中
已配置的 vendor_configs 凭证。现在始终通过 resolve_llm_config() 从 DB
解析默认模型的完整凭证(含 api_key)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复长耗时回复双气泡 + 首条未格式化 (ISSUE-031); (#426)

ADK 仅持久化 partial=false 终态事件,realtime 与 hydration 在
同一逻辑消息上派出不同的 messageId(首个 partial id vs 终态 id)。
isSemanticEquivalentEntry 的 8s 时间窗在长耗时回复下硬拒绝,导致
ledger 双 entry → events 过滤失败 → conversation tree 双节点 →
UI 渲染双气泡(首条因 streaming-markdown 尾部判定走 raw text 分支)。

修复 (最小干预 + 正交分解):
- message-ledger.ts: 内容严格相等时跳过 8s 时间窗硬拒绝。
- conversation-tree.ts: assistant 已收尾节点在内容严格相等时
  也允许 findMatchingTextNodeId 命中复用,作为防御性收敛。
- 三层回归测试覆盖 ">8s 跨度 + messageId 不同 + 内容严格相等"。

UI 全量 70 文件 396 测试通过;typecheck/typecheck:test/eslint 零报错。
docs/issue.md 沉淀 ISSUE-031;CHANGELOG.md 同步条目。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(home-chat): 修复 Home 对话 title 凭证缺失与 OTLP logs/metrics 404 双联缺陷 (#427)

* fix(home-chat): 修复 Home 对话 title 凭证缺失 + OTLP logs/metrics 404 双联缺陷;

(1) SessionSummarizer 同步 __init__ 在 60s 缓存 miss 时回退到无 api_key 硬编码默认,
导致 LiteLLM AuthenticationError;改为 async classmethod create() 经 resolve_llm_config()
从 DB 读取完整凭证(与 commit 8ce35d5 修复 DynamicRootLiteLlm 同 SoT),调用方
session_service._generate_title_for_session 切换为 await SessionSummarizer.create(),
对 resolver 返回 kwargs 做防御性浅拷贝避免与 60s 缓存层耦合。

(2) ADK 上游 _get_otel_exporters() 把 OTEL_EXPORTER_OTLP_ENDPOINT 视为 OTLP 三件套
总开关,无差别注册 OTLPSpanExporter / OTLPMetricExporter / OTLPLogExporter;后两者
对 Langfuse 不存在的 /v1/metrics、/v1/logs 上报触发 SPA 404 SSR 错误页(每次对话
反复输出大段 HTML)。bootstrap.py 新增 _install_noop_otel_logs_metrics_providers()
在 OTel env var 设置后立即抢注无 processor / 无 reader 的 SDK Logger/Meter Provider,
利用 OTel SDK Once-lock 让 ADK 后续 set_*_provider 静默 no-op,从而阻断 logs/metrics
上报;TracerProvider 链路与 OTEL_EXPORTER_OTLP_HEADERS 不动,traces 仍正常进入 Langfuse。

新增 tests/unit_tests/engine/test_summarization.py(3 例)+
tests/unit_tests/observability/test_otel_noop_providers.py(3 例,子进程隔离 OTel 全局
状态)锁定回归。CHANGELOG / docs/issue.md 沉淀 ISSUE-031(title 凭证缺失)与
ISSUE-032(OTLP logs/metrics 404)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(otel-noop): 移除 _sdk_config hasattr 兜底,让 SDK 私有属性变更显式触发回归;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(session-title): 修复 DummySummarizer 缺失 async create() 导致集成测试 AttributeError;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(bootstrap-otel): 消除 ADK Web 启动期 OTel Override Provider 双 WARNING (ISSUE-034); (#428)

将 ISSUE-033 的「抢占式 set_logger_provider/set_meter_provider」改为 patch
`google.adk.telemetry.setup._get_otel_exporters`,让其只返回 traces 的
span_processors,metric_readers/log_record_processors 永久置空。ADK
maybe_set_otel_providers 的 if 分支由此天然短路,set_*_provider 根本不被
调用,从源头消除 OTel SDK 的 "Overriding of current ... is not allowed"
WARNING;traces 链路、ADK ApiServerSpanExporter、TracingManager、LiteLLM
"otel" callback 行为完全不变。配套更新 3 个子进程隔离单测验证新语义,
并在 docs/issue.md 追加 ISSUE-034 完整记录。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(e2e-auth): 浏览器验证协议落地 + Playwright 会话复用贯通 Google OAuth (#429)

* docs(browser-validation): 落地浏览器验证协议并补 ISSUE-034

- AGENTS.md(即 CLAUDE.md symlink)新增"Browser Validation Protocol"子节,
  约定登录态浏览器验证必须复用用户常用 Chrome 会话,禁止 sandbox 浏览器
  通过 Google 同意屏,明确凭证守则与三步连通性自检;
- 新建 docs/agents/browser-validation.md:含三种 MCP 浏览器工具能力对照、
  Mermaid 选型决策图、storageState 工作时序、风控应对、IEEE 引用;
  实测附注 chrome-devtools MCP 在 macOS 默认即可复用用户主 profile 登录态;
- docs/issue.md 追加 ISSUE-034,记录 sandbox 浏览器走 Google OAuth 被拦
  的表因/根因/处理方式/防范,便于跨上下文复用。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(e2e-auth): Playwright 会话复用以贯通 Google OAuth E2E

- playwright.config.ts 在 PLAYWRIGHT_AUTH=1 时启用两个项目:
  * setup(headless: false,匹配 *.setup.ts),让用户在弹出窗手动登录;
  * chromium-authenticated(dependencies: ['setup']),使用 storageState
    复用一次性人工登录的会话;
  支持 PLAYWRIGHT_STORAGE_STATE 与 PLAYWRIGHT_USER_DATA_DIR 覆盖默认;
  现有 chromium project 加 testIgnore 排除 .setup.ts,CI/默认行为零变;
- 新增 tests/e2e/auth.setup.ts:打开 /auth/google/login,5 分钟内允许
  用户在 Google 同意屏中手动完成登录,回跳后断言 /api/auth/me 2xx,
  写入 storageState;
- .gitignore 追加 apps/negentropy-ui/.auth/ 与 .userdata/,
  防止会话凭证随分支推送外泄。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(e2e-auth): 修复 OAuth setup 早退与 authed spec 双跑;

- auth.setup.ts: waitForURL 谓词追加 host 约束,避免在跳往 accounts.google.com
  瞬间因 pathname 已离开 /auth/google 而误判完成,导致 /api/auth/me 在用户登录前
  失败、storageState 永不写出。
- playwright.config.ts: 基础 chromium project 的 testIgnore 追加
  /.*\.authed\.spec\.ts$/,防止 PLAYWRIGHT_AUTH=1 时同一份认证 spec 在
  chromium-authenticated 与 chromium 中各跑一次(后者无 storageState 必失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 Home 双气泡复发与 LLM 模型未 Send 即刷新丢失 (ISSUE-032/033); (#430)

ISSUE-032 (双气泡复发,与 ISSUE-031 正交):
- 根因:root agent prompt 主动导航 + log_activity tool 让 ADK 走双轮 LLM 调用,
  两轮各自带独立 messageId 走完整 TEXT_MESSAGE_* 三件套,UI 在同一
  assistant-reply bubble 内并列渲染两段近重复文本。
- 修复:utils/chat-display.ts::dedupeRedundantTextSegments 在
  buildAssistantReplyBlock 出口对同一 reply 内的 text segment 做字符二元组
  Jaccard 相似度计算,相似度 ≥ 0.5 且双方长度 ≥ 30 时丢弃前段、保留信息更
  完备的最终段。tool-group / reasoning / error 顺序不动。
- assistant-reply.message.content 联动重组,复制时也拿到折叠后的内容。

ISSUE-033 (LLM 模型未 Send 即刷新丢失):
- 根因:后端事实源 session.state.selected_llm_model 仅在 /run_sse 时随
  state_delta 写入,未 Send 时不更新;前端 perThreadLlmRef 是 useRef
  刷新即丢;snapshotForDisplay 也无值,回退到 default。
- 修复:app/home-body.tsx 顶部新增 readPersistedLlmModel /
  writePersistedLlmModel (typeof window 守卫 + try/catch SSR 安全);
  handleSelectedLlmModelChange 即时落盘到 localStorage;Effect 1 优先
  从 localStorage 还原;Effect 2 命中 snapshot 时同步回写 localStorage,
  让「后端 state ↔ localStorage」互为镜像。既有 forwardedProps.selected_llm_model
  在 Send 时仍写后端 state,跨设备一致性最终收敛。

测试:
- 新增 2 例 chat-display.test.ts 用例:折叠近重复段 + 差异度大不被折叠
- UI 全量 70 文件 398 测试通过;typecheck/typecheck:test/eslint 零报错

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038) (#431)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038);

ISSUE-034 的 patch 调用 original() 后再丢弃 metric_readers /
log_record_processors,但上游 _get_otel_exporters 已构造
PeriodicExportingMetricReader 并启动 60s 守护线程——reader 未注册
到 MeterProvider 导致每 tick 触发 "Cannot call collect on a
MetricReader ..." WARNING。改为绕过 original(),直接复用
_get_otel_span_exporter() 仅构造 traces span processor,根源
避免 OTLP metrics/logs exporter 被实例化。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(bootstrap-otel): 修正 _disable_adk_otel_logs_metrics_exporters docstring 中的过期 hooks 引用;

旧 docstring 沿用重构前 `hooks = original()` 的中间变量术语,但新实现已不再调用 `original()`,函数体内也没有 `hooks` 绑定。
更新指引为「恢复 _get_otel_exporters 原函数闭包」或「直接构造完整 OTelHooks」,避免误导后续维护者寻找已不存在的对象。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-039) (#432)

* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-038);

- chat-display: dedupeRedundantTextSegments 增加四层判定(精确匹配 / 严格前缀 / 等价内容 / Jaccard),覆盖 ADK 双轮 LLM 短回复(如 "Pong!")的双气泡盲区。
- session-hydration: mergeEventsWithRealtimePriority 交换参数顺序,让 realtime 事件覆盖 hydrated;TEXT_MESSAGE_CONTENT 的 eventKey 时间戳改用 toFixed(3) 消除浮点抖动导致的同一事件重复保留。
- message-ledger: MessageLedgerEntry 新增可选 sourceOrder 作 createdAt 相同时的稳定 tiebreaker,替代 UUID localeCompare 的随机字典序;抽出 compareLedgerEntriesByTime 复用,类型保持向后兼容(缺省回退 Number.MAX_SAFE_INTEGER)。
- 新增 5 项单元测试覆盖:短回复精确匹配、前缀含尾部追加、Jaccard 长文本、eventKey 浮点稳定、sourceOrder 稳定排序;docs/issue.md 增补 ISSUE-038 摘要。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(home-chat): 补 mergeEventsWithRealtimePriority 生命周期事件覆盖回归用例;

针对 ISSUE-039 第 3 项修复(mergeEventsWithRealtimePriority 参数顺序交换)
原有 RUN_STARTED 类生命周期事件用例缺位——之前的 messageId 重叠用例在
step 3 即被过滤为 filteredHydratedEvents=[],无法验证 step 4 mergeEvents
入参顺序对 key 冲突归并的影响。

补一条 RUN_STARTED 用例:realtime / hydrated 同 threadId/runId/timestamp
(eventKey 字节级一致)→ 用对象引用断言保留的是 realtime 版本,作为参数
顺序交换的最直接证据。该用例在交换前会失败、交换后通过,形成有效回归网。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040) (#433)

* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040);

- 过滤 ADK Part 中 thought=true 与 type=thinking|thought|reasoning 系列推理字段,避免 reasoning_content 溢出到 TEXT_MESSAGE_CONTENT;推理文本改路由为 ne.a2ui.thought 自定义事件保留可观测性。
- createStepFinishedEvent 同步透出 stepName,AdkMessageStreamNormalizer 持有 stepId→stepName 映射,根治 ag-ui v0.0.47 校验器 "Cannot send 'STEP_FINISHED' for step \"undefined\"" 中断 run 导致的推理头永驻 started 现象。
- conversation-tree fallback 段重建消息节点时优先复用 ledger 已有 sourceOrder,避免被推到 events 末尾破坏 compareLedgerEntriesByTime tiebreaker。
- session-hydration eventKey 全事件类型统一走 toFixed(3) 毫秒级时间戳,并为 STEP_STARTED/STEP_FINISHED 显式按 (threadId, runId, stepId) 作 key,覆盖 STEP_*/CUSTOM/STATE_*/RAW 在浮点抖动下的去重盲区。
- 新增 9 例单元回归覆盖 thought part 过滤 / STEP_FINISHED stepName / fallback sourceOrder / eventKey 浮点抖动;docs/issue.md 追加 ISSUE-040 全栈解析。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 消除 hydration sort 字典序污染 lifecycle 顺序导致的多消息刷新乱序 (ISSUE-040 Q3 长尾);

- hydrateSessionDetail 引入 WeakMap<BaseEvent, emitOrder>,sort tiebreaker 用 normalizer 推入顺序代替 eventKey().localeCompare,保留 TEXT_MESSAGE_* 三件套 START→CONTENT→END 与跨 messageId 的 turn 边界。
- mergeEvents 同步改为按首次出现位置记录 insertionOrder 作 tiebreaker,避免最后一步 mergeEvents([], normalizedEvents) 再把刚排好的事件按字典序乱序。
- 新增同 timestamp 下 lifecycle 顺序断言用例;多轮真实后端 events fixture 经修复链路输出 user(R1)→assistant(R1)→user(R2)→assistant(R2) 完全符合时间线。
- docs/issue.md 在 ISSUE-040 末尾追加 Q3 长尾闭环(H5 字典序污染根因与最小干预修复)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(home-chat): 强化 ISSUE-040 H3 fallback sourceOrder 回归用例;

- 旧用例与单 snapshot 单条消息时新旧公式恰巧同值,断言无差异,无法拦截 H3 退化;
- 新用例构造「snapshot 数组顺序 vs ledger 时间序」错位场景:让 sourceOrder 在两条消息间发生互换,对回滚 H3 修复有强差异断言(已本地反向核验:回滚 conversation-tree.ts 修复后断言失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs (#434)

* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs;

将 publication catalog 的第一层 CONTAINER 节点(如 Harness-Engineering)
从左侧 Sidebar 迁移为顶部 Header tabs;第二层及以下保留于 Sidebar,整树向上提升一档。
设计参考 GitHub Docs / Stripe Docs / Docusaurus 的"顶 tabs + 左 sidebar 子树"模式。

主要变更:
- lib/wiki-api.ts 追加 findFirstDocumentSlug / findActiveTopLevelSlug / resolveSectionView
  纯函数,作为 Header tabs 与 Sidebar 切片的单一事实源。
- 新增 WikiHeader Server Component(仅 <Link>,SSG 友好):渲染品牌 + 水平 tabs;
  CONTAINER tab 跳转 DFS 首个后代 DOCUMENT;无文档则禁用 span。
- WikiLayoutShell 增加 header? prop,渲染于 .wiki-layout 之外作为兄弟节点,
  避免触动既有 3 列 Grid 与 data-toc 三态。
- /{pubSlug} 与 /{pubSlug}/{...entrySlug} 两条路由共用 resolveSectionView 派生视图:
  pub 根页默认激活首项;entry 页按 slug 反查所属一级。
- globals.css 引入 --wiki-header-height 并把 sidebar / toc-aside 的 sticky top
  改为 var 引用,确保滚动时 Header 常驻不挡 sidebar。
- 新增 wiki-section-view.test.ts 12 用例覆盖空树 / 单 / 多 / 深路径 / DOCUMENT-only
  / 无后代 DOCUMENT 等边界。

回归保障:home / 不变;既有 WikiNavTree / WikiToc 测试 API 未变;47/47 单测全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(wiki-header): Header 缺失时 sidebar/toc 不再残留偏移;

通过 data-header 属性标记 Header 是否存在,CSS 侧条件生效
--wiki-header-height 偏移,避免空导航树时出现 56px 空白间隙。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* refactor(config): 废弃 .env*,统一 YAML 三级配置(local > user > default) (#436)

* refactor(config): 废弃 .env* 加载链路,引入 config.local.yaml 统一 YAML 三级配置;

- 移除 10 个 Python 配置模块中的 env_file / _get_env_files 逻辑
- yaml_loader 新增 config.local.yaml 作为最高优先级 YAML 来源
- config.default.yaml 合并 .env 全部非机密差异值(含 OAuth 端口 6600→3292 校正)
- 新增 3 例 config.local.yaml 优先级测试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(config): 同步 .env 废弃后的文档与 CHANGELOG;

- development.md / sso.md / framework.md / user-guide.md / zh-CN/README.md 中 .env 引用替换为 config.local.yaml
- CHANGELOG 新增 ISSUE-041 变更记录
- docs/issue.md 新增 ISSUE-041 经验沉淀
- .gitignore 新增 apps/negentropy/config.local.yaml 排除规则

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(config): 放宽 .gitignore 中 config.local.yaml 匹配规则,覆盖任意 cwd 场景;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#435)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#437)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复跨 runId 双气泡时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

fallback 路径从无条件移除改为内容覆盖检查——跨所有同 threadId keeper 逐 child
匹配,避免含独特历史内容的 synthetic turn 被误折叠。加强 C3 断言为
toHaveLength(2) + synthetictoBeDefined。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(conversation-tree): isSyntheticTurnNode 补充 "default" runId 识别对齐 isSyntheticRunId (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(ctl): 新增全套服务一键启停脚本 (#438)

* feat(ctl): 新增全套服务一键启停脚本 scripts/ctl.sh

支持 start/stop/restart/status/logs/build 子命令,覆盖依赖安装、
数据库迁移、前端构建、健康检查的完整生命周期。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 修复 is_running 变量泄漏与并行 wait 退出码丢失;

- is_running() 中 pid_file 添加 local 声明,防止全局作用域污染
- 三处并行 wait 改为逐个检查退出码,任一子进程失败即报错中止

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 修复健康检查不感知进程崩溃、路径逻辑重复与服务名校验缺失;

- wait_for_health 在 HTTP 轮询间隔中加入 is_running 检查,进程崩溃时立即返回失败
- is_running 改用 pid_file() 函数获取路径,消除硬编码重复
- cmd_logs 入口校验服务名是否属于 ALL_SERVICES,非法名称给出明确提示

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 使用 exec 替代 eval 确保进程 PID 精确追踪与信号直达;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 知识图谱模块生产就绪改造 — 实体管理、混合检索、路径探索、统计面板 (#439)

* feat(kg): 知识图谱模块生产就绪改造 — 语料库级图谱、实体管理、混合检索、路径探索、统计面板

后端变更:
- 新增 GET /graph/entities 实体分页列表(类型筛选+名称搜索)
- 新增 GET /graph/entities/{id} 实体详情含出/入关系
- 新增 GET /graph/stats 图谱统计(实体数/类型分布/置信度/密度/度数)
- 重写 find_neighbors: 递归 CTE 在 kg_relations 上实现多跳遍历
- 重写 find_path: 递归 CTE BFS 在 kg_relations 上查找最短路径

前端变更:
- 重写 graph/page.tsx: 语料库选择器 + 构建/浏览全流程
- 新增 EntityListPanel: 表格视图+类型筛选+分页
- 新增 EntityDetailPanel: 实体详情+关系列表(出边/入边)
- 新增 SearchBar: 混合检索(语义+图结构)
- 新增 PathExplorer: 双实体选择+BFS路径查找
- 新增 NeighborExplorer: 1/2/3跳邻居展开
- 新增 GraphStatsPanel: 实体数/类型分布/置信度/密度/度数
- 新增 BuildHistoryList: 结构化构建历史卡片(状态徽章+统计+耗时)

文档变更:
- 扩展 user-guide.md §4.5 为完整知识图谱用户指引
- 更新 knowledge-graph.md §3 新增架构模式精炼(Cognee ECL/Graphiti 双时态)
- 更新 knowledge-graph.md §4 交付物清单

测试变更:
- 新增 test_graph_entity_service.py: 9 项单元测试覆盖实体列表/详情/Schema

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复知识图谱模块 CI 失败 — 类型错误、ID 前缀、测试 mock;

- 移除 NeighborExplorer 组件调用中不存在的 entityName prop(TS2322)
- 为 find_neighbors 返回的 GraphNode.id 补齐 entity: 前缀
- 重写 find_path 测试,mock session.execute 而非 find_neighbors

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复审查发现的 7 项问题 — 安全编码、状态管理、双向路径搜索;

- 路由 path params 加 encodeURIComponent 防路径遍历(3 个 route 文件)
- EntityDetailPanel: 用 loadedEntityId 派生 loading 状态,切换实体时正确展示加载态并清除旧数据
- EntityListPanel: 搜索输入 300ms 防抖,用 completedKey 派生 loading 状态
- GraphStatsPanel: 用 result 组合状态区分加载中/失败/成功
- NeighborExplorer: entityId 变更时重置 expanded/neighbors
- graph_repository find_path: 递归 CTE 增加反向遍历分支,与 find_neighbors 双向语义对齐

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复审查发现的遗留问题 — 常量提取、路径搜索、会话管理;

- 前端:提取 ENTITY_TYPE_COLORS 至 constants.ts,消除三处 TYPE_COLORS 残留引用(会导致运行时崩溃)
- 后端:修复 find_path 递归 CTE 中 path 追加错误(r.target_id → ps.target_id)
- 后端:get_stats 改为接收外部 db 会话,消除自建会话
- 后端:get_entity_detail 增加 corpus_id 可选过滤,增强数据隔离

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): 记忆模块生产就绪化 — 巩固管线重构 + 事实提取 + 上下文集成 + 文档完善 (#440)

* feat(memory): 重构记忆巩固管线为三阶段智能架构并增强核心模块

- 重构 _simple_consolidate 为三阶段管线(分段→去重→存储),借鉴 Claude Code AutoDream 四阶段范式
- 新增 PatternFactExtractor 基于正则模式的对话事实自动提取(preference/profile/rule/custom)
- 新增 ContextAssembler 记忆上下文组装器,管理 token 预算分配(30%记忆/50%历史/20%系统)
- 新增 AsyncScheduler 应用层调度器回退,当 pg_cron 不可用时提供等效定时任务能力
- 增强 search_memory API 支持分页(limit/offset)和过滤(memory_type/date_from/date_to)
- 集成 ContextAssembler 到 perception.py 记忆搜索回退路径
- 新增 34 条单元测试覆盖事实提取和调度器(全部通过)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(memory): 补充工业框架对标分析与用户操作指南

- docs/memory.md §2.4 新增 Claude Code 记忆架构深度对标(AutoDream 四阶段整理、三重门控调度、四类型分类法、三层上下文压缩、漂移防御)
- docs/memory.md §2.5 新增 Agent Harness 设计模式对标(三层压缩管线、Skill 按需加载、Task Graph 持久化)
- docs/memory.md §2.6 新增 Negentropy 差异化定位总结表
- docs/user-guide.md §5.8-§5.12 新增记忆形成机制、保留分数解读、搜索最佳实践、自动化配置指南、故障排除

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 恢复巩固管线 metadata 中遗漏的 event_count 字段

三阶段管线重构后 metadata 字典遗漏了原有的 event_count 字段,
导致 test_memory_service_lifecycle 集成测试 KeyError 失败。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 7 项问题

1. search_memory 的 memory_type/date_from/date_to/offset 过滤参数现在在 vector_search 和 ilike_search 中实际生效
2. context_assembler 的 lazy import 移至文件顶部,与同文件风格一致
3. _simple_consolidate docstring 从「三阶段」更正为「四阶段」(含事实提取)
4. api.py search_memories 的 total 字段添加 TODO 标记(需独立 COUNT 查询)
5. AsyncScheduler 失败时回退 last_run_at,允许尽快重试而非等完整 interval
6. PatternFactExtractor 三段重复遍历提取为 _match_patterns 辅助方法
7. _consolidate SQL 拼接改为参数化绑定 :lookback::interval,消除注入风险

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 3 项问题

- offset 分页参数未透传到底层搜索方法,现已正确传递
- datetime.fromisoformat() 缺少校验,非法日期返回 400 而非 500
- AsyncScheduler 派发任务未被追踪,stop() 时一并取消在途任务

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 2 项问题

- 巩固管线阶段 4 事实提取调用包裹 try/except,防止导入或工厂失败中断管线
- 搜索接口 total 字段改为 -1 标记"未知",避免分页客户端误读

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + Token 精确计数 + 检索反馈闭环 (#442)

* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + 精确 Token 计数 + 检索反馈闭环

- TokenCounter: 基于 tiktoken cl100k_base 编码器精确计数,替代 LENGTH/4 粗略估算
- LLMFactExtractor: LLM 结构化输出事实提取,PatternFactExtractor 作为降级后备
- MemorySummarizer: LLM 生成结构化用户画像摘要,缓存至 memory_summaries 表(TTL 24h)
- SummaryService: memory_summaries 表 CRUD(upsert 语义)
- RetrievalTracker: 检索效果反馈闭环,记录检索事件 + 显式反馈 API
- ContextAssembler: 优先注入摘要,tiktoken 精确 token 计数
- 新增 Alembic migration 0013/0014(memory_summaries + memory_retrieval_logs)
- 新增 MemorySummary + MemoryRetrievalLog ORM 模型
- 11 条新增单元测试,62 条全部通过,零回归

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(memory): Phase 2 文档沉淀 — 两级提取策略 + 摘要巩固 + 精确计数 + 检索反馈 + 新增文献

- §4.2 扩展为两级事实提取策略说明(LLMFactExtractor + PatternFactExtractor)
- §5.4.1 新增摘要巩固策略(记忆再巩固理论 + 5 项工程对标)
- §6.3 更新 Token 估算为 tiktoken BPE 精确计数
- §6.5 新增检索效果反馈闭环(Rocchio + LTR + LongMemEval 评估维度)
- §15 新增 6 篇参考文献(Sennrich 2016, Sara 2015, Rocchio 1971, Burges 2005, Mem0, Letta)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 LLM 事实提取 prompt 类型名不匹配 + 检索指标 SQL 聚合优化;

- prompt 模板中 "pref" 改为 "preference",与 _VALID_FACT_TYPES 验证器对齐,避免 LLM 输出被静默降级为 "custom"
- get_effectiveness_metrics 改用 SQL COUNT+CASE 聚合,避免将全量日志行加载到 Python 内存

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* refactor(memory): Review 反馈修复 — 检索日志可观测性 + query 透传 + 模型配置去重;

1. 检索追踪 except 从 silent pass 改为 logger.debug,使故障可诊断
2. _record_access 新增 query 参数并从所有调用点透传,消除空 query 问题
3. 提取 _resolve_model_config 为共享工具 engine/utils/model_config.py,
   LLMFactExtractor 和 MemorySummarizer 统一引用,消除 DRY 违规
4. 同步更新单元测试 mock 路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐 (#441)

* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐

- create_relation() 新增写入 kg_relations 一等公民表,保留 JSONB 过渡兼容
- get_graph() 优先从 kg_entities + kg_relations 读取,空时回退 JSONB
- clear_graph() 增加 kg_entities/kg_relations 表清理
- build_graph() 完成后调用 KgEntityService.batch_sync_from_graph_build()
- 更新 test_graph_repository 适配新读写路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 新增 PageRank 实体重要性评分与 RRF 混合检索

- 新增 graph_algorithms 模块,基于 NetworkX 实现 PageRank (Brin & Page, 1998) 计算,
  结果持久化至 kg_entities.importance_score
- 混合检索支持 Reciprocal Rank Fusion (Cormack et al., SIGIR 2009) 模式,
  可通过 GraphQueryConfig.use_rrf / rrf_k 配置,向后兼容线性加权模式
- 图谱构建完成后自动触发 PageRank 计算
- 实体列表支持按重要性排序(sort_by=importance)
- 统计面板展示 Top 5 PageRank 实体
- 图谱可视化节点半径映射 PageRank 分数,突出重要实体

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 新增 Louvain 社区检测与图谱可视化增强

- 新增 compute_louvain() 算法,基于 NetworkX 内置 Louvain (Blondel et al., 2008)
  在无向投影图上运行社区检测,结果持久化至 kg_entities.community_id
- 图谱构建完成后自动触发 Louvain 计算(紧接 PageRank 之后)
- 统计面板新增社区分布(community_count + community_distribution)
- 实体列表和详情响应包含 community_id 字段
- 图谱可视化节点按社区着色(Tableau 10 色盲友好调色板)
- 统计面板展示 Top 8 社区分布柱状图
- 实体表格新增社区列,显示色块标识
- 显式声明 networkx>=3.0 依赖(此前为隐式运行时导入)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 新增 Alembic migration 0015 — 添加 importance_score 和 community_id 列

CI 集成测试失败根因:ORM 模型新增了 importance_score (PageRank) 和 community_id (Louvain)
列,但缺少对应的 Alembic migration,导致测试数据库 schema 不匹配。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复 Review 反馈的三个问题

1. RRF 搜索 graph_score 恒为 0 — 将 importance_score 写入 entity_data
2. PageRank/Louvain 逐条 UPDATE — 改为 VALUES CTE 批量更新
3. 一等公民表路径缺 app_name 过滤 — 文档明确 corpus 级去重设计意图

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 测试覆盖 (#443)

* test(memory): Phase 2 组件测试覆盖 — TokenCounter / SummaryService / RetrievalTracker / MemorySummarizer;

新增 39 个单元测试用例,覆盖 Phase 2 四个核心组件:
- TokenCounter: 精确计数、空输入、幂等性、异步一致性、单调性(蜕变测试)
- SummaryService: upsert/get/delete CRUD 路径
- RetrievalTracker: 检索日志、引用标记、反馈记录、效果指标计算
- MemorySummarizer: 摘要生成、TTL 缓存命中/过期、LLM 失败降级、重试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 文档沉淀;

Gap 1 反馈闭环:
- _record_access 修复 user_id/app_name 透传(此前始终为空字符串)
- PostgresMemoryService 存储 _last_retrieval_log_id 供下游消费
- ContextAssembler 注入 mark_referenced 隐式反馈信号(RLHF[33])
- API 新增 POST /memory/retrieval/feedback 和 GET /memory/retrieval/metrics

Gap 2 Query-Aware:
- assemble() 新增 query/query_embedding 可选参数
- _call_get_context_window 传递 7 个参数(含 p_query, p_query_embedding)
- SQL 函数 NULL safe 退化:无 query 时保持纯 retention_score 排序
- 隐式反馈标记在上下文组装成功后触发

Gap 3 近重复检测:
- _is_duplicate 阈值从 0.9 降至 0.85(Henzinger[40])
- 新增 Jaccard 词重叠二次校验(0.80-0.85 区间,Broder[37])
- FactService 新增 merge_similar_facts() 语义去重方法

文档沉淀:
- docs/memory.md 权威源文件索引扩充 Phase 2 组件
- §15 追加 13 篇参考文献 [31]–[43]

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 merge_similar_facts 过度删除 + retrieval_log_id 并发安全问题;

- merge_similar_facts: 锚点事实被删除后立即 break 内层循环,避免基于已删除 embedding 继续比对导致误删
- _record_access: 移除 _last_retrieval_log_id 实例属性,改为返回 log_id,消除共享可变状态的并发竞态
- ContextAssembler.assemble: memory_service 参数改为显式 retrieval_log_id,调用方直接传入

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存 (#444)

* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存

Gap 3 [P1] 构建管线健壮性 (Nygard, 2018; Majors, 2022):
- Migration 0016: kg_build_runs 增加 progress_percent + warnings 列
- build_graph: 批处理循环进度上报、LLM 提取失败重试 1 次、算法失败警告累积
-…
ThreeFish-AI added a commit that referenced this pull request May 17, 2026
…识管理统一入口(100 PRs / 843 文件) (#560)

* feat(agent-defs): 主 Agent 入库 + 按 DB 读 instruction + 模型选择回退 (#420)

* fix(agent-defs): 修复 Agent 加载路径 + 主 Agent 纳入 Interface Sync + 运行时按 DB 读 instruction;

- cli.py: --reload_agents 改用 Path(__file__) 推导的绝对路径,杜绝 cwd 依赖导致的「src/negentropy/negentropy」双重段错误;
- subagent_presets: 新增 NegentropyEngine root payload(adk_config.kind="root"),Sync 后 DB 出现主 Agent 行;
- sync API: 循环写入 config.kind,末尾调 invalidate_cache(prefix="subagent:") 批量失效;
- SubAgentResponse: 新增顶层 kind 字段(root/subagent),供前端置顶 + 徽章;
- model_resolver: 抽取 _load_subagent_row 共用单行查询,新增 resolve_subagent_instruction;
- _dynamic_instruction: 新增 InstructionProvider 工厂,root + 5 子 Agent 的 instruction 接入运行时 DB 读取;
- 测试: 更新 test_subagent_presets 覆盖 root payload + kind 断言;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-llm): 修复无 Session 时模型选择回退 + SubAgents 列表 Root 置顶徽章;

- home-body: 新增 pendingLlmRef,改写 handleSelectedLlmModelChange 与 Effect 1,
  使「无 session 选模型→建 session→自动发送」全流程保持选择不丢失;
- SubAgents page: 按 kind="root" 置顶排序,Sync 按钮文案从「Sync Negentropy 5」改为「Sync Negentropy」;
- SubAgentCard: Root Agent 显示 violet 色 Root 徽章;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(model-resolver): SubAgent 行缺失/未启用补回 60s TTL 负命中缓存;

回归点:重构 `_resolve_subagent_row` 时把空占位写入移到了 `loaded is None`
判断之后,导致禁用 Faculty 与未 Sync 环境下每次 LLM 请求都触发一次 DB 查询。
本次在 `loaded is None` 分支补 `_cache[cache_key] = ("", {"i": ""}, now)`,
让负命中同样落入 60s TTL,避免重复 DB 压力。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-llm): pending 模型选择仅对 startNewSession 新 id 消费;

回归点:Effect 1 的 pending 转移分支会在「首次进入既有 session」时触发,
把无 session 阶段的 pending 模型写入该 session 的 perThreadLlmRef,
并让 Effect 2 跳过 snapshot 初始化,导致服务器端记忆模型被静默替换。

修复方式:
- 新增 `pendingLlmTargetIdRef` 仅记录 startNewSession 返回的新 id;
- 通过 `startNewSessionWithLlmTarget` 包装内联调用与 `onNewSession` 两条路径;
- Effect 1 仅在 `sessionId === pendingLlmTargetIdRef.current` 时转移 pending,
  其余进入既有 session 的分支主动丢弃 pending,让 snapshot 正常生效。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): 修复 KB Retrieve 全屏空白(前端聚合 rejection × 后端 hybrid/rrf 降级 × 502 上游错误码 × 诊断仪器化) (#421)

* fix(knowledge): 修复 Knowledge Base Retrieve 全屏空白(前端聚合 rejection + 后端 hybrid/rrf 降级 + 502 错误码 + 诊断日志);

双层 Bug 同因联修(详见 docs/issue.md ISSUE-026):
1. 前端 searchAcrossCorpora 旧实现以 Promise.allSettled 仅取 fulfilled,rejected 静默丢失,导致全部 Corpus 失败时返回 {count:0,items:[]} 走"成功路径"使 UI 空白且无任何提示——本次改为聚合三态(全成功/部分失败/全失败),SearchResults 类型扩展 errors[],handleRetrieve 对部分失败 toast.warning 透出原因;
2. 后端 service.search hybrid/rrf 旧实现未捕获 EmbeddingFailed,外部 Embedding 上游故障直接 500,丧失"keyword 仍可用"的优雅降级——本次 hybrid 失败回退 keyword-only、rrf 失败走与 not embedding_fn 等价的回退路径,semantic 仍传播以保留显式失败语义;
3. api.py _map_exception_to_http 拆分 EmbeddingFailed 分支映射到 502 Bad Gateway(保留 EMBEDDING_FAILED code),与 SearchError 自身错误的 500 区分,便于前端识别"上游修复后再试"语义;
4. embedding.py 调用 litellm 前后增加结构化诊断日志:api_base_host(脱敏 path/credentials 仅留 host)+ input_count + text_preview + kwargs_keys;失败附 upstream_response_text(沿异常链 __cause__/__context__ 提取 MaskedHTTPStatusError.text,已被 litellm 脱敏 URL,限长 500 字节);
5. 测试锁定:tests/unit_tests/knowledge/test_search_resilience.py 5 例(hybrid/rrf 降级 + semantic 传播 + EmbeddingFailed→502 + SearchError→500)+ tests/unit/knowledge/searchAcrossCorpora.test.ts 3 例(allSettled 三态);
6. docs/issue.md 追加 ISSUE-026,含后续防范(Promise.allSettled 必须聚合 rejection / vendor 失败必须 502 / hybrid 必须有降级路径 / vendor 调用必须 host+upstream_text 双信号)与同类问题影响清单。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): searchAcrossCorpora 聚合保留 KnowledgeError code 并修正 _map_exception_to_http docstring;

Review #1(前端契约): SearchResultError 仅透 message 会丢弃 KnowledgeError.code(如 EMBEDDING_FAILED),削弱本次 502/500 拆分对前端"上游修复 vs 自身错误"的可分流价值——本次扩展 SearchResultError 增加可选 code,rejection instanceof KnowledgeError 时回填;全失败分支由 throw new Error 改为 throw new KnowledgeError(aggregatedCode, msg, {errors}),code 一致时透传原 code、混合时退化为 AGGREGATED_SEARCH_ERRORS,既保留分流能力又携带逐条失败明细;新增 1 例同 code 透传 + 1 例混合 code 退化的单测,全部 4 例通过。

Review #2(后端文档): api._map_exception_to_http docstring 仍只列 400/404/409/500,与新增 EmbeddingFailed→502 分支不一致;本次补 "502: 上游服务错误(vendor / Embedding 等外部依赖)" 一行,避免后续维护者按旧映射加分支。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(wiki-favicon): 修复 negentropy-wiki 站点 favicon.ico 单分辨率畸形导致浏览器回落默认地球图标; (#423)

- 根因:apps/negentropy-wiki/src/app/favicon.ico 是单分辨率畸形 ICO(file 输出 256x-1,高度字节 0xFF),且源图 logo.png 为非方形 800x798,导致 Chrome/Firefox/Safari 解析失败、tab 回落默认地球图标;
- 修复:用 Pillow 对 logo.png 做透明 padding 至 800x800 方形,再生成多分辨率 ICO(16/32/48/64/128/256 共六档)覆盖原文件;体积从 269KB 降至 118KB;
- 验证:file 输出 6 icons; pnpm build 后 .next/standalone 内 favicon route + body + meta 完整;pnpm start 后 curl /favicon.ico 返回 200 image/x-icon,HTML 自动注入 <link rel="icon">;
- 防范:docs/issue.md 追加 ISSUE-027,沉淀「ICO 必须方形 + 多分辨率」工程约束与 Pillow 流水线模板,禁止「原图直裹 ICO 头」反模式;
- 不动:layout.tsx / next.config.ts / start-production.mjs,保留 App Router metadata 自动注入路径,最小干预。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(mcp-resources): 接入 Resource Templates 并贯通 PDF 图片到 Wiki Markdown (#422)

* feat(mcp-client): 接入 MCP Resource Templates 与同会话动态资源拉取;

新增 McpResourceTemplate 模型与 Alembic migration 0012,扩展 McpClientService 在
连接发现阶段并发调用 list_resource_templates(旧 server 不支持时静默兜底,不
阻断 tools 发现),新增 call_tool_and_resolve_resources:在同一 ClientSession 内
完成工具调用与所有 resource_link URI 的并发拉取(Semaphore 限流 4,return_exceptions
保证单条失败不击穿主流程)。这是接入 Negentropy Perceives 动态 FileResource
(perceives://pdf/<job_id>/<filename>)的协议层基石——动态实例的生命周期与工具
会话强绑定,必须在 session 关闭前完成 resources/read 才能避免事后失链。

Interface API 同步:load_mcp_server_tools 端点扩展为 capability 全量同步(tools
+ resource_templates,软删除已下线的 templates),LoadToolsResponse 新增
resource_templates 字段(向后兼容),新增 GET /mcp/servers/{id}/resource-templates
端点;list_mcp_servers 拆解为分段计数避免 JOIN 笛卡尔积;McpServerResponse 暴露
resource_template_count 给前端展示。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(perceives-resources): PDF 图片资源端到端贯通到 GCS 与 Wiki Markdown;

把 Perceives MCP 工具调用返回的 ResourceLink 接入既有提取流水线(Ingest 与
Re-Parse from GCS),让 PDF 图片资源在主仓 ↔ Perceives 之间通过 MCP 协议
完整贯通:

- 提取层(extraction.py):新增 _extract_resource_link_assets 把 ResourceLink
  与同会话 read_resource 拉取的 base64 配对为 ExtractionAsset;_call_tool_with_plan
  改用 resolve_resource_links=True 路径,确保动态 URI 不会因会话关闭失链;
  _build_success_result 接收 resolved_resources / resource_errors,按 "warn +
  占位" 容错策略合并 assets 并标记 partial_failure 不阻断主入库;新增
  _rewrite_markdown_image_links 在 Markdown 写入 GCS 之前把相对路径图片引用
  重写为 /api/documents/{doc_id}/assets/{filename},重写采用 capture group 偏移
  以避免 alt 文本含同名 src 时误替换。

- Knowledge API:新增 GET /knowledge/wiki/documents/{document_id}/assets/{filename}
  公开端点,filename 严格白名单 ^[A-Za-z0-9._-]+$ 与 180 字符上限;鉴权策略与
  既有 wiki entry content 端点对齐——仅放通至少被一条 WikiPublicationEntry
  引用的 document,避免持任意 doc_id 拖走未发布文档资产。

- 前端 MCP 卡片(negentropy-ui):新增 Resource Templates 折叠区与 ResourceDetailPanel,
  视觉与 Tools 区完全镜像;page.tsx 在 tools:load 响应中同步消费
  resource_templates 段,状态合并到 ServerWithTools;动态实例(带 job_id)
  按设计不入卡片。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(mcp-client): Resource Templates 同步加 capability flag,避免静默兜底误清空模板表;

`_discover_on_transport` 对 `list_resource_templates` 的所有异常都会静默兜底返回空列表(兼容旧 server 与瞬态错误),但 `load_mcp_server_tools` 会把空列表当作权威结果裁剪 stale 行,导致一次网络抖动或 server bug 即抹掉全部模板;同时与 tools 同步"只增量更新、不裁剪"的语义不对称。

- `McpConnectionResult` 新增 `resource_templates_listed: bool`,仅在 `list_resource_templates` 成功返回时为 True;
- `load_mcp_server_tools` 仅在该 flag 为 True(权威空列表)时才裁剪 stale 模板,未支持/错误场景保留既有 DB 行;
- 单元测试覆盖 flag 在权威空列表与异常兜底两种路径下的取值。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(mcp-card): 单测 server fixture 补 resource_template_count 修 UI Type Checks;

`McpServer` 类型新增的必填字段 `resource_template_count` 未同步到 `McpServerCard.test.tsx` 的 server 固件,导致 ui-quality / UI Type Checks 在 5 处 `<McpServerCard server={...}>` 调用上报 TS2741。

- 在 server 固件加 `resource_template_count: 0`,spread 派生用例自动获得新字段。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(knowledge): 查询时 honor Corpus 自配 embedding 模型,修复 query/index 模型不一致 (ISSUE-028) (#424)

search() 原直接使用实例化时锁定的 self._embedding_fn(全局默认 gemini/text-embedding-004),
未读 corpus.config.models.embedding_config_id;而 _attach_embeddings 索引侧已按 corpus pin 走
专属 fn。两侧不对称导致:用户在 Corpus Settings 已切到 openai/text-embedding-3-small(1536 维),
索引按 OpenAI 生成,查询仍走 Gemini 全局默认经 localhost:3392 翻译代理报 400。

修复:
- 新增 _resolve_embedding_fn(corpus_config) 助手,corpus pin 优先 → 退回 service 默认 fn;
- search() 入口加载 corpus_config + embedding_fn 本地变量,rrf/hybrid/semantic 三分支替换;
- ISSUE-026 keyword 兜底 + 502 映射 + 诊断日志原样保留,零回归;
- 新增 5 例单元测试覆盖 corpus pin 命中/落空/兜底/rrf/semantic 上抛,577 全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError (#425)

* fix(docs): 同步文档启动命令与 cli.py 修复,消除 Home Send 500 复发路径;

cli.py 的 agents_dir 已在 35204ff 从 src/negentropy 修正为 src,
但 README / docs 下 4 个文件 7 处仍写 --reload_agents src/negentropy,
用户照文档启动复现 ValueError: Agent not found 500。
统一替换为 uv run negentropy serve(SSOT),
追加 ISSUE-029(文档漂移)与 ISSUE-030(SubAgents root Agent 防回归)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError;

DynamicRootLiteLlm/DynamicSubagentLiteLlm 在 ContextVar 或 sub_agents.model
为空时直接返回 None,回退到构造时无 api_key 的硬编码实例,绕过了 DB 中
已配置的 vendor_configs 凭证。现在始终通过 resolve_llm_config() 从 DB
解析默认模型的完整凭证(含 api_key)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复长耗时回复双气泡 + 首条未格式化 (ISSUE-031); (#426)

ADK 仅持久化 partial=false 终态事件,realtime 与 hydration 在
同一逻辑消息上派出不同的 messageId(首个 partial id vs 终态 id)。
isSemanticEquivalentEntry 的 8s 时间窗在长耗时回复下硬拒绝,导致
ledger 双 entry → events 过滤失败 → conversation tree 双节点 →
UI 渲染双气泡(首条因 streaming-markdown 尾部判定走 raw text 分支)。

修复 (最小干预 + 正交分解):
- message-ledger.ts: 内容严格相等时跳过 8s 时间窗硬拒绝。
- conversation-tree.ts: assistant 已收尾节点在内容严格相等时
  也允许 findMatchingTextNodeId 命中复用,作为防御性收敛。
- 三层回归测试覆盖 ">8s 跨度 + messageId 不同 + 内容严格相等"。

UI 全量 70 文件 396 测试通过;typecheck/typecheck:test/eslint 零报错。
docs/issue.md 沉淀 ISSUE-031;CHANGELOG.md 同步条目。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(home-chat): 修复 Home 对话 title 凭证缺失与 OTLP logs/metrics 404 双联缺陷 (#427)

* fix(home-chat): 修复 Home 对话 title 凭证缺失 + OTLP logs/metrics 404 双联缺陷;

(1) SessionSummarizer 同步 __init__ 在 60s 缓存 miss 时回退到无 api_key 硬编码默认,
导致 LiteLLM AuthenticationError;改为 async classmethod create() 经 resolve_llm_config()
从 DB 读取完整凭证(与 commit 8ce35d5 修复 DynamicRootLiteLlm 同 SoT),调用方
session_service._generate_title_for_session 切换为 await SessionSummarizer.create(),
对 resolver 返回 kwargs 做防御性浅拷贝避免与 60s 缓存层耦合。

(2) ADK 上游 _get_otel_exporters() 把 OTEL_EXPORTER_OTLP_ENDPOINT 视为 OTLP 三件套
总开关,无差别注册 OTLPSpanExporter / OTLPMetricExporter / OTLPLogExporter;后两者
对 Langfuse 不存在的 /v1/metrics、/v1/logs 上报触发 SPA 404 SSR 错误页(每次对话
反复输出大段 HTML)。bootstrap.py 新增 _install_noop_otel_logs_metrics_providers()
在 OTel env var 设置后立即抢注无 processor / 无 reader 的 SDK Logger/Meter Provider,
利用 OTel SDK Once-lock 让 ADK 后续 set_*_provider 静默 no-op,从而阻断 logs/metrics
上报;TracerProvider 链路与 OTEL_EXPORTER_OTLP_HEADERS 不动,traces 仍正常进入 Langfuse。

新增 tests/unit_tests/engine/test_summarization.py(3 例)+
tests/unit_tests/observability/test_otel_noop_providers.py(3 例,子进程隔离 OTel 全局
状态)锁定回归。CHANGELOG / docs/issue.md 沉淀 ISSUE-031(title 凭证缺失)与
ISSUE-032(OTLP logs/metrics 404)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(otel-noop): 移除 _sdk_config hasattr 兜底,让 SDK 私有属性变更显式触发回归;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(session-title): 修复 DummySummarizer 缺失 async create() 导致集成测试 AttributeError;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(bootstrap-otel): 消除 ADK Web 启动期 OTel Override Provider 双 WARNING (ISSUE-034); (#428)

将 ISSUE-033 的「抢占式 set_logger_provider/set_meter_provider」改为 patch
`google.adk.telemetry.setup._get_otel_exporters`,让其只返回 traces 的
span_processors,metric_readers/log_record_processors 永久置空。ADK
maybe_set_otel_providers 的 if 分支由此天然短路,set_*_provider 根本不被
调用,从源头消除 OTel SDK 的 "Overriding of current ... is not allowed"
WARNING;traces 链路、ADK ApiServerSpanExporter、TracingManager、LiteLLM
"otel" callback 行为完全不变。配套更新 3 个子进程隔离单测验证新语义,
并在 docs/issue.md 追加 ISSUE-034 完整记录。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(e2e-auth): 浏览器验证协议落地 + Playwright 会话复用贯通 Google OAuth (#429)

* docs(browser-validation): 落地浏览器验证协议并补 ISSUE-034

- AGENTS.md(即 CLAUDE.md symlink)新增"Browser Validation Protocol"子节,
  约定登录态浏览器验证必须复用用户常用 Chrome 会话,禁止 sandbox 浏览器
  通过 Google 同意屏,明确凭证守则与三步连通性自检;
- 新建 docs/agents/browser-validation.md:含三种 MCP 浏览器工具能力对照、
  Mermaid 选型决策图、storageState 工作时序、风控应对、IEEE 引用;
  实测附注 chrome-devtools MCP 在 macOS 默认即可复用用户主 profile 登录态;
- docs/issue.md 追加 ISSUE-034,记录 sandbox 浏览器走 Google OAuth 被拦
  的表因/根因/处理方式/防范,便于跨上下文复用。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(e2e-auth): Playwright 会话复用以贯通 Google OAuth E2E

- playwright.config.ts 在 PLAYWRIGHT_AUTH=1 时启用两个项目:
  * setup(headless: false,匹配 *.setup.ts),让用户在弹出窗手动登录;
  * chromium-authenticated(dependencies: ['setup']),使用 storageState
    复用一次性人工登录的会话;
  支持 PLAYWRIGHT_STORAGE_STATE 与 PLAYWRIGHT_USER_DATA_DIR 覆盖默认;
  现有 chromium project 加 testIgnore 排除 .setup.ts,CI/默认行为零变;
- 新增 tests/e2e/auth.setup.ts:打开 /auth/google/login,5 分钟内允许
  用户在 Google 同意屏中手动完成登录,回跳后断言 /api/auth/me 2xx,
  写入 storageState;
- .gitignore 追加 apps/negentropy-ui/.auth/ 与 .userdata/,
  防止会话凭证随分支推送外泄。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(e2e-auth): 修复 OAuth setup 早退与 authed spec 双跑;

- auth.setup.ts: waitForURL 谓词追加 host 约束,避免在跳往 accounts.google.com
  瞬间因 pathname 已离开 /auth/google 而误判完成,导致 /api/auth/me 在用户登录前
  失败、storageState 永不写出。
- playwright.config.ts: 基础 chromium project 的 testIgnore 追加
  /.*\.authed\.spec\.ts$/,防止 PLAYWRIGHT_AUTH=1 时同一份认证 spec 在
  chromium-authenticated 与 chromium 中各跑一次(后者无 storageState 必失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 Home 双气泡复发与 LLM 模型未 Send 即刷新丢失 (ISSUE-032/033); (#430)

ISSUE-032 (双气泡复发,与 ISSUE-031 正交):
- 根因:root agent prompt 主动导航 + log_activity tool 让 ADK 走双轮 LLM 调用,
  两轮各自带独立 messageId 走完整 TEXT_MESSAGE_* 三件套,UI 在同一
  assistant-reply bubble 内并列渲染两段近重复文本。
- 修复:utils/chat-display.ts::dedupeRedundantTextSegments 在
  buildAssistantReplyBlock 出口对同一 reply 内的 text segment 做字符二元组
  Jaccard 相似度计算,相似度 ≥ 0.5 且双方长度 ≥ 30 时丢弃前段、保留信息更
  完备的最终段。tool-group / reasoning / error 顺序不动。
- assistant-reply.message.content 联动重组,复制时也拿到折叠后的内容。

ISSUE-033 (LLM 模型未 Send 即刷新丢失):
- 根因:后端事实源 session.state.selected_llm_model 仅在 /run_sse 时随
  state_delta 写入,未 Send 时不更新;前端 perThreadLlmRef 是 useRef
  刷新即丢;snapshotForDisplay 也无值,回退到 default。
- 修复:app/home-body.tsx 顶部新增 readPersistedLlmModel /
  writePersistedLlmModel (typeof window 守卫 + try/catch SSR 安全);
  handleSelectedLlmModelChange 即时落盘到 localStorage;Effect 1 优先
  从 localStorage 还原;Effect 2 命中 snapshot 时同步回写 localStorage,
  让「后端 state ↔ localStorage」互为镜像。既有 forwardedProps.selected_llm_model
  在 Send 时仍写后端 state,跨设备一致性最终收敛。

测试:
- 新增 2 例 chat-display.test.ts 用例:折叠近重复段 + 差异度大不被折叠
- UI 全量 70 文件 398 测试通过;typecheck/typecheck:test/eslint 零报错

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038) (#431)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038);

ISSUE-034 的 patch 调用 original() 后再丢弃 metric_readers /
log_record_processors,但上游 _get_otel_exporters 已构造
PeriodicExportingMetricReader 并启动 60s 守护线程——reader 未注册
到 MeterProvider 导致每 tick 触发 "Cannot call collect on a
MetricReader ..." WARNING。改为绕过 original(),直接复用
_get_otel_span_exporter() 仅构造 traces span processor,根源
避免 OTLP metrics/logs exporter 被实例化。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(bootstrap-otel): 修正 _disable_adk_otel_logs_metrics_exporters docstring 中的过期 hooks 引用;

旧 docstring 沿用重构前 `hooks = original()` 的中间变量术语,但新实现已不再调用 `original()`,函数体内也没有 `hooks` 绑定。
更新指引为「恢复 _get_otel_exporters 原函数闭包」或「直接构造完整 OTelHooks」,避免误导后续维护者寻找已不存在的对象。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-039) (#432)

* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-038);

- chat-display: dedupeRedundantTextSegments 增加四层判定(精确匹配 / 严格前缀 / 等价内容 / Jaccard),覆盖 ADK 双轮 LLM 短回复(如 "Pong!")的双气泡盲区。
- session-hydration: mergeEventsWithRealtimePriority 交换参数顺序,让 realtime 事件覆盖 hydrated;TEXT_MESSAGE_CONTENT 的 eventKey 时间戳改用 toFixed(3) 消除浮点抖动导致的同一事件重复保留。
- message-ledger: MessageLedgerEntry 新增可选 sourceOrder 作 createdAt 相同时的稳定 tiebreaker,替代 UUID localeCompare 的随机字典序;抽出 compareLedgerEntriesByTime 复用,类型保持向后兼容(缺省回退 Number.MAX_SAFE_INTEGER)。
- 新增 5 项单元测试覆盖:短回复精确匹配、前缀含尾部追加、Jaccard 长文本、eventKey 浮点稳定、sourceOrder 稳定排序;docs/issue.md 增补 ISSUE-038 摘要。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(home-chat): 补 mergeEventsWithRealtimePriority 生命周期事件覆盖回归用例;

针对 ISSUE-039 第 3 项修复(mergeEventsWithRealtimePriority 参数顺序交换)
原有 RUN_STARTED 类生命周期事件用例缺位——之前的 messageId 重叠用例在
step 3 即被过滤为 filteredHydratedEvents=[],无法验证 step 4 mergeEvents
入参顺序对 key 冲突归并的影响。

补一条 RUN_STARTED 用例:realtime / hydrated 同 threadId/runId/timestamp
(eventKey 字节级一致)→ 用对象引用断言保留的是 realtime 版本,作为参数
顺序交换的最直接证据。该用例在交换前会失败、交换后通过,形成有效回归网。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040) (#433)

* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040);

- 过滤 ADK Part 中 thought=true 与 type=thinking|thought|reasoning 系列推理字段,避免 reasoning_content 溢出到 TEXT_MESSAGE_CONTENT;推理文本改路由为 ne.a2ui.thought 自定义事件保留可观测性。
- createStepFinishedEvent 同步透出 stepName,AdkMessageStreamNormalizer 持有 stepId→stepName 映射,根治 ag-ui v0.0.47 校验器 "Cannot send 'STEP_FINISHED' for step \"undefined\"" 中断 run 导致的推理头永驻 started 现象。
- conversation-tree fallback 段重建消息节点时优先复用 ledger 已有 sourceOrder,避免被推到 events 末尾破坏 compareLedgerEntriesByTime tiebreaker。
- session-hydration eventKey 全事件类型统一走 toFixed(3) 毫秒级时间戳,并为 STEP_STARTED/STEP_FINISHED 显式按 (threadId, runId, stepId) 作 key,覆盖 STEP_*/CUSTOM/STATE_*/RAW 在浮点抖动下的去重盲区。
- 新增 9 例单元回归覆盖 thought part 过滤 / STEP_FINISHED stepName / fallback sourceOrder / eventKey 浮点抖动;docs/issue.md 追加 ISSUE-040 全栈解析。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 消除 hydration sort 字典序污染 lifecycle 顺序导致的多消息刷新乱序 (ISSUE-040 Q3 长尾);

- hydrateSessionDetail 引入 WeakMap<BaseEvent, emitOrder>,sort tiebreaker 用 normalizer 推入顺序代替 eventKey().localeCompare,保留 TEXT_MESSAGE_* 三件套 START→CONTENT→END 与跨 messageId 的 turn 边界。
- mergeEvents 同步改为按首次出现位置记录 insertionOrder 作 tiebreaker,避免最后一步 mergeEvents([], normalizedEvents) 再把刚排好的事件按字典序乱序。
- 新增同 timestamp 下 lifecycle 顺序断言用例;多轮真实后端 events fixture 经修复链路输出 user(R1)→assistant(R1)→user(R2)→assistant(R2) 完全符合时间线。
- docs/issue.md 在 ISSUE-040 末尾追加 Q3 长尾闭环(H5 字典序污染根因与最小干预修复)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* test(home-chat): 强化 ISSUE-040 H3 fallback sourceOrder 回归用例;

- 旧用例与单 snapshot 单条消息时新旧公式恰巧同值,断言无差异,无法拦截 H3 退化;
- 新用例构造「snapshot 数组顺序 vs ledger 时间序」错位场景:让 sourceOrder 在两条消息间发生互换,对回滚 H3 修复有强差异断言(已本地反向核验:回滚 conversation-tree.ts 修复后断言失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs (#434)

* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs;

将 publication catalog 的第一层 CONTAINER 节点(如 Harness-Engineering)
从左侧 Sidebar 迁移为顶部 Header tabs;第二层及以下保留于 Sidebar,整树向上提升一档。
设计参考 GitHub Docs / Stripe Docs / Docusaurus 的"顶 tabs + 左 sidebar 子树"模式。

主要变更:
- lib/wiki-api.ts 追加 findFirstDocumentSlug / findActiveTopLevelSlug / resolveSectionView
  纯函数,作为 Header tabs 与 Sidebar 切片的单一事实源。
- 新增 WikiHeader Server Component(仅 <Link>,SSG 友好):渲染品牌 + 水平 tabs;
  CONTAINER tab 跳转 DFS 首个后代 DOCUMENT;无文档则禁用 span。
- WikiLayoutShell 增加 header? prop,渲染于 .wiki-layout 之外作为兄弟节点,
  避免触动既有 3 列 Grid 与 data-toc 三态。
- /{pubSlug} 与 /{pubSlug}/{...entrySlug} 两条路由共用 resolveSectionView 派生视图:
  pub 根页默认激活首项;entry 页按 slug 反查所属一级。
- globals.css 引入 --wiki-header-height 并把 sidebar / toc-aside 的 sticky top
  改为 var 引用,确保滚动时 Header 常驻不挡 sidebar。
- 新增 wiki-section-view.test.ts 12 用例覆盖空树 / 单 / 多 / 深路径 / DOCUMENT-only
  / 无后代 DOCUMENT 等边界。

回归保障:home / 不变;既有 WikiNavTree / WikiToc 测试 API 未变;47/47 单测全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(wiki-header): Header 缺失时 sidebar/toc 不再残留偏移;

通过 data-header 属性标记 Header 是否存在,CSS 侧条件生效
--wiki-header-height 偏移,避免空导航树时出现 56px 空白间隙。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* refactor(config): 废弃 .env*,统一 YAML 三级配置(local > user > default) (#436)

* refactor(config): 废弃 .env* 加载链路,引入 config.local.yaml 统一 YAML 三级配置;

- 移除 10 个 Python 配置模块中的 env_file / _get_env_files 逻辑
- yaml_loader 新增 config.local.yaml 作为最高优先级 YAML 来源
- config.default.yaml 合并 .env 全部非机密差异值(含 OAuth 端口 6600→3292 校正)
- 新增 3 例 config.local.yaml 优先级测试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(config): 同步 .env 废弃后的文档与 CHANGELOG;

- development.md / sso.md / framework.md / user-guide.md / zh-CN/README.md 中 .env 引用替换为 config.local.yaml
- CHANGELOG 新增 ISSUE-041 变更记录
- docs/issue.md 新增 ISSUE-041 经验沉淀
- .gitignore 新增 apps/negentropy/config.local.yaml 排除规则

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(config): 放宽 .gitignore 中 config.local.yaml 匹配规则,覆盖任意 cwd 场景;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#435)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#437)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(home-chat): 修复跨 runId 双气泡时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

fallback 路径从无条件移除改为内容覆盖检查——跨所有同 threadId keeper 逐 child
匹配,避免含独特历史内容的 synthetic turn 被误折叠。加强 C3 断言为
toHaveLength(2) + synthetictoBeDefined。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(conversation-tree): isSyntheticTurnNode 补充 "default" runId 识别对齐 isSyntheticRunId (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(ctl): 新增全套服务一键启停脚本 (#438)

* feat(ctl): 新增全套服务一键启停脚本 scripts/ctl.sh

支持 start/stop/restart/status/logs/build 子命令,覆盖依赖安装、
数据库迁移、前端构建、健康检查的完整生命周期。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 修复 is_running 变量泄漏与并行 wait 退出码丢失;

- is_running() 中 pid_file 添加 local 声明,防止全局作用域污染
- 三处并行 wait 改为逐个检查退出码,任一子进程失败即报错中止

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 修复健康检查不感知进程崩溃、路径逻辑重复与服务名校验缺失;

- wait_for_health 在 HTTP 轮询间隔中加入 is_running 检查,进程崩溃时立即返回失败
- is_running 改用 pid_file() 函数获取路径,消除硬编码重复
- cmd_logs 入口校验服务名是否属于 ALL_SERVICES,非法名称给出明确提示

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(ctl): 使用 exec 替代 eval 确保进程 PID 精确追踪与信号直达;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 知识图谱模块生产就绪改造 — 实体管理、混合检索、路径探索、统计面板 (#439)

* feat(kg): 知识图谱模块生产就绪改造 — 语料库级图谱、实体管理、混合检索、路径探索、统计面板

后端变更:
- 新增 GET /graph/entities 实体分页列表(类型筛选+名称搜索)
- 新增 GET /graph/entities/{id} 实体详情含出/入关系
- 新增 GET /graph/stats 图谱统计(实体数/类型分布/置信度/密度/度数)
- 重写 find_neighbors: 递归 CTE 在 kg_relations 上实现多跳遍历
- 重写 find_path: 递归 CTE BFS 在 kg_relations 上查找最短路径

前端变更:
- 重写 graph/page.tsx: 语料库选择器 + 构建/浏览全流程
- 新增 EntityListPanel: 表格视图+类型筛选+分页
- 新增 EntityDetailPanel: 实体详情+关系列表(出边/入边)
- 新增 SearchBar: 混合检索(语义+图结构)
- 新增 PathExplorer: 双实体选择+BFS路径查找
- 新增 NeighborExplorer: 1/2/3跳邻居展开
- 新增 GraphStatsPanel: 实体数/类型分布/置信度/密度/度数
- 新增 BuildHistoryList: 结构化构建历史卡片(状态徽章+统计+耗时)

文档变更:
- 扩展 user-guide.md §4.5 为完整知识图谱用户指引
- 更新 knowledge-graph.md §3 新增架构模式精炼(Cognee ECL/Graphiti 双时态)
- 更新 knowledge-graph.md §4 交付物清单

测试变更:
- 新增 test_graph_entity_service.py: 9 项单元测试覆盖实体列表/详情/Schema

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复知识图谱模块 CI 失败 — 类型错误、ID 前缀、测试 mock;

- 移除 NeighborExplorer 组件调用中不存在的 entityName prop(TS2322)
- 为 find_neighbors 返回的 GraphNode.id 补齐 entity: 前缀
- 重写 find_path 测试,mock session.execute 而非 find_neighbors

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复审查发现的 7 项问题 — 安全编码、状态管理、双向路径搜索;

- 路由 path params 加 encodeURIComponent 防路径遍历(3 个 route 文件)
- EntityDetailPanel: 用 loadedEntityId 派生 loading 状态,切换实体时正确展示加载态并清除旧数据
- EntityListPanel: 搜索输入 300ms 防抖,用 completedKey 派生 loading 状态
- GraphStatsPanel: 用 result 组合状态区分加载中/失败/成功
- NeighborExplorer: entityId 变更时重置 expanded/neighbors
- graph_repository find_path: 递归 CTE 增加反向遍历分支,与 find_neighbors 双向语义对齐

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复审查发现的遗留问题 — 常量提取、路径搜索、会话管理;

- 前端:提取 ENTITY_TYPE_COLORS 至 constants.ts,消除三处 TYPE_COLORS 残留引用(会导致运行时崩溃)
- 后端:修复 find_path 递归 CTE 中 path 追加错误(r.target_id → ps.target_id)
- 后端:get_stats 改为接收外部 db 会话,消除自建会话
- 后端:get_entity_detail 增加 corpus_id 可选过滤,增强数据隔离

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): 记忆模块生产就绪化 — 巩固管线重构 + 事实提取 + 上下文集成 + 文档完善 (#440)

* feat(memory): 重构记忆巩固管线为三阶段智能架构并增强核心模块

- 重构 _simple_consolidate 为三阶段管线(分段→去重→存储),借鉴 Claude Code AutoDream 四阶段范式
- 新增 PatternFactExtractor 基于正则模式的对话事实自动提取(preference/profile/rule/custom)
- 新增 ContextAssembler 记忆上下文组装器,管理 token 预算分配(30%记忆/50%历史/20%系统)
- 新增 AsyncScheduler 应用层调度器回退,当 pg_cron 不可用时提供等效定时任务能力
- 增强 search_memory API 支持分页(limit/offset)和过滤(memory_type/date_from/date_to)
- 集成 ContextAssembler 到 perception.py 记忆搜索回退路径
- 新增 34 条单元测试覆盖事实提取和调度器(全部通过)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(memory): 补充工业框架对标分析与用户操作指南

- docs/memory.md §2.4 新增 Claude Code 记忆架构深度对标(AutoDream 四阶段整理、三重门控调度、四类型分类法、三层上下文压缩、漂移防御)
- docs/memory.md §2.5 新增 Agent Harness 设计模式对标(三层压缩管线、Skill 按需加载、Task Graph 持久化)
- docs/memory.md §2.6 新增 Negentropy 差异化定位总结表
- docs/user-guide.md §5.8-§5.12 新增记忆形成机制、保留分数解读、搜索最佳实践、自动化配置指南、故障排除

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 恢复巩固管线 metadata 中遗漏的 event_count 字段

三阶段管线重构后 metadata 字典遗漏了原有的 event_count 字段,
导致 test_memory_service_lifecycle 集成测试 KeyError 失败。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 7 项问题

1. search_memory 的 memory_type/date_from/date_to/offset 过滤参数现在在 vector_search 和 ilike_search 中实际生效
2. context_assembler 的 lazy import 移至文件顶部,与同文件风格一致
3. _simple_consolidate docstring 从「三阶段」更正为「四阶段」(含事实提取)
4. api.py search_memories 的 total 字段添加 TODO 标记(需独立 COUNT 查询)
5. AsyncScheduler 失败时回退 last_run_at,允许尽快重试而非等完整 interval
6. PatternFactExtractor 三段重复遍历提取为 _match_patterns 辅助方法
7. _consolidate SQL 拼接改为参数化绑定 :lookback::interval,消除注入风险

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 3 项问题

- offset 分页参数未透传到底层搜索方法,现已正确传递
- datetime.fromisoformat() 缺少校验,非法日期返回 400 而非 500
- AsyncScheduler 派发任务未被追踪,stop() 时一并取消在途任务

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 Code Review 反馈的 2 项问题

- 巩固管线阶段 4 事实提取调用包裹 try/except,防止导入或工厂失败中断管线
- 搜索接口 total 字段改为 -1 标记"未知",避免分页客户端误读

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + Token 精确计数 + 检索反馈闭环 (#442)

* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + 精确 Token 计数 + 检索反馈闭环

- TokenCounter: 基于 tiktoken cl100k_base 编码器精确计数,替代 LENGTH/4 粗略估算
- LLMFactExtractor: LLM 结构化输出事实提取,PatternFactExtractor 作为降级后备
- MemorySummarizer: LLM 生成结构化用户画像摘要,缓存至 memory_summaries 表(TTL 24h)
- SummaryService: memory_summaries 表 CRUD(upsert 语义)
- RetrievalTracker: 检索效果反馈闭环,记录检索事件 + 显式反馈 API
- ContextAssembler: 优先注入摘要,tiktoken 精确 token 计数
- 新增 Alembic migration 0013/0014(memory_summaries + memory_retrieval_logs)
- 新增 MemorySummary + MemoryRetrievalLog ORM 模型
- 11 条新增单元测试,62 条全部通过,零回归

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(memory): Phase 2 文档沉淀 — 两级提取策略 + 摘要巩固 + 精确计数 + 检索反馈 + 新增文献

- §4.2 扩展为两级事实提取策略说明(LLMFactExtractor + PatternFactExtractor)
- §5.4.1 新增摘要巩固策略(记忆再巩固理论 + 5 项工程对标)
- §6.3 更新 Token 估算为 tiktoken BPE 精确计数
- §6.5 新增检索效果反馈闭环(Rocchio + LTR + LongMemEval 评估维度)
- §15 新增 6 篇参考文献(Sennrich 2016, Sara 2015, Rocchio 1971, Burges 2005, Mem0, Letta)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 LLM 事实提取 prompt 类型名不匹配 + 检索指标 SQL 聚合优化;

- prompt 模板中 "pref" 改为 "preference",与 _VALID_FACT_TYPES 验证器对齐,避免 LLM 输出被静默降级为 "custom"
- get_effectiveness_metrics 改用 SQL COUNT+CASE 聚合,避免将全量日志行加载到 Python 内存

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* refactor(memory): Review 反馈修复 — 检索日志可观测性 + query 透传 + 模型配置去重;

1. 检索追踪 except 从 silent pass 改为 logger.debug,使故障可诊断
2. _record_access 新增 query 参数并从所有调用点透传,消除空 query 问题
3. 提取 _resolve_model_config 为共享工具 engine/utils/model_config.py,
   LLMFactExtractor 和 MemorySummarizer 统一引用,消除 DRY 违规
4. 同步更新单元测试 mock 路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐 (#441)

* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐

- create_relation() 新增写入 kg_relations 一等公民表,保留 JSONB 过渡兼容
- get_graph() 优先从 kg_entities + kg_relations 读取,空时回退 JSONB
- clear_graph() 增加 kg_entities/kg_relations 表清理
- build_graph() 完成后调用 KgEntityService.batch_sync_from_graph_build()
- 更新 test_graph_repository 适配新读写路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 新增 PageRank 实体重要性评分与 RRF 混合检索

- 新增 graph_algorithms 模块,基于 NetworkX 实现 PageRank (Brin & Page, 1998) 计算,
  结果持久化至 kg_entities.importance_score
- 混合检索支持 Reciprocal Rank Fusion (Cormack et al., SIGIR 2009) 模式,
  可通过 GraphQueryConfig.use_rrf / rrf_k 配置,向后兼容线性加权模式
- 图谱构建完成后自动触发 PageRank 计算
- 实体列表支持按重要性排序(sort_by=importance)
- 统计面板展示 Top 5 PageRank 实体
- 图谱可视化节点半径映射 PageRank 分数,突出重要实体

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): 新增 Louvain 社区检测与图谱可视化增强

- 新增 compute_louvain() 算法,基于 NetworkX 内置 Louvain (Blondel et al., 2008)
  在无向投影图上运行社区检测,结果持久化至 kg_entities.community_id
- 图谱构建完成后自动触发 Louvain 计算(紧接 PageRank 之后)
- 统计面板新增社区分布(community_count + community_distribution)
- 实体列表和详情响应包含 community_id 字段
- 图谱可视化节点按社区着色(Tableau 10 色盲友好调色板)
- 统计面板展示 Top 8 社区分布柱状图
- 实体表格新增社区列,显示色块标识
- 显式声明 networkx>=3.0 依赖(此前为隐式运行时导入)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 新增 Alembic migration 0015 — 添加 importance_score 和 community_id 列

CI 集成测试失败根因:ORM 模型新增了 importance_score (PageRank) 和 community_id (Louvain)
列,但缺少对应的 Alembic migration,导致测试数据库 schema 不匹配。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(kg): 修复 Review 反馈的三个问题

1. RRF 搜索 graph_score 恒为 0 — 将 importance_score 写入 entity_data
2. PageRank/Louvain 逐条 UPDATE — 改为 VALUES CTE 批量更新
3. 一等公民表路径缺 app_name 过滤 — 文档明确 corpus 级去重设计意图

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 测试覆盖 (#443)

* test(memory): Phase 2 组件测试覆盖 — TokenCounter / SummaryService / RetrievalTracker / MemorySummarizer;

新增 39 个单元测试用例,覆盖 Phase 2 四个核心组件:
- TokenCounter: 精确计数、空输入、幂等性、异步一致性、单调性(蜕变测试)
- SummaryService: upsert/get/delete CRUD 路径
- RetrievalTracker: 检索日志、引用标记、反馈记录、效果指标计算
- MemorySummarizer: 摘要生成、TTL 缓存命中/过期、LLM 失败降级、重试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 文档沉淀;

Gap 1 反馈闭环:
- _record_access 修复 user_id/app_name 透传(此前始终为空字符串)
- PostgresMemoryService 存储 _last_retrieval_log_id 供下游消费
- ContextAssembler 注入 mark_referenced 隐式反馈信号(RLHF[33])
- API 新增 POST /memory/retrieval/feedback 和 GET /memory/retrieval/metrics

Gap 2 Query-Aware:
- assemble() 新增 query/query_embedding 可选参数
- _call_get_context_window 传递 7 个参数(含 p_query, p_query_embedding)
- SQL 函数 NULL safe 退化:无 query 时保持纯 retention_score 排序
- 隐式反馈标记在上下文组装成功后触发

Gap 3 近重复检测:
- _is_duplicate 阈值从 0.9 降至 0.85(Henzinger[40])
- 新增 Jaccard 词重叠二次校验(0.80-0.85 区间,Broder[37])
- FactService 新增 merge_similar_facts() 语义去重方法

文档沉淀:
- docs/memory.md 权威源文件索引扩充 Phase 2 组件
- §15 追加 13 篇参考文献 [31]–[43]

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(memory): 修复 merge_similar_facts 过度删除 + retrieval_log_id 并发安全问题;

- merge_similar_facts: 锚点事实被删除后立即 break 内层循环,避免基于已删除 embedding 继续比对导致误删
- _record_access: 移除 _last_retrieval_log_id 实例属性,改为返回 log_id,消除共享可变状态的并发竞态
- ContextAssembler.assemble: memory_service 参数改为显式 retrieval_log_id,调用方直接传入

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存 (#444)

* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存

Gap 3 [P1] 构建管线健壮性 (Nygard, 2018; Majors, 2022):
- Migration 0016: kg_build_runs 增加 progress_percent + warnings 列
- build_graph: 批处理循环进度上报、LLM 提取失败…
ThreeFish-AI added a commit that referenced this pull request May 19, 2026
…识管理统一入口(100 PRs / 843 文件) (#560) (#579)

* feat(agent-defs): 主 Agent 入库 + 按 DB 读 instruction + 模型选择回退 (#420)

* fix(agent-defs): 修复 Agent 加载路径 + 主 Agent 纳入 Interface Sync + 运行时按 DB 读 instruction;

- cli.py: --reload_agents 改用 Path(__file__) 推导的绝对路径,杜绝 cwd 依赖导致的「src/negentropy/negentropy」双重段错误;
- subagent_presets: 新增 NegentropyEngine root payload(adk_config.kind="root"),Sync 后 DB 出现主 Agent 行;
- sync API: 循环写入 config.kind,末尾调 invalidate_cache(prefix="subagent:") 批量失效;
- SubAgentResponse: 新增顶层 kind 字段(root/subagent),供前端置顶 + 徽章;
- model_resolver: 抽取 _load_subagent_row 共用单行查询,新增 resolve_subagent_instruction;
- _dynamic_instruction: 新增 InstructionProvider 工厂,root + 5 子 Agent 的 instruction 接入运行时 DB 读取;
- 测试: 更新 test_subagent_presets 覆盖 root payload + kind 断言;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-llm): 修复无 Session 时模型选择回退 + SubAgents 列表 Root 置顶徽章;

- home-body: 新增 pendingLlmRef,改写 handleSelectedLlmModelChange 与 Effect 1,
  使「无 session 选模型→建 session→自动发送」全流程保持选择不丢失;
- SubAgents page: 按 kind="root" 置顶排序,Sync 按钮文案从「Sync Negentropy 5」改为「Sync Negentropy」;
- SubAgentCard: Root Agent 显示 violet 色 Root 徽章;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(model-resolver): SubAgent 行缺失/未启用补回 60s TTL 负命中缓存;

回归点:重构 `_resolve_subagent_row` 时把空占位写入移到了 `loaded is None`
判断之后,导致禁用 Faculty 与未 Sync 环境下每次 LLM 请求都触发一次 DB 查询。
本次在 `loaded is None` 分支补 `_cache[cache_key] = ("", {"i": ""}, now)`,
让负命中同样落入 60s TTL,避免重复 DB 压力。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-llm): pending 模型选择仅对 startNewSession 新 id 消费;

回归点:Effect 1 的 pending 转移分支会在「首次进入既有 session」时触发,
把无 session 阶段的 pending 模型写入该 session 的 perThreadLlmRef,
并让 Effect 2 跳过 snapshot 初始化,导致服务器端记忆模型被静默替换。

修复方式:
- 新增 `pendingLlmTargetIdRef` 仅记录 startNewSession 返回的新 id;
- 通过 `startNewSessionWithLlmTarget` 包装内联调用与 `onNewSession` 两条路径;
- Effect 1 仅在 `sessionId === pendingLlmTargetIdRef.current` 时转移 pending,
  其余进入既有 session 的分支主动丢弃 pending,让 snapshot 正常生效。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(knowledge): 修复 KB Retrieve 全屏空白(前端聚合 rejection × 后端 hybrid/rrf 降级 × 502 上游错误码 × 诊断仪器化) (#421)

* fix(knowledge): 修复 Knowledge Base Retrieve 全屏空白(前端聚合 rejection + 后端 hybrid/rrf 降级 + 502 错误码 + 诊断日志);

双层 Bug 同因联修(详见 docs/issue.md ISSUE-026):
1. 前端 searchAcrossCorpora 旧实现以 Promise.allSettled 仅取 fulfilled,rejected 静默丢失,导致全部 Corpus 失败时返回 {count:0,items:[]} 走"成功路径"使 UI 空白且无任何提示——本次改为聚合三态(全成功/部分失败/全失败),SearchResults 类型扩展 errors[],handleRetrieve 对部分失败 toast.warning 透出原因;
2. 后端 service.search hybrid/rrf 旧实现未捕获 EmbeddingFailed,外部 Embedding 上游故障直接 500,丧失"keyword 仍可用"的优雅降级——本次 hybrid 失败回退 keyword-only、rrf 失败走与 not embedding_fn 等价的回退路径,semantic 仍传播以保留显式失败语义;
3. api.py _map_exception_to_http 拆分 EmbeddingFailed 分支映射到 502 Bad Gateway(保留 EMBEDDING_FAILED code),与 SearchError 自身错误的 500 区分,便于前端识别"上游修复后再试"语义;
4. embedding.py 调用 litellm 前后增加结构化诊断日志:api_base_host(脱敏 path/credentials 仅留 host)+ input_count + text_preview + kwargs_keys;失败附 upstream_response_text(沿异常链 __cause__/__context__ 提取 MaskedHTTPStatusError.text,已被 litellm 脱敏 URL,限长 500 字节);
5. 测试锁定:tests/unit_tests/knowledge/test_search_resilience.py 5 例(hybrid/rrf 降级 + semantic 传播 + EmbeddingFailed→502 + SearchError→500)+ tests/unit/knowledge/searchAcrossCorpora.test.ts 3 例(allSettled 三态);
6. docs/issue.md 追加 ISSUE-026,含后续防范(Promise.allSettled 必须聚合 rejection / vendor 失败必须 502 / hybrid 必须有降级路径 / vendor 调用必须 host+upstream_text 双信号)与同类问题影响清单。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(knowledge): searchAcrossCorpora 聚合保留 KnowledgeError code 并修正 _map_exception_to_http docstring;

Review #1(前端契约): SearchResultError 仅透 message 会丢弃 KnowledgeError.code(如 EMBEDDING_FAILED),削弱本次 502/500 拆分对前端"上游修复 vs 自身错误"的可分流价值——本次扩展 SearchResultError 增加可选 code,rejection instanceof KnowledgeError 时回填;全失败分支由 throw new Error 改为 throw new KnowledgeError(aggregatedCode, msg, {errors}),code 一致时透传原 code、混合时退化为 AGGREGATED_SEARCH_ERRORS,既保留分流能力又携带逐条失败明细;新增 1 例同 code 透传 + 1 例混合 code 退化的单测,全部 4 例通过。

Review #2(后端文档): api._map_exception_to_http docstring 仍只列 400/404/409/500,与新增 EmbeddingFailed→502 分支不一致;本次补 "502: 上游服务错误(vendor / Embedding 等外部依赖)" 一行,避免后续维护者按旧映射加分支。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(wiki-favicon): 修复 negentropy-wiki 站点 favicon.ico 单分辨率畸形导致浏览器回落默认地球图标; (#423)

- 根因:apps/negentropy-wiki/src/app/favicon.ico 是单分辨率畸形 ICO(file 输出 256x-1,高度字节 0xFF),且源图 logo.png 为非方形 800x798,导致 Chrome/Firefox/Safari 解析失败、tab 回落默认地球图标;
- 修复:用 Pillow 对 logo.png 做透明 padding 至 800x800 方形,再生成多分辨率 ICO(16/32/48/64/128/256 共六档)覆盖原文件;体积从 269KB 降至 118KB;
- 验证:file 输出 6 icons; pnpm build 后 .next/standalone 内 favicon route + body + meta 完整;pnpm start 后 curl /favicon.ico 返回 200 image/x-icon,HTML 自动注入 <link rel="icon">;
- 防范:docs/issue.md 追加 ISSUE-027,沉淀「ICO 必须方形 + 多分辨率」工程约束与 Pillow 流水线模板,禁止「原图直裹 ICO 头」反模式;
- 不动:layout.tsx / next.config.ts / start-production.mjs,保留 App Router metadata 自动注入路径,最小干预。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(mcp-resources): 接入 Resource Templates 并贯通 PDF 图片到 Wiki Markdown (#422)

* feat(mcp-client): 接入 MCP Resource Templates 与同会话动态资源拉取;

新增 McpResourceTemplate 模型与 Alembic migration 0012,扩展 McpClientService 在
连接发现阶段并发调用 list_resource_templates(旧 server 不支持时静默兜底,不
阻断 tools 发现),新增 call_tool_and_resolve_resources:在同一 ClientSession 内
完成工具调用与所有 resource_link URI 的并发拉取(Semaphore 限流 4,return_exceptions
保证单条失败不击穿主流程)。这是接入 Negentropy Perceives 动态 FileResource
(perceives://pdf/<job_id>/<filename>)的协议层基石——动态实例的生命周期与工具
会话强绑定,必须在 session 关闭前完成 resources/read 才能避免事后失链。

Interface API 同步:load_mcp_server_tools 端点扩展为 capability 全量同步(tools
+ resource_templates,软删除已下线的 templates),LoadToolsResponse 新增
resource_templates 字段(向后兼容),新增 GET /mcp/servers/{id}/resource-templates
端点;list_mcp_servers 拆解为分段计数避免 JOIN 笛卡尔积;McpServerResponse 暴露
resource_template_count 给前端展示。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(perceives-resources): PDF 图片资源端到端贯通到 GCS 与 Wiki Markdown;

把 Perceives MCP 工具调用返回的 ResourceLink 接入既有提取流水线(Ingest 与
Re-Parse from GCS),让 PDF 图片资源在主仓 ↔ Perceives 之间通过 MCP 协议
完整贯通:

- 提取层(extraction.py):新增 _extract_resource_link_assets 把 ResourceLink
  与同会话 read_resource 拉取的 base64 配对为 ExtractionAsset;_call_tool_with_plan
  改用 resolve_resource_links=True 路径,确保动态 URI 不会因会话关闭失链;
  _build_success_result 接收 resolved_resources / resource_errors,按 "warn +
  占位" 容错策略合并 assets 并标记 partial_failure 不阻断主入库;新增
  _rewrite_markdown_image_links 在 Markdown 写入 GCS 之前把相对路径图片引用
  重写为 /api/documents/{doc_id}/assets/{filename},重写采用 capture group 偏移
  以避免 alt 文本含同名 src 时误替换。

- Knowledge API:新增 GET /knowledge/wiki/documents/{document_id}/assets/{filename}
  公开端点,filename 严格白名单 ^[A-Za-z0-9._-]+$ 与 180 字符上限;鉴权策略与
  既有 wiki entry content 端点对齐——仅放通至少被一条 WikiPublicationEntry
  引用的 document,避免持任意 doc_id 拖走未发布文档资产。

- 前端 MCP 卡片(negentropy-ui):新增 Resource Templates 折叠区与 ResourceDetailPanel,
  视觉与 Tools 区完全镜像;page.tsx 在 tools:load 响应中同步消费
  resource_templates 段,状态合并到 ServerWithTools;动态实例(带 job_id)
  按设计不入卡片。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(mcp-client): Resource Templates 同步加 capability flag,避免静默兜底误清空模板表;

`_discover_on_transport` 对 `list_resource_templates` 的所有异常都会静默兜底返回空列表(兼容旧 server 与瞬态错误),但 `load_mcp_server_tools` 会把空列表当作权威结果裁剪 stale 行,导致一次网络抖动或 server bug 即抹掉全部模板;同时与 tools 同步"只增量更新、不裁剪"的语义不对称。

- `McpConnectionResult` 新增 `resource_templates_listed: bool`,仅在 `list_resource_templates` 成功返回时为 True;
- `load_mcp_server_tools` 仅在该 flag 为 True(权威空列表)时才裁剪 stale 模板,未支持/错误场景保留既有 DB 行;
- 单元测试覆盖 flag 在权威空列表与异常兜底两种路径下的取值。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(mcp-card): 单测 server fixture 补 resource_template_count 修 UI Type Checks;

`McpServer` 类型新增的必填字段 `resource_template_count` 未同步到 `McpServerCard.test.tsx` 的 server 固件,导致 ui-quality / UI Type Checks 在 5 处 `<McpServerCard server={...}>` 调用上报 TS2741。

- 在 server 固件加 `resource_template_count: 0`,spread 派生用例自动获得新字段。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(knowledge): 查询时 honor Corpus 自配 embedding 模型,修复 query/index 模型不一致 (ISSUE-028) (#424)

search() 原直接使用实例化时锁定的 self._embedding_fn(全局默认 gemini/text-embedding-004),
未读 corpus.config.models.embedding_config_id;而 _attach_embeddings 索引侧已按 corpus pin 走
专属 fn。两侧不对称导致:用户在 Corpus Settings 已切到 openai/text-embedding-3-small(1536 维),
索引按 OpenAI 生成,查询仍走 Gemini 全局默认经 localhost:3392 翻译代理报 400。

修复:
- 新增 _resolve_embedding_fn(corpus_config) 助手,corpus pin 优先 → 退回 service 默认 fn;
- search() 入口加载 corpus_config + embedding_fn 本地变量,rrf/hybrid/semantic 三分支替换;
- ISSUE-026 keyword 兜底 + 502 映射 + 诊断日志原样保留,零回归;
- 新增 5 例单元测试覆盖 corpus pin 命中/落空/兜底/rrf/semantic 上抛,577 全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError (#425)

* fix(docs): 同步文档启动命令与 cli.py 修复,消除 Home Send 500 复发路径;

cli.py 的 agents_dir 已在 35204ff 从 src/negentropy 修正为 src,
但 README / docs 下 4 个文件 7 处仍写 --reload_agents src/negentropy,
用户照文档启动复现 ValueError: Agent not found 500。
统一替换为 uv run negentropy serve(SSOT),
追加 ISSUE-029(文档漂移)与 ISSUE-030(SubAgents root Agent 防回归)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(agent-llm): 修复 Home Send 时 LLM 凭证未从 DB 读取导致 AuthenticationError;

DynamicRootLiteLlm/DynamicSubagentLiteLlm 在 ContextVar 或 sub_agents.model
为空时直接返回 None,回退到构造时无 api_key 的硬编码实例,绕过了 DB 中
已配置的 vendor_configs 凭证。现在始终通过 resolve_llm_config() 从 DB
解析默认模型的完整凭证(含 api_key)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复长耗时回复双气泡 + 首条未格式化 (ISSUE-031); (#426)

ADK 仅持久化 partial=false 终态事件,realtime 与 hydration 在
同一逻辑消息上派出不同的 messageId(首个 partial id vs 终态 id)。
isSemanticEquivalentEntry 的 8s 时间窗在长耗时回复下硬拒绝,导致
ledger 双 entry → events 过滤失败 → conversation tree 双节点 →
UI 渲染双气泡(首条因 streaming-markdown 尾部判定走 raw text 分支)。

修复 (最小干预 + 正交分解):
- message-ledger.ts: 内容严格相等时跳过 8s 时间窗硬拒绝。
- conversation-tree.ts: assistant 已收尾节点在内容严格相等时
  也允许 findMatchingTextNodeId 命中复用,作为防御性收敛。
- 三层回归测试覆盖 ">8s 跨度 + messageId 不同 + 内容严格相等"。

UI 全量 70 文件 396 测试通过;typecheck/typecheck:test/eslint 零报错。
docs/issue.md 沉淀 ISSUE-031;CHANGELOG.md 同步条目。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(home-chat): 修复 Home 对话 title 凭证缺失与 OTLP logs/metrics 404 双联缺陷 (#427)

* fix(home-chat): 修复 Home 对话 title 凭证缺失 + OTLP logs/metrics 404 双联缺陷;

(1) SessionSummarizer 同步 __init__ 在 60s 缓存 miss 时回退到无 api_key 硬编码默认,
导致 LiteLLM AuthenticationError;改为 async classmethod create() 经 resolve_llm_config()
从 DB 读取完整凭证(与 commit 8ce35d5 修复 DynamicRootLiteLlm 同 SoT),调用方
session_service._generate_title_for_session 切换为 await SessionSummarizer.create(),
对 resolver 返回 kwargs 做防御性浅拷贝避免与 60s 缓存层耦合。

(2) ADK 上游 _get_otel_exporters() 把 OTEL_EXPORTER_OTLP_ENDPOINT 视为 OTLP 三件套
总开关,无差别注册 OTLPSpanExporter / OTLPMetricExporter / OTLPLogExporter;后两者
对 Langfuse 不存在的 /v1/metrics、/v1/logs 上报触发 SPA 404 SSR 错误页(每次对话
反复输出大段 HTML)。bootstrap.py 新增 _install_noop_otel_logs_metrics_providers()
在 OTel env var 设置后立即抢注无 processor / 无 reader 的 SDK Logger/Meter Provider,
利用 OTel SDK Once-lock 让 ADK 后续 set_*_provider 静默 no-op,从而阻断 logs/metrics
上报;TracerProvider 链路与 OTEL_EXPORTER_OTLP_HEADERS 不动,traces 仍正常进入 Langfuse。

新增 tests/unit_tests/engine/test_summarization.py(3 例)+
tests/unit_tests/observability/test_otel_noop_providers.py(3 例,子进程隔离 OTel 全局
状态)锁定回归。CHANGELOG / docs/issue.md 沉淀 ISSUE-031(title 凭证缺失)与
ISSUE-032(OTLP logs/metrics 404)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(otel-noop): 移除 _sdk_config hasattr 兜底,让 SDK 私有属性变更显式触发回归;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(session-title): 修复 DummySummarizer 缺失 async create() 导致集成测试 AttributeError;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(bootstrap-otel): 消除 ADK Web 启动期 OTel Override Provider 双 WARNING (ISSUE-034); (#428)

将 ISSUE-033 的「抢占式 set_logger_provider/set_meter_provider」改为 patch
`google.adk.telemetry.setup._get_otel_exporters`,让其只返回 traces 的
span_processors,metric_readers/log_record_processors 永久置空。ADK
maybe_set_otel_providers 的 if 分支由此天然短路,set_*_provider 根本不被
调用,从源头消除 OTel SDK 的 "Overriding of current ... is not allowed"
WARNING;traces 链路、ADK ApiServerSpanExporter、TracingManager、LiteLLM
"otel" callback 行为完全不变。配套更新 3 个子进程隔离单测验证新语义,
并在 docs/issue.md 追加 ISSUE-034 完整记录。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* feat(e2e-auth): 浏览器验证协议落地 + Playwright 会话复用贯通 Google OAuth (#429)

* docs(browser-validation): 落地浏览器验证协议并补 ISSUE-034

- AGENTS.md(即 CLAUDE.md symlink)新增"Browser Validation Protocol"子节,
  约定登录态浏览器验证必须复用用户常用 Chrome 会话,禁止 sandbox 浏览器
  通过 Google 同意屏,明确凭证守则与三步连通性自检;
- 新建 docs/agents/browser-validation.md:含三种 MCP 浏览器工具能力对照、
  Mermaid 选型决策图、storageState 工作时序、风控应对、IEEE 引用;
  实测附注 chrome-devtools MCP 在 macOS 默认即可复用用户主 profile 登录态;
- docs/issue.md 追加 ISSUE-034,记录 sandbox 浏览器走 Google OAuth 被拦
  的表因/根因/处理方式/防范,便于跨上下文复用。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(e2e-auth): Playwright 会话复用以贯通 Google OAuth E2E

- playwright.config.ts 在 PLAYWRIGHT_AUTH=1 时启用两个项目:
  * setup(headless: false,匹配 *.setup.ts),让用户在弹出窗手动登录;
  * chromium-authenticated(dependencies: ['setup']),使用 storageState
    复用一次性人工登录的会话;
  支持 PLAYWRIGHT_STORAGE_STATE 与 PLAYWRIGHT_USER_DATA_DIR 覆盖默认;
  现有 chromium project 加 testIgnore 排除 .setup.ts,CI/默认行为零变;
- 新增 tests/e2e/auth.setup.ts:打开 /auth/google/login,5 分钟内允许
  用户在 Google 同意屏中手动完成登录,回跳后断言 /api/auth/me 2xx,
  写入 storageState;
- .gitignore 追加 apps/negentropy-ui/.auth/ 与 .userdata/,
  防止会话凭证随分支推送外泄。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(e2e-auth): 修复 OAuth setup 早退与 authed spec 双跑;

- auth.setup.ts: waitForURL 谓词追加 host 约束,避免在跳往 accounts.google.com
  瞬间因 pathname 已离开 /auth/google 而误判完成,导致 /api/auth/me 在用户登录前
  失败、storageState 永不写出。
- playwright.config.ts: 基础 chromium project 的 testIgnore 追加
  /.*\.authed\.spec\.ts$/,防止 PLAYWRIGHT_AUTH=1 时同一份认证 spec 在
  chromium-authenticated 与 chromium 中各跑一次(后者无 storageState 必失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复 Home 双气泡复发与 LLM 模型未 Send 即刷新丢失 (ISSUE-032/033); (#430)

ISSUE-032 (双气泡复发,与 ISSUE-031 正交):
- 根因:root agent prompt 主动导航 + log_activity tool 让 ADK 走双轮 LLM 调用,
  两轮各自带独立 messageId 走完整 TEXT_MESSAGE_* 三件套,UI 在同一
  assistant-reply bubble 内并列渲染两段近重复文本。
- 修复:utils/chat-display.ts::dedupeRedundantTextSegments 在
  buildAssistantReplyBlock 出口对同一 reply 内的 text segment 做字符二元组
  Jaccard 相似度计算,相似度 ≥ 0.5 且双方长度 ≥ 30 时丢弃前段、保留信息更
  完备的最终段。tool-group / reasoning / error 顺序不动。
- assistant-reply.message.content 联动重组,复制时也拿到折叠后的内容。

ISSUE-033 (LLM 模型未 Send 即刷新丢失):
- 根因:后端事实源 session.state.selected_llm_model 仅在 /run_sse 时随
  state_delta 写入,未 Send 时不更新;前端 perThreadLlmRef 是 useRef
  刷新即丢;snapshotForDisplay 也无值,回退到 default。
- 修复:app/home-body.tsx 顶部新增 readPersistedLlmModel /
  writePersistedLlmModel (typeof window 守卫 + try/catch SSR 安全);
  handleSelectedLlmModelChange 即时落盘到 localStorage;Effect 1 优先
  从 localStorage 还原;Effect 2 命中 snapshot 时同步回写 localStorage,
  让「后端 state ↔ localStorage」互为镜像。既有 forwardedProps.selected_llm_model
  在 Send 时仍写后端 state,跨设备一致性最终收敛。

测试:
- 新增 2 例 chat-display.test.ts 用例:折叠近重复段 + 差异度大不被折叠
- UI 全量 70 文件 398 测试通过;typecheck/typecheck:test/eslint 零报错

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038) (#431)

* fix(bootstrap-otel): 消除被丢弃 PeriodicExportingMetricReader 守护线程的周期 WARNING (ISSUE-038);

ISSUE-034 的 patch 调用 original() 后再丢弃 metric_readers /
log_record_processors,但上游 _get_otel_exporters 已构造
PeriodicExportingMetricReader 并启动 60s 守护线程——reader 未注册
到 MeterProvider 导致每 tick 触发 "Cannot call collect on a
MetricReader ..." WARNING。改为绕过 original(),直接复用
_get_otel_span_exporter() 仅构造 traces span processor,根源
避免 OTLP metrics/logs exporter 被实例化。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(bootstrap-otel): 修正 _disable_adk_otel_logs_metrics_exporters docstring 中的过期 hooks 引用;

旧 docstring 沿用重构前 `hooks = original()` 的中间变量术语,但新实现已不再调用 `original()`,函数体内也没有 `hooks` 绑定。
更新指引为「恢复 _get_otel_exporters 原函数闭包」或「直接构造完整 OTelHooks」,避免误导后续维护者寻找已不存在的对象。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-039) (#432)

* fix(home-chat): 修复 Home 双气泡盲区与刷新后消息乱序 (ISSUE-038);

- chat-display: dedupeRedundantTextSegments 增加四层判定(精确匹配 / 严格前缀 / 等价内容 / Jaccard),覆盖 ADK 双轮 LLM 短回复(如 "Pong!")的双气泡盲区。
- session-hydration: mergeEventsWithRealtimePriority 交换参数顺序,让 realtime 事件覆盖 hydrated;TEXT_MESSAGE_CONTENT 的 eventKey 时间戳改用 toFixed(3) 消除浮点抖动导致的同一事件重复保留。
- message-ledger: MessageLedgerEntry 新增可选 sourceOrder 作 createdAt 相同时的稳定 tiebreaker,替代 UUID localeCompare 的随机字典序;抽出 compareLedgerEntriesByTime 复用,类型保持向后兼容(缺省回退 Number.MAX_SAFE_INTEGER)。
- 新增 5 项单元测试覆盖:短回复精确匹配、前缀含尾部追加、Jaccard 长文本、eventKey 浮点稳定、sourceOrder 稳定排序;docs/issue.md 增补 ISSUE-038 摘要。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(home-chat): 补 mergeEventsWithRealtimePriority 生命周期事件覆盖回归用例;

针对 ISSUE-039 第 3 项修复(mergeEventsWithRealtimePriority 参数顺序交换)
原有 RUN_STARTED 类生命周期事件用例缺位——之前的 messageId 重叠用例在
step 3 即被过滤为 filteredHydratedEvents=[],无法验证 step 4 mergeEvents
入参顺序对 key 冲突归并的影响。

补一条 RUN_STARTED 用例:realtime / hydrated 同 threadId/runId/timestamp
(eventKey 字节级一致)→ 用对象引用断言保留的是 realtime 版本,作为参数
顺序交换的最直接证据。该用例在交换前会失败、交换后通过,形成有效回归网。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040) (#433)

* fix(home-chat): 消除 LLM 思考独白溢出 / 推理头常驻 / 刷新乱序残留 (ISSUE-040);

- 过滤 ADK Part 中 thought=true 与 type=thinking|thought|reasoning 系列推理字段,避免 reasoning_content 溢出到 TEXT_MESSAGE_CONTENT;推理文本改路由为 ne.a2ui.thought 自定义事件保留可观测性。
- createStepFinishedEvent 同步透出 stepName,AdkMessageStreamNormalizer 持有 stepId→stepName 映射,根治 ag-ui v0.0.47 校验器 "Cannot send 'STEP_FINISHED' for step \"undefined\"" 中断 run 导致的推理头永驻 started 现象。
- conversation-tree fallback 段重建消息节点时优先复用 ledger 已有 sourceOrder,避免被推到 events 末尾破坏 compareLedgerEntriesByTime tiebreaker。
- session-hydration eventKey 全事件类型统一走 toFixed(3) 毫秒级时间戳,并为 STEP_STARTED/STEP_FINISHED 显式按 (threadId, runId, stepId) 作 key,覆盖 STEP_*/CUSTOM/STATE_*/RAW 在浮点抖动下的去重盲区。
- 新增 9 例单元回归覆盖 thought part 过滤 / STEP_FINISHED stepName / fallback sourceOrder / eventKey 浮点抖动;docs/issue.md 追加 ISSUE-040 全栈解析。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 消除 hydration sort 字典序污染 lifecycle 顺序导致的多消息刷新乱序 (ISSUE-040 Q3 长尾);

- hydrateSessionDetail 引入 WeakMap<BaseEvent, emitOrder>,sort tiebreaker 用 normalizer 推入顺序代替 eventKey().localeCompare,保留 TEXT_MESSAGE_* 三件套 START→CONTENT→END 与跨 messageId 的 turn 边界。
- mergeEvents 同步改为按首次出现位置记录 insertionOrder 作 tiebreaker,避免最后一步 mergeEvents([], normalizedEvents) 再把刚排好的事件按字典序乱序。
- 新增同 timestamp 下 lifecycle 顺序断言用例;多轮真实后端 events fixture 经修复链路输出 user(R1)→assistant(R1)→user(R2)→assistant(R2) 完全符合时间线。
- docs/issue.md 在 ISSUE-040 末尾追加 Q3 长尾闭环(H5 字典序污染根因与最小干预修复)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* test(home-chat): 强化 ISSUE-040 H3 fallback sourceOrder 回归用例;

- 旧用例与单 snapshot 单条消息时新旧公式恰巧同值,断言无差异,无法拦截 H3 退化;
- 新用例构造「snapshot 数组顺序 vs ledger 时间序」错位场景:让 sourceOrder 在两条消息间发生互换,对回滚 H3 修复有强差异断言(已本地反向核验:回滚 conversation-tree.ts 修复后断言失败)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs (#434)

* feat(wiki-header): catalog 第一层提升为顶部 Header 导航 tabs;

将 publication catalog 的第一层 CONTAINER 节点(如 Harness-Engineering)
从左侧 Sidebar 迁移为顶部 Header tabs;第二层及以下保留于 Sidebar,整树向上提升一档。
设计参考 GitHub Docs / Stripe Docs / Docusaurus 的"顶 tabs + 左 sidebar 子树"模式。

主要变更:
- lib/wiki-api.ts 追加 findFirstDocumentSlug / findActiveTopLevelSlug / resolveSectionView
  纯函数,作为 Header tabs 与 Sidebar 切片的单一事实源。
- 新增 WikiHeader Server Component(仅 <Link>,SSG 友好):渲染品牌 + 水平 tabs;
  CONTAINER tab 跳转 DFS 首个后代 DOCUMENT;无文档则禁用 span。
- WikiLayoutShell 增加 header? prop,渲染于 .wiki-layout 之外作为兄弟节点,
  避免触动既有 3 列 Grid 与 data-toc 三态。
- /{pubSlug} 与 /{pubSlug}/{...entrySlug} 两条路由共用 resolveSectionView 派生视图:
  pub 根页默认激活首项;entry 页按 slug 反查所属一级。
- globals.css 引入 --wiki-header-height 并把 sidebar / toc-aside 的 sticky top
  改为 var 引用,确保滚动时 Header 常驻不挡 sidebar。
- 新增 wiki-section-view.test.ts 12 用例覆盖空树 / 单 / 多 / 深路径 / DOCUMENT-only
  / 无后代 DOCUMENT 等边界。

回归保障:home / 不变;既有 WikiNavTree / WikiToc 测试 API 未变;47/47 单测全绿。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(wiki-header): Header 缺失时 sidebar/toc 不再残留偏移;

通过 data-header 属性标记 Header 是否存在,CSS 侧条件生效
--wiki-header-height 偏移,避免空导航树时出现 56px 空白间隙。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* refactor(config): 废弃 .env*,统一 YAML 三级配置(local > user > default) (#436)

* refactor(config): 废弃 .env* 加载链路,引入 config.local.yaml 统一 YAML 三级配置;

- 移除 10 个 Python 配置模块中的 env_file / _get_env_files 逻辑
- yaml_loader 新增 config.local.yaml 作为最高优先级 YAML 来源
- config.default.yaml 合并 .env 全部非机密差异值(含 OAuth 端口 6600→3292 校正)
- 新增 3 例 config.local.yaml 优先级测试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(config): 同步 .env 废弃后的文档与 CHANGELOG;

- development.md / sso.md / framework.md / user-guide.md / zh-CN/README.md 中 .env 引用替换为 config.local.yaml
- CHANGELOG 新增 ISSUE-041 变更记录
- docs/issue.md 新增 ISSUE-041 经验沉淀
- .gitignore 新增 apps/negentropy/config.local.yaml 排除规则

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(config): 放宽 .gitignore 中 config.local.yaml 匹配规则,覆盖任意 cwd 场景;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#435)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041) (#437)

* fix(home-chat): 修复 realtime + hydration 跨 runId 双气泡复发 (ISSUE-041);

- 新增 isSyntheticRunId 共享识别函数(覆盖 runId 缺失 / DEFAULT_RUN_ID / runId === threadId 三类合成回退标记),三层 dedup 一致放宽:
  1. message-ledger.ts::isSemanticEquivalentEntry:runId 不等时若任一侧 synthetic 则放行,threadId + role + 内容前缀 + origin 多元仍是必要约束;
  2. conversation-tree.ts fallback 段 runMatches:识别合成 runId 兼容分支,避免同内容 fallback message 被强制重建为重复节点;
  3. conversation-tree.ts collapseDefaultTurnDuplicates → collapseSyntheticTurnDuplicates:扩展为识别 runId === threadId 的合成 turn;时间窗判定改为 per-child timestamp vs concrete turn timeRange,多轮场景下不再误放过期 concrete turn。
- session-hydration.ts::fallbackRunId 注释 ISSUE-041 契约(保留兜底防御,等 Phase 2 后端代理层注入 runId 后再渐进移除)。
- 新增 16 例自动化回归(含 1 例反向回滚断言):
  · message-ledger A1-A5 + isSyntheticRunId 单元 + 端到端 ledger merge(共 7 例);
  · conversation-tree C1/C2/C3/C5 + D4 反向回滚(共 5 例);
  · session-hydration D1/D1+/D2/D3 端到端(共 4 例)。
- docs/issue.md 追加 ISSUE-041 全栈解析(含 refresh 自愈非对称的根因证据、多轮二阶恶化、Phase 2-4 路线图、诊断抓手与同类问题影响),闭环 ISSUE-040 Q3 长尾自识别。

回归状态:482 测试全绿 + tsc 0 错误;浏览器实机 5 场景 × 3 次验证清单见 .context/issue-041/validation-protocol.md,待用户已登录态 Chrome 桥接就绪后执行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(rfcs): 新增 Phase 3 / Phase 4 架构 RFC 草稿(ISSUE-041 后续路线图);

- docs/rfcs/0001-conversation-architecture-refactor.md:Phase 3 架构重塑 RFC(Codex Thread→Turn→Item 数据模型 / 6 层去重金字塔精简到 3 层 / 抽象 utils/dedup/ + config/projection-thresholds.ts / 投影缓存 / 8 sub-PR 渐进迁移路线 / 兼容性回归与风险评估)。
- docs/rfcs/0002-ui-interaction-enhancements.md:Phase 4 UI 交互能力 backlog(Reasoning Panel + Sub-Agent 嵌套 / 工具进度 + 中断审批 / Conversation Branching + Timeline 增强;按用户优先级 1/2/3 分组,附实施依赖图与 Acceptance Criteria)。

均为 Draft 状态,待团队评审通过后启动多 PR 渐进迁移。本 commit 仅文档先行,不动代码。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 增强 synthetic turn 折叠相似度判定与时间窗整体吸收 (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 双层防御消除跨 runId 三气泡——泛化 turn 折叠 + 跨 block 去重 (ISSUE-041);

将 collapseSyntheticTurnDuplicates 泛化为 collapseOverlappingTurns:按 threadId 分组,
对 synthetic turn 与同组 concrete turn 时间重叠+内容覆盖的进行折叠(双 concrete turn
保留以防误折叠合法多 run);新增 chat-display 层 dedupeAdjacentAssistantBlocks
作为安全网,对时间窗内内容高度相似的相邻 assistant-reply block 保留更完整的一个。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(test): 补充 message-ledger 测试 fixture 缺失的 id 字段 (ISSUE-041)

tsconfig.vitest.json 类型检查报 TS2741:baseRealtime 对象缺少
MessageLedgerEntry 必需的 id 属性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(chat-display): 修复跨 block 去重时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

- CROSS_BLOCK_TIME_WINDOW_MS=120000 误将毫秒值与秒级时间戳比较,实际窗口约 33 小时
  而非预期的 2 分钟;改为 CROSS_BLOCK_TIME_WINDOW_SEC=120(秒)
- 移除 chat-display.ts 私有的 computeCharBigrams / bigramJaccard,统一从 message.ts
  导入 bigramJaccardSimilarity,避免两处实现分叉

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(home-chat): 修复跨 runId 双气泡时间窗单位错误 + 消除 bigramJaccard 重复实现 (ISSUE-041);

fallback 路径从无条件移除改为内容覆盖检查——跨所有同 threadId keeper 逐 child
匹配,避免含独特历史内容的 synthetic turn 被误折叠。加强 C3 断言为
toHaveLength(2) + synthetictoBeDefined。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(conversation-tree): isSyntheticTurnNode 补充 "default" runId 识别对齐 isSyntheticRunId (ISSUE-041);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(ctl): 新增全套服务一键启停脚本 (#438)

* feat(ctl): 新增全套服务一键启停脚本 scripts/ctl.sh

支持 start/stop/restart/status/logs/build 子命令,覆盖依赖安装、
数据库迁移、前端构建、健康检查的完整生命周期。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(ctl): 修复 is_running 变量泄漏与并行 wait 退出码丢失;

- is_running() 中 pid_file 添加 local 声明,防止全局作用域污染
- 三处并行 wait 改为逐个检查退出码,任一子进程失败即报错中止

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(ctl): 修复健康检查不感知进程崩溃、路径逻辑重复与服务名校验缺失;

- wait_for_health 在 HTTP 轮询间隔中加入 is_running 检查,进程崩溃时立即返回失败
- is_running 改用 pid_file() 函数获取路径,消除硬编码重复
- cmd_logs 入口校验服务名是否属于 ALL_SERVICES,非法名称给出明确提示

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(ctl): 使用 exec 替代 eval 确保进程 PID 精确追踪与信号直达;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(kg): 知识图谱模块生产就绪改造 — 实体管理、混合检索、路径探索、统计面板 (#439)

* feat(kg): 知识图谱模块生产就绪改造 — 语料库级图谱、实体管理、混合检索、路径探索、统计面板

后端变更:
- 新增 GET /graph/entities 实体分页列表(类型筛选+名称搜索)
- 新增 GET /graph/entities/{id} 实体详情含出/入关系
- 新增 GET /graph/stats 图谱统计(实体数/类型分布/置信度/密度/度数)
- 重写 find_neighbors: 递归 CTE 在 kg_relations 上实现多跳遍历
- 重写 find_path: 递归 CTE BFS 在 kg_relations 上查找最短路径

前端变更:
- 重写 graph/page.tsx: 语料库选择器 + 构建/浏览全流程
- 新增 EntityListPanel: 表格视图+类型筛选+分页
- 新增 EntityDetailPanel: 实体详情+关系列表(出边/入边)
- 新增 SearchBar: 混合检索(语义+图结构)
- 新增 PathExplorer: 双实体选择+BFS路径查找
- 新增 NeighborExplorer: 1/2/3跳邻居展开
- 新增 GraphStatsPanel: 实体数/类型分布/置信度/密度/度数
- 新增 BuildHistoryList: 结构化构建历史卡片(状态徽章+统计+耗时)

文档变更:
- 扩展 user-guide.md §4.5 为完整知识图谱用户指引
- 更新 knowledge-graph.md §3 新增架构模式精炼(Cognee ECL/Graphiti 双时态)
- 更新 knowledge-graph.md §4 交付物清单

测试变更:
- 新增 test_graph_entity_service.py: 9 项单元测试覆盖实体列表/详情/Schema

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 修复知识图谱模块 CI 失败 — 类型错误、ID 前缀、测试 mock;

- 移除 NeighborExplorer 组件调用中不存在的 entityName prop(TS2322)
- 为 find_neighbors 返回的 GraphNode.id 补齐 entity: 前缀
- 重写 find_path 测试,mock session.execute 而非 find_neighbors

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 修复审查发现的 7 项问题 — 安全编码、状态管理、双向路径搜索;

- 路由 path params 加 encodeURIComponent 防路径遍历(3 个 route 文件)
- EntityDetailPanel: 用 loadedEntityId 派生 loading 状态,切换实体时正确展示加载态并清除旧数据
- EntityListPanel: 搜索输入 300ms 防抖,用 completedKey 派生 loading 状态
- GraphStatsPanel: 用 result 组合状态区分加载中/失败/成功
- NeighborExplorer: entityId 变更时重置 expanded/neighbors
- graph_repository find_path: 递归 CTE 增加反向遍历分支,与 find_neighbors 双向语义对齐

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 修复审查发现的遗留问题 — 常量提取、路径搜索、会话管理;

- 前端:提取 ENTITY_TYPE_COLORS 至 constants.ts,消除三处 TYPE_COLORS 残留引用(会导致运行时崩溃)
- 后端:修复 find_path 递归 CTE 中 path 追加错误(r.target_id → ps.target_id)
- 后端:get_stats 改为接收外部 db 会话,消除自建会话
- 后端:get_entity_detail 增加 corpus_id 可选过滤,增强数据隔离

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(memory): 记忆模块生产就绪化 — 巩固管线重构 + 事实提取 + 上下文集成 + 文档完善 (#440)

* feat(memory): 重构记忆巩固管线为三阶段智能架构并增强核心模块

- 重构 _simple_consolidate 为三阶段管线(分段→去重→存储),借鉴 Claude Code AutoDream 四阶段范式
- 新增 PatternFactExtractor 基于正则模式的对话事实自动提取(preference/profile/rule/custom)
- 新增 ContextAssembler 记忆上下文组装器,管理 token 预算分配(30%记忆/50%历史/20%系统)
- 新增 AsyncScheduler 应用层调度器回退,当 pg_cron 不可用时提供等效定时任务能力
- 增强 search_memory API 支持分页(limit/offset)和过滤(memory_type/date_from/date_to)
- 集成 ContextAssembler 到 perception.py 记忆搜索回退路径
- 新增 34 条单元测试覆盖事实提取和调度器(全部通过)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(memory): 补充工业框架对标分析与用户操作指南

- docs/memory.md §2.4 新增 Claude Code 记忆架构深度对标(AutoDream 四阶段整理、三重门控调度、四类型分类法、三层上下文压缩、漂移防御)
- docs/memory.md §2.5 新增 Agent Harness 设计模式对标(三层压缩管线、Skill 按需加载、Task Graph 持久化)
- docs/memory.md §2.6 新增 Negentropy 差异化定位总结表
- docs/user-guide.md §5.8-§5.12 新增记忆形成机制、保留分数解读、搜索最佳实践、自动化配置指南、故障排除

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 恢复巩固管线 metadata 中遗漏的 event_count 字段

三阶段管线重构后 metadata 字典遗漏了原有的 event_count 字段,
导致 test_memory_service_lifecycle 集成测试 KeyError 失败。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 修复 Code Review 反馈的 7 项问题

1. search_memory 的 memory_type/date_from/date_to/offset 过滤参数现在在 vector_search 和 ilike_search 中实际生效
2. context_assembler 的 lazy import 移至文件顶部,与同文件风格一致
3. _simple_consolidate docstring 从「三阶段」更正为「四阶段」(含事实提取)
4. api.py search_memories 的 total 字段添加 TODO 标记(需独立 COUNT 查询)
5. AsyncScheduler 失败时回退 last_run_at,允许尽快重试而非等完整 interval
6. PatternFactExtractor 三段重复遍历提取为 _match_patterns 辅助方法
7. _consolidate SQL 拼接改为参数化绑定 :lookback::interval,消除注入风险

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 修复 Code Review 反馈的 3 项问题

- offset 分页参数未透传到底层搜索方法,现已正确传递
- datetime.fromisoformat() 缺少校验,非法日期返回 400 而非 500
- AsyncScheduler 派发任务未被追踪,stop() 时一并取消在途任务

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 修复 Code Review 反馈的 2 项问题

- 巩固管线阶段 4 事实提取调用包裹 try/except,防止导入或工厂失败中断管线
- 搜索接口 total 字段改为 -1 标记"未知",避免分页客户端误读

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + Token 精确计数 + 检索反馈闭环 (#442)

* feat(memory): 记忆模块 Phase 2 — LLM 事实提取 + 摘要生成 + 精确 Token 计数 + 检索反馈闭环

- TokenCounter: 基于 tiktoken cl100k_base 编码器精确计数,替代 LENGTH/4 粗略估算
- LLMFactExtractor: LLM 结构化输出事实提取,PatternFactExtractor 作为降级后备
- MemorySummarizer: LLM 生成结构化用户画像摘要,缓存至 memory_summaries 表(TTL 24h)
- SummaryService: memory_summaries 表 CRUD(upsert 语义)
- RetrievalTracker: 检索效果反馈闭环,记录检索事件 + 显式反馈 API
- ContextAssembler: 优先注入摘要,tiktoken 精确 token 计数
- 新增 Alembic migration 0013/0014(memory_summaries + memory_retrieval_logs)
- 新增 MemorySummary + MemoryRetrievalLog ORM 模型
- 11 条新增单元测试,62 条全部通过,零回归

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* docs(memory): Phase 2 文档沉淀 — 两级提取策略 + 摘要巩固 + 精确计数 + 检索反馈 + 新增文献

- §4.2 扩展为两级事实提取策略说明(LLMFactExtractor + PatternFactExtractor)
- §5.4.1 新增摘要巩固策略(记忆再巩固理论 + 5 项工程对标)
- §6.3 更新 Token 估算为 tiktoken BPE 精确计数
- §6.5 新增检索效果反馈闭环(Rocchio + LTR + LongMemEval 评估维度)
- §15 新增 6 篇参考文献(Sennrich 2016, Sara 2015, Rocchio 1971, Burges 2005, Mem0, Letta)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 修复 LLM 事实提取 prompt 类型名不匹配 + 检索指标 SQL 聚合优化;

- prompt 模板中 "pref" 改为 "preference",与 _VALID_FACT_TYPES 验证器对齐,避免 LLM 输出被静默降级为 "custom"
- get_effectiveness_metrics 改用 SQL COUNT+CASE 聚合,避免将全量日志行加载到 Python 内存

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* refactor(memory): Review 反馈修复 — 检索日志可观测性 + query 透传 + 模型配置去重;

1. 检索追踪 except 从 silent pass 改为 logger.debug,使故障可诊断
2. _record_access 新增 query 参数并从所有调用点透传,消除空 query 问题
3. 提取 _resolve_model_config 为共享工具 engine/utils/model_config.py,
   LLMFactExtractor 和 MemorySummarizer 统一引用,消除 DRY 违规
4. 同步更新单元测试 mock 路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐 (#441)

* fix(kg): 修复图谱双写数据流断链 — 一等公民表对齐

- create_relation() 新增写入 kg_relations 一等公民表,保留 JSONB 过渡兼容
- get_graph() 优先从 kg_entities + kg_relations 读取,空时回退 JSONB
- clear_graph() 增加 kg_entities/kg_relations 表清理
- build_graph() 完成后调用 KgEntityService.batch_sync_from_graph_build()
- 更新 test_graph_repository 适配新读写路径

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(kg): 新增 PageRank 实体重要性评分与 RRF 混合检索

- 新增 graph_algorithms 模块,基于 NetworkX 实现 PageRank (Brin & Page, 1998) 计算,
  结果持久化至 kg_entities.importance_score
- 混合检索支持 Reciprocal Rank Fusion (Cormack et al., SIGIR 2009) 模式,
  可通过 GraphQueryConfig.use_rrf / rrf_k 配置,向后兼容线性加权模式
- 图谱构建完成后自动触发 PageRank 计算
- 实体列表支持按重要性排序(sort_by=importance)
- 统计面板展示 Top 5 PageRank 实体
- 图谱可视化节点半径映射 PageRank 分数,突出重要实体

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(kg): 新增 Louvain 社区检测与图谱可视化增强

- 新增 compute_louvain() 算法,基于 NetworkX 内置 Louvain (Blondel et al., 2008)
  在无向投影图上运行社区检测,结果持久化至 kg_entities.community_id
- 图谱构建完成后自动触发 Louvain 计算(紧接 PageRank 之后)
- 统计面板新增社区分布(community_count + community_distribution)
- 实体列表和详情响应包含 community_id 字段
- 图谱可视化节点按社区着色(Tableau 10 色盲友好调色板)
- 统计面板展示 Top 8 社区分布柱状图
- 实体表格新增社区列,显示色块标识
- 显式声明 networkx>=3.0 依赖(此前为隐式运行时导入)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 新增 Alembic migration 0015 — 添加 importance_score 和 community_id 列

CI 集成测试失败根因:ORM 模型新增了 importance_score (PageRank) 和 community_id (Louvain)
列,但缺少对应的 Alembic migration,导致测试数据库 schema 不匹配。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(kg): 修复 Review 反馈的三个问题

1. RRF 搜索 graph_score 恒为 0 — 将 importance_score 写入 entity_data
2. PageRank/Louvain 逐条 UPDATE — 改为 VALUES CTE 批量更新
3. 一等公民表路径缺 app_name 过滤 — 文档明确 corpus 级去重设计意图

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 测试覆盖 (#443)

* test(memory): Phase 2 组件测试覆盖 — TokenCounter / SummaryService / RetrievalTracker / MemorySummarizer;

新增 39 个单元测试用例,覆盖 Phase 2 四个核心组件:
- TokenCounter: 精确计数、空输入、幂等性、异步一致性、单调性(蜕变测试)
- SummaryService: upsert/get/delete CRUD 路径
- RetrievalTracker: 检索日志、引用标记、反馈记录、效果指标计算
- MemorySummarizer: 摘要生成、TTL 缓存命中/过期、LLM 失败降级、重试

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(memory): Phase 2+ 增强 — 反馈闭环闭合 + Query-Aware 组装 + 近重复检测 + 文档沉淀;

Gap 1 反馈闭环:
- _record_access 修复 user_id/app_name 透传(此前始终为空字符串)
- PostgresMemoryService 存储 _last_retrieval_log_id 供下游消费
- ContextAssembler 注入 mark_referenced 隐式反馈信号(RLHF[33])
- API 新增 POST /memory/retrieval/feedback 和 GET /memory/retrieval/metrics

Gap 2 Query-Aware:
- assemble() 新增 query/query_embedding 可选参数
- _call_get_context_window 传递 7 个参数(含 p_query, p_query_embedding)
- SQL 函数 NULL safe 退化:无 query 时保持纯 retention_score 排序
- 隐式反馈标记在上下文组装成功后触发

Gap 3 近重复检测:
- _is_duplicate 阈值从 0.9 降至 0.85(Henzinger[40])
- 新增 Jaccard 词重叠二次校验(0.80-0.85 区间,Broder[37])
- FactService 新增 merge_similar_facts() 语义去重方法

文档沉淀:
- docs/memory.md 权威源文件索引扩充 Phase 2 组件
- §15 追加 13 篇参考文献 [31]–[43]

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* fix(memory): 修复 merge_similar_facts 过度删除 + retrieval_log_id 并发安全问题;

- merge_similar_facts: 锚点事实被删除后立即 break 内层循环,避免基于已删除 embedding 继续比对导致误删
- _record_access: 移除 _last_retrieval_log_id 实例属性,改为返回 log_id,消除共享可变状态的并发竞态
- ContextAssembler.assemble: memory_service 参数改为显式 retrieval_log_id,调用方直接传入

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)


* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存 (#444)

* feat(kg): Phase 3 生产就绪增强 — 增量构建 + 语义去重 + 管线健壮性 + 查询缓存

Gap 3 [P1] 构建管线健壮性 (Nygard, 2018; Majors, 2022):
- Migration 0016: kg_build_runs 增加 progress_percent + warnings 列
- build_graph: 批处理循环进度上报、LLM 提取失败…

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant