Skip to content

Releases: ZK-Andy/dsh-continual-evolve

v0.19.4

Choose a tag to compare

@ZK-Andy ZK-Andy released this 03 Nov 15:21

中文 | English

本版是安全修复版:关闭 dsh-bounty #904 报告的凭据门禁绕过——MY_API_KEY="…"、OPENAI_API_KEY="…"、GITHUB_TOKEN="…" 这类标准 env 写法此前能绕过 secretLeakReason 沉淀进记忆库。950 测试 / 77 文件、22 道门禁红绿俱验、CI 全绿。

安全修复与升级注意

  • 凭据门禁覆盖带前缀的名字(60ed881,@ZK-Andy):credential-assignment 模式名前的 \b 在 _ 前不成立,导致带前缀的赋值全部漏判。改为零宽后顾 (?<![A-Za-z0-9]):-、空白、标点与串首行为不变,唯一多放行的就是 _ 前缀位;单次命中的匹配文本与脱敏输出逐字不变。新增五类前缀名回归(MY_API_KEY、OPENAI_API_KEY、GITHUB_TOKEN、DB_PASSWORD、APP_SECRET),回退旧边界必红。理由见 ADR 2026-11-03-secret-prefixed-credential-bypass。
  • 升级前请读:存量条目会被巡检重判。守卫不只拦新增:quarantineSecrets 会对全部 active 记忆、技能与 prompt 重新判定,而 applied 抽取后会自动触发巡检。升级后首次巡检会把库中已有的 MY_API_KEY="…" 类行隔离;若被隔离的是技能条目,其托管文件会被删除(手写文件保留并记 warning)。这是本次修复的预期行为——命中即隔离,不做例外。
  • 已知缺口(本笔未扩面):无引号赋值(MY_API_KEY=abc…)、camelCase 前缀(myApiKey)、_ 后缀名(SECRET_KEY、PASSWORD_HASH、API_KEY_ID)、值含 ${} 插值的形态仍不在守卫内;与「凭据类字段名 = 引号长字面量即拦」的承诺不完全对齐,后续按实例评估。

其他改动

  • README 双语同步(ab34002,@ZK-Andy):测试徽章与开发段更新为 950 测试 / 77 文件。
  • 全量测试 950/77 绿,类型检查、lint、22 道文档与结构门禁全绿。

Full Changelog: v0.19.3...v0.19.4
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.4

Security Fix and Upgrade Note

This is a security fix release: it closes the credential-gate bypass reported in dsh-bounty #904 — standard env spellings such as MY_API_KEY="…", OPENAI_API_KEY="…", and GITHUB_TOKEN="…" could slip past secretLeakReason into the memory store. 950 tests / 77 files, all 22 gates proven red/green, CI green.

  • The leak guard now covers prefixed credential names (60ed881, @ZK-Andy): the \b before the name in the credential-assignment pattern never matches before _, so prefixed assignments were all missed. It is replaced by the zero-width lookbehind (?<![A-Za-z0-9]): behavior after -, whitespace, punctuation and at string start is unchanged, and the only newly admitted position is the _ prefix. For a single hit, the matched text and redaction output stay byte-identical. Five regression cases cover the prefixed names (MY_API_KEY, OPENAI_API_KEY, GITHUB_TOKEN, DB_PASSWORD, APP_SECRET) and fail if the old boundary returns. Rationale: ADR 2026-11-03-secret-prefixed-credential-bypass.
  • Read before upgrading: existing rows are re-judged by patrol. The guard does not only stop new writes: quarantineSecrets re-judges every active memory, skill and prompt, and patrol runs automatically after an applied extraction. On the first patrol after upgrade, rows already in the store that contain MY_API_KEY="…"-style lines are quarantined; if the quarantined entry is a skill, its managed files are removed (hand-written files are kept with a warning). This is intended — a hit is quarantined, no exceptions.
  • Known gaps (out of scope here): unquoted assignments (MY_API_KEY=abc…), camelCase prefixes (myApiKey), _-suffixed names (SECRET_KEY, PASSWORD_HASH, API_KEY_ID), and values containing ${} interpolation are still not covered. The promise "credential-like field name = quoted long literal is blocked" is therefore not fully aligned for these shapes; they will be evaluated per instance.

Other Changes

  • Bilingual README sync (ab34002, @ZK-Andy): the test badge and the development section now read 950 tests / 77 files.
  • The full suite is green at 950/77, and typecheck, lint, and all 22 documentation/structure gates pass.

Full Changelog: v0.19.3...v0.19.4
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.4

v0.19.3

Choose a tag to compare

@ZK-Andy ZK-Andy released this 20 Oct 19:20

中文 | English

本版是一次结构收敛:把架构漂移按四批收掉——退役面纯删、卡片归档区与列表行同形、投影规则与建表 DDL 归位、规范与门禁对齐。对外只有一处可见变化(归档区的呈现),其余是内部形状收敛:存储语义、注入内容与评审口径不变。948 测试 / 77 文件、22 道门禁红绿俱验、CI 全绿。

移除与停用

  • 评测任务集退役面纯删(7be8bea,@ZK-Andy):services/eval-taskset.ts 及其测试删除——合成四臂下线后它生产零引用,只有自己的测试引用它,却随包发布。store.writeEvalCases 与 data/eval-cases.ts 的写入面一并下线(表形状与 30 天裁剪保留),只服务该写入面的零消费者常量(EVAL_*_CHAR_CAP、EVAL_LAST_FOUR_ARM_KEY 等)与 redactText 同步删除。files 白名单移除仓内保留、包内无读者的 evals/tasks 与 evals/baseline。理由见 ADR 2026-10-20-architecture-drift-remediation。

