Skip to content

[PR] merge: tier-5 train — dsh prepare/streaming domain (7 PRs: bili_final terminal marker, auto-fold storm gate, wire-only guard) - #4590

Merged
ranxianglei merged 9 commits into
masterfrom
2026-10-24_tier5-prepare-train
Oct 24, 2026
Merged

ranxianglei merged 9 commits into
masterfrom
2026-10-24_tier5-prepare-train

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

这是什么

第五列车:dsh prepare/流式域 7 个 PR 重放。合并方式请选 Merge commit。

车上清单

原 PR 修的 issue 重放要点
#3045 Closes #3013, Closes #3022 dsh 压缩拒绝终态化:bili_final 机器可读标记 + 风暴可见日志(每 100 次重浮)。文案适配 master 现契约:#3651 已移除 allowDshCompaction 开关,风暴日志里失效的开关指引已删
#3440 Closes #3433 增量车道 anthropic-wire-only 契约强制(wireMessagesLookAnthropic 守卫)
#3460 Closes #3444 auto-fold 折叠风暴:测量下限 + 收益门。floor 参数织入 master 的 nudgeOn 单门结构(4 个 prepare 的 growthFoldingArmed 三参化)
#3592 Closes #3587 原生 Pi compress 载体身份保持(reconcilePluginFoldCallIds)
#3880 Closes #3876 externalSummary 误放警告(与 #3635 caps 并集)
#3951 Refs #3011(C9) fork 收养跳过具名 + 重启自愈链接
#3954 Closes #3926 空 tool_calls 数组当缺席——修复本体 master 已由 #4466 落地,本车保留其 154 行回归钉

出车(被超越)

验证

关单

Closes #3013, Closes #3022, Closes #3433, Closes #3444, Closes #3587, Closes #3876, Closes #3926
Refs #3011

ranxianglei and others added 7 commits October 24, 2026 23:11
…ible logging (A1+A3)

Field report #3013: one session burned 5069 refused dsh compaction calls
(5038 retries, median 328ms, 0 outbound) while the user watched a stuck
'生成中'. Two halves:

