From 20d9297ded7161861596da109bbeb892ecce812a Mon Sep 17 00:00:00 2001 From: ranxianglei Date: Sat, 19 Sep 2026 09:02:16 +0800 Subject: [PATCH] =?UTF-8?q?release:=20v1.18.2=20=E2=80=94=20strip=20leaked?= =?UTF-8?q?=20bare=20ACP=20refs=20(#431)=20+=20Windows=20path=20protection?= =?UTF-8?q?=20fix=20(#402)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 17 +++++++++ CHANGELOG.zh-CN.md | 17 +++++++++ devlog/2026-09-19_release-v1.18.2/REQ.md | 37 ++++++++++++++++++++ devlog/2026-09-19_release-v1.18.2/WORKLOG.md | 25 +++++++++++++ package.json | 2 +- 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 devlog/2026-09-19_release-v1.18.2/REQ.md create mode 100644 devlog/2026-09-19_release-v1.18.2/WORKLOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a4d153e..6b9efdab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +### v1.18.2 — strip leaked bare ACP refs from assistant text tail + fix silent no-op in Windows path protection + +**PR #432 + PR #403.** Two bug fixes bundled — no config or state-format changes. + +**1. Leaked bare-ref stripping** (#432, fixes #431): +Models occasionally degenerate at end-of-generation and echo the `` annotation pattern they saw on the last visible message, leaving a **bare ref + garbage** fragment at the end of completed text (e.g., `m00057 `). The previous sanitizer only removed complete/incomplete *tags*, so tag-less fragments leaked through, persisted into OpenCode's DB, and re-entered later context and compression summaries. +- New pure function `stripLeakedTrailingRefs(text, { nextMessageRef, nextBlockRef })` (`lib/messages/utils.ts`): single-pass regex scan for **line-leading** bare refs (`m\d{4,5}`, `b[1-9]\d*`); truncates from the first match whose numeric value is ≥ the next-to-allocate bound (`messageIds.nextRef` / `prune.messages.nextBlockId`), trimming trailing whitespace. +- Why "future refs only" is safe: refs are strictly monotonic — output produced before value V existed cannot legitimately cite V, so stripping V+ at the tail has zero false positives against real citations ("see m00042" survives; mid-line future refs like "between m00056 and m00999" also survive). +- The `text.complete` handler (`lib/hooks.ts`) applies this after the existing tag stripping via a synchronous registry lookup; when session state is unavailable (eviction, internal sessions) it falls back to today's tag-only behavior. O(text) per completion. +- Known limitation (documented): echoes of **already-assigned** refs are not covered — deliberate, since those may be legitimate citations. +- +222-line regression suite (`tests/leaked-trailing-ref.test.ts`), plus review-nit coverage (mixed below/future-bound sequences, non-integer bound guards, b0 exclusion, 4-digit m-refs) and a cast-free bounds-narrowing refactor. + +**2. Windows path protection actually works now** (#403, fixes #402): +`normalizePath()` searched for a **two**-character string (source literal `"\\\\"`) instead of a single backslash, so real Windows paths were never normalized and `protectedFilePatterns` silently failed to protect them — a no-op on the one platform that needs it. Now `replaceAll("\\", "/")`. Ported from upstream DCP commit 5f8f33b; +104 tests (5 of 8 fail against pre-fix code). + +**Install**: `opencode plugin opencode-acp@latest --global` + ### v1.18.1 — paper preprint v0.2 into the repo (docs only) **PR #394.** No runtime code changes — this release ships ACP's research preprint and its figures into the repository, linked from both READMEs. diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 9ff9cf11..ec9c05d4 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -1,5 +1,22 @@ # 更新日志 +### v1.18.2 — 剥离助手文本尾部泄漏的裸 ACP 引用 + 修复 Windows 路径保护静默失效 + +**PR #432 + PR #403。** 捆绑两个 bug 修复 —— 无配置或状态格式变更。 + +**1. 泄漏裸引用剥离**(#432,修复 #431): +模型偶尔在生成末尾退化,回显最后一条可见消息上看到的 `` 标注模式,在完成文本尾部留下**裸引用 + 垃圾**片段(如 `m00057 <随机多语言文本>`)。旧 sanitizer 只剥离完整/不完整的 *标签*,这些无标签片段因此漏过、被持久化进 OpenCode DB,并重新进入后续上下文与压缩摘要。 +- 新纯函数 `stripLeakedTrailingRefs(text, { nextMessageRef, nextBlockRef })`(`lib/messages/utils.ts`):单次正则扫描**行首**裸引用(`m\d{4,5}`、`b[1-9]\d*`);首个数值 ≥ 待分配边界(`messageIds.nextRef` / `prune.messages.nextBlockId`)的匹配触发从该处到文末的截断(尾随空白修剪)。 +- 为何只剥"未来引用"是安全的:引用严格单调递增 —— 在数值 V 存在之前产生的输出不可能合法引用 V,对真实引用零误伤("see m00042" 保留;行中未来引用如 "between m00056 and m00999" 也保留)。 +- `text.complete` handler(`lib/hooks.ts`)在既有标签剥离之后经同步 registry 查找应用;会话状态不可用时(驱逐、内部会话)→ 回退到纯标签行为。每次完成 O(text)。 +- 已知限制(已文档化):**已分配**引用的回显不在覆盖范围 —— 有意为之,那些可能是合法引用。 +- +222 行回归测试(`tests/leaked-trailing-ref.test.ts`),另加评审补测(混合 below/future 边界序列、非整数边界守卫、b0 排除、4 位 m 引用)与无 cast 边界收窄重构。 + +**2. Windows 路径保护真正生效**(#403,修复 #402): +`normalizePath()` 搜索的是**两字符**字符串(源码字面量 `"\\\\"`)而非单个反斜杠,真实 Windows 路径从未被归一化,`protectedFilePatterns` 在其唯一需要的平台上静默失效(no-op)。现改为 `replaceAll("\\", "/")`。移植自上游 DCP 提交 5f8f33b;+104 行测试(其中 5 个在修复前代码上失败)。 + +**安装**:`opencode plugin opencode-acp@latest --global` + ### v1.18.1 — 论文预印本 v0.2 入库(纯文档) **PR #394。** 无运行时代码变更 —— 本次发布将 ACP 的研究预印本及其配图收入仓库,并在两个 README 中加链接。 diff --git a/devlog/2026-09-19_release-v1.18.2/REQ.md b/devlog/2026-09-19_release-v1.18.2/REQ.md new file mode 100644 index 00000000..9fd86f93 --- /dev/null +++ b/devlog/2026-09-19_release-v1.18.2/REQ.md @@ -0,0 +1,37 @@ +# REQ - Release v1.18.2 (patch) + +- Task ID: `2026-09-19_release-v1.18.2` +- Home Repo: `opencode-acp` +- Created: 2026-09-19 +- Status: InProgress +- Priority: P1 +- Owner: ranxianglei +- References: https://github.com/ranxianglei/opencode-acp/issues/400 (floor 12, "发新版本") + +## Scope + +Bump `package.json` 1.18.1 → 1.18.2 and ship everything merged to master since v1.18.1: + +| PR / commit | Content | Issue | +|-------------|---------|-------| +| #432 | Strip leaked bare ACP refs from completed assistant text — new pure function `stripLeakedTrailingRefs()` in `lib/messages/utils.ts`, applied by the `text.complete` handler in `lib/hooks.ts`; +222-line test suite `tests/leaked-trailing-ref.test.ts`, review-nit tests, cast-free bounds-narrowing refactor | fixes #431 | +| #403 | Normalize single Windows path separators in `protectedFilePatterns` (`lib/protected-patterns.ts` one-character fix; +104 tests) | fixes #402 | +| c6066c4b (CI) | `.github/workflows/publish-stable-from-acp.yml` — publishes the separate `opencode-stable` CLI fork; CI-only, no runtime code | — | +| #433 | promote-stable devlog only (side effect already executed: npm `stable` = 1.18.1) | — | + +Both runtime changes are bug fixes → semver PATCH: **v1.18.2**. + +## Changes in this branch + +1. `package.json`: `version` 1.18.1 → 1.18.2 +2. `CHANGELOG.md`: new `### v1.18.2` entry at top +3. `CHANGELOG.zh-CN.md`: new `### v1.18.2` entry at top +4. This devlog folder (`REQ.md` + `WORKLOG.md`) + +No other code changes. Branch name `YYYY-MM-DD_release-v{VERSION}` + human merge triggers `release.yml`: auto-tag `v1.18.2` → build → test → npm publish to `latest` → GitHub Release. + +## Verification plan + +- `./scripts/ci/check-pr.sh 2026-09-19_release-v1.18.2 origin/master` (changelog check active this time because version changed) +- `npm run typecheck`, `npm run build`, `npm run test` +- After human merge: verify `npm view opencode-acp dist-tags.latest` = 1.18.2 and the GitHub Release exists. diff --git a/devlog/2026-09-19_release-v1.18.2/WORKLOG.md b/devlog/2026-09-19_release-v1.18.2/WORKLOG.md new file mode 100644 index 00000000..03998789 --- /dev/null +++ b/devlog/2026-09-19_release-v1.18.2/WORKLOG.md @@ -0,0 +1,25 @@ +# WORKLOG - Release v1.18.2 + +## Steps + +1. Branched `2026-09-19_release-v1.18.2` from `origin/master` (`026dbe73`, includes merges of #432 + #433). +2. Bumped `package.json` version 1.18.1 → 1.18.2. +3. Added `### v1.18.2` entries at the top of `CHANGELOG.md` + `CHANGELOG.zh-CN.md`. +4. Created this devlog folder (`REQ.md` + `WORKLOG.md`). +5. Local verification (below). +6. Pushed branch + opened release PR (references issue #400 floor 12; does **not** close #400 — long-lived release issue). + +## Local verification (2026-09-19) + +| Check | Result | +|-------|--------| +| `./scripts/ci/check-pr.sh 2026-09-19_release-v1.18.2 origin/master` | branch name ✓, devlog REQ/WORKLOG ✓, changelog `### v1.18.2` present in both files ✓ | +| `npm run typecheck` | clean | +| `npm run build` | success — `dist/index.js` 484.35 KB | +| `npm test` | **1290/1292** — 2 failures are sandbox-only (hardcoded `/tmp` paths vs this workdir's read-only `/tmp` mount): `tests/soft-block.test.ts` and E2E "toFile on inactive block writes block summary". Pre-existing on master; GitHub CI runners unaffected (PR #433's full CI matrix was green with the same suite). | + +## Post-merge (human merge + automated CI) + +- Human merges the PR → `release.yml` detects release branch → tags `v1.18.2` → `npm ci` → `check:package` → full test → publishes to npm `latest` → creates GitHub Release. +- Verify after publish: `npm view opencode-acp dist-tags.latest` = 1.18.2; `gh release view v1.18.2`. +- Note: npm `stable` stays at 1.18.1 until a future promote-stable request. diff --git a/package.json b/package.json index 1863bf3f..69d9328e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "opencode-acp", - "version": "1.18.1", + "version": "1.18.2", "type": "module", "description": "Active Context Pruning — model-driven context management for OpenCode (hardened fork of DCP with 35 bug fixes)", "main": "./dist/index.js",