问题修复

  • 卡片归档区与列表行同形(7be8bea,@ZK-Andy):归档行改走列表行渲染器的只读分支(徽标、展开、预览动作全关),archive_reason 的五个取值进卡片内联字典(zh/en),中文界面不再裸出英文枚举。此前同一份记忆在卡片里有两套形态。
  • 被提级的归档行给出全局活副本指针(7be8bea,@ZK-Andy):仅当 archive_reason = promoted-source 且全局活行的 origin_workspace 恰为本工作区时给 globalCopyId,徽标标「内容在全局(id)」并保留 id 段供人工对账。分区隔离下别的分区同 id 的全局行不是这条记忆的活副本,所以指针不乱指。提级产生的行不再被读成「内容被撤销」。

其他改动

  • 投影规则收成一处(7be8bea,@ZK-Andy):「本地行遮蔽全局同 id 行」只在 data/memory-reads.ts 的 globalOnly 定义一次,注入、检索、卡片 mergedVisible 三个读者各传自己的候选集。卡片与注入/检索对「这个工作区看见哪些记忆」不再可能给出不同答案。
  • 建表 DDL 下放到各表模块(7be8bea,@ZK-Andy):data/schema.ts 400 → 247 行,只留 guard 与聚合;extraction_log/item_events/review_log/memories 各自回本表模块,migrate 的 import 面不变。
  • 配置读取归位(7be8bea,@ZK-Andy):mountExtractionWhenAvailable 改收已解析的布尔,assemble.ts 不再出现 config.;分层门禁 R3 扩到「非 index.ts 出现 EvolveConfig 即红」,并配规则级红绿样例。
  • 规范与门禁对齐(7be8bea,@ZK-Andy):编码规范的 try 条款给事务/批处理开例外(判据是「try 内是一个完整事务」,不是语句条数);预算棘轮 --update 必须带 --reason <ADR> 且指向存在的笔记,否则拒绝重定基线;评审档门禁把 docs/plans、docs/research 移出行为契约面。门禁矩阵 20 → 22 对。
  • README 数据同步(33a0a7c,@ZK-Andy):测试文件数、lint 命令与卡片归档区说明对齐当前形态。
  • 修复计划与自审更正入 ADR(b3ab32f、e44180f,@ZK-Andy)。
  • 已知余量与未覆盖面:投影收敛本批只覆盖 memories,技能读路径仍自带一份「本地遮蔽全局」实现;data/review-accounts.ts 因接收 review_log DDL 恰好 400/400、零余量。

Removals

  • The eval task-set's retired surface is deleted outright (7be8bea, @ZK-Andy): services/eval-taskset.ts and its test are gone — after the synthetic four-arm loop was killed it had zero production references, only its own test referenced it, yet it still shipped in the package. store.writeEvalCases and the write surface of data/eval-cases.ts come down with it (table shape and the 30-day pruning stay), along with the zero-consumer constants that only served that write path (EVAL_*_CHAR_CAP, EVAL_LAST_FOUR_ARM_KEY, …) and redactText. The files allowlist drops evals/tasks and evals/baseline — kept in the repo, shipped to nobody. Rationale: ADR 2026-10-20-architecture-drift-remediation.

Bug Fixes

  • The card's archived zone now renders like the list (7be8bea, @ZK-Andy): archived rows go through the list-row renderer's read-only branch (badges and expansion kept, preview and actions off), and the five archive_reason values move into a card-level inline dictionary (zh/en) — a Chinese UI no longer shows a raw English enum. One memory used to have two shapes in the same card.
  • Promoted archived rows point at their live global copy (7be8bea, @ZK-Andy): globalCopyId is given only when archive_reason = promoted-source and the global live row's origin_workspace is exactly this workspace; the badge reads "content lives in global (id)" and keeps the id segment for manual reconciliation. Partitions are isolated, so another partition's same-id global row is not this memory's live copy — the pointer never misleads. A promoted row no longer reads as "the content was revoked".

Other Changes

  • One projection rule (7be8bea, @ZK-Andy): "a local row shadows the global row with the same id" is defined once, in data/memory-reads.ts's globalOnly; injection, search, and the card's mergedVisible each pass their own candidate set. The card and the injection/search path can no longer disagree about "which memories does this workspace see".
  • Table DDL moves down into its own table modules (7be8bea, @ZK-Andy): data/schema.ts goes 400 → 247 lines, keeping only guards and aggregation; extraction_log / item_events / review_log / memories go back to their modules, with migrate's import surface unchanged.
  • Config reads move to the assembly root (7be8bea, @ZK-Andy): mountExtractionWhenAvailable now takes an already-resolved boolean and assemble.ts no longer mentions config.; the layering gate R3 widens to "an EvolveConfig outside index.ts is red", with rule-level red/green samples.
  • Standards and gates realigned (7be8bea, @ZK-Andy): the coding standard's try clause gets an exception for transactions and batches (the test is "one complete transaction inside try", not a statement count); the budget ratchet's --update now requires --reason <ADR> pointing at an existing note, otherwise the baseline reset is refused; the review-tier gate moves docs/plans and docs/research out of the behavior-contract surface. The gate matrix grows 20 → 22 pairs.
  • README data sync (33a0a7c, @ZK-Andy): test-file count, lint command, and the card's archived-zone description match the current shape.
  • Remediation plan and self-review corrections landed in the ADR (b3ab32f, e44180f, @ZK-Andy).
  • Known headroom and uncovered ground: this batch's projection convergence covers memories only — the skill read path still carries its own "local shadows global" implementation; data/review-accounts.ts sits at exactly 400/400 lines after taking the review_log DDL, with zero headroom.