A1 — the refusal body now carries bili_final:true (top level on both
protocol shapes; inside error on the openai envelope where retryable
lives). retryable:false did not stop the loop: dsh's retry pressure comes
from its own raw ledger (#2490), which nothing on bili's side can shrink,
so the same call fails identically forever. bili_final is the stable
machine-readable contract for dsh upstream to latch (consumption is a
cross-project follow-up). REFUSAL_MESSAGE now states the terminal
semantics and the levers (bili compress / #2474 recipe / #2028 opt-in;
dropped the stale web-UI mention deleted by #3042).

A3 — logging. Pipeline lane: after the once-warn, every 100th refusal
logs an info with the running count, the #2490 mechanism, and the levers
(previously: 5051 silent refusals, zero log lines, user blind).
Passthrough lane: was warn-per-refusal (the spam direction) — now warns
on the process's first refusal, then the same 1-per-100 cadence.

Tests: tests/issue3013-refusal-terminal.test.ts (A1 body shapes on both
protocols incl. error.bili_final; A3 storm cadence on both lanes via
setLogCapture with log:true rigs — request-scoped log is gated on
opts.log, log:false rigs made guard lines no-ops). Red-green proven.
Family regressions green (dsh guard/2028/2709/2658/2432/2451, claude
guard #2612, codex 2451, archives): 97 tests.

(cherry picked from commit 34b6c7e)
…turns path (#3433)

dsh-native's maybeIncrementalNative claimed 'anthropic wire only' but only checked messages-array + model-string, so OpenAI chat-completions bodies (assistant.tool_calls / role:"tool") were converted onto a lane that ingests with anthropicToCore: tool calls silently dropped, role:"tool" mis-mapped into user text, content:null bodies throwing mid-apply. pi/pi-native shared the same gap in the factory hook (pi serves openai/responses/google provider APIs).

- wire the existing wireMessagesLookAnthropic into the dsh-native and pi entry points (omp/opencode parity; restores the PLUGIN.md-documented contract)
- enforce the same predicate at the lane boundary: 400 for non-anthropic message shapes instead of trusting every host to pre-filter (mirror of the client helper, keep-in-sync marked)
- regression tests: dsh OpenAI shape rides full resend (+ anthropic control), pi OpenAI shape not replaced under a live lane (+ anthropic control), lane 400s role:"tool"/tool_calls and still accepts a valid seed afterwards

(cherry picked from commit 6f9956c)
…floor + benefit gate (#3444)

A configured autoFoldTargetTokens below the session's irreducible baseline (system prompt + tool schemas + live tail) could never be reached: the trigger re-fired on every request and burned a full external-summary round trip per request for ever-smaller slivers (reported saves down to ~685 tokens, each costing up to ~60s of chain latency).

Two complementary facets, same mechanism family (growth-fold economics):

1. Measured floor: an exhausted honest growth pass (folded everything foldable, no chain failure) whose rebuilt payload still sits at/above the target records the post-fold size as the session's irreducible floor (session metadata, latest measurement wins). The effective target is raised to max(configured, floor, MIN) capped at the window; a floor at/above the overflow bar disarms growth folding entirely and releases the nudge suppression (growthFoldingArmed gains a measuredFloor argument, threaded through all four prepare-* lanes).

2. Benefit gate: a growth fold only fires when the text channel exceeds the budget by at least AUTO_FOLD_MIN_BENEFIT_TOKENS (4096) of expected saving, and a pass that actually saves less than that arms the standard 10-minute backoff (#2662 queue-drop congestion exemption mirrored). Image-dominant overage keeps its original unconditional arm (images are not foldable). Classic overflow preflight (bar = window) is untouched.

Regression tests: two e2e lanes (sub-floor system-prompt baseline stops re-folding marginal growth; giant-live-tail sub-benefit pass arms the backoff) plus truth-table rows for the floor argument and an autoFoldFloor invalid-value unit test.

(cherry picked from commit e44c0d0)
… heals across a restart (#3925 -> #3011 C9)

Proxy-mode anonymous forks ('new session from here' with no session id) were
detected at the first request (prefix-affinity LCP >= 3, via='new',
reason='forked') but only fed into maybeAdoptForkBlocks — which bails silently
when forkAdoption is off (the default). No lineage metadata was recorded, so
neither the startup sweep (reconcileDerivedLineage iterates
derivedFromSessionId entries only) nor the read-time decompress/search_context
parent walk could ever recover the lost block state. The child replayed the
whole parent history (including the parent's compress tool calls), context
re-inflated, and search_context reported 'no compressed blocks'.

- record derivedFrom/derivedFromSessionId on every detected anonymous fork
  whose parent loads (memory or disk), before the outcome branches, and make
  it durable immediately (writeNow) like persistLineageLinkNow (#2986);
  a bili restart then lets the existing sweep inherit the parent's fully-
  present blocks, and read-time search/decompress fall back to the parent
  chain for free
- on the disabled bail, persist a forkAdoptionSkipped marker {parentId,
  blocks, tok} and upgrade the log to warn so the degradation is visible
- acp_status (no-scope views) prints one FORK ADOPTION SKIPPED line naming
  the parent, the block/tok counts and how to enable adoption; suppressed
  once the child has any active block; malformed markers are ignored
- success path sets derivedBlocksAdopted = true (#3351 discipline)

Behavior changes (old -> new):
- anon fork children: no persistent lineage -> persistent parent link even
  when adoption is off (enables restart healing + read-time fallback)
- bail log: info -> warn
- acp_status: gains the conditional warning line (additive display)
- success path: derivedBlocksAdopted now set (sweep skip already held via
  blocks > 0; marker keeps the gate consistent)

The forkAdoption default itself is deliberately untouched here — flipping it
is a product decision tracked in #3011.

Refs #3925, #3011, #3025

(cherry picked from commit 703f16d)
Gateways that stamp every chunk with `tool_calls: []` (WorkBuddy /
DeepSeek-family private deployments) routed all frames into the
tool-frame branch: text events lost their raw passthrough, round-1
forwarding in core.ts found nothing to emit, and the settle-time prose
rescue early-returned with pending empty — ALL round-1 text was silently
dropped while finish_reason/usage looked healthy.

Normalize an empty (or non-array) tool_calls field to absent at the
single classification point so such frames take the normal text path.
Non-empty arrays keep the tool-frame path unchanged.

Regression pins (tests/issue3926-empty-tool-calls.test.ts): adapter-level
exact-once round-1 text + no fabricated tool calls; gate negative row for
non-empty arrays; loop-level client-boundary end-to-end pin. Verified the
new tests fail on the unfixed code and pass on this one.

Fixes #3926

(cherry picked from commit d2e5321)
@ranxianglei ranxianglei changed the title merge: tier-5 train — dsh prepare/streaming domain (7 PRs: bili_final terminal marker, auto-fold storm gate, wire-only guard) [PR] merge: tier-5 train — dsh prepare/streaming domain (7 PRs: bili_final terminal marker, auto-fold storm gate, wire-only guard) Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-24_tier5-prepare-train (4d34abf)

Latest build — install this exact version

npm install -g [email protected]

This exact version is immutable and reproducible. The rolling pr tag tracks the newest test build across all PRs.

Recent builds (commit → version)

commit version build
4d34abf [email protected] build
f13411c [email protected] build

Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr4590.tgz
npm install -g package

Install instructions are refreshed on each push.

…cates the Set definition (master-red too, #3675 comment tripped indexOf), de-export 3 internal-only symbols, regenerate derived config docs
@ranxianglei
ranxianglei merged commit 146b34f into master Oct 24, 2026
44 of 55 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.827-master.146b34f (rolling master tag).

npm install -g [email protected]  # this exact build
npm install -g billion-context@master  # always the newest merged build

npm view billion-context@master prints the current version at any time.

This was referenced Oct 24, 2026
ranxianglei pushed a commit to z0d0dOr/billion-context that referenced this pull request Oct 24, 2026
…n-red from ranxianglei#4590)

ranxianglei#4590 (tier5-prepare-train, merged as 146b34f) added
tests/issue3890-parent-gone-confirm-drain.test.ts without registering it in
scripts/live-files.mjs, so the SPAWN_RE tripwire at the top of
scripts/run-ci-tests.mjs aborts every test shard at startup
("process-spawning test files missing from LIVE_FILES") before any test runs.
It surfaces on every PR head that rebases past 146b34f; master's own test
lanes were plan-skipped, so it never surfaced there.

Concurrency review before registering (ranxianglei#1248 discipline): the unit half only
imports the pure tickWatchedPid; the live half spawns ONE fixture child that
binds listen(0) and reports READY <port> on stdout, with isolated XDG dirs per
run — no fixed port, so its zone slot band stays inert. Appended (not inserted
mid-list) so no existing slot renumbers.

Verified locally by replicating the exact tripwire scan (existence check +
SPAWN_RE over all tests/*.test.ts): clean. Tracked in ranxianglei#4599.
ranxianglei pushed a commit that referenced this pull request Oct 24, 2026
…#4597)

Conflicts (2, both union-of-intent):
- src/web/page.ts: keep master's #3536 empty-favicon head change AND keep the full nav (overview/sessions/config/connect/logs/updates/blog). Note: master's #4590 line-rewrite silently dropped the #/updates nav link from page.ts while client.ts still routes #/updates — this merge keeps the link alive on this branch; the master-side loss is reported separately.
- CHANGELOG.md: keep both sides' Unreleased/Added entries (master's D5-5 + #4316 layer-3 PR3 blocks, then this PR's blog entry).
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.

[Bug][Pi] lost native compress call identity evicts active carriers and resurrects early summary anchors auto-fold sharp edges: a sub-floor autoFoldTargetTokens causes a fold storm, and externalSummary.* file edits do not take effect until a PUT /__bili/config [bug] dsh-native not wired to wireMessagesLookAnthropic: Enabling pluginIncrementalTurns on the OpenAI lane silently dro | [bug] dsh-native 未接入 wireMessagesLookAnthropic:OpenAI 车道启用 pluginIncrementalTurns 会静默丢弃 tool_calls / role:"tool" dsh 原生安装车道压缩所有权死锁:auto-compaction 恒 ARMED × 永久拒绝 × raw-ledger 压力 ⇒ 拒绝-重试无限循环(现场 5069 次空转) After the folded ledger was unanchored, rejections no longer take effect: all 5069 compaction/start attempts failed and no longer produce outbound (billion-context 0.1.187 → 0.1.195) | 折叠账本脱锚后拒绝不再生效:compaction/start 5069 次全部失败且不再产生 outbound(billion-conte…

2 participants