feat: per-model growth-nudge floor modelMinNudgeLimits (issue #344) - #345
feat: per-model growth-nudge floor modelMinNudgeLimits (issue #344)#345ranxianglei wants to merge 17 commits into
Conversation
Growth-triggered compression nudges fired well below a configured minContextLimit because computeShouldNudge() only uses overMinLimit to pick the tips variant, not to gate the decision. Add an explicit (overMaxLimit || overMinLimit) gate to the T1 growth path in injectCompressNudges so a configured minimum acts as a lower bound. - overMaxLimit and the emergency override bypass the gate - T2/T3 tier-promotion nudges are unaffected (independent cadence) - 4 new tests; 2 existing growth-mechanism tests had minContextLimit lowered so they still isolate the growth mechanism devlog: devlog/2026-08-28_min-gate-growth-nudges/
- Gate only applies when minContextLimit resolves (minLimitResolved): percent limits with an unknown model context window keep pre-#342 growth-only behavior instead of suppressing all growth nudges - Unmask 2 existing tests whose minContextLimit sat above the test context (post-compress small growth, baseline init) - 3 new tests: unresolvable-limit fallback, emergency override bypass, T2 tier-promotion independence from the min gate - Correct stale min/max defaults in README.md and CONFIGURATION.md (45%/55% -> 80%/80%, matching lib/config.ts since v1.14.16) - Devlog: REQ constraints/acceptance, WORKLOG results (1036 tests)
…minContextLimit Per @Dog's feedback in issue #342: minContextLimit defaults to 80% (lib/config.ts:200) and is documented as the soft lower threshold for turn/iteration reminders, so gating growth nudges on it suppresses ALL growth nudges below 80% for default users — effectively disabling compression for most of a session. The dual-agent review's minLimitResolved guard did not address this (a default user with a known context still gets growth nudges suppressed below 80%). Use minNudgeContextPercent (default 15, a percent of model context) as the growth-nudge floor instead. It is the intended 'don't nudge below this' knob and was previously a no-op (plumbed into computeShouldNudge but ignored). When the model context limit is unknown the floor is unresolvable and growth nudges keep pre-#342 behavior. overMaxLimit and the emergency override bypass the floor; T2/T3 tier-promotion nudges are unaffected. - Reverts the review commit's minLimitResolved mechanism (dead code here) - Preserves the review commit's README/CONFIGURATION default fixes (80%/80%) - Tests: 4 floor tests + 2 new (unresolvable model limit, T2 independence) re-pointed at the floor; pre-existing test #27 raised into the [floor, max) range. 1035 tests, 0 failures.
…th-floor redesign Re-point stale references left by the floor redesign (ecfe7f0): - README.md: minContextLimit governs turn/iteration reminders only; growth nudges have their own floor (minNudgeContextPercent) - CONFIGURATION.md: minContextLimit description (turn/iteration only); minNudgeContextPercent description (growth-nudge floor, over-max and emergency bypasses, unknown-window fallback) - lib/messages/inject/utils.ts: fix the @deprecated comment on minNudgeContextPercent (field is active; floor computed in inject.ts) - tests/inject.test.ts: section header re-pointed to the floor - WORKLOG: record ecfe7f0 hash + this commit's row
Add optional compress.modelMinNudgeLimits (Record<provider/model, number | "X%">) as a per-model override for the T1 growth-nudge floor introduced in PR #343. Precedence: per-model entry -> global minNudgeContextPercent x model context -> growth-only when the model context is unknown. Absolute per-model floors apply even with unknown model context (mirrors modelMaxLimits/modelMinLimits); per-model percents fall through to the global percent when unresolvable. - lib/messages/inject/utils.ts: new resolveMinNudgeFloorTokens() - lib/messages/inject/inject.ts: floor resolved via the helper - lib/config.ts: field + merge (?? semantics) + deepClone - lib/config-validation.ts: VALID_CONFIG_KEYS, no recursion, validateModelLimits reuse - dcp.schema.json, CONFIGURATION.md, README.md: documented - tests/inject.test.ts: userMsgWithModel helper + 9 issue #344 tests (multi-turn, side-effect assertions, production config, growth cycle, over-max bypass, modelMinLimits independence; mutation-verified) - tests/config-validation.test.ts: 4 new tests - devlog/2026-08-28_model-min-nudge-limits/: REQ.md + WORKLOG.md
📦 Built Plugin ArtifactBranch: Option A — Install from npm PR tag (recommended)opencode plugin opencode-acp@pr-345 --globalEach push to this PR publishes a new version under the Option B — Install from GitHubopencode plugin "github:ranxianglei/opencode-acp#2026-08-28_model-min-nudge-limits" --globalOption C — Download artifact
tar xzf opencode-acp-pr345.tgz
cp -r package/dist ~/.cache/opencode/packages/opencode-acp@latest/node_modules/opencode-acp/dist
This comment is automatically updated on each push. |
[bot] On it — reviewing PR #345 ( |
|
[bot] Dual-agent review complete — no blockers. Two independent agents reviewed Code review — verified the full precedence contract (per-model entry → global Test review — §5.6 all pass (real imports, name fidelity, Should-fix applied: missing zh-CN doc parity → Nits noted, not taken: negative-number validation gap is pre-existing and shared with |
The branch was forked from #343 before its floor-redesign + doc-alignment commits (ecfe7f0, b71e10b); the stacked commit carried stale pre-redesign wording that silently reverted #343's intentional doc fixes: - CONFIGURATION.md / README.md / README.zh-CN.md / CONFIGURATION.zh-CN.md: minContextLimit is the turn/iteration-reminder threshold, not a global nudge gate; growth nudges are floored by minNudgeContextPercent (with over-max / 98% emergency bypass). Restored #343 wording; the new modelMinNudgeLimits sections keep their per-model cross-reference. - tests/inject.test.ts: restored the issue #342 section header (minNudgeContextPercent floor, not minContextLimit). - lib/messages/inject/utils.ts: restored the minNudgeContextPercent param comment (floor is computed in inject.ts, not deprecated). - devlog/2026-08-28_min-gate-growth-nudges/WORKLOG.md: restored from the #343 branch (this PR had rewritten another PR's devlog, replacing real commit hashes with <pending>). - CONFIGURATION.zh-CN.md: fixed leading-space indentation defect from the zh-CN parity commit and aligned the minNudgeContextPercent description with the (corrected) English floor semantics.
[bot] PR #345 review complete — fixes pushed, ready for merge (after #343). Dual-agent review (per the report above): no blockers — precedence contract, edge cases, §5.7 mutation split, and §5.6/§5.7 test requirements all verified; the zh-CN parity should-fix was already applied ( Additional findings from my independent review — the dual-agent review missed a doc-regression: this branch was forked from #343 before its floor-redesign + doc-alignment commits (
Commits pushed (
Verification (re-run after the fixes): Reminder: this PR is stacked on #343 ( |
|
继续 |
[bot] PR #345 的工作已全部完成,当前状态汇总: 已完成(代码侧无剩余工作):
刚刚核实的仓库状态:
接下来需要人工操作(按 AGENTS.md §5.1.1.2 我不能合并 PR):
|
A 15% default floor binds on windows >= ~400K (P% x W > baseline + 50K growth threshold): on 1M-window models every compress cycle is suppressed until 150K context usage, shifting the steady-state working range ~2x upward. For the dominant large-window user profile (baseline 10-50K, cycle ceiling ~110K) this is a silent, bug-level behavior change. 5% only binds on >= ~2M-class windows, keeping the floor inert for typical working cycles. Users who want a higher floor set it explicitly (0 disables). - lib/config.ts default 15 -> 5 - lib/messages/inject/inject.ts policy passthrough + floor fallback 15 -> 5, with rationale comment - dcp.schema.json default + stale description fixed - CONFIGURATION.md / CONFIGURATION.zh-CN.md defaults + rationale - tests/inject.test.ts: default-lock test (mutation-sensitive: fails if the fallback reverts to 15)
Merges 2026-08-28_min-gate-growth-nudges (f3a3fc8+2419871: default minNudgeContextPercent 15% -> 5%) into the per-model floor stack and aligns it: - lib/messages/inject/utils.ts: resolveMinNudgeFloorTokens global-percent fallback 15 -> 5 (+ rationale comment; JSDoc updated) - lib/messages/inject/inject.ts: kept resolveMinNudgeFloorTokens call, folded in the low-default rationale comment - tests/inject.test.ts: kept all #344 per-model tests; moved the #342-follow-up default-lock test (from the base branch) before the #344 section - CONFIGURATION.md: merged descriptions (deliberately-low default rationale + per-model override pointer) Verified: typecheck, 1049/1049 tests, build.
|
Merged the 5% default-floor fix from the #343 base branch — commits This stack's own copy of the global-percent fallback ( Model: Claude Sonnet 4.6 |
…ment note - CONFIGURATION.zh-CN.md: the minNudgeContextPercent description now carries the deliberately-low-default rationale added to the English description by the 5% merge (5% inert for typical cycles, binds only on >=2M-class windows; 0 disables; raise to 15-30% to wait longer). - WORKLOG: header amendment note pointing to §8, mirroring the base branch's WORKLOG treatment of the same 15% -> 5% change.
[bot] Verified the 5% default-floor merge locally — plus 2 residual doc-parity gaps fixed ( Merge verification ( Independently re-ran: Residual gaps I fixed (
Branch tip is now |
|
Model: Claude Sonnet 4.6 Closing in favor of #351, which replaces this PR's flat |
…roviders (issue ranxianglei#344) Replaces the flat modelMinNudgeLimits surface (PR ranxianglei#345, superseded) with compress.providers.{provider}.models.{model}.minNudgeContextPercent, cascading field-by-field: model > provider > global. 0 disables explicitly; unknown ids fall back to global; percent resolves against the active model window. Deep-merged across the three config file layers per provider/model key. Validated + schema + CONFIGURATION (en/zh) + devlog + 17 new tests (mutation-verified M1/M2/M3). 1053/1053 green.
Summary
Follow-up to PR #343 (issue #342): adds an optional per-model growth-nudge floor for mixed-model installations, where no single global
minNudgeContextPercentcan express the intended floors.Precedence (per the issue):
modelMinNudgeLimits[provider/model]minNudgeContextPercent× model context (PR fix: gate T1 growth nudges on minContextLimit (issue #342) #343 behavior, unchanged when the new field is unset)Absolute per-model floors apply even when the model context window is unknown (mirrors
modelMaxLimits/modelMinLimits); a per-model percent with unknown context falls through to the global percent (also unresolvable → growth-only).modelMinLimitskeeps its turn/iteration-reminder meaning — untouched.Changes
lib/messages/inject/utils.ts— newresolveMinNudgeFloorTokens(config, modelContextLimit, providerId, modelId)lib/messages/inject/inject.ts— floor resolved via the helper (provider/model from existinggetModelInfo)lib/config.ts—CompressConfig.modelMinNudgeLimits+ merge (??replace-inherited, same asmodelMinLimits) + deepClonelib/config-validation.ts— valid key, no dynamic-key recursion,validateModelLimitsreusedcp.schema.json,CONFIGURATION.md,README.md— documentedtests/inject.test.ts—userMsgWithModel()helper + 9issue #344:teststests/config-validation.test.ts— 4 new testsdevlog/2026-08-28_model-min-nudge-limits/— REQ.md + WORKLOG.mdTests
npm run test), typecheck + build green,scripts/ci/check-pr.shgreenlastPerMessageNudgeTokens/lastNudgeShownTokensside-effect assertions); per-model percent resolves against the per-model window (20% of 1,048,576 → 209,715); unlisted model keeps the global floor; unknown-context fallbacks (absolute applies, percent falls through); production config (preserveRecentMessages: 2); full growth cycle baseline → nudge → compress → new baseline → nudge; over-max bypass;modelMinLimitsindependenceNote on base
This branch is stacked on PR #343 (
2026-08-28_min-gate-growth-nudges) because the floor it extends (minNudgeFloorTokens/overMinNudgeFloor) only exists there. The diff against master therefore includes #343's commits until #343 merges; after that this PR's diff shrinks to the changes above. Merging #343 first is required (this PR is the follow-up, not a replacement).Compatibility
No behavior change when
modelMinNudgeLimitsis unset (global computation is PR #343's verbatim). No persisted-state ordcptag changes. No version bump (release handled separately).