Full Changelog: v0.19.2...v0.19.3
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.3

v0.19.2

Choose a tag to compare

@ZK-Andy ZK-Andy released this 19 Oct 22:58

中文 | English

本版是一次减法 + 收口:移除合成四臂评测与外锚(evolve_eval_run 工具与 evals/runs 生成链一并下线,离线召回评测与基线保留),并补上两处写门禁与两处门禁兼容性修复。945 测试 / 77 文件、20 道门禁与 CI 全绿。

移除与停用

  • 合成四臂评测与外锚下线(1f258a2,@ZK-Andy):services/eval-runner.ts、四臂执行链、evolve_eval_run 工具、compare.md 产物、休眠提示词补充的调用面全部删除——这条链产出的数字没有任何读者动作,属于往库里合法排污。保留:离线召回评测 npm run eval:recall 与 evals/ 基线(月度 CI 守基线,不再卡发版)。同时新增两道锁:架构标准不变量「新机制必须声明回边与读者」,ADR 模板强制 ## Feedback edge 小节。理由见 ADR kill-dead-eval-loop。
  • 评测门径维持冻结(333debc,@ZK-Andy):合成数作废、p95 口径线过期不重议,待生产账本反证再议。

问题修复

  • 提级可移植性门禁(971eba7,@ZK-Andy):记忆的标题/钩子/正文/不适用条件任一含源工作区绝对路径,进全局即 fail-closed 并点名字段——提级是两个工作区之间的搬运,源路径进全局等于把私有上下文广播出去。判词落在提级唯一漏斗上,手动 move-to-global 与自动提级两路同吃。
  • 归档与隔离行拒绝原地改写(4523131,@ZK-Andy):update 只改 active 行。此前撞上已归档 id 会原地改写历史快照,而提案仍返回成功——写了一份永不进入注入的副本还自称更新了。现在:判词门点明状态与归档原因;MEMORIES.updateSql 追加 AND status = 'active' 作机械兜底;updateRow 返回变更行数,0 行不再被读成落地。
  • freshness 门兼容 runner 的 markdown 列表 commit 行(4261e59,@ZK-Andy):回填产物把 commit 写在列表头,门禁认不出,误报数据过期。
  • tier 门豁免 evals/runs 机器回填数据(4866ae0,@ZK-Andy):机器生成的回填数据不再按人工编辑口径计 diff。

其他改动

  • 休眠提示词存储补齐五项覆盖(90c2286,@ZK-Andy):readback、隔离场景、常量、try-finally、tmp 清理。
  • 首跑产物回填(b0740a2,@ZK-Andy):evals/runs 入库,作为后续口径的输入。
  • 工作流与交接基线读数跟进到当前形态(f397e3f,@ZK-Andy)。

Removals

  • The synthetic four-arm eval loop and its anchors are gone (1f258a2, @ZK-Andy): services/eval-runner.ts, the four-arm execution chain, the evolve_eval_run tool, compare.md output, and the dormant prompt-supplement call surface are all removed — the numbers that chain produced drove no reader action, which made them legal pollution of the store. Kept: the offline recall eval (npm run eval:recall) and the evals/ baselines (monthly CI guards the baseline; it no longer gates releases). Two locks land with the removal: the architecture invariant "every new mechanism declares its feedback edge and readers", and a mandatory ## Feedback edge section in the ADR template. Rationale: ADR kill-dead-eval-loop.
  • The eval-gate verdict stays frozen (333debc, @ZK-Andy): synthetic numbers voided, the old p95 line is not reopened; revisit only against production-ledger counter-evidence.

Bug Fixes

  • Promotion portability gate (971eba7, @ZK-Andy): a memory whose title, hook, body, or caveat carries the source workspace's absolute path is refused (fail-closed) when it would enter the global partition, with the offending field named. Promotion moves knowledge between workspaces; a source path in the global partition broadcasts private context. The verdict sits on the single promotion funnel, so the manual move-to-global and the automatic path both hit it.
  • Archived and quarantined rows refuse in-place rewrites (4523131, @ZK-Andy): update now only rewrites active rows. Hitting an archived id used to rewrite the historical snapshot while the proposal still reported success — an edit to a copy that never re-enters injection, reported as an update. Now: a gate names the status and the archive reason; MEMORIES.updateSql carries AND status = 'active' as the mechanical backstop; updateRow returns the changed-row count, so zero rows can no longer be read as a landed edit.
  • Freshness gate reads the runner's markdown commit list (4261e59, @ZK-Andy): backfilled artifacts put their commit on a list header the gate failed to parse, so it reported the data as stale.
  • Tier gate exempts machine-written evals/runs data (4866ae0, @ZK-Andy): backfilled machine data no longer counts as a human edit when the diff is scored.

Other Changes

  • Dormant prompt-store coverage filled in (90c2286, @ZK-Andy): readback, isolation scenario, constants, try-finally, tmp cleanup.
  • First-run artifacts backfilled (b0740a2, @ZK-Andy): evals/runs landed in the store as input for later measurement decisions.
  • Workflow and handoff baseline readings brought up to date (f397e3f, @ZK-Andy).

Full Changelog: v0.19.1...v0.19.2
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.2

v0.19.1

Choose a tag to compare

@ZK-Andy ZK-Andy released this 19 Oct 18:30

中文 | English

