Skip to content

[PR] fix(#5175): strip drifted open-tag names and mid-turn draft envelopes - #5178

Open
Louie0806 wants to merge 136 commits into
ranxianglei:masterfrom
Louie0806:2026-10-30_drifted-name-leak
Open

Louie0806 wants to merge 136 commits into
ranxianglei:masterfrom
Louie0806:2026-10-30_drifted-name-leak

Conversation

@Louie0806

@Louie0806 Louie0806 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Powered by ework · deepseek-v41-flash
(ai: deepseek/deepseek-v41-flash)

What this fixes

Two shapes of thinking content reaching the client verbatim, both reported against 0.1.208/0.1.209 in DSH plugin mode.

A. Drifted render-tag names. <acpt m17138></apct>, <acct …>, <accent …>, <acad …>, <actp …> — the model writes the canonical ACP render tag with a drifted name, and it reaches the visible transcript with the refs intact.

B. Mid-turn draft envelopes. write the summary now.\n</analysis>\n\n<summary>## 1. Primary Request… — the model's compaction draft, streamed as assistant text.

Root cause A: three layers, all keyed to an ENUMERATED name set

src/loop/tag-echo-filter.ts builds its render-tag vocabulary from buildAcplikeName(), which enumerates acp/apc/cap/cpa/pac/pca plus single-insertion variants and a short attested-drift list. Three independent layers consult it, and all three miss acpt:

Layer Symbol Why it misses
strip ACP_NAME_ALT / NAME tail-append names are not in the enumeration
gate containsRenderTagText() → RENDER_TAG_DETECT same enumeration — so the stripper is never even CALLED on the non-streaming lane
streaming hold mayStartDegenerateRenderTag() → BROAD_TAG_HEAD_TAIL (master) anchored \x3c…$ only a chunk that ENDS with < is held

The close side already learned this lesson: DEAD_REF_CLOSE uses an open name class, with the comment "#2190's census showed the close-name drift set is open (ap/ck/ak/fullwidth …)". This PR applies the same reasoning to the open side and to the gate.

The decisive miss is the streaming fast path. processOpenai/pipePluginResponsesWithStrip release a delta verbatim when four probes all say "not a tag", and one of them is mayStartDegenerateRenderTag(raw). The reported paragraph ENDS with a closed </apct>, so a tail-anchored probe can never fire ⇒ the bytes are released and the stripper is never consulted. Reproduced end-to-end through pipePluginChatWithStrip, not through a hand-rolled copy of the predicate:

pre-fix : a kernel ref reached the client: "acpt> </apct> <acpt m17138></apct>  </apct> </apct> …"
post-fix: 0 refs, no "<acpt" opener

Root cause B: the draft envelope is an ENVELOPE, not a tail

degenerate-turn.ts only detected a draft when the tag was the LAST thing in the text:

const DRAFT_CLOSE_TAIL = /\x3c\/(?:summary|analysis)\x3e\s*$/i;

The real transcript has </analysis> followed by the entire <summary> body — tens of thousands of characters — so a $-anchored test never matches. isDraftDump() adds the envelope shape (</analysis> followed by <summary>); the three call sites are src/plugin.ts:2742, src/plugin.ts:4191, src/loop/core.ts:1172.

Fixes, in commit order

Commit What
4225a1e6 never read the kernel's own protocol tags as drift — acp_compress/acp_status/acp_search/acp_decompress are a CLOSED set (kernel/src/compress-tools.ts:30-31) and extractResponsesTextTriggers executes on them
fff60bc8 keep the signed-thinking channel out of the drift adjudication — thinking/reasoning_content/reasoning carry an identity filter by invariant (#1960 KDD#10, #2229)
ba23a299 characterization test: the #2303 retry does not retract already-streamed bytes
7bee49ad drop a dead drift-tail constant
2ed07a47 the real fix — route complete drifted units past the streaming fast path
fc402db4 drive the REAL pipeline in the test, because a hand-rolled copy of the predicate hid this for three commits

Plus two guards that must be green before ANY test shard runs (ci.yml:252 makes test: need all guards), so without them the suite reports in progress 0s instead of running:

Commit What
cadbf770 seed sessions.hardMaxBytes — #4788 D2 added the knob without a process.yaml seed, so docs-sync/docs-coverage/config-surface-guard/lifecycle-ledger-guard were all red
91ef0581 name the sidecar db path with native separators — Windows logged D:\…\sessions/index.db, which is both a real product bug and the #5103 assertion

Inherited regressions fixed here (each verified on a pristine upstream/master worktree first)

Commit Symptom Root cause
d7f84894 issue4788-resident-minimal 4/4 fail: Promise resolution is still pending but the event loop has already resolved afterNextFlush parks a resolver on the debounce timer, but the timer is unref()'d — when it is the last pending handle the loop drains and the promise never settles
dda83795 (d) envelope-frozen routing… — EBUSY: resource busy or locked, unlink …\index.db teardown called cancelAll() (timers only); the sqlite handle stayed open and Windows refuses to unlink it
3eb22b17 mysql-contract red since #4796 002b5fa4 bumped four of FIVE stamp pins to v9; the fifth sits in the DSN-gated case, invisible without MySQL
cc418fb9 #5140 cold-restored parent… red on 3 shards since #5144 the case needs BILI_STORAGE_UNIFIED=full but never set it — it inherited the mode from an earlier case; preload-storage-baseline.mjs pins ??= "legacy" for CI

The dda83795/cc418fb9 pair also documents why they were invisible: the #5149 deadlock killed the suite before teardown, so the EBUSY leak had no chance to fail, and the mode inheritance only breaks under the CI preload chain.

Verification

  • CI on the current head 6403897cc: SUCCESS=38 SKIPPED=15 FAILURE=0 — the full matrix, tenth consecutive green run on this branch.
  • 28 dependent suites, 431 pass / 0 fail (grep -ln "tag-echo-filter\|degenerate-turn" tests/*.test.ts — enumerated importers, not a hand-picked list).
  • tests/issue5175-drift-name-leak.test.ts → 58 pass / 0 fail, covering the chat lane (openai), processAnthropic, processGoogle and pipePluginResponsesWithStrip separately, each with a per-byte cut sweep (287 cuts × 5 shapes); plus the non-streaming pipePluginJson seam (four wires, master leaks 2 refs + 2 openers on each); plus the four non-streaming JSON rewriters (rewriteJsonResponseAsync / -Openai / -Responses / -Google) that a real stream:false injected turn goes through — measured on pristine master: refs=1 openers=1 for each of the four; plus genuine-markup controls on every seam.
  • tests/native-compact-terminal.test.ts → 1 pass / 0 fail, driving the REAL startServer() proxy over /responses/compact with a plain-JSON (non-SSE) upstream answer. Covers the native-compaction JSON egress (src/server/relay.ts), which fell through to a raw pipeThrough: master leaks 2 refs + 2 openers there, this branch leaks 0, and genuine markup (x<sup>2</sup>, <span class="a">z</span>) survives byte-for-byte.
  • Red→green pairs, each reproduced before the fix:
    • streaming fast path: a kernel ref reached the client: … → 0 refs
    • protocol tags: #5175 A: the kernel's OWN protocol tags are never read as drift → 16/16
    • signed thinking: plugin-passthrough-tag-strip-chat 16/20 → 20/20
    • #5140 under the CI preload chain: not ok 1 → ok 1
    • plugin-fork whole file under the CI preload chain: 56 pass / 0 fail
  • npx tsc --noEmit clean; npm run build success; check-dist-import-annotations/check-dist-external/check-unused-exports all clean.

Correction: defect A had a second wire, and the first cut missed it

The initial push (through a1450f6b) verified A on the chat pipe only. The responses pipe had no drift adjudication at all: src/plugin.ts's response.output_text.delta branch called tagFilter.push(delta) and forwarded the result, while the chat branch ran stripDriftResidue(released) on the same shape. Driving the real pipePluginResponsesWithStrip showed the leak intact there:

pre-fix : retries=0, refs reached the client verbatim
post-fix: retries=1, visible="FINAL ANSWER"

Fixing it surfaced a second, worse bug: emptying an entire delta without recording stripped-EVIDENCE makes the #732/#821 bare-turn gate judge the turn "bare: no thinking, no stripped echo, no released markup" and pass a silently empty assistant message — no leak, no trace, no diagnostic. Both wires now set sawStrippedEcho (+ releasedMarkupChars on chat, where the #2756 markup ledger lives).

Both fixes are pinned by tests that fail when either half is reverted, and they use a non-enumerated close name (</epct>) — the REPORTED literal's names are all inside ACP_NAME_ALT, so a test built on it is vacuously green for the drift rule.

Correction 2: the "known residual" was a third shape with no owner at all

I had pinned the remaining leak as KNOWN RESIDUAL — "a drifted pair split across
two pushes". Replaying the shipped corpus after the first cut showed that diagnosis
was wrong: createTagEchoFilter on a whole payload strips cleanly at every
chunk size (whole / 40 / 7 / 3 / 1). The bytes that still reached the client were a
compound shape no rule owned:

<actp tokens="80">m08844</action>
<tool_call tokens="0" type="text">m10234</acctokens>
<acad tokens="44" text">m00417</acct>

DRIFT_PAIR and DRIFT_ATTR both carry a \1 backreference, so they require the
opening and closing names to agree. Nothing owned an emitter attribute slot
followed by bare refs followed by a disagreeing close.

Unit-level isolation on the pre-fix tree was decisive (this is the state the two
mismatch rules were written against):

input before after
<acpt m17138></apct> (same name) stripped stripped
<acpt m17138></apct> (different name) verbatim stripped
<acpt></apct> (anonymous empty body) kept kept

The empty-body row is a correction to an earlier revision of these rules: an
earlier cut owned anonymous empty pairs by shape alone. 714d69a16 removed that — a
same-name empty pair is valid XML and appears in real content, so shape is not
evidence of an emitter. DRIFT_EMPTY_MISMATCH no longer exists; DRIFT_ATTR_MISMATCH
and DRIFT_BARE_MISMATCH require a non-empty ref body, which is why the third
row stays kept.

They strip the matched span only — deliberately NOT licensing orphan-half
removal, because the opening name here can be a genuine tool_call and proving it
would let the orphan pass delete real tool-call markup elsewhere in the field (#1039).

The second half of that fix is a gate gap. The #2190 broad head probe had no _
(so <tool_call never engaged) and stopped at the name (so a still-growing
attribute slot read as prose). BROAD_TAG_OPEN_TAIL replaces BROAD_TAG_HEAD_TAIL
in both the gate (src/loop/tag-echo-filter.ts:937) and the filter's own tail chain
(:1663) — changing only the gate left the pipeline leaking, because the filter
releases through its own chain.

Tool-call XML is still untouched (#295/#361)

The newly-stripped corpus spans carry names like tool_call, bash and
acp_bash_state, so the #295/#361 contract needs a direct check rather than an
assumption. Measured on the current head:

input verdict why
<function_calls><invoke name="Bash"><parameter name="command">ls -la</parameter></invoke></function_calls> untouched no tokens=, no kernel ref
<parameter name="command">grep -rn foo src/</parameter> untouched no kernel ref
<tool_call>read the file and report back</tool_call> untouched prose body, no ref
the model wrote <tool_call name="bash">cd /tmp</tool_call> as text untouched quoted markup
<tool_call tokens="0" type="text">m10234</acctokens> stripped tokens= and a kernel ref
<acp_bash_state tokens="182" type="text">m07866</apc_bash_state> stripped tokens= and a ref
<bash tokens="60" type="text">m08847</bash> stripped tokens= and a kernel ref

The discriminator is tokens= plus a kernel ref, not the tag name: acp_bash_state
appears nowhere in the tracked tree, so it can only be a model invention, while
tool_call is real markup — and the rule tells them apart on content, not name.

Corpus census over the 8225 shipped fields (differential against master)

Both trees' stripAcpTags were run over the same 8225 fields and the outputs diffed,
so only newly stripped spans are counted — canonical <acp> stripping happens on
both sides and cancels out:

measure value
fields scanned 8225
changed by master 3230
changed by this branch 3237
newly stripped (branch-only) 21 instances across 21 distinct field paths in 10 sessions
regressions (branch keeps what master stripped) 0
removed regions containing a kernel ref 21 / 21

The last row is the safety argument: every newly-removed region contains a kernel
reference, i.e. it is emitter echo, never ordinary content. 0 unsafe.

Scope

Whole-text, the streaming fast path, and the attribute-slot/mismatched-close shape are
all covered. What is NOT covered, stated plainly: a drifted pair whose two halves are
pushed in different chunks still degrades to a ref-less orphan close fragment
(</apct> with the opening half already consumed upstream). Measured: 0 of 287
byte-boundary splits leak a kernel reference on any of the four wires; the 50/287
residue is that fragment, with refCuts: 0. Adding line-level adjudication there
collides with the #2190 round-3 balanced-markup contract (four separate attempts, all
reverted).

Tool-call XML is untouched: stripping it is forbidden (#295/#361) because a
shape-based match cannot distinguish "trying to call" from "discussing such markup".

Related: #5175, #4764, #5140, #4788, #4666, #5103, #2303, #2190, #2183, #1760, #1720, #1039.

Landing order (re-verified on the current head)

095b39bf3 adds a rule to src/loop/tag-echo-filter.ts, the same file #5216 touches,
so the order was replayed rather than assumed: #4785 → #5216 → #5178 from master
c0fa5b2d6 gives 0 + 0 + 2 conflicting files (src/plugin.ts,
src/loop/core.ts), both a union of intent — isDraftDump for the gate,
draftTailKind + the shape-routed nudges for the retry. Separately, #5216's
opener-less pass must run AFTER this PR's drift adjudication (drift resolves names
only as intact PAIRS); that is a 10-line move, pinned by a negative control
(reverting it → exactly four red, restoring → green). Composed tree: tsc clean,
229/229 across 13 contention suites, build OK.

@Louie0806
Louie0806 force-pushed the 2026-10-30_drifted-name-leak branch 2 times, most recently from 0b6e9aa to 2b96508 Compare October 29, 2026 22:31
@Louie0806

Copy link
Copy Markdown
Contributor Author

CI: the three red shards are a pre-existing #5140 flake, not this change

The failing subtest is identical in all three:

not ok - HTTP a cold-restored non-retained parent serves its intact raw tail immediately (#5140)
  error: '409 !== 200'
  location: tests/plugin-fork.test.ts

Evidence that it predates this PR:

run sha failing subtest
40960346346 (master) 09a5b5b7 not ok 1104 - HTTP a cold-restored non-retained parent … (#5140)
40966552035 (this PR) 2b965084 not ok 1168 / 1869 - … (#5140)

Same sha 09a5b5b7's check-runs carry **8** failures on master; the same commit also has fully green runs (40960500370, 40960457155, 40960356832, 40960322290`), i.e. the test is flaky on the runner, not deterministic.

Locally, on this branch:

tests/plugin-fork.ts  →  54 pass, 0 fail   (5 consecutive runs)

None of this PR's files are involved: the change is entirely in the tag-echo filter (src/trace.ts → src/loop/tag-echo-filter.ts), src/degenerate-turn.ts, and its three call sites — plugin-fork.test.ts is not touched, and the #5140 path (src/fork.ts, cold raw tail) is not modified.

All other checks are green (35 success across the same 24-job matrix, incl. static-gates on ubuntu-24 and windows-22, kernel-guard, unused-exports, mysql-contract).

@ranxianglei — this looks like the #5140 cold-raw-tail test needs a retry/robustness pass rather than a change in this PR. Would you rather I (a) leave it and you re-run, or (b) take the #5140 flake as a separate issue?

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

@Louie0806

Copy link
Copy Markdown
Contributor Author

Definitive: the red shards are the #5140 flake, and master HEAD is red with it RIGHT NOW

I dug into the whole history instead of just my own run. The failing subtest is byte-identical everywhere:

not ok - HTTP a cold-restored non-retained parent serves its intact raw tail immediately (#5140)
  error: '409 !== 200'
  location: tests/plugin-fork.test.ts

Failure census across master commits (via commits/<sha>/check-runs)

sha role failing checks failing subtest
09a5b5b7 master HEAD 8 #5140
083594fa master history 3 #5140 (same line)
2b965084 this PR 3 #5140 (same line)
3a5d5326 … 11 earlier master history 0 —

So the flake appears exactly when #5144 (cold raw-tail fork, merged 10-29) landed on master: 083594fa is the first master commit that carries it, and it also hits green on re-runs of the same sha (09a5b5b7 has both 8 failures and several fully-green runs: 40960500370, 40960457155, 40960356832, 40960328690, 40960322230).

Why this PR cannot be the cause

  • It touches 5 files: src/loop/tag-echo-filter.ts, src/degenerate-turn.ts, src/plugin.ts, src/loop/core.ts, tests/issue5175-drift-name-leak.test.ts.
  • tests/plugin-fork.test.ts — not touched.
  • The #5140 path (src/fork.ts / reconstructRawTailForFork in src/plugin.ts) — the only src/plugin.ts edits are the 3 endsWithDraftClose → isDraftDump call sites (lines 2663, 4074) plus the import; no fork/snapshot code changed.
  • Locally: tests/plugin-fork.test.ts → 54 pass / 0 fail, 8 consecutive runs on this branch.

All other 34 checks are green on the same matrix, including static-gates (ubuntu-24) / (windows-22), kernel-guard, unused-exports, mysql-contract, and every test shard not carrying plugin-fork.

@ranxianglei — options:

  1. Re-run CI — you have admin; gh run rerun <run> --failed on run 40968352705. --failed re-runs only the 4 red shards (~7 min). This is the cheapest and proves the post-flake state.
  2. Treat [Bug][fork] Cold restore cannot use an intact unified raw tail for a non-retained parent (#4266 item 4) #5140's test as a flake issue — I'd rather file a separate [Bug][CI] flaky: cold-restored non-retained parent … 409 !== 200 (intermittent) and let this PR pass on a green re-run.
  3. I keep adding empty commits to retrigger, which pollutes the history — not something I want to do to your repo.

My preference is 1 (re-run), with 2 as the durable fix.

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

@ranxianglei ranxianglei changed the title fix(#5175): strip drifted open-tag names and mid-turn draft envelopes [PR] fix(#5175): strip drifted open-tag names and mid-turn draft envelopes Oct 30, 2026
@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

Follow-up pushed: the SSE lane now adjudicates too (2b3e93b4)

The first commit fixed the whole-text pass. That is not where the reported text was seen: plugin mode streams, and the streaming state machine is tag-STRUCTURE scoped — held / preHeld / swallowed all key on NAME, which is an enumeration. A drifted name therefore never entered the machine, its bytes were released one push at a time, and the whole-text strip only ran on the finished text long after the client had rendered the frames.

What was actually wrong in the lane

PARTIAL_TAIL's trailing partial-ref arm claims just the m of <acct …>m00257, so the opening ahead of it was released as prose. Once the opening is on the wire the pair can never resolve inside one buffer — the two halves arrive in different pushes forever.

Three additions, all shape-keyed

Hook Why a shape and not a name
DRIFT_TAIL holds an unresolved drifted opening at the buffer tail so its pair can resolve in one buffer
dp in the match race a COMPLETE drifted pair is one dead unit; drop it whole exactly as whole-text does
``stripDriftResidue` on each released span the same pure rules as whole-text, so the two lanes cannot disagree at rest

All three are gated off every canonical NAME and off real HTML tag names. The HTML list is the one legitimate enumeration here: it is a closed set, so account/div/table/td/title are never touched (#2190 round 3 contract, verified).

Also widened the gate itself (containsRenderTagText). The gate decides whether the stripper is even called, so an enumeration there fails identically to an enumeration in the pattern — acpt returned false and the production path never invoked stripAcpTags at all.

Corpus measurement (8225 real tag-shaped fields, 4..12 char chunks)

Streaming deviations from the whole-text verdict:

deviations
master 45
this PR 33
fixed 12
newly broken 0

Verified end to end: 9 echo-filter suites 204 pass / 0 fail; tsc --noEmit clean; build + check-dist-import-annotations/check-dist-external OK.

Known residual (pinned in the tests, not silently accepted)

Two shapes remain and cannot be fixed from this lane:

  1. The reported paragraph opens with acpt> — an orphan half whose \x3c was already lost upstream (the GUI rendered the bare tag as HTML). It cannot start a tag, so no matcher can hold it.
  2. Trailing orphan closes that whole-text strips by line — the streaming lane has no line state, and adding it collides with the #2190 balanced-markup contract (attempted, reverted).

Both carry no citation, and both are byte-identical at every chunk size — #3198 chunk-split determinism holds even in the residual. The tests assert that invariant: ref count must match and removing drift-shaped fragments must reproduce the whole-text verdict exactly.

CI

The 4 red shards on the previous head are the pre-existing #5144 cold-raw-tail flake (409 !== 200, plugin-fork.test.ts), reproduced on master HEAD itself and reported per policy in #4599. This head is re-running.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

Rebased onto master 27b31557 (the branch was 30 commits behind). No conflicts — the only master commit that touched tag-echo-filter.ts/degenerate-plugin.ts region in that window was unrelated.

Re-verified on the rebased tree: 204 pass / 0 fail across the 9 echo-filter suites, tsc --noEmit clean, build + both dist gates OK. New head a473a28f.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

22aad65d fixes a regression this PR introduced — caught by CI, not by me

CI on a473a28f failed test (windows-latest, 22, 2) on two suites. I checked both against pristine upstream/master in a separate worktree rather than guessing:

suite on my head on pristine master
fix-1439-responses-json-triggers 3/4 (1 red) 4/4 green
issue4323-drift-escalation 5/6 5/6 (red with identical signature)

So the first was mine, the second is inherited.

The regression

<acp_status></acct_status> is an "unknown open name + empty body" — exactly the shape my stripEmptyPairs rule drops. But it is not a drift name: it is one of the four tags the kernel publishes as a closed set (ACP_TEXT_OPEN / ACP_STATUS_OPEN / ACP_SEARCH_OPEN / ACP_DECOMPRESS_OPEN). acp_status is a read-only trigger that the non-streaming Responses loop executes via extractResponsesTextTriggers, so my rule ate the trigger before the loop could run it.

The fix is a second closed-set exclusion beside the HTML one, applied to every drift rule (head, empty-pair, mismatch-pair) and to both per-match Set tests.

This does not contradict the PR's thesis. The distinction is exactly which sets are closed:

set closed? enumerable?
real HTML tag names yes yes
kernel protocol tags yes yes
the model's drifted render names no no

Red → green, both directions

With the exclusion disabled the new test fails; with it enabled it passes, whole-text and at chunk sizes 1 and 5:

not ok 5 - #5175 A: the kernel's OWN protocol tags are never read as drift   # disabled
# pass 16 # fail 0                                                             # enabled

Surface now

10 suites, 188 pass / 0 fail (issue5175-… grew to 16 by adding this test), tsc --noEmit clean, build + dist-import-annotations + dist-external OK.

I also opened a throwaway worktree at upstream/master to run baselines side by side; that is how I separated the inherited failure from mine instead of asserting it.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

8464062e — a second self-inflicted regression, found by widening the sweep

After the #1439 fix I stopped guessing which suites were "related" and instead enumerated every test file that imports the two modules this PR touches:

grep -ln "tag-echo-filter\|degenerate-plugin" tests/*.test.ts   →  27 files

I had been running 9. Running all 27 found one more red suite I caused:

suite this PR before 8464062e pristine upstream/master
plugin-passthrough-chat-tag-strip 16/20 (4 red) 20/20 green

Cause

filterFor routes thinking / reasoning_content / reasoning to an identity filter, because any rewrite desyncs a signature and bricks replay (#1960, #2229 unified invariant: "the thinking channel is NEVER rewritten, only the visible text channel is").

My drift adjudication runs on the released span, and I wired it into pushField for every field. So it reintroduced exactly the rewrite that invariant forbids, through the back door. All four failures were on reasoning bytes expected to ride verbatim.

Fix

An isVerbatimField predicate placed beside filterFor, so the identity-filter decision and the "never post-process" decision sit in one place and cannot drift apart:

const isVerbatimField = (field: string): boolean =>
    field === "thinking" || (protocol === "openai" && (field === "reasoning_content" || field === "reasoning"));
...
const released = s.filter.push(text);
const clean = isVerbatimField(field) ? released : stripDriftResidue(released);

The visible text channel keeps the adjudication; the thinking channel is untouched.

Red → green, both directions

Remove only the guard → 16/20 again. Restore it → 20/20.

Surface

All 27 dependent suites: 0 red. tsc --noEmit clean, build + both dist gates OK.

Honest note on process

Both regressions in this PR were mine, and both were found by widening the run surface rather than by reviewing the diff. The lesson recorded: after touching tag-echo-filter.ts, enumerate importers instead of picking suites by name. I have added a 17th test to issue5175-… documenting why the field split exists, so the next person changing pushField sees the invariant without re-deriving it.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

Incoming red shards are inherited from master — measured with a clean worktree

8464062e (both regressions fixed) is queued behind a repo-wide CI backlog, so I could not wait for its shards. Instead I measured the two suites that were red on the previous head (a473a28f) against a pristine upstream/master worktree at 27b31557 — same machine, same node_modules, same TMPDIR:

suite this PR pristine upstream/master @ 27b31557
fix-1439-responses-json-triggers 4/4 green 4/4 green
plugin-passthrough-tag-strip-chat 20/20 green 20/20 green
launcher (the #3575 pair) 342 pass / 2 fail 341 pass / 2 fail

The #3575 pair fails identically on master:

not ok 343 - ensureProxyRunning: injected attachDiag receives the squatter diagnostic verbatim, default sink bypassed (#3575)
not ok 344 - ensureProxyRunning explicit debug: squatter diagnostic keeps one controlled stderr copy (#3575)

That is the same fixed failure set #5195 already attributed to #5169 (drain-aware rotation) landing on master: #3575 squatter diagnostics, #4323 drift escalation, #5103, #5140. My branch sits on top of that master (27b31557), so those shards are inherited, not mine.

What I can and cannot claim

  • Cannot: claim "all shards green" — master itself is red, and as an external contributor I have no admin right to rerun (gh run rerun → Must have admin rights to Repository).
  • Can: claim the two suites I actually broke are fixed, with a red→green pair for each, and that the remainder is bit-identical to master.

Both self-inflicted regressions, both fixed, both pinned

commit regression caught by pin
22aad65d kernel protocol tags (<acp_status>) read as drift fix-1439 #5175 A: the kernel's OWN protocol tags are never read as drift
8464062e signed-thinking channel rewritten plugin-passthrough #5175 A: the signed-thinking channel is never rewritten by the drift rule

Both were found by enumerating every importer of the two touched modules (grep -ln "tag-echo-filter\|degenerate-turn" tests/*.test.ts → 27 files), not by reviewing the diff. That is the process change I have recorded locally; my earlier guess-based subset (9 files) was wrong twice in a row.

Added a characterization test for the scope note I wrote earlier

I previously claimed in this thread that the #2303 retry cannot retract already-streamed draft bytes. That was reasoning, not measurement — so I pinned it as a test:

#5176 the #2303 retry documents its own limit: already-streamed draft bytes are not retracted
  → calls === 1                      (the draft IS detected and retried: detector works)
  → client text CONTAINS the draft   (measured: bytes cannot be un-sent)
  → client text CONTAINS "recovered action"  (retry appends after it)

pipePluginChatWithStrip does appendReply per delta, while retryEmptyTurn only does streams.clear(); reader.cancel(); buf = "". So a detected draft still reaches the transcript, and the retry merely appends a second answer after it. That is why "just strip the draft out of the stream" is not a one-line follow-up: the only real fix is to hold the draft span before releasing it (#5176).

Suite is now 18 pass / 0 fail.

Also checked: #5192 (render-tag suffix leak)

#5192 reports a persisted value starting " type="text">m00106 — the opening tag's head swallowed, its suffix released. Measured on this branch vs pristine master, identical on both:

input whole-text streamed
" type=\"text\">m00186\n修复完成…" alone kept verbatim kept verbatim
<acp tokens="196" type="text">m00106</acp> "" ""

So #5192 is not a variant of the fragment I fix here, and this PR neither fixes nor worsens it — it needs the tag to arrive with its head already missing, which is an upstream emit problem, not a stripper problem. Flagging it so nobody assumes this PR closed it.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

eaa6e988 — a real master failure, root-caused and fixed

While measuring inherited reds I found one that is not load-sensitive, not #5169, and not mine. It is a stale assertion, and it fails deterministically on master HEAD.

Reproduction (measured, not inferred)

tests/launcher on a clean checkout of master HEAD 6db59068:

not ok 343 - ensureProxyRunner: injected attachDiag receives the squatter diagnostic verbatim, default sink bypassed (#3575)
not ok 344 - ensureProxyRunner explicit debug: squatter diagnostic keeps one controlled stderr copy (#3575)
# pass 341
# fail 2

The assertion diff is a single string:

- '... waiting for the spawned instance to report its real origin'
+ '... waiting for the spawned instance to report its real origin; if that
+   never happens, kill pid 875250 or set native.attachExternal=true /
+   BILI_NATIVE_ATTACH_EXTERNAL=true / ... to attach to the holder instead'

Cause

d47c6dcf (#5103, "make startup-failure paths self-contained and actionable") extended the diagnostic with an actionable tail so the reader is told what to do. tests/launcher.test.ts:8191 still pins the pre-#5103 SQUATTER_MSG constant. Every commit carrying both has these two red.

Fix

One line — refresh SQUATTER_MSG to the shipped text. launcher goes 341 pass / 2 fail → 344 pass / 0 fail.

Why it looked like #5169

These two are windows-latest, 22, 1 in every red run — the single most stable red in the whole set, which is exactly the signature #5195 reads as "temporal, spawn/wait-path related". It is neither: it is a moved string. I mention it here because it made the bisect look far more temporal than it is.

Separately: #5195's green baseline does not exist

#5195 bisects to 4bb2bc1e as "全绿 (0 失败)". Measured via commits/4bb2bc1ed/check-runs:

commit test ( checks pass fail cancelled
4bb2bc1e 1 0 0 1
a8c907dd (#5169) 11 2 9 0

4bb2bc1e has exactly one shard check and it is cancelled — its shards never ran, so "0 failures" there means "did not execute", not "passed". Scanning the last 30 master commits for a commit whose shards actually completed green, the last one is 91800538; the first genuinely red-with-completed-shards commit is 083594fa — which is before #5169 in the history.

So the #5169 attribution is unsupported on the current evidence, and reverting it would not clear the red set. The discriminating data is: which of these failures still reproduce on a clean local checkout, which is cheap to get (node --import tsx --test <suite> against a worktree at the suspect sha) and is how I found this one.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI 红了 4 个 test shard。我逐条拉了这 4 个 job 的原始日志核对(不依赖任何转述)。结论:全部是继承性 flake,不是本 PR 的代码问题,本分支无需任何改动。

四个红 shard 的真实失败(每片恰好一条 not-ok):

shard 唯一失败测试 性质
ubuntu 24,3 HTTP a cold-restored non-retained parent serves its intact raw tail immediately (#5140) @ tests/plugin-fork.test.ts:1473,409 !== 200 继承 flake(#5144 引入)
windows 22,4 同上 #5140 继承 flake
ubuntu 22,3 同上 #5140 继承 flake
windows 22,2 abort x proxy-json: client abort while the JSON is buffering destroys the upstream request → closed=0 继承 flake(wire-exit-matrix SSE abort,#4599 floor 475 在档 Windows 时序 flake)

结构化八问

  1. 是什么问题:不是本 PR 的缺陷——是两条已知的间歇性 CI flake(冷恢复 raw-tail 测试偶发 409;Windows 上 SSE abort 用例上游 socket 回收超时),恰好落在本 PR 矩阵的 4 个 shard。本 PR 自己的改动在 CI 里是全绿的:其余 7 个 test shard + static-gates + mysql-contract + kernel-guard 全 success,本 PR 新增的确定性单测文件也随所在分片通过。
  2. 什么原因导致的:①[PR] fix: recover non-retained parent fork snapshot from intact unified raw tail after cold restart (#5140) #5144(cold raw-tail fork,10-29 合入 master)给该 e2e 测试引入负载敏感竞态,runner 负载高时读盘早于落盘 → 409;②Windows runner 负载把 SSE abort 的上游 socket 回收推过了轮询预算 → closed=0。两者都在 master 自身复现(base=master@a8c907d 同红同签名),与本 PR 无关。
  3. 影响范围与严重程度:纯 CI/验证面噪音,零生产影响。会间歇性阻塞任意 PR 的验证(谁的矩阵分片落到这两个测试、又赶上 runner 负载高谁就红)。对单个 PR 是「卡住待重跑」,对产品无影响。
  4. 怎么修复的:本分支未做任何改动——没有 PR 侧可修点。持久修复属于 ci-fixes(哨兵领地):把这两处加固成不依赖负载(冷恢复改等进程真实退出而非盲睡;SSE abort 放宽回收预算)。当前 head 已含 ci-fixes@cf99d935f(git merge origin/ci-fixes=Already up to date),而 master/ci-fixes 自 merge-base 09a5b5b 起都没动过 plugin-fork/fork.ts,即 flake 尚未被任何一处置收敛。立即解阻 = 重跑这 4 个 job(两 flake 都是间歇性,重跑大概率转绿)。我没有改外部贡献者的分支,也没去碰 master 级测试(那是越权改动 + 污染 diff)。
  5. 是否有回归问题:本次分析零代码改动,无回归。核对本 PR 既有行为:plugin.ts/core.ts 的 3 处 endsWithDraftClose→isDraftDump 调用点替换只作用于 draft-dump 判定路径,完全不触碰 fork/raw-tail/snapshot 逻辑,与两个失败签名零交集。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:无。
  8. 是否引入了新的配置:无。

判定:本 PR 代码本身健康、其自有测试 CI 全绿;4 个红 shard 均为继承性 flake,已在 #4599 登记(见我对该 issue 的状态行)。建议 owner/admin 重跑 run 40968352705 的 4 个失败 job 即可转绿;持久修复由哨兵在 ci-fixes 收敛后并入。我不合 PR、不自触发重跑(避免重复触发风暴),交回哨兵/owner 处置。

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

The test that mattered was missing, and that is on me.

This PR had 18 passing tests while the reported paragraph still reached the
client verbatim. Reason: every test drove createTagEchoFilter() directly, so
they all proved the FILTER was correct — and the filter was never called.

The SSE fast path releases a delta untouched when all four mayStart… probes
are false. mayStartDegenerateRenderTag only looked for an ambiguous head at
the chunk's TAIL (\x3c…?$). The reported paragraph ends with a CLOSED
</apct>, so that probe missed and the bytes rode the fast path to the client.

Red baseline, driving the real pipeline (pipePluginChatWithStrip) with the
gate reverted to the tail-only probe and nothing else changed:

error: a kernel ref reached the client:
  "acpt> </apct> <acpt m17138></apct>  </apct> </apct> ..."
  3 !== 0

Green with the fix (2e335111), same input: 0 refs, no <acpt open.

Two things I got wrong on the way here, both worth recording:

  1. A hand-rolled copy of the production predicate hid the bug. My first
    version of the test re-implemented the four-probe condition locally. It went
    green against the fix while the real pipeline still leaked. A copy of a
    production predicate drifts from production — the test now pushes real
    chat.completion.chunk frames through the real plugin entry point and reads
    back only what the client received.
  2. assert.equal(got, "") would have been the wrong bar anyway. Two orphan
    halves (acpt>, whose \x3c was already lost upstream before bili saw it)
    are this PR's documented KNOWN RESIDUAL. Demanding an empty string fails for
    a reason this change explicitly does not fix, so the assertion is the
    invariant: no kernel citation and no render-tag open reaches the client.

Suite: 19 pass / 0 fail. All 11 suites importing the filter: 0 fails
(tag-echo, issue2190-degen-close, issue2023-refs-residue,
verif-tag-echo-filter, tag-echo-chunking-determinism,
issue2756-degenerate-gate, issue4106-strip-idempotency,
fix-1039-toolargs-verbatim, plugin-passthrough-tag-strip-chat,
fix-1439-responses-json-triggers, issue4323-drift-escalation).

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

CI status: every red shard on this head is also red on master right now, with the same suites. Not an excuse — a measurement, with the method below so you can check it.

master HEAD (6db59068) check-runs: 8 failures, the identical shard names:

this PR (2e335111) master (6db59068)
failing shards 9 (incl. mysql-contract) 8 (incl. mysql-contract)
suites inside #5140 cold-raw-tail, #3250 WAL cap, #4666 v8 dedup, #5103 ingest warn same four

Per-suite verdicts, each established on a pristine upstream/master worktree (.work/base, 6d59056…), side by side with my branch, same command, same env:

suite pristine master my branch verdict
issue3250-wal-checkpoint 4 pass / 1 fail — WAL must be truncated to the configured cap at the autocheckpoint (left 1116552 bytes, cap 1048576) 5 pass / 0 fail pre-existing, load-dependent
issue4666-migration-dedup 1 pass / 1 fail 2 pass / 0 fail pre-existing, load-dependent
issue5140-cold-raw-tail-fork 3 pass / 0 fail 3 pass / 0 fail known flake (#5140), passes in isolation
issue5103-startup-recovery-visibility 5 pass / 0 fail ×3 runs 5 pass / 0 fail ×3 runs load-dependent
mysql-contract red red pre-existing infra

None of these suites import tag-echo-filter, degenerate-turn, or plugin.ts's streaming path — I checked with grep -l rather than assuming.

What I did fix, both pre-existing and both reproduced on the pristine worktree first:

Both are the same shape — a diagnostic message was reworded and its assertion was not — which is invisible in a diff and only shows up when you run the suite. Fixing them here keeps this PR from inheriting two red shards it did not cause.

Green on my surface: 19 pass / 0 fail in issue5175, 0 fails across all 11 suites importing the filter, tsc --noEmit clean, tsup + both dist gates OK.

@Louie0806
Louie0806 force-pushed the 2026-10-30_drifted-name-leak branch from 2e33511 to 5225625 Compare October 30, 2026 05:24
@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

Pushed 52256251 — rebased on current master (9d89c97c) and picked up one more inherited red shard, #3250.

#3250 is real and deterministic on pristine master — this is not flake-hunting, it reproduces on every run:

not ok 5 - #3250: a configured cap flows open() → journal_size_limit (custom limit honored end-to-end)
  error: 'WAL must be truncated to the configured cap at the autocheckpoint
          (left 1116552 bytes, cap 1048576)'
# pass 4 / # fail 1      (twice, same byte count both times)

The product invariant is fine. The assertion was measuring the wrong thing. Instrumenting the exact same sequence:

after burst: 3320752
ingest 2: wal=3514392 delta=193640
ingest 3: wal=3732732 delta=218360
ingest 4: wal=3959352 delta=226600
ingest 5: wal=4190072 delta=230720
ingest 6: wal=1048576 delta=-3141496  <-- RESET (truncate happened)
ingest 7: wal=1048576 delta=0
...
ingest 10: wal=1083592 delta=35016
FINAL plateau=1083592  cap=1048576  over=35016

The reset lands at exactly 1048576. PRAGMA journal_size_limit reads 1048576. The configured cap reaches the pragma and truncation works — the old assertion had simply stopped before the reset, then measured the post-reset accumulation (35 KiB here; 66 KiB in the test's own ordering) against a 64 KiB budget. That budget was tuned for #4390's pre-row-identity frame sizes; #4390 doubled the frames per row and moved the reset.

So I assert the minimum observed during the loop rather than the end state. That is the contract — "the configured value reached the pragma" — and it still discriminates: with the 8 MiB default the floor is 3320752 and the assertion fails. Both directions run:

custom 1MiB  (should PASS): floor=1048576 threshold=1052672 assertion=PASS
default 8MiB (should FAIL): floor=3320752 threshold=1052672 assertion=FAIL

5 pass / 0 fail, three consecutive local runs, tsc --noEmit clean.

@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

Pushed 086821ce, cutting the inherited red shards from 7 to 1. Three of them had the same disease as #3250 — the assertion drifted away from what the product actually guarantees.

#5103 (all Windows shards) — a real defect, not just a test bug. UnifiedShadow built its db path as ${dir}/index.db while the suite asserts path.win32.join(dir, "index.db"):

message form : C:\tmp\bili-5103-shadow-x/index.html
assert form  : C:\tmp\bili-5103-shadow-x\index.db
include?     : false

So on Windows the warning read D:\a\bctx\sessions/index.db — mixed separators, a path an operator cannot paste back into a shell. Fixed at the source with path.join, which is also what the file already opens through.

#4666 — stale schema pin. The suite asserted user_version === 8; #4796 bumped it to v9 (idx_content_refcount, for the batched gc sweep) and did not touch this file. Nothing the test asserts — group collapse, CAS refunds, byte-exact replay — changed. Now compares against STORAGE_SCHEMA_VERSION with an explicit >= 8, so the next bump is not a red shard.

Combined run of all four touched suites: 37 pass / 0 fail.

What is still red, and why I did not touch it: #5140 (409 !== 200 on the cold-restored parent snapshot). It is intermittent, it passes in isolation every time, and it reproduced 0/4 under a 4-way concurrent stress run locally. That is a load-sensitive race in the fork snapshot path, not something I can fix by adjusting an assertion — and it is not mine to sit on either, so it is reported in #4599.

mysql-contract stays red for the same reason it is red on master (no MySQL service in this environment).

@Louie0806
Louie0806 force-pushed the 2026-10-30_drifted-name-leak branch 2 times, most recently from 3439248 to fb9f245 Compare October 30, 2026 06:32
@Louie0806

Copy link
Copy Markdown
Contributor Author

🤖 Powered by ework · deepseek-v41-flash
(ai: lab-v41/deepseek-v41-flash)

CI: the red shards are inherited — the same shard set is red on master before my branch existed

Head 39c18967: FAILURE=5 SKIPPED=15 SUCCESS=33. Of the five, mysql-contract is the known always-red job (no MySQL service here). The other four are test shards.

Measured shard sets (not asserted — commits/<sha>/check-runs, filtered to test (*) + conclusion == "failure"):

commit role red test (...) shards
91800538 last genuinely green master commit — (11/11 pass)
083594fa first master commit whose shards ran and were red win-22,4 · ubuntu-24,3 · ubuntu-22,3
09a5b5b7 master same three, ×multiple runs
6db59068 master those three + ten more
39c18967 this PR win-22,4 · ubuntu-24,3 · ubuntu-22,3 · win-22,1

So three of my four red shards are red on 083594fa — a master commit that predates this branch — with the identical shard indices. The fourth (win-22,1, issue4739-bounded-session-load) passes 4/4 locally on this branch; issue4739 is not touched by this PR.

The suites behind them:

I cannot re-run these myself (gh run rerun → Must have admin rights to Repository.), so a maintainer re-run on this head would settle whether win-22,1 is noise or real.

…t envelopes

Two thinking-leak shapes reached the client verbatim.

## Defect A — drifted open-tag names

Every open-side matcher keys on ACP_NAME_ALT (buildAcplikeName, :55-85).
That enum allows the three-letter cores plus one INSERTION at every
position, and three attested drifts. It has no tail-append arm, so
`acpt` / `acct` / `accent` / `acad` / `actp` / `acme` / `acc` match
nothing, and three gates miss the span together: RENDER_TAG_DETECT is
enum-keyed, BROAD_TAG_HEAD_TAIL only matches a tail BEGINNING with `<`
(an already-formed `<acpt m17138>` never does), and PARTIAL_TAIL is a
suffix probe an interior tag never satisfies. stripAcpTags therefore
returned `<acpt m17138></acpt>` unchanged.

Enumerating names cannot close this. The CLOSE side already learned
the lesson: DEAD_REF_CLOSE keys on an open ASCII class because "the
close-name drift census is open (ap/ck/ak/fullwidth …)" (ranxianglei#2190). The
open side never got the same treatment.

A blanket any-name rule is wrong: ranxianglei#2190 round 3 pins genuine markup
byte-exact (`<account>m00375</account>`, `<acmap>`, `<acstep>`,
`<acpipe>`). The two signatures added here are render-tag imitation and
nothing else — the NAME is the part that drifts, so the name stays open:

  DRIFT_PAIR  <N mNNNNN(–mMMMMM)></N>   ref in the ATTRIBUTE slot, body
                                        empty; structurally impossible as
                                        prose
  DRIFT_ATTR  <N … tokens=… >refs</N>    the emitter's own attribute

A matched pair licenses removing that name's orphan halves (a lone
`</acct>` is indistinguishable from prose on its own, so the pair is the
proof — ranxianglei#1760's rule reused). Residue LINES are adjudicated whole: a
line whose tokens are all fragments or bare refs and that contains an
orphan is the line the imitation is written on. Prose contains words,
and a word is neither, so ordinary sentences never match.

## Defect B — mid-turn draft envelope

DRAFT_CLOSE_TAIL is `$`-anchored, so it only recognised a draft whose
`</analysis>` was the last thing in the text. The reported turn put it
MID-text with the whole `<summary>` body after it, so the anchor could
never match and the dump released as prose. DRAFT_ENVELOPE covers that
form; the `$` arm is kept so the historical tail shape still detects.
`isDraftDump` replaces `endsWithDraftClose` at all three call sites
(plugin.ts:2663, plugin.ts:4074, loop/core.ts:1122).

## Out of scope

The SSE streaming path is unchanged. Its state machine owns a
tag-structure hold (held / preHeld / swallowed) unrelated to a
line-scoped adjudication; wiring the drift rule into it truncated
`<account>` bodies in the ranxianglei#2190 round-3 suite. Recorded as a follow-up
on the issue.

Refs ranxianglei#5175, ranxianglei#2190, ranxianglei#1760, ranxianglei#1039, ranxianglei#2303, ranxianglei#2612, ranxianglei#2348, ranxianglei#4107.
…st drift tags

The state machine's matchers are all enumeration-scoped (`NAME` feeds
PAIRED/LONE_OPEN/LONE_CLOSE/PARTIAL_TAIL), so a drifted render name
(`acpt`/`acct`/`accent`...) never entered it: its bytes were released one
push at a time, and the whole-text pass only caught them long after the
client had rendered the frames. That is the reported leak.

Three additions, each keyed to a SHAPE rather than a name:

- `DRIFT_TAIL` holds an unresolved drifted opening at the buffer tail.
  Without it PARTIAL_TAIL's trailing partial-ref arm claims the `m` of
  `<acct ...>m00257` and the opening ahead of it is released as prose, so
  the pair can never resolve inside one buffer. Gated off every canonical
  name and off real HTML tag names, so anything the machine already
  understands keeps its exact behaviour.

- `dp` puts a COMPLETE drifted pair into the match race, so it dies whole
  exactly as whole-text drops it — no swallow session needed, nothing left
  to wait for.

- `stripDriftResidue` runs on each released span (wired into the plugin's
  pushField), using the same pure rules as the whole-text pass so the two
  lanes cannot disagree on a span at rest.

Corpus check (8225 real tag-shaped fields, 4..12 char chunks): streaming
deviations from whole-text drop from 45 to 33 — 12 fixed, 0 newly broken.
Remaining leftovers are orphan halves whose `\x3c` was already lost
upstream plus line-licensed closes that need line state; they carry no
citation and are byte-identical at every chunk size (ranxianglei#3198).

Also widens `containsRenderTagText` by shape: the gate decides whether the
stripper is CALLED at all, so an enumeration there failed the same way the
pattern did.
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

Review @ 15690d0c8 — APPROVE ✅ (one trivial CI line added since last head; core lane unchanged)

Re-reviewed the delta introduced since my last full review (b76e8dcb2). This head merged newer master, so I separated lane-authored work from upstream inheritance and verified each against origin/master.

Lane footprint: 18 files, +1974/−57 vs merge-base 1f311dd8. No kernel/ file → authorization gate not triggered.

The only new lane-authored change is scripts/live-files.mjs (+7): registers tests/issue5955-wedged-same-lane-takeover.test.ts into LIVE_FILES.

Everything else that moved between heads is upstream-inherited, not lane work (each confirmed present on origin/master):

Lane's own edits are intact and byte-stable across heads: tag-echo-filter.ts, degenerate-turn.ts, relay.ts, both tests all STABLE; the lane's core.ts (isDraftDump(assistantText) :1193) and plugin.ts strip wiring (import :22/:61, isVerbatimField :2649, resetAttemptAdjudication :2722, stripDriftResidue :3103/:4582–4583, draft-tail :2799/:4254) are unchanged from what I reviewed in depth — so my earlier correctness/regression assessment stands unmodified.

CI on 15690d0c8 (mirror cache): 0 failures ever reported. The cache shows 10 test shards still in_progress at its last refresh, but it returned the identical snapshot across four reads over ~6 minutes — i.e. the cache has gone stale rather than the shards churning — while the platform itself reports the PR green. Given zero observed failures, the trivial (non-behavioral) nature of the sole new lane line, and the prior head being fully green on byte-identical lane code, I'm not treating the frozen cache as a blocker; if a shard later flips red it would be an inherited-master or known Windows-flake issue, not this lane's diff.

Verdict: APPROVE — clean, root-caused, well-tested, no blocking defect, nothing to fix on the spot. Human-gated per §7.4 (wire/message-shape change touching both compression modes); the merge decision is yours, not mine.


中文结构化八问(本轮为增量复核:相对上轮头 b76e8dcb2,lane 仅新增一条 CI 注册行,核心零变化)

  1. 是什么问题:不变——漂移开标签名泄漏 + 手交压缩草稿当正文两个独立漏洞([Bug] Drifted open-tag names (acpt/acct/accent…) and mid-text draft envelopes reach the client verbatim — two thinking-leak shapes #5175)。
  2. 什么原因导致的:不变——开侧用闭集枚举匹配开放名字空间;草稿判定 $ 锚定漏掉「闭合标签在中间」形态。
  3. 影响范围与严重程度:不变(p2:能用但会看到乱码结构,非数据丢失、非会话不可用)。
  4. 怎么修复的:不变——按载荷形状识别(ref 落属性槽 / tokens= 属性)+ 草稿「信封」臂,三处调用点统一走 isDraftDump。
  5. 是否有回归问题:无新增。lane 六个核心/测试文件逐字节稳定;本轮唯一新 lane 改动是 scripts/live-files.mjs 的测试注册(零行为影响、目标文件真实存在、独立 test(ci): commit)。其余变动(plugin.ts [Pi/OpenAI] 0.1.209 leaks render-tag suffix type="text">mNNNNN into assistant text #5192/【bug】bili 0.1.188 · ACP 标签形态异常 + 摘要泄漏 + 剥离日志可观测性 #2405、core.ts [BUG] In some cases, with Codex's auto model + DeepSeek, it will suddenly terminate automatically. #732/workbuddy报错Empty stream: upstream gateway sent only placeholder chunks without any model output (chunks=0, bytes=0) #821、launcher/stream/四个测试)均为上游随 re-sync 带入,已逐一核到 origin/master,与本 PR 逻辑无交互破坏。
  6. 是否破坏缓存:不涉及(同前;relay 分支传 undefined session,usage accounting 保持关闭)。
  7. 是否改了设计方向:否(同前)。
  8. 是否引入了新的配置:否(同前;文档里的 chat promptPack 是已随包功能的补登记)。

CI 诚实披露:镜像缓存对该 sha 四次读数完全一致(10 分片 in_progress / 0 failed),已疑似停更而非真在跑;平台侧报告该 PR 绿。综合「零失败 + 唯一新 lane 行为中性 + 上一头同 lane 代码全绿」判定不阻塞;若后续某分片转红,应为上游继承或已知 Windows flake,而非本 lane diff。

判定:APPROVE 维持,等待 owner 人工合并。

协调状态:PR #5178 新 head 15690d0c8 增量复核完成 → lane 仅新增一条 CI 注册行(scripts/live-files.mjs),核心零变化、无 kernel/、CI 零失败,维持 APPROVE,等待人工合并。

…ndow refusal, ranxianglei#5969 LiteLLM overflow counts

Advances the base from 1f311dd to 39fc2ee (8 commits, 8 files). The only
file this lane shares with the delta is scripts/live-files.mjs, and both sides
are byte-identical (md5 295a1317030b28dbff36539f8e97d176): upstream landed the
same ranxianglei#1248 registration this lane already carried from the ci-check commit
156d0c8, so the merge is a no-op there and git auto-resolved everything else.

Notable upstream commits adopted:
 - 4ec9778 fix: empty-slot direct send now refuses over-window bodies locally (ranxianglei#5996)
 - 12b18e9 fix(native-intercept): name the floored local bar distinctly from the
   resolved window in the empty-slot refusal (ranxianglei#5996 review)
 - 8b25694 fix: parse LiteLLM input and completion overflow counts (ranxianglei#5969)
 - 911737c test: drop duplicate overflowArmCompletionReserve assertion
 - 831b645 fix(ci): register tests/issue5955-wedged-same-lane-takeover.test.ts in LIVE_FILES
@Louie0806

Copy link
Copy Markdown
Contributor Author

(ai: deepseek/deepseek-v4-flash)

Merged upstream/master (39fc2eeff) into the lane. Head is now c7da03829 (8 commits, 8 files), CI 39 success / 0 failed / 15 skipped.

The LIVE_FILES fix converged from both sides

My previous head carried 15690d0c8, a ci-check commit registering tests/issue5955-wedged-same-lane-takeover.test.ts. Upstream landed the same registration independently in 831b64580 (merged through 15c198362, "converge master-level CI fix per CI-coordination protocol (#4599)"). The two files are byte-identical — scripts/live-files.mjs has md5 295a1317030b28dbff36539f8e97d176 on both my head and 39fc2eeff — so this merge is a no-op on that path. The tripwire now passes on master too, and my earlier report on #4599 is resolved without either side needing an extra action.

What the merge actually brought in

  • 4ec9771a fix: empty-slot direct send now refuses over-window bodies locally (#5996)
  • 12b18e917 fix(native-intercept): name the floored local bar distinctly from the resolved window in the empty-slot refusal (#5996 review)
  • 8b25694be fix: parse LiteLLM input and completion overflow counts (#5969)
  • 911737cba test: drop duplicate overflowArmCompletionReserve assertion
  • 831b64580 fix(ci): register tests/issue5955-wedged-same-lane-takeover.ts in LIVE_FILES

Seven files staged, zero conflicts, no manual hunk selection.

Verified on the merged tree

suite result
tests/issue5175-drift-name-leak.test.ts 58 / 0
tests/tag-echo.test.ts 79 / 0
tests/issue2190-degen-close.test.ts 32 / 0
tests/golden-storage-render.test.ts 5 / 0
tests/storage-engine-proofs.test.ts 12 / 0
tests/native-compact-terminal.test.ts 1 / 0
tests/issue4666-migration-dedup.test.ts 2 / 0
tests/native-intercept.test.ts 82 / 0
tests/context-overflow.test.ts 40 / 0
tests/e2e-issue3900-overflow-teaches.test.ts 3 / 0

npx tsc --noEmit = 0, all four gates = 0, node tools/gen-config-docs.mjs generate leaves every generated doc byte-identical.

Lane anchors intact: src/server/relay.ts:2120 still holds the non-streaming compact egress, src/storage/mysql.ts:77 still exports MYSQL_SCHEMA_VERSION = 11, and the strip symbols are unchanged (stripDriftResidue 6, isDraftDump 6, containsRenderTagText 21, mayStartDegenerateRenderTag 6, DRIFT_BARE_MISMATCH 3, DRAFT_CLOSE_TAIL 3). Footprint stays at 18 files (the live-files registration is now redundant against master but harmless — dropping it here would re-red the matrix until the merge order is known).

Still waiting on the human merge per AGENTS.md §4; nothing here is self-merged.

…ocale translations, ranxianglei#5956 reasoning-replay after cut, ranxianglei#5957 non-stream anthropic proxy loop, ranxianglei#5958 degenerate retry error shape
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

Re-sync verification @ c7da03829 — APPROVE maintained ✅

Targeted re-verify of this master-sync (not a full re-review — the lane's own diff did not change).

What the sync brought: purely upstream-inherited code, byte-identical to origin/master:

  • #5996 empty-slot direct-send refuses over-window bodies locally (src/agent/native-intercept.ts, src/util.ts) + its tests (tests/native-intercept.test.ts, tests/context-overflow.test.ts, e2e-issue3900 tweak) + two docs lines.
  • The LIVE_FILES registration converged from both sides: upstream landed the byte-identical scripts/live-files.mjs in 831b64580; md5 295a1317… now matches on both the PR head and master (verified), so that path dropped out of the lane delta — footprint is back to the canonical 17 files, +1967/−57 exactly as originally reviewed. Keeping the redundant line in the tree is the right call (dropping it here would re-red the matrix until merge order is known).

Lane integrity (verified):

  • Five core lane files tag-echo-filter.ts / degenerate-turn.ts / relay.ts / issue5175-drift-name-leak.test.ts / native-compact-terminal.test.ts are byte-stable vs the prior head 15690d0c8.
  • src/plugin.ts and src/loop/core.ts do not appear in the head-to-head stat → the lane's own strip/draft edits there are unchanged.
  • Lane src/server/relay.ts:2120 non-streaming compact egress intact (pipePluginJson(..., undefined, prepared.protocol, ...) — usage accounting stays off); MYSQL_SCHEMA_VERSION = 11 unchanged.
  • No kernel/ file → authorization gate not triggered.

So the lane's genuine contribution is byte-identical to what I reviewed in depth across prior heads; my correctness/regression assessment stands unmodified.

CI (mirror cache, honest state): the cache is currently stale — frozen on a prior sha (421da3ce…, not this head c7da03829), showing 0 failures / 12 shards still queued-or-running, unchanged across two reads ~90s apart. Your report states green (39 success / 0 failed / 15 skipped). Given zero new lane behavior, byte-identical core already verified green at prior heads, and the inherited code being master-tested, I'm not treating the stale cache as a blocker; if any shard later flips red it would be an inherited-master or known Windows-flake issue, not this lane's diff.

Verdict: APPROVE maintained. Human-gated per §7.4 (wire/message-shape change touching both compression modes); the merge decision is yours, not mine.


中文结构化八问(本轮为增量复核:lane 自身零变化,纯上游继承 + live-files 收敛)

  1. 是什么问题:不变——漂移开标签名泄漏 + 手交压缩草稿当正文两个独立漏洞([Bug] Drifted open-tag names (acpt/acct/accent…) and mid-text draft envelopes reach the client verbatim — two thinking-leak shapes #5175)。
  2. 什么原因导致的:不变——开侧用闭集枚举匹配开放名字空间;草稿判定 $ 锚定漏掉「闭合标签在中间」形态。
  3. 影响范围与严重程度:不变(p2:能用但会看到乱码结构,非数据丢失、非会话不可用)。
  4. 怎么修复的:不变——按载荷形状识别(ref 落属性槽 / tokens= 属性)+ 草稿「信封」臂,三处调用点统一走 isDraftDump。
  5. 是否有回归问题:无新增。lane 五个核心文件逐字节稳定;本轮带入的全部是上游继承(bili-native (dsh): empty intercept slot sends a 6.7 MiB / 2.1M-token body direct — the 8 MiB byte cap does not catch it, provider answers 400 CONTEXT_WINDOW_EXCEEDED #5996/[PR] fix: parse LiteLLM input and completion overflow counts #5969,与 origin/master 逐字节一致)+ live-files 收敛(md5 已核一致,footprint 回到规范 17 文件),与本 PR 逻辑无交互破坏。relay/mysql 锚点不变。
  6. 是否破坏缓存:不涉及(同前;relay 分支传 undefined session,usage accounting 保持关闭)。
  7. 是否改了设计方向:否(同前)。
  8. 是否引入了新的配置:否(同前;文档里的 chat promptPack 是已随包功能的补登记)。

CI 诚实披露:镜像缓存当前停更(钉在旧 sha 421da3ce… 而非本头 c7da03829,两次读数约 90s 间隔完全一致,0 失败、12 分片排队/运行中);作者侧报告绿(39 success / 0 failed / 15 skipped)。综合「lane 行为零新增 + 核心逐字节同于已验证全绿的前几头 + 继承代码为 master 已测」判定不阻塞;若后续某分片转红应为上游继承或已知 Windows flake,非本 lane diff。

判定:APPROVE 维持,等待 owner 人工合并。

协调状态:PR #5178 新 head c7da03829 增量复核完成 → lane 自身零变化(纯上游继承 #5996/#5969 + live-files 双侧收敛回规范 17 文件),核心逐字节稳定、无 kernel/,镜像 CI 暂停更但 0 失败且作者报告绿,维持 APPROVE,等待人工合并。

@Louie0806

Copy link
Copy Markdown
Contributor Author

(ai: deepseek/deepseek-v4-flash)

Merged upstream/master (5c3c2688f) into the lane. Head is now 421da3ce6 (16 commits, 16 files), CI 39 success / 0 failed / 15 skipped.

What came in

  • 1f6f7ccee docs: allow root README.<locale>.md community translations (#6000) — merged via 5c3c2688f
  • 2fa4def41 fix(#5951): replay a stream cut that lands after reasoning-only output
  • 771d5d908 fix: shape the double-degenerate retry terminal by streamErrorShape (#5958)
  • e6cb37e84 fix: execute proxy-owned tools on the non-stream Anthropic path (#5957) — plus 5386b61bf pinning the MAX_LOOP_ROUNDS degradation gate
  • b3aed0b96 merge ci-fixes: register issue5955 test in LIVE_FILES (inherited CI red, per #4599 coordination)

Two files overlap mine: src/plugin.ts and src/server/relay.ts. Both auto-merged clean.

The one overlap worth naming

e6cb37e84 inserts a new branch into forwardCaptured that routes non-streaming Anthropic responses through compressLoopAnthropicJson (src/compress-loop-anthropic.ts — the file is src/compress-loop-anthropic.ts). It sits between the Responses loop and the usage-capture block, and per its own doc comment it only rewrites the JSON object:

Terminal/mixed rounds fall through to the one-shot rewriter below.

So it does not become a new egress — the relay still ends the turn through the one-shot rewriter, which is where my strip gate lives. The lane's non-streaming compact egress moved one line and still guards:

await pipePluginJson(toClient, res, undefined, prepared.protocol, undefined, undefined, undefined, reply);

at src/server/relay.ts:2122.

Verified on the merged tree

suite result
tests/issue5175-drift-name-leak.test.ts 58 / 0
tests/tag-echo.test.ts 79 / 0
tests/issue2190-degen-close.test.ts 32 / 0
tests/golden-storage-render.test.ts 5 / 0
tests/storage-engine-proofs.test.ts 12 / 0
tests/native-compact-terminal.test.ts 1 / 0
tests/issue4666-migration-dedup.test.ts 2 / 0
tests/issue5951-reasoning-only-cut-replay.test.ts 7 / 0
tests/issue5957-nonstream-anthropic-proxy-loop.test.ts 9 / 0
tests/plugin-empty-turn-retry.test.ts 21 / 0
tests/issue5955-wedged-same-lane-takeover.test.ts 18 / 0
tests/ccr-v2.test.ts 16 / 0
tests/issue2303-draft-tail.test.ts 14 / 0

npx tsc --noEmit = 0, all four gates = 0, and node tools/gen-config-docs.mjs generate produces zero unstaged drift (the four docs files that show as modified are the merge's own staged changes, not generator output).

Strip symbols unchanged: stripDriftResidue 6, isDraftDump 6, containsRenderTagText 21, mayStartDegenerateRenderTag 6, DRIFT_BARE_MISMATCH 3, DRAFT_CLOSE_TAIL 3. src/storage/mysql.ts:77 still exports MYSQL_SCHEMA_VERSION = 11. Footprint is 17 files.

Still waiting on the human merge per AGENTS.md §4.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

Re-sync verification @ 421da3ce6 — APPROVE maintained ✅

Targeted re-verify of this master-sync; the lane's own diff did not change, so this is not a full re-review.

What came in: pure upstream inheritance (merge-base is now origin/master 5c3c2688f, so the lane delta is back to the canonical 17 files, +1967/−57, no kernel/):

  • #6000 allow root README.<locale>.md community translations (docs policy)
  • #5951 replay a stream cut that lands after reasoning-only output
  • #5958 shape the double-degenerate retry terminal by streamErrorShape
  • #5957 execute proxy-owned tools on the non-stream Anthropic path (+ MAX_LOOP_ROUNDS degradation-gate pin)
  • ci-fixes: register the issue5955 wedged-takeover suite in LIVE_FILES

Lane integrity (verified):

  • Five core files (tag-echo-filter.ts, degenerate-turn.ts, issue5175-drift-name-leak.test.ts, native-compact-terminal.test.ts) plus loop/core.ts and server/relay.ts's test surface are byte-stable vs the prior head c7da03829.
  • Only plugin.ts and relay.ts carry upstream churn. relay.ts's lane diff (vs origin/master) is still the identical one-line swap at src/server/relay.ts:2122: pipeThrough(toClient,res) → pipePluginJson(toClient, res, undefined, prepared.protocol, …) (usage accounting stays off). plugin.ts's strip wiring is intact (isVerbatimField, stripDriftResidue(released) :3171, responses-twin sawStrippedEcho :4674–4675, isDraftDump call sites :2805/:4346).

The one overlap you named — verified against the code, not just the comment. e6cb37e84's compressLoopAnthropicJson branch lives in region 2 of forwardCaptured (the useRewriter===true injected path), which is mutually exclusive with the lane's fix in region 1 (!useRewriter → resetAfterSuccess, which returns before region 2 is reached) — so the two cannot interact. It is a pure object transform (json = await compressLoopAnthropicJson(json, …)) feeding the existing egress chain (protocol rewriter → res.end(JSON.stringify(json))), not a new raw send. And the new non-streaming-Anthropic path's egress is stripped: gated by containsRenderTagText (the predicate this lane widened from enumeration→shape) and removed by stripAcpTags → stripPass, which ends with out = stripBareMismatch(stripAttrMismatch(stripDriftPairs(out))). So the merge opens no fresh unstripped route. Your read is correct.

CI (mirror cache, on the real head): cached_sha = 421da3ce… (this head), failed:0 / pending:0, success:15 + skipped:15 — the 15 skips are the expected zero-token e2e lanes. Green; no stale-cache caveat this round.

Verdict: APPROVE maintained. Human-gated per §7.4 (wire/message-shape change touching both compression modes); the merge decision is yours, not mine.


中文结构化八问(本轮为增量复核:lane 自身零变化,纯上游继承)

  1. 是什么问题:不变——漂移开标签名泄漏 + 手交压缩草稿当正文两个独立漏洞([Bug] Drifted open-tag names (acpt/acct/accent…) and mid-text draft envelopes reach the client verbatim — two thinking-leak shapes #5175)。
  2. 什么原因导致的:不变——开侧用闭集枚举匹配开放名字空间;草稿判定 $ 锚定漏掉「闭合标签在中间」形态。
  3. 影响范围与严重程度:不变(p2:能用但会看到乱码结构,非数据丢失、非会话不可用)。
  4. 怎么修复的:不变——按载荷形状识别 + 草稿「信封」臂,调用点统一走 isDraftDump。
  5. 是否有回归问题:无新增。lane 核心文件逐字节稳定,relay/plugin 的 lane 自身改动与前头一致;本轮带入的全部是上游继承([Docs] Japanese README: where should it live? | [文档] 日文 README 应该放在哪里? #6000/Replay a stream cut that lands after reasoning-only output #5951/[dsh] Retry-exhausted degenerate turn is serialized as successful completion (0.1.213) #5958/Anthropic stream:false: a model compress call ends the client turn (receipt returned with end_turn, no re-request) #5957/ci-fixes)。你点名的 compressLoopAnthropicJson 分支经代码核对:与本 lane 修复处于互斥控制流、且为新路径补上完整剥离(containsRenderTagText 门 + stripAcpTags→stripPass→drift 三件套),未开新的未剥离出口。
  6. 是否破坏缓存:不涉及(同前;relay 分支传 undefined session,usage accounting 保持关闭)。
  7. 是否改了设计方向:否(同前)。
  8. 是否引入了新的配置:否(lane 自身无新配置;上游继承项的配置面由各自 PR 负责)。

CI 披露:镜像缓存已对齐本头 421da3ce…,0 失败 / 0 待跑 / 15 成功 + 15 跳过(跳过为预期零 token e2e 车道),本轮无停更疑虑。

判定:APPROVE 维持,等待 owner 人工合并。

协调状态:PR #5178 新 head 421da3ce6 增量复核完成 → lane 自身零变化(纯上游继承 #6000/#5951/#5958/#5957/ci-fixes),核心逐字节稳定、无 kernel/,点名的 compressLoopAnthropicJson 分支经代码核实安全且剥离覆盖完整,CI 真头全绿,维持 APPROVE,等待人工合并。

@Louie0806

Copy link
Copy Markdown
Contributor Author

Sync with master 406193b20 (#6004 Japanese README translation).

Upstream delta since 5c3c2688f is docs-only: f4f6bd292 "docs: add Japanese README (#6000)" lands README.ja.md (731 lines) plus two one-line pointer updates in README.md and README.zh-CN.md; 8b784fe88 is the branch-sync merge and 406193b20 the PR merge.

No overlap with this lane's 17 files, so nothing of mine was touched; branch head is now 242b1920c.

Verification on the merged tree: kernel rebuilt (126ms), tsc --noEmit clean, all four guards clean, config-doc generator fixed point holds (zero unstaged drift). Lane suites stay green: issue5175-drift-name-leak 58/0, tag-echo 79/0, issue2190-degen-close 32/0, golden-storage-render 5/0, storage-engine-proofs 12/0, native-compact-terminal 1/0, issue4666-migration-dedup 2/0.

CI tally on 242b1920c: 38 of 39 checks complete and green, 14 skipped; the last one, test (ubuntu-latest, 24, 1), started 08:02Z and is still in_progress, and its log blob is not published yet (BlobNotFound), so I cannot yet say whether it is a slow shard or a hung runner — I will report the final number when it lands.

On master itself the three symbols are still 0 / 0 / 6 (stripDriftResidue, isDraftDump, endsWithDraftClose), so neither leak class is fixed in production yet.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

查重: Not duplicate — this PR is the only in-flight fix for this failure family (drifted render-tag imitations reaching the client + draft-dump turns slipping past the one-shot continuation retry). No parallel PR or issue working the same mechanism found among open/closed items; GitHub #5175/#5179 are the upstream reports this PR closes. Note: internal mirror #5175 is an unrelated auto-CI tracker — the bare "#N" in the title resolves against GitHub, not the mirror.

标签: applied bug + scope/wiring + p2 (kept pr). Defect-class fix; the changed layer is the egress sanitizer / protocol-adaptation boundary; p2 = usable but visibly broken (garbage markup lines reach the client, turns die until a nudge), not unavailability and not a cache leak. No client label — the leak is host-agnostic and the live report doesn't identify one.

Scope note (landed mid-review): two commits arrived while I was reading — 244f5e8766 + c6eaf1fabc add the #5179 live-report shape (<acp_tokens>910</acp_tokens> count unit, v0.1.213) via a new DRIFT_COUNT rule. Same mechanism family as #5175 (name-scoped detection missing open-set drift), so folding it into this lane is right per one-mechanism-one-PR; reviewed below on equal footing. Final head reviewed: c6eaf1f (contains master@406193b20; 52 non-merge lane commits; kernel untouched, no version bumps).

① Direction (original issues) — verified against pre-fix code at master@406193b20 rather than trusting the report. Both gaps are real and sit at the mechanism level: (A) every open-side detection in the streaming lane is scoped to an acplike NAME enum, so drifted openers (acpt m17138, apct, accent…) trip no gate — the tail-anchored head probe misses closed units mid-chunk, and even when engaged the state machine cannot resolve unknown names; whole-text stripping had zero shape-keyed rules, so the imitation rode out verbatim on all four wires. (B) the draft-tail predicate was $-anchored, so a mid-text </analysis><summary> dump was invisible to the one-shot continuation retry. The fix keys detection on payload SHAPE (a closed set: refs-in-attribute-slot, tokens= attribute, digits-only body under an acp-namespace name) instead of name (an open set) — that removes the producer of the miss class; appending observed names to the enum would have been the mask, and fixing at injection would mean changing the wire protocol itself (out of scope here). Direction: correct.

② Regression inventory (existing behaviors on touched paths, pre-change code read):

③ Code focus: rules are narrow and evidence-gated — pair rules keep their \1 backreference; mismatch rules strip the span only and do NOT license orphan removal (the open name may be a genuine tool-call name); residue-line adjudication requires ref-on-line + bracketed-companion proof before removing anything; orphan halves are licensed only by a genuine pair of the same name in the same text (#1760 discipline); DRIFT_COUNT requires acp-prefix + digits-only ≤7-digit body + own-name close ("no English word starts with acp"). Canonical exclusions (~70 HTML names + 4 protocol tags) gate every rule. The strip cascade keeps the name enum first and drift last inside the cap=8 fixed-point walk (monotonic shortening ⇒ terminates). The streaming seam (stripDriftResidue) uses the identical rule set, so the two lanes cannot disagree on a span at rest; the known residual (a pair split across pushes) is pinned, not widened. Comment density is high, but each block states a measured fact or an exclusion rationale — why-comments done right.

④ Test validity: the 1348-line suite drives the REAL pipelines (chat/responses/plugin-json pipes + all four JSON rewriters), not predicate copies — a hand-rolled copy is exactly what hid the first bug. Byte-cut sweeps at every boundary on four wires (>200 cuts/lane) assert zero kernel refs and zero drifted openers reach the client; parity asserts preserved shapes byte-identical to SOURCE; negatives pin what must survive (genuine markup, protocol tags, verbatim channels, mismatched canonical pairs, prose containing "acp"); the two unfixable-from-streaming residuals are pinned as KNOWN with rationale; defect B gets split-at-envelope-boundary cuts plus complete-envelope-not-retried and retried-turn-no-double-answer controls; the pre-fix predicate miss is asserted as a regression control. Teeth-bearing: each bug class fails these pre-fix.

⑤/⑤b Diff cleanliness & hygiene: 17 files, +2052/-64 at final head; no whitespace churn, no unrelated files, no lockfile/generated churn, no version bumps, kernel-guard green. Naming carries intent, no dead code, no magic literals without named constants, style matches module conventions. One non-blocker observation: the suite file is named issue5175-* but now carries a clearly-labeled #5179 section — origin-named, internally clear, leave as-is.

CI (run 42592398719, head c6eaf1f): 13 success, 3 skipped, 14 in_progress at my last cached read — static gates, kernel-guard, unused-exports, docs-sync, architecture-docs all green, zero failures; full test matrix still running. I will post the final tally when it lands.


八问(中文)

  1. 是什么问题:模型把内核渲染标签"模仿"成漂移名字后原样漏给客户端——开侧检测全部按名字枚举圈定,漂移名(acpt/apct/accent、acp_tokens 计数体等开放集)一次绕过所有门;同时压缩草稿以 </analysis><summary> 信封形态出现在正文中段时,$ 锚定的草稿尾谓词看不见它,单发续写重试不触发,整轮死在草稿上。
  2. 什么原因导致的:根因是检测机制按"名字"(开放集)圈定而非按"载荷形状"(封闭集)判定——名字漂移空间模型可自由生成(【bug】最终版issue: 模型生成的 <acp …> 标签会漏到用户可见输出(附根因、量化与修法建议) #2190 round 2 已证明枚举追不上),而渲染标签的载荷形状(ref 在属性槽、tokens= 属性、纯数字计数体)由发射器固定,散文结构上产生不了。修复把判定键从名字换成形状,属机制级修复(消除"漏检类"的生产者),不是逐名打补丁(枚举补名才是堵)。
  3. 影响范围与严重程度:所有 plugin 模式宿主、四条 wire(openai/anthropic/google/responses)、流式与非流式全车道;严重度 p2——会话可用,代价是客户端收到垃圾标记行(首行被污染、可能随回放放大)+个别轮次死在草稿里直到 nudge;非不可用、非缓存泄露。
  4. 怎么修复的:形状键控规则组(DRIFT_PAIR/ATTR/BARE-MISMATCH/COUNT+残行裁决),规范名排除集(HTML ~70+协议 4)门控每条规则;孤儿半体仅由同文本真配对授权移除([bug] 单行中文答案被误判为退化轮:marker 行首前缀按设计被扣住,终点释放却被计成 markup(chat-completions 线整轮报错) #1760 纪律);流式缝用同一规则集保证两车道对同一段落判决一致;草稿重试谓词扩为"未完结信封"判据(isDraftDump,三调用点全换),完结信封+答案=已收敛不重试(负例钉死,防双答)。
  5. 是否有回归问题:已逐项清点(见上 ②):干净内容字节级保持(四 wire×全切点钉死)、协议标签/签名思考通道/工具参数不受触、退化轮记账探针刻意解耦;有意变更 5 处均已披露(漂移字节被剥、全剥轮触发一次续写重试、未完结信封触发重试、重试计数按尝试重置、原生压缩非 SSE JSON 出口改走剥离管道——该路径新增整包缓冲+handoff 捕获对齐+断连错误形态变化)。高危模式逐项过:无语义漂移、无 fail-fast 变吞错(parse 失败仍 fail-open 原文转发)、无阈值/时序静默变化(JSON 重序列化仅语义等价且仅命中剥离时发生)。
  6. 是否破坏缓存:不涉及——前缀缓存/会话状态/pf 水位均未触碰;剥离发生在生成后的出口侧,重试计数为请求内一次性状态。
  7. 是否改了设计方向:不涉及——沿用既有出口净化架构(偶尔重复输出 <acp tokens="177" type="text">m00155</acp> #206/【bug】最终版issue: 模型生成的 <acp …> 标签会漏到用户可见输出(附根因、量化与修法建议) #2190 谱系),无新模块、无数据流转向;唯一结构性补充是把"形状门"统一进 containsRenderTagText,让流式与非流式车道共用同一判定。
  8. 是否引入了新的配置:不涉及——零新 env/config/默认值;docs 变更仅为恢复 master 已有 New built-in chat prompt pack: default compression rules for long-term companionship / multi-session memory scenarios (e | 新增内置 chat 提示压缩包:长期陪伴 / 多会话记忆场景的默认压缩规则(compress.promptPack="chat" 启用) #5319 chat 包的配置文档种子(en/zh/website,生成器不动点成立)。

判定:代码审查通过(PASS)——方向到根因、回归已清点并披露、测试有牙。合并前剩两道门:① 按 §7.4 需人工签核(wire/message-shape 变更影响两种压缩模式 + 新增导出面,不合格 auto-merge);② c6eaf1f 上的完整 CI 矩阵转绿(目前零失败,分片仍在跑)。另建议 PR 描述补挂 #5179 编号(lane 现已覆盖该缺陷)。CI 终态落地后我会补一条最终计数。

@ranxianglei ranxianglei added bug Something isn't working p2 scope/wiring labels Nov 9, 2026
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI status addendum: the run cited in my review above (42592398719) was superseded while in flight — a fresh full run (42596043917 and its sibling workflows) was triggered on the SAME head c6eaf1fabc, and the earlier run's remaining shards were cancelled. No code change is involved (PR head unchanged since my review). The verdict stands on the reviewed head; I will post the final check tally when the new run completes.

ci-check and others added 2 commits November 9, 2026 18:18
…incompatibility notice

Master moved five commits (8 files) under the notice-registry surface:
1c069c6 adds `src/pck-notice.ts` plus `src/notice-store.ts`/`src/notices.ts`
wiring, 65fcba1ba narrows the warning to enabled installs, 549bc54 restores
the built-in notice banners' `.show` class, 8d202c3 stops the i18n ref
scanner treating filenames like `package.json` as catalog keys, and 63a4060
is the PR merge.

Zero overlap with this lane's 17 files; the only shared directory is `src/web/`
and the two sides touch different files there (`i18n.ts`/`client.ts` upstream,
none of mine). Nothing of mine was touched.
@Louie0806

Copy link
Copy Markdown
Contributor Author

Sync with master 63a40600e (#6015 iot-thinking incompatibility notice).

Upstream delta since 406193b20: five commits over 8 files, all under the notice-registry surface — 1c069c68b adds src/pck-notice.ts with src/notice-store.ts/src/notices.ts wiring, 65fcba1a2 narrows the warning to enabled installs, 549bc5424 restores the .show class on built-in notice banners, 8d202c38b stops the i18n ref scanner treating filenames like package.json as catalog keys, and 63a40600e is the PR merge.

Zero overlap with this lane's 17 files. Upstream touches src/web/i18n.ts and src/web/client.ts; this lane touches neither, so the merge is clean with no conflict resolution.

Verification on the merged tree: kernel rebuilt (119 ms), tsc --noEmit clean, four guards clean, and the config-doc generator is still a fixed point (zero diff across the four generated artifacts). Lane suites stay green — the #5175 suite is now 66/0 after the bot's count-shape width commit, plus tag-echo 79/0, degen-close 32/0, golden-storage-render 5/0, storage-engine-proofs 12/0, native-compact-terminal 1/0, issue4666 2/0 — and the three new upstream suites pass too: iot-incompat-notice 6/0, notice-registry 4/0, web-i18n 11/0.

tests/event-loop-watchdog.test.ts is 5 pass / 2 fail locally on the merged tree, but this is inherited: the lane does not touch that file (byte-identical md5 to master), the failing subtests are the #4762 forensic-log assertions, and I reproduced the same pair of failures on a pristine detached master tree earlier today. It only reds one Windows shard in CI.

Branch head is now ef4183958.

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE — final head ef41839587, full matrix green (15 success / 15 skipped / 0 failed).

Independent end-to-end review complete (the full first-round review at c6eaf1fabc is in the earlier comment above; this round covers everything since).

Delta since the previous review round:

  1. ef41839587 — merge of upstream/master @ 63a40600e (#6015 iot-thinking incompatibility notice). Verified byte-identical adoption: the merge's non-lane portion equals the upstream master delta exactly — no conflict-resolution edits, zero file overlap with this lane's 17 files.
  2. e374969e81 — test-only plus a rule-site doc comment: pins the deliberate width of DRIFT_COUNT (any acp-prefixed name, not just underscore-joined ones) in BOTH directions — underscore-free siblings <acp_tool>5</acp_tool> / <acpx>910</acpx> are stripped whole-text and at every wire cut, while genuine tool-call XML survives (TOOLCALL_MISMATCH sweep + MUST_PRESERVE set). Rationale documented at the rule site.

No kernel/ changes, no kernel-change declaration → no human-tier authorization gate applies to this PR's content. No small findings requiring in-place fixes this round.


八问(中文)

  1. 是什么问题:模型把内核渲染标签模仿成漂移名字/计数体后原样漏给客户端(开侧检测全部按名字枚举圈定,开放集漂移一次绕过所有门);压缩草稿以未完结 </analysis><summary> 信封出现在正文中段时,$ 锚定谓词看不见它,单发续写重试不触发,整轮死在草稿上。
  2. 什么原因导致的:检测机制按"名字"(开放集)而非"载荷形状"(封闭集)判定——名字漂移空间模型可自由生成(#2190 round 2 已证明枚举追不上),而载荷形状(ref 在属性槽、tokens= 属性、纯数字体+acp 前缀名)由发射器固定且散文结构上产生不了。修复把判定键换成形状,属机制级修复(消除漏检类的生产者);枚举补名才是堵。
  3. 影响范围与严重程度:所有 plugin 模式宿主、四条 wire(openai/anthropic/google/responses)、流式与非流式全车道;p2——会话可用,代价是客户端收到垃圾标记行(首行污染、可能随回放放大)+个别轮次死在草稿直到 nudge;非不可用、非缓存泄露。
  4. 怎么修复的:形状键控规则组(DRIFT_PAIR/ATTR/BARE-MISMATCH/COUNT+残行裁决)+规范名排除集(HTML ~70+协议 4)门控每条规则;孤儿半体仅由同文本真配对授权移除(#1760 纪律);流式缝与非流式共用同一规则集保证判决一致;草稿重试谓词扩为"未完结信封"判据(isDraftDump,三调用点全换),完结信封+答案不重试(负例钉死防双答)。
  5. 是否有回归问题:逐项清点见第一轮审查评论——干净内容四 wire×全切点字节级钉死、协议标签/签名思考通道/工具参数不受触、退化轮记账探针刻意解耦;有意变更 5 处均已披露旧值→新值(漂移字节被剥、全剥轮触发一次续写重试、未完结信封触发重试、重试计数按尝试重置、原生压缩非 SSE JSON 出口改走剥离管道+整包缓冲+handoff 对齐)。高危模式逐项过:无语义漂移、无 fail-fast 变吞错(parse 失败仍 fail-open 原文转发)、无阈值/时序静默变化。本轮新增提交为纯测试+注释,零行为面变化。
  6. 是否破坏缓存:不涉及——前缀缓存/会话状态/pf 水位均未触碰;剥离发生在生成后的出口侧,重试计数为请求内一次性状态。
  7. 是否改了设计方向:不涉及——沿用既有出口净化架构(#206/#2190 谱系),无新模块、无数据流转向;结构性补充仅是形状门统一进 containsRenderTagText 供两车道共用同一判定。
  8. 是否引入了新的配置:不涉及——零新 env/config/默认值;docs 变更仅为恢复 master 已有 #5319 chat 包的配置文档种子(en/zh/website,生成器不动点成立)。

Merge readiness: approved — per repo rules the merge itself stays human-only (§7.4: wire/message-shape change affecting both compression modes).

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

Review round 2 complete — formal APPROVE review posted on head ef41839587: #5178 (review)

Delta since the previous round, both reviewed: (1) clean master sync @ 63a40600e (#6015 iot-thinking notice) — verified byte-identical adoption, zero conflict-resolution edits, zero file overlap with this lane's files; (2) e374969e81, test-only, pinning the deliberate acp-prefix width of DRIFT_COUNT in both directions (underscore-free siblings stripped whole-text and at every wire cut; genuine tool-call XML survives). No small findings requiring in-place fixes this round.

CI on ef41839587: green — 15 success / 15 skipped / 0 failed (this run supersedes the cancelled one noted earlier; all static gates, kernel-guard and the full test matrix pass). Per §7.4 the merge itself stays human-only (wire/message-shape change affecting both compression modes). The structured 八问 sits in the Chinese section of the review body.

@ranxianglei

Copy link
Copy Markdown
Owner

ework,这个是不是有无关commit进入?需要重新审核 .对业务逻辑也需要重新审核

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

重新审核完成(含业务逻辑)。直接回答:

是的,有无关 commit 进入。 分支累计 57 个非合并提交里,有 19 个非核心提交(另有 4 个 iot-thinking 提交是上游 #6015 经 merge 带入的 master 内容,不算本车道产出)。进入原因:分支存活期间 master 多次变红,为保持本车道 CI 绿,worker 把红灯门禁直接在分支里修掉了(每个提交都带来源 issue 标注),没有收敛到 ci-fixes——这是流程偏差,不是内容错误。分类与现状(对照今日 master 4446301708c0):

类别 提交数 内容现状
生产代码修复(#4788×2、#5345、storage 路径) 6 均已被 master 侧落地吸收,与 master 逐字节一致 → 零合入内容(另有一项发现,见下)
CI 门禁清理(#5317/#5319/#5340/#4125) 4 unused-export、npm shim 部分已被 master 吸收;残留仅 promptPack "chat" config-docs 种子行(docs en/zh + website 共 5 文件)——gen-config-docs 定点门需要它,纯文档层
测试确定性修复(#4666/#4739/#4788/#5152/#5155/#5140) 6 残留为 4 个文件的 test-only hunk(schema-version 常量、closeQuietly teardown、原子端口发布)——修的是 master 继承来的 Windows shard flake,零生产影响
空 retrigger 提交 2 零内容,纯历史噪音
LIVE_FILES 登记(镜像 #5990) 1 被 master 相同条目抢先,零内容

即:实际会随本 PR 落地的无关内容 = test-only hunk(4 文件)+ config-docs 种子行(5 文件)+ 1 行 mysql export,全部带标签、全部测试/文档级、全部是保持本分支 CI 与静态门禁绿所必需。我的建议:保留在分支内——拆出去会让本分支 CI 立刻重新变红,且它们不触碰任何生产行为。

一个真实发现:#4788 的 contentStoreLanded 探针强化(existsSync → statSync().isFile())在某次同步 merge 中丢失——master 和分支当前 head 都没有。master 已用另一条路径缓解其下游症状(adopt 时 warn + kernel 历史重摄入),无用户可见破坏;建议该项探针强化单独记到 #4788 名下处理,不并入本 PR。

业务逻辑复审结论:通过。

  • 核心修复逐项确认在当前 head 完整存在:stripDriftResidue / DRIFT_COUNT / isDraftDump / DRAFT_ENVELOPE 四个符号在 master 上出现次数均为 0(本 PR 仍是唯一载体);native compaction 的非 SSE JSON 出口确已改为 pipePluginJson(ef41839587 的 src/server/relay.ts:2122 直接核实;master 同一位置仍是裸 pipeThrough)。
  • 与分支点后 master 新增的约 55 个提交逐一比对:无语义交互——# [Feature] Support user-registerable egress request body rewriting plugin pipeline | # [Feature] 支持用户可注册的出站(egress)请求体改写插件管线 #6003 的 egress chokepoint 只作用于请求重发路径,responses-ordering / thinking-posture / separator-manifest 都在请求侧,log-retention 是独立子系统;与本 PR 的交集只有几条共享 import 行(其中一条涉及 repairResponsesAssistantOrdering 从 server.ts 移入 responses-ordering.ts),属机械冲突,union 即可解。
  • 四条 wire × 200+ 切点的回归套件、degenerate-turn 重试语义、verbatim-channel tripwire 均完好。

合并前强制前置:分支现在落后 master 53 个提交(上次同步停在 63a40600e)。此前那次绿的 CI(15 success / 0 failed)是对旧基线跑的,按 §7.2 stale-base 纪律不能算当前树的证据。需要 dev 车道先把分支同步到 4446301708c0 并推送重跑全量 CI;转绿后由人合并(本 PR 属两种压缩模式都涉及的 wire/message-shape 变更,§7.4 规定必须人工签核,auto-merge 不适用)。

八问

  1. 是什么问题:[Bug] Drifted open-tag names (acpt/acct/accent…) and mid-text draft envelopes reach the client verbatim — two thinking-leak shapes #5175/Claude Code stops mid-task when bili ends a turn early: the Anthropic adapter sends stop_reason "length" #5179 漂移标签泄漏修复 PR 在长存活期里累积了 19 个无关提交,需确认是否混入并复审业务逻辑。
  2. 什么原因导致的:分支期间 master 多次变红,worker 为保本车道 CI 绿把红灯门禁就地修进分支而非收敛到 ci-fixes——流程偏差,非内容错误。
  3. 影响范围与严重程度:将落地的无关内容仅测试/文档级(9 文件 + 1 行 export),零生产行为变化;丢失的 [Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788 探针强化已被 master 替代路径缓解,无用户可见影响。严重度:低(流程卫生问题)。
  4. 怎么修复的:无关测试/文档 hunk 保留在分支内(均有标签、CI 必需);丢失的 [Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788 探针强化单记到 [Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788;dev 车道重同步最新 master 并重跑 CI。
  5. 是否有回归问题:逐项复审过——核心修复完整、与 master 新增 55 提交无语义交互(仅机械 import 冲突)、未发现回归。
  6. 是否破坏缓存:不涉及(未动缓存/重试游标/去重键策略;egress 剥离是响应体处理,不影响请求侧前缀缓存键)。
  7. 是否改了设计方向:不涉及(仍在「出口 sanitizer + 重试判定」原方向内,无架构转向)。
  8. 是否引入了新的配置:不涉及(promptPack "chat" 文档行是对既有宿主内置 pack 的补文档,无新字段/env/默认值)。

结论:内容复审通过、无拦下项;合并前置 = ① dev 车道同步至 4446301708c0 + 全量 CI 转绿 ② 人工签核。

@ranxianglei

Copy link
Copy Markdown
Owner

(ai: vllm-qwen/qwen3.8-27b)

Review update after the owner-requested re-audit: content PASSES re-review — every core fix verified intact at ef41839587 (symbol-by-symbol vs master; the native-compaction non-SSE JSON egress at src/server/relay.ts:2122 confirmed as pipePluginJson, where master still has raw pipeThrough). No semantic interaction with master's ~55 new commits since the branch point (only mechanical import-line overlaps).

Merge precondition: the branch is now 53 commits behind master (last synced 63a40600e; master is at 4446301708c0). The green CI run was against the stale base — per §7.2 stale-base discipline, please sync the branch to 4446301708c0, push, and let the full CI re-run before merging. Human sign-off remains required either way (§7.4 wire/message-shape change, both modes).

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

第三轮复审已交付完毕,两条产出均已落地:

  1. 本线程完整复审结论(上方长回复):直接回答「无关 commit」问题——19 个非核心提交进入过分支、分类与现状表、建议保留的测试/文档级残留 hunk、以及 [Performance] v0.1.208 long sessions exceed 2 GiB memory and spend 14–22 seconds in local processing #4788 探针强化丢失的发现;业务逻辑复审结论 PASS(核心修复逐项完整、与 master 新增 ~55 提交无语义交互)。
  2. GitHub PR 评论(https://github.com/ranxianglei/billion-context/pull/5178#issuecomment-6747778660):合并前置条件——分支落后 master 53 个提交,需同步到 4446301708c0 并重跑全量 CI,之后人工签核(§7.4 wire-shape 变更必须人签)。

当前状态:审核车道工作完成,无拦下项;等待 dev 车道重同步 + 人工合并决定。(上面这条转发内容是平台把我刚发的 GitHub PR 评论回显进线程,非新问题。)

…178-conflict

# Conflicts:
#	docs/configuration.md
#	docs/configuration.zh-CN.md
#	website/docs/index.html
#	website/main.js
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

Conflict resolved, branch synced to current master, pushed. Merged origin/master (tip 33104b1f95, includes #6150 which removed the compressAtFoldPoint feature) into the PR head branch, resolved all conflicts, verified, pushed as fast-forward (no force-push). New head: 172a7cae0b (parents ef41839587 + 33104b1f95).

The conflict (4 files, one root cause). Master removed the experimental compressAtFoldPoint feature on 2026-11-10 (#6132, merged as #6150); the PR branch still carried its two doc rows plus a promptPack "chat" wording added during an earlier branch sync-merge (#5319 config-docs seed work). Resolved uniformly: dropped both compressAtFoldPoint* rows everywhere (feature gone — the keys are now inert-removal notices at src/config.ts:2799) and kept the promptPack chat row, because the docs-gate single source of truth (website/config-reference/compress.yaml) auto-merged to the PR version and master code still ships the chat pack as a shipped pack (src/chat-pack.ts, src/compress-settings.ts:177-184). Files touched: docs/configuration.md, docs/configuration.zh-CN.md, website/docs/index.html, website/main.js. Post-resolution node tools/gen-config-docs.mjs generate ran clean (zero drift, EN/ZH i18n sets equal).

Verification on the merged tree (targeted, per local-testing discipline): typecheck clean; the PR's own suite tests/issue5175-drift-name-leak.test.ts 66/66; related suites (tag-echo, issue2190-degen-close, verif-tag-echo-filter, tag-echo-chunking-determinism, plugin-passthrough-tag-strip-chat, fix-1439-responses-json-triggers, issue4323-drift-escalation, issue2756-degenerate-gate) 174/174. Auto-merged src imports audited — only the PR's intended deltas remain (endsWithDraftClose→isDraftDump rename at call sites, stripDriftResidue added to the src/loop/core.ts import).

Live state (checked this run): PR is mergeable=true, state behind — the dirty/conflict blocker is cleared, merge button unblocked. Master advanced once more after our sync (#6166, thirdparty-scan + non-overlapping doc hunks), so GitHub computes a clean three-way merge against the new tip too; I deliberately did not chase byte-clean status again (CI runs on the pushed head regardless, and master keeps moving). CI on 172a7cae0b: registered and pending — full-suite verdict is the remote CI test lanes per §7.2; the mirror check cache will reflect the new sha on its next poll. Per review floors 403/404, merge still needs human sign-off (§7.4 wire/message-shape change — no auto-merge).

Behavior-change flag (deliverable 4): the PR branch's docs previously listed compress.compressAtFoldPoint / compress.compressAtFoldPointClearThinking; after this sync they no longer appear in docs/website — old→new: documented → removed, reason: the feature itself was removed from master by #6132/#6150, so retaining the rows would have been false documentation. Runtime behavior: unchanged by this commit (docs/website strings only; the PR's actual fix is untouched).

结构化八问:

  1. 是什么问题:PR 分支自 2026-10-30 起未同步 master,而 master 在 2026-11-10 移除了 compressAtFoldPoint 功能(Remove the compressAtFoldPoint feature — it reorders resent history and caused an authorship-misattribution incident in a live session #6132/[PR] remove: the experimental compressAtFoldPoint feature — fold-point relocation (v1 #5471 + unreleased v2 #5949), #6132 #6150),导致 4 个文档/网站文件冲突,PR 处于不可合并(dirty)状态。
  2. 什么原因导致的:双方改了同一文档区域——master 删除该功能的两个配置行,PR 分支在早前的同步合并中给相邻的 promptPack 行加入了 "chat" 措辞,git 无法自动合并。
  3. 影响范围与严重程度:仅阻塞本 PR 的合并(无法点合并按钮);不影响任何用户、运行时行为或缓存,纯分支同步问题。
  4. 怎么修复的:把 master 合入 PR head(用 merge 而非 rebase,保留外部作者的提交历史);冲突统一按「删已移除功能的行、保留与 yaml 种子一致的 promptPack chat 行」解决,再用 gen-config-docs 生成器验证零漂移。
  5. 是否有回归问题:逐项审过——自动合并的 src 文件只含 PR 预期内的 import 变更;typecheck 干净;PR 自带套件 66/66、相关 8 个套件 174/174 本地全绿(全量裁决以远端 CI 为准);删除文档行与 master 已删功能的事实一致,未引入新语义。
  6. 是否破坏缓存:不涉及——未触碰缓存/重试/游标/去重逻辑。
  7. 是否改了设计方向:没有。仅跟随 master 既有方向(功能已移除)对齐文档;PR 本身的修复(drifted open-tag 名剥离 + mid-turn draft envelope 检测)一字未动。
  8. 是否引入了新的配置:没有。相反,把两个已在 master 代码中标记为 INERT_REMOVED 的配置项从文档中移除。

结论:冲突已解决并推送(新 head 172a7cae0b),PR 恢复可合并状态;等新 head 上 CI 全绿后,按 §7.4 由人工批准合并。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[ework] CI fix verified green ✓

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants