### 要解决的问题 / Problem `GET /context`(#370 落地、0.8.14 发布)在查询嵌入不可用时会静默降级:`embedder` 未注入(`createStandaloneApi` 的可选参数,宿主与 `dsh-mneme-serve` 各传 semantic 装配的同一实例),或嵌入超时(`withEmbedTimeout`,默认 3000ms)时,端点按「规则 + BM25」档返回。响应仍是 200,形状与语义档完全一致——`{profile, rules, items, pinnedCount}` 里没有任何字段能区分这两档。 `GET /search` 有对应信号:回 `mode: "vector" | "keyword"`。 影响面:以 `/context` 为唯一注入来源的第三方(如 Mneme-Bridge 的 remote 模式)无法感知自己长期跑在降级档上——它的回落逻辑只在 404 / 网络失败 / 响应形状不符时触发,静默降级不触发。对外表现是「检索质量莫名下降」而非报错,排查成本落在调用方。这个缺口在 #363 的接入评审里由 Mneme-Bridge 侧提出。 ### 期望的方案 / Proposed solution `/context` 响应增加一个档位字段(命名待定:与 `/search` 对齐用 `mode`,或独立的 `tier` / `degraded`): - 纯增量:现有四个键的语义与形状不动,存量调用方零感知; - 语义档(嵌入成功)与规则档(embedder 缺失、嵌入超时或失败)可区分; - 具体命名与取值形态在实现 PR 里定。 ### 考虑过的替代方案 / Alternatives considered 1. **不加字段,调用方自行探测 embedder 可用性**——嵌入超时是运行时事件、无法预知,且 daemon 与宿主是不同进程,做不到; 2. **降级时返回非 200**——破坏现有契约:规则档是合法结果不是错误,`/context` 的既有行为明确「嵌入失败绝不 500」; 3. **用 `/health` 类端点暴露 embedder 状态**——反映不了单次请求的超时,粒度不够。 ### 实现口径确认 / Implementation gates 本项是响应字段增量,不涉及新配置键与 schema 变更;若要加开启开关,则按 opt-in 默认关注册进 settings 白名单。验收含回归测试:`dsh-mneme/test/standalone-api.test.js:592` 的响应形状锁(当前锁四键)需同步,并补两档的档位用例(embedder 注入 / 缺省 / 嵌入超时三条路)。
Activity
modusensus commentedon Oct 20, 2026
现状(2026-10-21 对照
main实测)没做,
/context的响应里仍然没有任何档位信号。dsh-mneme/src/api-standalone.js的/context处理器(约:679-684)当前返回四键::683是pinnedCount: pinnedStats.shown ?? 0。没有mode、没有tier、没有degraded。为什么这条比看起来重要
嵌入降级(向量不可用、退化成纯 BM25)在调用方视角是完全静默的:拿到的
items看起来正常,只是召回质量悄悄变差。外部集成方无法据此降级自己的期望或打日志。还缺什么
tier: "full" | "degraded" | "unknown"),fail-closed:判不出来就报unknown,不要报full;/health的既有三态口径保持同源;tier必填。接手建议
改动面很小(一个处理器 + 一个测试)。
/health已经在报embeddingDimensionBreakdown(2e45040),数据源是现成的,不需要新算。z2Ace0107 commentedon Oct 23, 2026
想接这条,按你建议的口径做:
src/api-standalone.js的/context处理器加tier字段,取值full/degraded/unknown,fail-closed——判不出来报unknown,不报full;/health的三态口径同源;tier必填。纯增量,现有四键的语义和形状不动,存量调用方零感知;不加配置键。数据源用
/health已经在算的embeddingDimensionBreakdown,不重算。我同时认了 #461 和 #421,按由易到难串行做(#461 → #383 → #421),两周内都交 PR。
feat(standalone): /context 补 embed-dimension 档位并把 tier 扫进文档(slow-stac…
feat(standalone): /context 响应加 tier 档位信号,嵌入降级不再静默(#383)
Merge pull request #508 from z2Ace0107/codex/issue-383-context-tier
modusensus commentedon Nov 2, 2026
已在 0.9.5 交付,本 issue 关闭。
落点
dsh-mneme/src/api-standalone.js:889-961:/context响应新增第五键tier,三值full/degraded/unknown。unknown(语义路未启用,不宣称档位);查询向量非空 →full;否则 →degraded。unknown,不报full。把「不知道」写成「正常」正是这条 issue 要消灭的那种静默。实现口径与你提议的差异
你建议用
/health已在算的embeddingDimensionBreakdown作数据源、降级原因做进响应体。实际实现把原因留在 daemon stderr 的那行 warn 里,响应体只多tier一个键——理由是一个键已经够调用方决定「要不要重试或提示」,而把原因枚举也放进去会多出一份需要跟着/health三态口径同步维护的枚举。tier的语义与/search的mode是两回事(前者描述嵌入通道,后者描述检索算法),所以没有复用那个名字。存量四个键的语义与形状一个字节没动,没加任何配置键。
@z2Ace0107 你的 PR #508 与后续评审补丁 #513 都合进 main 了,CHANGELOG 的 0.9.5 节把
/context的tier、/memory/provenance与两处 M.O. 去重键修复一起记在你名下。谢谢你——尤其tier那份「判不出来报 unknown 不报 full」的取舍,是这条 issue 真正的落点。顺带一条你可能想知道的:#508 与 #507 合并时都没带
Fixes #N关键字,所以代码进了 main、issue 一直挂在 open。这不影响任何东西,只是我们这边收口的习惯——以后带一句Fixes #383就能自动关。如果对
unknown这一档在你们的调用方那边够不够用还有想法,随时 reopen 或另开一条,我们接着改。