发版例外说明:本版带三面改动但无覆盖 HEAD 的 compare.md(verify-eval-freshness 红灯)。首跑只能在发版后跑(evolve_eval_run 随发版进 desktop),经人工特批先发版,发版后第一时间首跑回填 compare,数据作为下版 gate 输入。

新功能

- feat(injection): 索引行去类型标签、描述截 20 字,指南压两段 (@ZK-Andy) - feat(p1): 速赢批——卡片双读数+事件档零变化门槛+解析容错+溯源默认 (@ZK-Andy) - feat(p2): 提取轨借鉴——两段式分类+提案机械校验+审计可回放 (@ZK-Andy) - feat(p4): 记忆生命周期 P4-a——归档原因、版本行合并与只读归档区 (@ZK-Andy) - feat(p4): P4-b 普通 update 语义统一——版本行一律,评审复写除外 (@ZK-Andy) - feat(p5): P5a评测基建——evals统一+recall接线+eval_cases表+防忘infra (@ZK-Andy) - feat(p5): P5b评测跑批与runner——四臂×repeat-2+手动触发工具 (@ZK-Andy) - feat(p6): 注入分层四段+冲突守则+压缩后重注入+seeded全量集成测试 (@ZK-Andy) - feat(process): 三重审核TS门禁移植——档位判定+简报冻结+轮次收敛 (@ZK-Andy)

问题修复

  • fix(gates): 断 extraction-ring↔propose 值导入环,下沉 extraction-item 叶模块 (@ZK-Andy)
  • fix(p4): 归档原因回填随迁移自动跑——无需手动脚本 (@ZK-Andy)
  • fix(p5): P5b覆盖率追平——挂载双路径+判官分支+loader改道 (@ZK-Andy)
  • fix(retro): 未发版回溯三审收口——corrects边继承+repoint冻结+评测钳制+文档同步 (@ZK-Andy)
  • fix(review): 未发版盘查六修复——软门对齐M1/三parser容错/compare恒等声明/组序文案/预算单家/快照重定 (@ZK-Andy)

其他改动

  • docs(readme): 借 uv/bubbletea 模板重整中英结构 (@ZK-Andy)
  • docs(readme): 默认展示改中文 (@ZK-Andy)
  • test(injection): 补齐 indexLineOf 分支,覆盖率回到阈值以上 (@ZK-Andy)
  • docs(notes): 记忆召回度量方案(proposed) (@ZK-Andy)
  • docs(notes): 归档可见性方案(proposed) (@ZK-Andy)
  • docs(plans): RSI 任务级 fitness 与机械门禁缺口两份执行计划落盘 (@ZK-Andy)
  • docs(research): PilotDeck 2.0 记忆机制差距分析(AGPL 只学设计) (@ZK-Andy)
  • docs(plans): 架构功能性补充总纲(13 条散待办整合为 P1–P6 单一计划) (@ZK-Andy)
  • docs(plans): 总纲 v2——评审 9 项修订(P0 门禁先行/工期 9.5/借鉴归位/事件档门槛/双 gate 双 runner) (@ZK-Andy)
  • docs(plans): 二审补丁——RSI §5 补 D10 注记、归档 ADR 三值起步、§5 P3 平行轨、递延数字点名进 §7 (@ZK-Andy)
  • docs(plans): 总纲 v4——三审架构接地+四审源码核验(D9/D11/P5a拆分/递延数字点名) (@ZK-Andy)
  • chore(gates): P0门禁先行批——G6 schema快照+G3红绿俱验(9门×2样本,712测试绿) (@ZK-Andy)
  • test(p2): 全丢弃批次短路记账覆盖——补 extraction-propose.ts 行覆盖到阈值上 (@ZK-Andy)
  • chore(gates): G-batch1——G1 ADR 覆盖率 + G2 依赖环 + G4 预算棘轮 (@ZK-Andy)
  • test(gates): 补 extraction-item 叶模块分支覆盖(runIdOf 双边 + errorText 五形态) (@ZK-Andy)
  • chore(gates): G-batch2——G5 导出面快照 + G12 归层 + G9 测试配对 (@ZK-Andy)
  • chore(gates): G-batch3——G7 历史词 + G8 Alternatives + G11 函数形状;G10 只落评估 (@ZK-Andy)
  • chore(gates): G10 变异抽样落地——stryker 周任务 + PR 非阻塞播报 (@ZK-Andy)
  • docs(gates): 补 G5 引擎注记(tsc 声明 emit 代 ts-morph,零新依赖) (@ZK-Andy)
  • test(p4): 补覆盖率缺口——回填边界、原因回落与快照降级 (@ZK-Andy)
  • docs(p5): P5a ADR v2——评审8条重写,P5a缩零ctx、runner移P5b、D11=A落袋 (@ZK-Andy)
  • docs(p5): P5a ADR v3——复审条件通过增补(卡片加回/基线纪律/JSON/arm白名单) (@ZK-Andy)
  • docs(p5): P5a ADR v4——state键契约与runner归宿前置 (@ZK-Andy)
  • chore(gates): 重定memory-rules棘轮基线——revert误删空行 (@ZK-Andy)
  • docs(review): 架构审核S2收口——排序语义双家互指注释 (@ZK-Andy)

Features

