Skip to content

fix(nudge): same-turn growth re-inject after a full growth floor (closes #269) - #316

Merged
ranxianglei merged 2 commits into
masterfrom
2026-09-06_issue269-growth-reinject
Sep 7, 2026
Merged

fix(nudge): same-turn growth re-inject after a full growth floor (closes #269)#316
ranxianglei merged 2 commits into
masterfrom
2026-09-06_issue269-growth-reinject

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

问题

issue #269:模型忽略 78% 压力 nudge 后,同轮内的所有后续 nudge 重示都被 per-turn 去重(Set)拦掉,直到 95% emergency 机械截断才放行 —— 没有中间的再次提醒机会。

根因(两层)

  1. 内核 0.0.55 的 T1 growth / T2/T3 cadence 在决策时自行 stamp(lastNudgeShownTokens / lastShownByTier),growth 分支确实有增长门槛;但 pressure 分支(75%+)完全不受 cadence 门控 —— 每个 context 事件都重新决策注入。
  2. 适配器层的 nudgeShownFor(turnKey) Set 去重是为防止同轮多次事件重复注入(合理),但它不区分「同一决策的重复触发」和「增长后的新决策」,把后者也拦了。

修法(适配器层增长感知)

  • markNudgeShown(turnKey, tokenCount):Set 之外并行 Map 记录注入时刻的 token 刻度
  • 同轮增长 ≥ max(minGrowthFloor, minGrowthRatio × adaptiveGrowth)(镜像内核 decideNudge 的防抖公式,默认 22.5K)→ 允许重注入;对 growth 分支与内核 cadence 等价(不会更激进),对 pressure 分支补上了原本缺失的增长节流
  • drop re-anchor(镜像内核 nudgeNode):压缩后 tokenCount 掉到 shownAt − adaptiveGrowth 以下时,基线重锚到新刻度 —— 否则压缩后重新长回压力带会被压缩前峰值压制,又是直冲 emergency(测试 B 专门覆盖)
  • 基线维护(读 shownAt + re-anchor)移出 if (turn.nudge?.shouldInject):idle 事件也要推进 re-anchor,否则压缩轮不注入时基线永远停在旧峰值

行为对照

场景 之前 现在
78% 注入后同轮 +2K 抑制 抑制(< 22.5K 门槛)
78% 注入后同轮 +23K 抑制直到 95% 重注入提醒
压缩 150K→90K 后长回 136K(75.6%) 抑制(−14K < 0)直到 emergency 重注入(基线已重锚)
95% emergency 每事件注入 不变
compress 连续失败 retry-cap 硬断路 不变

测试

tests/nudge-reinject.test.ts(3 例):同轮注入/抑制/重注入 cadence、drop-reanchor、emergency 绕过。全量 591/595,唯一失败是本环境已知的 runNpm captures stderr(master 同挂,网络环境相关)。

Fixes #269

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

📦 Built Extension Artifact

Branch: 2026-09-06_issue269-growth-reinject (f650f76)

Option A — Install from npm PR tag (recommended)

pi install npm:billion-context-pi@pr-316

Each push to this PR publishes a new version under the pr-316 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pi-pr316.tgz
pi install ./package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 ework agent · qwen3.8-27b

[bot] 🏷 Review 结论:LGTM,无阻塞问题。 所有声明已对照 acp-kernel 0.0.55 源码逐条核实,本地 CI 检查全绿。

根因验证(两层均成立)

  • 内核侧:decideNudge 的 pressure 分支(≥75%)只要求 bestPending >= minPressureBenefit,完全无 cadence 门控——每个 context 事件都重新决策注入;growth 分支才有 growthReady 门控(+T2/T3 per-tier cadence)。Title: Context never auto-compresses when the model ignores the nudge — climbs 75%→95%+ on long agentic tasks (no enforcement path) #269 场景确认:模型忽略 78% nudge 后,内核在后续每个事件上都在决策「应注入」。
  • 适配器侧:去重 Set 不区分「同一决策的重复触发」与「增长后的新决策」,把后者也拦了——真正的缺口在这里。内核是每事件无状态决策、看不到适配器的注入历史,所以修在适配器层是对的。

公式镜像准确

  • adaptiveGrowth = min(growthCap, max(growthFloor, round(limit×growthRatio))) 与内核 resolveAdaptiveGrowth 逐行一致;
  • reInjectFloor = max(20000, 0.45×50000) = 22500,默认配置下「默认 22.5K」成立;
  • drop re-anchor 形状与内核 nudgeNode 一致(<,同 delta);参考点差异(适配器取最后一次实际注入刻度,内核取 per-event baseline + 压缩后归零)使行为等价或更保守,不会比内核 growth cadence 更激进。

本地验证(branch review-316 @ 97f7b8e)

  • npm run typecheck clean;npm run build 成功(dist/index.js 718.82 KB,acp-kernel 仍内联,零运行时依赖);
  • 全量测试:595 = 592 pass / 0 fail / 3 skip——3 个 skip 均为既有 test.skip(tests/integration.test.ts:292, 317, 611),与本改动无关;比 PR 记录的 591/595 还好(runNpm captures stderr 本环境通过);
  • 新增 tests/nudge-reinject.test.ts 3 例全过(同轮 cadence / drop-reanchor / emergency bypass)。

一个轻微观察(非阻塞,非回归)
压力带内压缩量小于一个 adaptiveGrowth(50K)时(如 240K 注入 → 压缩到 210K,仍 ≥75%),re-anchor 条件(drop > 50K)不触发,基线停在旧峰值,下次提醒需 ~262.5K > window → 静默直到 95% emergency。内核在压缩成功时即清零自己的 stamp,该 corner 比内核 pressure 分支意图更保守;但修复前此场景同样静默到 95%,严格说没有变差。若想收紧:src/index.ts:373-374noteCompressOutcomes 已有压缩结果,成功 outcome 时补一行 re-anchor 即可闭合。是否并入本 PR 由 owner 定,也可以留后续。

合规项:无 version bump ✓,CHANGELOG/CONFIGURATION en+zh 同步更新(顺手修了 zh 旧笔误)✓,无 as any/@ts-ignore ✓,Fixes #269 关联 ✓。

@ranxianglei

Copy link
Copy Markdown
Owner Author

冲突了 解决下

 #269)

Per-turn dedup suppressed ALL kernel re-shows within one user turn, so a
model that ignored a 78% pressure nudge was driven straight into the 95%
emergency band. The kernel's pressure branch re-decides injection on every
context event, so only the adapter layer can pace re-shows:

- markNudgeShown now records tokenCount at injection; the nudge re-injects
  once the context has grown by max(minGrowthFloor, minGrowthRatio x
  adaptiveGrowth) (mirrors the kernel decideNudge cadence; 22.5K default)
- drop re-anchor mirrors the kernel nudgeNode: after a successful compress
  the baseline re-anchors to the new scale, so regrowth into the pressure
  band is not held against the pre-compress peak
- baseline maintenance runs on every context event (also idle ones), not
  only when shouldInject, or the re-anchor would never advance

Tests: tests/nudge-reinject.test.ts (inject/suppress/re-inject cadence,
drop re-anchor, emergency bypass unchanged).
@ranxianglei
ranxianglei force-pushed the 2026-09-06_issue269-growth-reinject branch from 97f7b8e to a5b2763 Compare September 7, 2026 01:24
# Conflicts:
#	CHANGELOG.md
#	src/runtime.ts
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 ework agent · qwen3.8-27b

[bot] 🏷 冲突已解决并推回分支(merge commit f650f76)。

冲突来源:PR 开着期间 master 前进了 4 个 commit(PR #297 bili proxy 让位修复 + PR #318 acp-kernel 0.0.56 bump),与本 PR 同时动了同一批文件。实际文本冲突 2 处(src/index.ts 自动合并干净):

  1. CHANGELOG.md — 两边各在 Unreleased 顶部插了一条。处置:两条都保留,master 的 0.0.56 条目在上、本 PR 的 nudge 条目在下(想调顺序直接挪即可)。
  2. src/runtime.ts — return 对象字面量。处置:取两侧并集 —— 保留 master 新增的 refusalMessage getter/setter,同时保留本 PR 的 Map 版 markNudgeShown(k, t) / nudgeShownTokensFor / clearNudgeTracking(master 侧还是旧单参 markNudgeShown,以本 PR 的双参版为准,接口声明两侧已各自就位)。

合并后关键复核 — 内核升级不影响本 PR:acp-kernel 0.0.56 的 nudge 逻辑在我镜像的每一处都与 0.0.55 逐字节一致(decideNudge growthFloor 公式、pressure 分支无门控、nudgeNode drop re-anchor/stamp、resolveAdaptiveGrowth、默认值 0.75/0.95/5e4/2e4/0.45)→ 镜像公式对新内核依然准确,无需改任何代码

验证(合并后):本地 typecheck clean、测试 612/615 pass 0 fail(3 个既有 skip)、build OK;GitHub CI 9/9 全绿(pr-validation、ubuntu/windows × Node 22/24 四路 test、e2e×2、docker、build-artifact)。

当前状态:mergeable=true(冲突已消除);mergeable_state=blocked 仅剩一个原因 —— master 保护规则要求 1 个 approving review,还差你点一下 Approve,之后即可直接合并(合并操作按规矩由你来)。

透明性注记:发现 master 移动之前,我先对原 commit 做过一次零内容 amend force-push(a5b2763,内容与 97f7b8e 逐字节相同,仅刷新 SHA 触发 GitHub 重新计算 mergeability);merge commit 在其之上。PR 现为 2 个 commit:原修复 + merge。

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.

Title: Context never auto-compresses when the model ignores the nudge — climbs 75%→95%+ on long agentic tasks (no enforcement path)

1 participant