Release exception: this version changes memory/skill/injection surfaces with no compare.md covering HEAD (verify-eval-freshness red). The first eval run can only happen after release (evolve_eval_run ships with the release), so it was approved to release first and backfill the compare right after; its data feeds the next version's gate.

  • Injection index slimming: typeless hook lines, 20-char descriptions, two-paragraph guide (@ZK-Andy)
  • P1 quick wins: card dual readouts, unchanged-event gate, parse tolerance, provenance defaults (@ZK-Andy)
  • P2 extraction track: two-stage classification, mechanical proposal checks, replayable audit (@ZK-Andy)
  • P4 memory lifecycle: archive reasons, version-row merging, read-only archive zone, unified update semantics (@ZK-Andy)
  • P5 eval loop: unified evals/ set, recall wiring, eval_cases table, four-arm × repeat-2 runner with manual trigger (@ZK-Andy)
  • P6 injection evolution: four-layer grouping, round-wins conflict rule, post-compaction re-injection, seeded integration tests (@ZK-Andy)
  • Triple-review TS gates: tiering, brief freeze, round convergence (@ZK-Andy)

Bug Fixes

  • Broke the extraction-ring↔propose value-import cycle; fixed archive backfill to ride migrations; P5b coverage parity; unreleased triple-review retro; unreleased six-fix review batch (identity gate aligned to M1, shared tolerant JSON parse, compare identity disclosure, layering copy, single-home budget measure, snapshot refresh) (@ZK-Andy)

Chores

  • README restructure (bilingual), recall/archival proposals, plan revisions v2–v4, G-batch1–3 + G10 gates, coverage backfills (@ZK-Andy)

Full Changelog: v0.19.0...v0.19.1
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.1

v0.19.0

Choose a tag to compare

@ZK-Andy ZK-Andy released this 18 Oct 03:57

中文 | English

新功能

  • 观测三件:代际自检、注入账本、检索评测(e60f29f,@ZK-Andy)。插件第一次能用数字回答三件事。① 代际自检(services/build-identity.ts):进程导入时对自身入口文件取 sha1(codeGeneration),查询时重读盘面(diskGeneration),两者不同即 restartRequired——卡片首行显示「运行代 / 盘面代」,不一致标红并写明需重启,plugin_log 每次 mount 落一条 build-identity。任一侧不可读一律判「不欠重启」:观测不可用绝不阻塞注入。② 注入账本(data/injection-log.ts):section 每会话只构建一次,因此每会话一行,记录索引点名的 id 与估算 token(30 天随其他账本裁剪);读侧按「该 id 的 memory_usage.last_used_at ≥ 注入时刻」算近 7 天「注入 N / 被读 M(X%)」转化率,卡片显示。局限写在明处:它答的是「有没有被读」,不是「回答有没有用上」。③ 检索评测(scripts/eval-recall.ts):npm run eval:recall 在临时库播种 fixture、跑固定查询、报 hit@1 与 MRR;空 fixture 按设计退出 1。
  • 注入预算改按 token,超了降级而不是丢掉(e60f29f)。旧的 memoryIndex.maxChars 是字符预算,中文实际是 1.2–1.5 token/字,所谓「6k」一直给的是 7000–9000 token。现在预算单位是 token(CJK 感知估算,默认 6000),超预算分三档降级:完整钩子行 → - [id] 行 → (其余 N 条未展开…) 计数行——被预算裁掉的记忆仍能 evolve_read 找回,而不是从上下文里消失。旧 maxChars 只被读一次并折算入库,不留第二读点。
  • 提取提案的确定性预筛(e60f29f)。正文与既有 active 记忆全等的 duplicate、字段没变的 no-change 提案不再进写门禁——它们此前会白改一次 updated_at、推进评审队列、在账本里算作「已应用」。跳过原因落 extraction_log.skip_reason(pre-screen: duplicate×N)。delete 与短禁令不受影响——「正文太短」那条规则试过,因误杀真实提案被移除。
  • 记忆可带「不适用条件」notWhen(e60f29f)。新增一列(≤200 字),随钩子渲染成「(不适用:…)」并在卡片打标记,evolve_write 与提取提案都可携带。只做提示,不参与检索过滤——负路由需要条件匹配引擎,属于下一批。

问题修复

  • 中文长查询零命中(e60f29f):"什么时候可以 publish" 整段被当成一个关键词,要求标题里出现「什么时候可以」这个 7 字连续片段,于是检索返回空。现在 CJK 长片段按 3 字窗口展开,窗口内 OR、词组间 AND。
  • AND 语义吃掉自然语言问句(e60f29f):词组凑不齐时整句零命中。增加第二趟——严格路全空且不止一个词时退回 OR 重试。
  • 索引顺序不确定(e60f29f):MEMORIES_ORDER 缺 tiebreak,同 updated_at 的行顺序由 SQLite 自定,破坏「会话内字节稳定」这一 prompt-cache 契约。补 , id ASC。
  • governance 工作流 shell 注入(8b94e16):issue 正文经 ${{ }} 插进 shell,代码围栏里的反引号让该步恒 exit 2——这项校验此前从未真正执行。现改为 scripts/governance-check.ts 纯函数校验、事件负载走环境变量,恒退出 0。

其他改动

  • chore(ci): Actions 升到 node24 运行时(18c3576,checkout v7 / setup-node v7 / pnpm-action-setup v6)
  • test(memory): 补注入账本、转化率、预筛、代际自检覆盖(f57d067,覆盖率 97.5 / 92.65)
  • docs(readme): 中英 README 重整并同步功能面(4dbb8f9)
  • docs(design): 设计文档同步观测批次,模块路径改为架构整改后的实名(a2f998c)

Features

  • Three observability additions (e60f29f, @ZK-Andy). The plugin can now answer three questions with data. ① Build identity (services/build-identity.ts): the process hashes its own entry file at import (codeGeneration) and re-reads it on demand (diskGeneration); they differ ⇒ restartRequired. The card's first line shows both and turns red with "restart the host"; plugin_log carries the same reading as a build-identity row. When either side is unreadable it reports "no restart owed" — observability never blocks injection. ② Injection ledger (data/injection-log.ts): the section is built once per session, so the ledger holds one row per session (ids named, estimated tokens, pruned with the other ledgers at 30 days); the card shows a 7-day "injected N / read M (X%)" conversion, where read means the body was served after the injection that named it. Its limit is stated, not hidden: it answers "was it read", never "did the answer use it". ③ Recall evaluation (scripts/eval-recall.ts): npm run eval:recall seeds a throwaway store from a fixture, runs fixed queries and reports hit@1 and MRR; an empty fixture is red by design.
  • The injection budget is tokens now, and overflow degrades instead of dropping (e60f29f). The old memoryIndex.maxChars was a character cap while Chinese costs ~1.2–1.5 tokens per character, so "6k" actually shipped 7000–9000 tokens. The budget is now tokens (CJK-aware estimate, default 6000) and an index that does not fit degrades in tiers: full hook lines → - [id]-only lines → a (其余 N 条未展开…) counter. A memory the budget could not afford stays reachable through evolve_read instead of vanishing. The legacy key is read once, converted, and never read again.
  • Deterministic pre-screen for extraction proposals (e60f29f). Proposals that duplicate an existing body (duplicate) or change nothing (no-change) no longer reach the write gate — they used to bump updated_at, move the review queue and count as "applied". The reason lands in extraction_log.skip_reason (pre-screen: duplicate×N). Deletes and short prohibitions are untouched: a "too short to be a rule" rule was tried and removed after it misfired on real proposals.
  • Memories can carry a caveat, notWhen (e60f29f). A new column (≤200 chars) rendered next to the hook as "(不适用:…)" and badged on the card; both evolve_write and extraction proposals may set it. Presentation only — retrieval never filters on it.

Bug Fixes

  • Chinese long queries returned nothing (e60f29f): "什么时候可以 publish" was treated as one keyword, requiring the literal 7-character run in the title. CJK fragments now expand into 3-character windows, OR-ed inside a token and AND-combined across tokens.
  • AND semantics swallowed natural-language questions (e60f29f): when the token groups could not all match, the whole query returned nothing. A second pass now retries with OR when the strict pass is empty and the query has more than one token.
  • Non-deterministic index order (e60f29f): MEMORIES_ORDER had no tiebreak, so rows sharing updated_at came back in SQLite's own order — breaking the byte-stable-per-session contract the prompt cache relies on. Added , id ASC.
  • governance workflow shell injection (8b94e16): the issue body was interpolated into a shell via ${{ }}, and backticks in code fences made that step exit 2 every time — the check had never actually run. Validation moved into scripts/governance-check.ts with the payload passed as an environment variable; the step always exits 0.

Chores

  • chore(ci): Actions upgraded to the node24 runtime (18c3576)
  • test(memory): coverage for the injection ledger, conversion stats, pre-screen and build identity (f57d067, coverage 97.5 / 92.65)
  • docs(readme): bilingual README restructured and synced with the feature set (4dbb8f9)
  • docs(design): design doc synced; module paths updated to the post-reorg homes (a2f998c)

Full Changelog: v0.18.2...v0.19.0
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.19.0

v0.18.2

Choose a tag to compare

@ZK-Andy ZK-Andy released this 17 Oct 17:10

中文 | English

新功能

- (无)

问题修复

  • 卡片投影合并全局记忆(83f00ba,@ZK-Andy):记忆被提级后,来源行归档、全局副本又落在卡片从不列出的全局分区,于是这条记忆在卡片上彻底消失。现在记忆投影照技能既有形状合并 L0 分区:每条带 scope(项目/全局),卡片显示「全局」徽标;隔离行同样标出所属分区;内容预览沿用「本地优先、缺失回落全局」的读语义。

其他改动

  • docs(readme): 测试文件数与 v0.18.1 数据同步(@ZK-Andy)

Features

- (none)

Bug Fixes

  • The card now merges the global memory partition (83f00ba, @ZK-Andy): once a memory was promoted, its source row was archived while the global copy lived in a partition the card never listed — so the memory vanished from the card entirely. The memory projection now merges the L0 partition the same way skills already did: every row carries scope (project/global) and the card renders a "global" badge; quarantined rows name their partition too, and the body preview keeps the local-first read semantics.

Chores

  • docs(readme): sync test counts with v0.18.1 (@ZK-Andy)

Full Changelog: v0.18.1...v0.18.2
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.18.2

v0.18.1

Choose a tag to compare

@ZK-Andy ZK-Andy released this 17 Oct 12:28

中文 | English

问题修复

  • 试运行不再在账本里声称「转正」。 实习期满的全局条目若拿到 keep 判词,review_log 原来一律写「实习转正(有跨分区引用)」——试运行(review.dryRun)下什么都没改却写着转正,读账本的人会被误导。现在分三种措辞:无跨分区引用(试运行)、有引用但仅试运行(「本会转正」)、真转正。这是 v0.18.0 的账本措辞修正,不影响任何状态变化。(@ZK-Andy)
  • CI 覆盖率门禁修复。 v0.18.0 的 CI 在按文件覆盖率门禁(91/83)上失败:新增的 data/tiering.ts、services/review-tiering.ts、services/review-row.ts 首版只到 83/44/78。补 38 例覆盖「拒绝理由、事务回滚重抛、证据表不可读不授权、试用三出口、技能拒绝层级判词、候选标记清除失败」等分支;顺带把 evolved 从可选链改成显式入参(去掉一批不可达分支)、删除未使用的 verdictCount 助手。现全仓 640 测试、覆盖率 97.75 / 93.13。(@ZK-Andy)

Bug Fixes

  • Trial mode no longer claims a confirmation it never made. A keep verdict on a global row whose probation came due used to ledger「实习转正(有跨分区引用)」unconditionally — under review.dryRun nothing changed while the row said it had been confirmed. The wording now has three cases: no cross-partition use (trial), use but trial only ("would have been confirmed"), and a real confirmation. Wording fix only; no state change differs. (@ZK-Andy)
  • CI coverage gate fixed. v0.18.0's CI failed the per-file coverage floor (91/83): the new data/tiering.ts, services/review-tiering.ts, and services/review-row.ts started at 83/44/78. 38 cases now cover the refusal reasons, transaction rollback-and-rethrow, an unreadable evidence table not authorizing a move, the three probation exits, skills refusing tiering verdicts, and a failed candidacy clear; evolved moved from optional chaining to an explicit parameter (dropping a batch of unreachable branches) and the unused verdictCount helper is gone. 640 tests, coverage 97.75 / 93.13. (@ZK-Andy)

Full Changelog: v0.18.0...v0.18.1
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.18.1

v0.18.0

Choose a tag to compare

@ZK-Andy ZK-Andy released this 17 Oct 12:13

中文 | English

新功能

  • 记忆分层:L0 跟人走、L1 跟项目走。 记忆现在分两层——L0(协作偏好、语言、工作方式、本机环境事实)住全局分区,L1(项目现状、机制指针、命令、门禁)住各工作区分区,L2(会话/任务状态)依旧不进库。读路径把全局分区合并进每个工作区的视图,L0 排在 L1 之前(注入索引因此先看到人物画像),同 id 时活动的本地行遮蔽全局行;归档行不遮蔽——提级后的源行正是归档状态。卡片的分区视图不合并,免得每行出现两次。(@ZK-Andy)
  • 两级试用漏斗,取代「一次判定就落全局」。 提取时归属三测全过会在提案里打 scope=person(条目仍住原分区,只作候选标记,非法值就地丢弃不让整批被拒);评审的第二次独立判定说 promote 才真的移动。移动是单事务:全局建行 + 项目行归档(永远只有一份 active)+ 目标分区补一条判词行,所以搬过去的行读作「已判」而不是「新写」。进全局带 30 天实习期并记住来源分区,实习行照常注入、标「(试用中)」——看不见的记忆赚不到跨项目引用。到期由队列的时钟档送去复审(不受最长免审期与抽样配额压制):非来源分区有过引用就转正,没有就退回来源分区,真过时/涉密则隔离。(@ZK-Andy)
  • 「放错家」有了四个出口,不再一律隔离。 评审新增三种判词:archive(内容没错但压根不该长期存在——保留历史、不再注入、按 id 仍可查;门槛是零引用 + 第二次独立淘汰判定 + 没有被任何活动条目 corrects 指向)、promote(人物画像该进 L0)、demote(绑某仓库的条目却住在全局,退回项目分区)。另有 export-suggestion:「内容对,但家该是仓库文档」——只记判词并在卡片标「建议入仓文档」,绝不自动往你的仓库写文件(那会绕过 ADR 流程与文档门禁)。物理删除仍然只由人做。(@ZK-Andy)
  • 手动兜底与账本:evolve_write(kind=memory, action="move-to-global") 把一条记忆手动提到全局(默认也进实习);review_log 的 verdict 白名单随之扩展,老库打开时由 schema guard 重建一次,历史判词一条不丢。(@ZK-Andy)

Features

  • Memory layers: L0 follows the person, L1 follows the project. Memories now live on two levels — L0 (collaboration preferences, language, working style, machine facts) sits in the global partition, L1 (project state, mechanism pointers, commands, gates) in each workspace partition, and L2 (session/task state) still never enters the store. Reads merge the global partition into every workspace view with L0 first (so the injection index leads with the person-level facts), and an active local row still shadows a global one by id — an archived row shadows nothing, which is exactly the state a promotion leaves behind. The card's per-partition view stays unmerged so no row is listed twice. (@ZK-Andy)
  • A two-stage promotion funnel replaces "judge once, write globally". When all three ownership tests pass, extraction marks the proposal scope=person (the row stays in its project — the marker is only a candidacy, and an invented value is dropped on the spot instead of rejecting the whole batch); the review's second, independent judgement has to say promote before anything moves. The move is one transaction: build the global row, archive the project row (exactly one active copy ever), and leave a verdict row in the target partition so the moved row reads as judged rather than brand new. A promoted row starts a 30-day probation and remembers its origin partition; probation rows are injected like any other and tagged「试用中」— an unseen memory cannot earn the cross-partition use that confirms it. When the window closes, the queue's clock tier brings it back (outranking both the exemption window and the sampling quota): a reference from a partition other than the origin promotes it for good, none sends it home, and a genuinely stale or leaked row is quarantined. (@ZK-Andy)
  • "Wrong home" now has four exits instead of quarantine for everything. The review gained three verdicts: archive (nothing wrong with the content, it simply should not exist long-term — history kept, no longer injected, still readable by id; gated on zero references, a second independent reject verdict, and no active row pointing at it via corrects), promote (person-level facts belong in L0), and demote (a repo-bound row that somehow sits in the global partition goes back to its project). A fourth, export-suggestion, means "the content is right but its home is the repo's docs": it records the advice and tags the row「建议入仓文档」on the card, and never writes into your repository (that would bypass the ADR flow and the doc gates). Physical deletion remains human-only. (@ZK-Andy)
  • Manual fallback and ledger: evolve_write(kind=memory, action="move-to-global") promotes a memory by hand (it enters probation too); the review_log verdict whitelist grows with these exits, and the schema guard rebuilds an older store once on open without losing a single historical verdict. (@ZK-Andy)

Full Changelog: v0.17.0...v0.18.0
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.18.0

v0.17.0

Choose a tag to compare

@ZK-Andy ZK-Andy released this 17 Oct 11:44

中文 | English

新功能

  • 评审改为事件驱动:时间不再是引擎,只是兜底。 过去 review.staleDays(默认 30 天)的语义是「上次评审超过 N 天就重新排队」,即每条记忆每 30 天必被重审一遍——这是与内容质量无关的固定维护税,记忆越多越亏(1000 条时每天约 33 条纯到期重审)。现在重审由事件触发:新记忆落盘时与既有条目字面相近、某条记忆 corrects 指向它、用户纠错类 feedback 落在同一主题——任一事件落进新表 item_events,条目随即回到队首。事件与正文在同一个事务里写入,因此不会出现「本体已改、牵连丢失」。日历降级为兜底抽样:staleDays 现在是最长免审期,超过只是「有资格被抽中」,抽样名额取批量的五分之一(至少 1 条),其余名额全给新写与事件。一条记忆连续两次 keep 且其间无事件,免审期翻倍(30→60→120 封顶);任何非 keep 判词或牵连事件都把它清零——同一条被反复议价、结论来回翻转的日子结束了。(@ZK-Andy)
  • 评审日账按来源分列。 review_daily 新增 requeued_link(事件牵连)/requeued_clock(日历时钟)/requeued_sampled(抽样)三列,requeued 恒等于三者之和且由代码求和得出,不由调用方传值——「今天为什么再审了这些条目」现在是一行可读的数字,而不是一个总数。(@ZK-Andy)
  • 连带修正「被纠正牵连」的老数据。 条目被 corrects 指向时,即使没有事件行也会进队——本版之前写下的纠正链不会因为换了触发制而从队列里消失。(@ZK-Andy)

Features

  • Reviews are now event-driven: the calendar is a backstop, not the engine. review.staleDays (30 by default) used to mean "any item whose last review is N days old requeues" — every memory re-reviewed every 30 days, a fixed maintenance tax unrelated to content quality that grows linearly with the store (about 33 pure-expiry reviews a day at 1000 items). Requeues now come from events: a drop-in write whose text lands near an existing item, a memory that names another as the thing it corrects, or a correction-shaped feedback write on the same topic. Any of them lands a row in the new item_events table and puts the item back at the front of the queue. Events commit in the same transaction as the body they describe, so "the text changed but the linkage was lost" cannot happen. The calendar becomes a sampling backstop: staleDays is now the longest exemption window — past it an item is merely eligible to be sampled, the sample slot is a fifth of the batch (one at minimum), and the remaining slots go to new writes and events. Two keeps in a row with no intervening event double the window (30→60→120, capped); any non-keep verdict or linkage event resets it — an item can no longer be re-argued day after day with the verdict flipping each time. (@ZK-Andy)
  • The daily review account is split by source. review_daily gains requeued_link (event linkage), requeued_clock (calendar milestones), and requeued_sampled (stale sampling); requeued is always their sum, derived in code rather than supplied by the caller, so "why did these items come back today" is a readable number instead of one total. (@ZK-Andy)
  • Old correction links keep working. An item named by a corrects link stays queued even without an event row, so correction chains written before this release do not vanish with the new trigger model. (@ZK-Andy)

Full Changelog: v0.16.5...v0.17.0
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.17.0

v0.16.5

Choose a tag to compare

@ZK-Andy ZK-Andy released this 17 Oct 08:30

中文 | English

新功能

  • 落点测试:事实落进仓库文件后不再重复提取。 提取提示词在归属三测之外新增一条判据——用户已把某条规则写进、或明确要把它写进仓库里的任何文件时,那个文件就是它的家,提取判 skip 并在理由里引用原话;同一句话在记忆与仓库文件各存一份即视为违规。判据挂在「事实落进仓库」这个动作上,不枚举任何文件名、目录或后缀,因此新增或改名工作区规则文件都不需要插件发版。便宜预检门同步加上同一判据。(@ZK-Andy)
  • 提取增量带上本轮工具名。 序列化增量时在头部加一行 tools-this-turn,只取工具名,参数与路径永不进入提示词——模型由此知道「本轮发生过文件写入」,但仍需自己判断哪条事实落进了哪个落点。该行占用的字符从正文预算中扣减,超长或超量的工具名有截断与去重上限。(@ZK-Andy)

Features

  • Landing-point test: a fact that already lives in a repo file is no longer extracted into memory. The extraction prompt gains a fourth ownership check: when the user has written a rule into — or explicitly asked to write it into — any file in the workspace, that file is the fact's home; the run skips with the user's own words quoted in the reason. One sentence living in both a memory and a repo file now counts as a violation. The rule keys on the act of landing in the repo and names no file, directory, or suffix, so adding or renaming a workspace rule file never requires a plugin release. The cheap pre-gate applies the same check. (@ZK-Andy)
  • The extraction increment now names the turn's tools. Serialization prepends a tools-this-turn line carrying tool names only — arguments and paths never enter the prompt — so the model can tell that a file write happened, while still judging which fact landed where. Its length comes out of the body budget, and oversized or excessive tool names are truncated and de-duplicated. (@ZK-Andy)

Full Changelog: v0.16.4...v0.16.5
npm: https://www.npmjs.com/package/dsh-continual-evolve/v/0.16.5