Skip to content

[PR] Native-Identity Fastpath: Observation Layer (M1) + Identity-Only Hit Gate (v5) | 原生身份快路径:观测层+身份制判据(一次做完) - #5576

Closed
ranxianglei wants to merge 23 commits into
masterfrom
2026-11-03_native-identity-observation
Closed

ranxianglei wants to merge 23 commits into
masterfrom
2026-11-03_native-identity-observation

Conversation

@ranxianglei

@ranxianglei ranxianglei commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

[PR] Native-Identity Fastpath: Observation Layer (M1) + Identity-Only Gate (v5) + Canonical-Ledger Unification (v6) | 原生身份快路径:观测层 + 身份制判据 + 标准账本统一 + 持久化快照 msgid 平面

One PR per owner ruling (2026-11-03): the native-identity fastpath work lands as a single stack on this branch, in four semantic layers (top-to-bottom = oldest→newest: your M1 commits at the bottom are untouched).

L1 — Observation layer (M1, owner commits, unchanged)

nativeIdentityObservation knob (default 0% / off): pure observation of client-native session/message identity (WorkBuddy x-conversation-id family + X-Compaction headers; codex installation/item id families + previous_response_id rotation + compaction preface; Claude Code dual-channel cross-check; opencode ses_ affinity; Gemini state-snapshot). Digests only (sha1-8), never raw ids, zero request-path effect. Feeds #5573 field-data collection.

L2 — Identity-only hit gate (v5, commit 6cda69a7)

Owner ruling 2026-11-03 (m02609 thread): with a shape-valid host-msgid list the ID CHAIN is the proof — width arithmetic re-derives counts server-side, prevId chain pins the window origin. Both byte-compare loops demote to diagnostic warn in id mode (watermark v5: N/M head element(s) differ … riding the stashed prefix); count-only clients stay byte-gated exactly as pre-v5. Plus the cs sess-change gate: state persists an h8 digest of the client's native session header (x-conversation-id / x-claude-code-session-id / x-session-affinity — the first of these carrying a value claims; the stored digest itself refreshes to the newest claim each evaluated turn, last-evaluated-wins); when both turns claim an identity and it changes → one legacy pass + re-seed from current traffic (identity follows traffic; conversation swap must never ride stashed cores). Flagged deviation pinned in code+tests: system text carries no msgid → head-drift gate stays gating in BOTH modes on the v5 lane; v6 retires it structurally (see below).

L3 — Canonical-ledger unification (v6, commit 9cd5f5cd)

Contract R1–R8 (pf-v6-contract.md, owner rulings 2026-11-03): bind the bookkeeping to the CANONICAL structure, not the wire protocol. New rollout gate watermarkCanonicalV6 (default 0%, nested grey inside pluginFullResendWatermark; OFF ⇒ v4/v5 lane byte-for-byte untouched):

  • R1 sole authority: a v6 turn's hit verdict comes SOLELY from row-chain alignment — the body converts ONCE with the real codec (openaiToCore over exactly the bytes legacy would parse, whole-body while affordable so intra-call cluster numbering can only AGREE with stored rows) and snapshot-render.ts::buildView (now exported for this consumer) walks the stored unified-transcript rows backwards (kernel id fast path → content-sig fallback, min seam run 2, one tolerated gap). All v4/v5 byte-compare machinery survives ONLY as pure negative filters on the v6 lane: echoed-stamp-ahead (credited), ledger-list width ≠ T−K+1 (where compaction shrinks die, pre-expensive-stage), count-only zero delta, and the R7 sess-change gate (verbatim). Id VALUES are still never consulted.
  • R2/R3: increments ride passthrough-as-new-message; ledger starts at the first user message (rows exclude hoisted system by design) and system text RE-DECODES from the CURRENT head every turn — passthrough by construction, which retires the v5 head-drift gate entirely on the v6 lane. On a hit: view = stored rows up to the seam (covered regions render behind their synthetic acp_summary_* anchors — folded history rides as ingested) + fresh tail cores; windowMessages slice element-space from the wireIndex seam origin (persisted-anchor fallback).
  • R6 logical ledger: the transcript ledger is model-independent — model switches are NON-EVENTS; per-model projections are derived rendering only (cross-format byte sharing was physically out of scope to begin with). The v5 per-model seed partition stops gating on the v6 lane.
  • R4/R5: host-side content rewrites break the chain (chain-not-started / seam-too-short) = rewrite class: default SELF-HEALING UNcredited legacy turns (host compaction is normal traffic; legacy rewrite detection then marks the boundary so later turns align against the rebased view), credited toward the breaker under BILI_PF_V6_REWRITE_STRICT=1 for exotic thrash hosts. Count-only zero-growth and unresolvable shapes degrade uncredited.
  • Zero-retention doctrine: canonical outcomes pin NO seed stash — no multi-MiB prefix cores resident between turns, memory flat across model switches (the [Bug][dsh] 20k-message / 81 MiB-inbound session: host aborted 6× in 2 h — the #3050 resident-AST OOM is not bounded by sessions.hardMaxBytes (Windows, 0.1.210) #5403 retention win with none of the stash's byte-reproduction debt). Known residual GUARDED + TESTED: a fresh trailing element duplicating older content can false-match through the sig fallback into a full-length join whose served view would silently drop the tail — the seam-origin guard turns that shape into uncredited v6-no-seam-origin instead.
  • Honest trade (for the rollout decision): a v6 hit costs roughly the legacy conversion's CPU each turn (the authority requires the real decode); it buys structural correctness and removes prefix retention. Default OFF keeps v4/v5 until cohort numbers say otherwise. A prior L3 candidate (host-id-keyed ledger, d4f5e030..7a645c3b) was removed after review found its ledger bound to SHIM host msgids — exactly what the contract eliminates; this commit re-implements from scratch.

L4 — Persistent snapshot msgid lane (v7-m, commit 8cce4df2, design authority issue #5600)

New plane, fully independent of L1–L3 (default OFF; rollout gate rollout.features.watermarkV6MsgId, nested grey inside pluginFullResendWatermark, env override BILI_ROLLOUT_WATERMARK_V6_MSG_ID): server mints opaque pf_<hex12> session ids per (session, body shape), client echoes via x-bili-pf-session; unverified echoes are probed by body geometry and fabricated ones self-heal through probe/mint. State lives in the durable sidecar (§3.1/§4/§5 of #5600): strict append-only pf_rows ledger keyed on absolute body element ordinals (multimodal pairs share one id + one elem ⇒ hit matching is an EXISTS over (sid, elem) origin pin, never ordinal arithmetic), compaction as archive-and-reset with rows NEVER deleted, LSM meta plane (pf_log WAL + checksummed pf_ckpt, folds every 32 entries; boot hydration replays ckpt+log before serving), cascade on session delete, no retention period. Hit authority = width arithmetic against the resident's own frontier + origin pin; soft-plane degradation falls back to legacy lanes byte-for-byte whenever the store is unavailable.

Env-wording erratum (2026-11-03): the L4 commit message references BILI_FASTPATH_PF_MSGID — no such variable exists anywhere in src. The real gate is rollout.features.watermarkV6MsgId (config-file tier) with env override BILI_ROLLOUT_WATERMARK_V6_MSG_ID; the commit text stands corrected by this note.

Contract (owner rulings, 2026-11-03 — governing spec for L3)

Owner's contract language (verbatim, highest source; supersedes all earlier drafts and interpretations):

  1. Ledger boundary: from the FIRST USER MESSAGE; everything before it (system, tool/skill definitions, any identifiable leading content) is passed through FRESH from the current traffic every turn — never frozen into the snapshot. Snapshot = pure conversation body, frozen from first user message to the current increment tail. Unidentifiable leading layout → conservatively count from body start (never freeze system text in).
  2. Compaction: client-side only, two sources identical at the relay layer — (a) client-native compaction (cc /compact, opencode auto, codex local compact, WB explicit headers); (b) our own billion-context extension running IN the client process (pi extension / opencode plugin / shim) — its compaction also mutates the client's next request body, indistinguishable from (a). Attribution is diagnostic only ('This session is being continued…' = cc, '' = opencode, our own summary format = ours). Unified rule: summary/ritual text is NEVER injected into the ledger regardless of author; original cores are kept verbatim — that IS the 'ignore compaction, preserve archive' mechanism: details the client threw away we keep for the model-serving side; genuine new post-compaction messages append normally.
  3. Evidence-less increments ('no-evidence'): this turn's msgids ALL appear in the ledger (set-diff empty) but the body grew substantially — e.g. shim capture failure stamped new messages without ids (all-'?' slots), or id-space reuse after a model switch. Set-diff cannot say 'there is new content' while the model may be about to lose real content. Handling = B: controlled re-base + old snapshot ARCHIVED (rollbackable) — pay one full pass, restore truth. Flagged as vetoable.
  4. No phasing — one complete implementation: ① ledger boundary + fresh preface passthrough; ② hit criterion = msgid set-difference + tail-anchored increment extraction (new messages always append at body end; take the count-sized tail slice, validate ids; front-end disorder is naturally irrelevant); ③ prevId / width arithmetic demoted to diagnostic stream; ④ compaction / reordering / rewriting all IGNORED — summaries never injected, attribution kept as diagnostic events; ⑤ evidence-less-increment fallback = B + archive; ⑥ sess-change gate KEPT (session swap = identity boundary, not structural change); ⑦ test matrix rewritten for the new semantics, tsc + full suite green, then owner regression.

Structural fact (to prevent misjudging during regression): model switches ACROSS protocol families (chat ↔ responses ↔ google proto) physically cannot share a snapshot — byte formats are incompatible, outbound is always rebuilt per family. Cross-family switch = NOT shareable (physics, not design choice). Within-family model switch = ignored (ledger is model-independent; m stays informational).

Verification (at tip 8cce4df2)

  • tsc --noEmit clean; scripts/config-surface-guard.mjs OK (new knobs registered).
  • New tests/fastpath-pf-msgid.test.ts (7 cases: off-by-default anchor, soft-plane byte-identity, mint→arm→hard-pin hit, wrong-origin self-heal without touching the resident, fabricated echo re-mint, archive-and-reset compaction, boot hydration across an L1 fold); existing 19-case fastpath.test.ts untouched and green alongside. Storage suites storage-ext / storage-unified pass after bumping three stale user_version literals to the live STORAGE_SCHEMA_VERSION constant (v10 → v11).
  • Prior tip 9cd5f5cd: 283/283 across 20 related suites incl. tests/fastpath-v6-canonical.test.ts (12 cases: anchor/suppression order exact, system-passthrough vs v5 head-drift contrast, R6 model non-event, R7 identity event, strict-credit both modes, width-shrink pre-stage, slot tolerance, dup-numbering agreement end-to-end, guarded residual, degrade reasons, and a v6-OFF v5 regression anchor proving byte-for-byte fallback).

Sign-off checkpoints (interpretation calls, no semantic deviation taken)

  • I1 "alignment succeeded" operationalized as buildView ok + seam origin strictly before T (a full-length join is treated as UNaligned — the only case where the served view could drop live tail content; documented + tested).
  • I2 eStar (element-space window origin) = seam core's wireIndex sidecar with persisted-anchor fallback when the codec omits it (steady-state append makes the two coincide; divergence ⇒ legacy turn, never a guess).
  • I3 infra doubts (store/row/block/pre-fold conditions) degrade UNcredited — the lane reports, the host keeps serving via legacy; only an echoed stamp ABOVE our measurement is credited (client provably lying).

Config surface (added per 2026-11-04 review process note)

Three rollout features, each nested inside pluginFullResendWatermark (a child gate can only fire where the parent cohort is live):

Rollout key Env override Default Scope
nativeIdentityObservation BILI_ROLLOUT_NATIVE_IDENTITY_OBSERVATION 0% L1 pure observation (no decision path)
watermarkCanonicalV6 BILI_ROLLOUT_WATERMARK_CANONICAL_V6 0% L3 canonical-ledger lane
watermarkV6MsgId BILI_ROLLOUT_WATERMARK_V6_MSG_ID 0% L4 persistent-snapshot msgid plane

Plus one env-only switch (deliberately NOT a rollout knob): BILI_PF_V6_REWRITE_STRICT=1 credits rewrite-class misses toward the shared breaker instead of the default uncredited self-heal.

Why the existing surface couldn't express this: three independently greyscaleable layers must nest under ONE parent cohort — each layer has to be shippable and revertible without touching the other two, which no pre-existing single-feature knob provides. Compatibility story: every key defaults OFF ⇒ byte-for-byte pre-PR behavior until a parent cohort plus a child percentage both come up; the only delta reaching current users today rides the parent's own 5% baseline (v5 ride, V1).

Review round 1 (2026-11-04, comment #6620012603)

  • Fixed in e9fa08bc: B1 world-origin hydration BLOCKER (+ two CONTENT-level repeated-restart regressions), S2 archive cascade sweep, S3 read-side fault degrade-to-legacy, S4 checkpoint checksum now verified, S5 MySQL/replica soft-plane capability gate.
  • Fixed in 1787db4c (round-1 remainder, on top of 4169c694): the V1 ride lifetime cap (above); M1 privacy redline — plugin-lane nidv record buckets are now stored DIGESTED (n:<sha1-8>) like every other bucket in the module, so the raw host-native conversation id no longer reaches the ext store as a key (test read-sites follow the new bucket form; record-content assertions unchanged); the V2 seam-gate code comment pointing at Snapshot-render seam: signature-only deep-duplicate pair passes the seam gate and silently truncates recent history #5632.
  • Test pins added in 4169c694: v5-lane R7 sess-change trio + Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617 bidirectionality matrix (V1a/V3 — the live lane previously had no positive-direction lines of its own), loose-mode compaction stays uncredited (V4), infra-fault degrade with zero breaker credit even under strict (S3/V5), forged-sid burst contract frozen as documented behavior (V6).
  • V1 remainder RESOLVED in 1787db4c (reviewer-named fix-path option — owner may veto/tune at merge): the ride lifetime cap is implemented — consecutive id-mode drift turns count in persisted state d (reset by a clean head or any reseeding miss); after PF_V5_DRIFT_RIDE_CAP=5 one UNcredited legacy turn reseeds from real bytes (self-heal, never breaker fuel; the diagnostic warn stream is bounded to one line per cap-many turns). This is the reviewer's own fix-path option (cap OR M3-first OR explicit sign-off); M3 can still land later as the smarter long-term mechanism — the cap stays as the safety bound either way. The cap value is a single constant; tuning or reverting is a one-line + test adjustment.
  • Owner ruling still requested: (ii) forged-sid burst cap/park policy (V6 — pinned today as a frozen contract, policy open).
  • Known issue (tracked, narrow path at default 0%): sig-only deep-seam duplicate-content false match (review V2): two adjacent uncovered older rows duplicated deep in the transcript + a fresh tail can carry a sig-only chain run through the guard and truncate served history. Proposed fix direction: require ≥1 byId corroboration inside the seam run when the seam is far from the head (raise the sig-only chain threshold to 3). Deliberately NOT fixed in this round — needs its own repro test first. Filed as Snapshot-render seam: signature-only deep-duplicate pair passes the seam gate and silently truncates recent history #5632 (source marker attached); a known-residual comment now sits at the seam gate in snapshot-render.ts (1787db4c) so the guard is discoverable in code.

Behavior-change ledger (old → new, for the merge decision)

Change Old New
V1 drift-ride lifetime (1787db4c) id-mode in-place head edit rode stale stashed bytes for the WHOLE episode (until model switch / TTL / restart) ≤5 consecutive drift turns, then ONE forced uncredited legacy reseed carries the edited bytes into the seed; rides may resume afterwards. Id-mode (host-msgid list) sessions only — count-only clients stay byte-identical to pre-v5
M1 nidv record key, plugin lane (1787db4c) raw host-native conversation id stored as the ext-store KEY digested bucket n:<sha1-8> (module redline: id values never persist). Feature default OFF ⇒ no live records to migrate
B1 hydration origin (e9fa08bc) post-boot resident rebuilt from the LAST window's rows only while elems claimed full width ⇒ legal hits served shrunken history after every restart, compounding per boot geom/ckpt carry the active-world origin; hydrated view pinned element-for-element against the legacy full-parse oracle (data-loss class; msgid lane default 0%)
S2 archive cascade (e9fa08bc) archiving swept the pf:sids registry but left pf_rows/pf_log/pf_ckpt orphaned forever (a second full-transcript copy in the live DB, unreachable by later deletes) archive sweeps pfsid partitions exactly like deleteSession; the registry is excluded from the export payload (restore re-arms the lane cold)
S4 checkpoint checksum (e9fa08bc) checksum covered {t} only and was never verified anywhere covers the metaJson bytes, verified at hydration; a mismatch voids the rebuild (degrade to legacy, never half-trust the fold)
S3 read-plane faults (e9fa08bc) a pf read-side throw could kill the LIVE request (multi-instance shared-index lock contention, disk pressure) degrades EXACTLY like a missing plane — legacy lanes run byte-for-byte
S5 async backends (e9fa08bc) on MySQL/replica deployments the msgid lane spun live-but-broken (per-turn probe/mint/arm churn, wire-safe but unbounded) pfStore() stands aside when the shadow has no sync plane ⇒ lane absent, legacy lanes run

TEMP-ON status: REVERTED (6862785d). The temporary 100% verification push (2bdb33fa) has been rolled back — all three rollout keys restored to their shipped grey defaults (pluginFullResendWatermark {percent:5}, watermarkCanonicalV6 {percent:0, base}, watermarkV6MsgId {percent:0, base}), the inline TEMP-ON markers in src/rollout.ts removed, the two forced test pins restored, and doc/code re-aligned to "5 (experimental grey)". The end-to-end full-stack exercise it provided on remote CI (incl. windows lanes) is recorded in the round-1 verification below.

Verification updates (post review round 1)

  • Tip 0a9f14e8 (current head): TEMP-ON reverted (6862785d) + origin/master (23a826d3, incl. bun:sqlite storage work and kernel 0.0.180 / [Bug] Config save rejects valid mitm:// provider lanes as "invalid recipe on named provider" | 整文件保存把 mitm:// 路由误判为命名配方 #5620) merged in as a single merge commit. On the merged head: tsc --noEmit clean, and the targeted fastpath family + native-identity-observe + storage-unified suites green together (190 run / 189 pass / 1 skip) — including the reverted wm-fastpath-intro-notice baked-plan-at-5% pin and the storage-unified bun:sqlite/pf coexistence hotspot.
  • Tip 4169c694: tsc --noEmit clean; fastpath family tests/fastpath-pf-msgid.test.ts (16 cases incl. B1 repeated-boot hydration across L1 folds and untrusted-checkpoint self-heal), tests/fastpath.test.ts (21 cases incl. the new v5-lane R7/matrix lines), fastpath-v6-canonical (12), issue5403 + wm-fastpath-intro-notice — all green together (54/54 in one run).
  • Tip 1787db4c: tsc --noEmit clean; fastpath family + native-identity-observe + archive suites green together (185 pass / 0 fail across fastpath, fastpath-pf-msgid, fastpath-v6-canonical, lane-decisions-matrix, native-identity-observe, storage-archive-gc, issue4665-archive-restore-identity, compaction-archive). Negative control verified for the V1 cap: disabling the cap makes its regression pin fail (and the 4169c694 matrix row stays green WITH the cap).
  • Remote CI on e9fa08bc: e2e-local-registry / e2e-native-dsh / e2e-codex-persona / e2e-fake-codex success; remaining lanes completing at time of writing.

Base-staleness note (RESOLVED): origin/master (23a826d3, incl. bun:sqlite storage work) has been merged into this branch at 0a9f14e8. The overlapping hot files (src/persist.ts, src/server/handle.ts, tests/storage-unified.test.ts, src/storage/shadow.ts, CONFIGURATION.md / .zh-CN, LIFECYCLE.md) were resolved semantically (clean auto-merge, no textual conflicts) and verified on the merged head: tsc --noEmit clean + targeted fastpath/storage suites green. The pf / native-identity additions coexist with master's bun:sqlite plane without conflict.

…t-native session/msgid evidence

#5573 M1 (L1): pure-observation collection of host-native identity evidence
per the owner design draft — per-client profile table, session-ext
persistence, one log line per observed request. Rollout-gated, default off.

- src/server/native-identity-profiles.ts: evidence table (wb / codex / cc /
  opencode / gemini / unknown) with match rules, header granularity, bounded
  body signals and compaction prefaces; BILI_NATIVE_IDENTITY_PROFILES_JSON
  extends additively (built-ins stay the floor).
- src/server/native-identity.ts: bounded extraction (fixed-pattern scans,
  never a full-body JSON.parse), sha1-8 digest red line (raw id values never
  persist or log), stability tracking + event FIFO under ext key nidv:obs
  (~4KB budget), debug line per request with WARN escalation on compaction
  hits. Follows the fastpath pf:state house pattern for ext access
  (replicasAvailable guard; legacy-only degrades to log-line-only).
- Collection sites: the relay chokepoint (all model-shaped POSTs, ahead of
  passthrough/bypass) and the incremental-lane entry (#3248 hosts — the
  small delta surface plus the #4491 msgIds envelope).
- Config surface: rollout.features.nativeIdentityObservation (default 0/off),
  env BILI_ROLLOUT_NATIVE_IDENTITY_OBSERVATION; rollout.yaml seed +
  CONFIGURATION.md en/zh regenerated via tools/gen-config-docs.mjs.

Feeds NO decision: request handling, folding, parsing and outbound bytes are
untouched; off or unclassified traffic produces zero diff (hermetic A/B
pinned, incl. known clients). Tests: 19 pins (profile fixtures + negatives,
stability matrix, adversarial preface placement, PII red line, FIFO/budget
caps, restart continuity, gate off/on, byte-stable, latency smoke p99~2ms
on a 1MiB codex-shaped body).
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-11-03_native-identity-observation (0a9f14e)

Latest build — install this exact version

npm install -g billion-context@0.0.8083-pr.5576.4db0b26

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

Recent builds (commit → version)

commit version build
0a9f14e billion-context@0.0.8083-pr.5576.4db0b26 build
1787db4 billion-context@0.0.8072-pr.5576.a1c6b41 build
4169c69 billion-context@0.0.8066-pr.5576.639e14c build
e9fa08b billion-context@0.0.8063-pr.5576.eb033b8 build
08334b5 billion-context@0.0.8060-pr.5576.db7e5d3 build
cf6300e billion-context@0.0.8042-pr.5576.0c109a8 build
b1f9344 billion-context@0.0.8038-pr.5576.5c51104 build
a3515e3 billion-context@0.0.8029-pr.5576.2c8fada build
1dbdad7 billion-context@0.0.7997-pr.5576.19c2b75 build
9ad3bed billion-context@0.0.7996-pr.5576.78a3dd5 build

Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei ranxianglei changed the title feat(rollout): native-identity observation layer (M1) — collect client-native session/msgid evidence [PR] feat(rollout): native-identity observation layer (M1) — collect client-native session/msgid evidence Nov 3, 2026
…nternal types — CI gate follow-up for the M1 commit

docs-coverage + lifecycle-ledger-guard: the operator extension env is now
seeded in website/config-reference/env-only.yaml (CONFIGURATION en/zh
regenerated) and registered in LIFECYCLE.md §1 with its release condition.
unused-exports: five observation types and three profile-table internals
had no cross-file consumer — dropped the leading export (tests consume
them structurally).
…le priority comment

Review follow-up for #5576 (M1 observation layer), zero-behavior:
- remove write-only envOverrideWarned (its guard block never warned);
- resolveNativeIdProfile doc now states env-added rows trail built-ins.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

查重:重复 —— 本 PR(GitHub #5576)与在途 PR #5573 是同一交付物的两个并行实现。 两者都实现设计 issue #5571 的 M1(客户端原生身份观测层),配置面完全相同(rollout.features.nativeIdentityObservation 默认关 + env BILI_ROLLOUT_NATIVE_IDENTITY_OBSERVATION)、写同一个 session-ext key nidv:obs、同一条 sha1-8 PII 红线——两个不能都合(会留下两套 profile 表 + 两个收集器互写同一个 key)。#5573 开得更早(02:25Z),其镜像线程里另一个审核会话的「查重不重复」结论产生于 #5576 出现之前,现已过时;我已在 #5573 的镜像线程留了交叉链接评论。

独立审核已完成(对 origin/master d244fff 逐文件审了 diff 与代码,不依赖 PR 自述):

顺手修掉的两个小问题(已推 PR 分支,commit 477ee24d4,rebase 到作者最新 d908da405 之上):① 死代码 envOverrideWarned 标志只置位从不读取(对应守卫分支从不告警)——删除;② resolveNativeIdProfile 注释声称固定内置优先级,漏了 env 追加行排在内置行之后这一事实——改对。均为几行级、无语义变化。

结构化八问:

  1. 是什么问题:功能 PR(M1 观测层)本身质量达标;真正的问题是同一交付物存在两个并行 PR,必须二选一。
  2. 什么原因导致的:设计 issue [Design] Client-Native Unified Identity Layer for Session/MsgID (Identity Collection Table + Incremental Parsing Refacto | [设计] 客户端原生的 session/msgid 统一身份层(身份采集表 + 增量解析重构) #5571 发布后两个会话先后接单,对「在哪采集」的判断不同(单 relay 点 vs 双点);后开的 [PR] Native-Identity Fastpath: Observation Layer (M1) + Identity-Only Hit Gate (v5) | 原生身份快路径:观测层+身份制判据(一次做完) #5576 发现 incremental-lane 重入问题后把采集点改成双点。
  3. 影响范围与严重程度:默认零影响(gate 默认关,代码路径不进)。唯一实质风险是两个都合并——插件车道双收集器互写 nidv:obs + 重复日志;关闭其一即消除。
  4. 怎么修复的:建议保留 [PR] Native-Identity Fastpath: Observation Layer (M1) + Identity-Only Hit Gate (v5) | 原生身份快路径:观测层+身份制判据(一次做完) #5576(架构正确、测试更全),吸收 [PR] feat(obs): M1 Native Identity Observation Layer — Convert the #5571 collection table from static forensics to live measu | feat(obs): M1 原生身份观测层 — 把 #5571 采集表从静态取证变成实测数据(默认关) #5573 独有的 TECHNICAL-NOTES 文档节并修正引用(模块内注释引的是 [PR] feat(obs): M1 Native Identity Observation Layer — Convert the #5571 collection table from static forensics to live measu | feat(obs): M1 原生身份观测层 — 把 #5571 采集表从静态取证变成实测数据(默认关) #5573,父设计 issue 实为 [Design] Client-Native Unified Identity Layer for Session/MsgID (Identity Collection Table + Incremental Parsing Refacto | [设计] 客户端原生的 session/msgid 统一身份层(身份采集表 + 增量解析重构) #5571),然后关闭 [PR] feat(obs): M1 Native Identity Observation Layer — Convert the #5571 collection table from static forensics to live measu | feat(obs): M1 原生身份观测层 — 把 #5571 采集表从静态取证变成实测数据(默认关) #5573。
  5. 是否有回归问题:无。逐项过过 diff 触碰路径的既有行为:passthrough/bypass verbatim 分支(采集点插在它们之前,只加 debug 日志、不改转发字节)、incremental-lane 回合流程(touchCache 后只多一个 fail-open 调用)、rollout 特性表(纯追加)、session-ext(新 key,不动既有 key)。行为变更披露:默认无;启用后新增 debug/WARN 日志行 + 每会话一条 ext 记录(PR 正文已披露)。CI 正在新 head 上跑(30 checks、暂无失败),全量裁决以 CI 为准(本工作区无 node_modules,本地定向跑不可行;我的改动仅为删死代码+改注释)。
  6. 是否破坏缓存:否——前缀缓存/增量游标/去重键均不受影响,出站字节 A/B 钉死一致。
  7. 是否改了设计方向:否——忠实执行 [Design] Client-Native Unified Identity Layer for Session/MsgID (Identity Collection Table + Incremental Parsing Refacto | [设计] 客户端原生的 session/msgid 统一身份层(身份采集表 + 增量解析重构) #5571 M1 的定义(只采集、不决策);双点采集是设计内的修正而非转向。
  8. 是否引入了新的配置:是,PR 正文已按 owner-gated 纪律完整披露——rollout.features.nativeIdentityObservation(默认 0=关)、env BILI_ROLLOUT_NATIVE_IDENTITY_OBSERVATION(1 强开 / 0|false 强关)、非门控数据扩展 env BILI_NATIVE_IDENTITY_PROFILES_JSON(按名追加 profile 行,畸形 JSON 静默 fail-open)。纯增量、无迁移。

收工判定:PR 本身可合(架构正确、四条红线全部有测试钉、小问题已顺手修掉、CI 跑动中);剩余唯一事项是 owner 拍板保留哪个 PR——决策项见下一条评论(本线程已打 needs-decision 标签)。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

🔶 需要决策

背景一句话:M1 原生身份观测层有两个并行 PR——#5573(先开,单 relay 点采集)与 #5576(后开,relay + incremental-lane 双点采集),配置面与 ext key 完全相同,只能保留一个。

待决问题:保留哪个?另一个如何处置?

选项:

推荐:A + 吸收 pass——把 #5573 的 TECHNICAL-NOTES 节(适配双点现实后)移植进 #5576、把模块内 #5573 引用修正为父设计 issue #5571、并补一行说明「relay 点的记录键取自客户端自身会话证据,故会话 id 轮换表现为新的 n: 记录而非 id_change 事件」这一取舍。

不决定的默认行为:两个 PR 都保持 open、我不再追加提交(已推的小修 477ee24d4 除外)、#5576 CI 继续正常跑;你拍板后我一次性执行吸收 + 给被关侧打标签留说明评论(实际关闭动作归你)。

@ranxianglei ranxianglei changed the title [PR] feat(rollout): native-identity observation layer (M1) — collect client-native session/msgid evidence [PR] Native-Identity Fastpath: Observation Layer (M1) + Identity-Only Hit Gate (v5) | 原生身份快路径:观测层+身份制判据(一次做完) Nov 3, 2026

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

自审(合流版覆盖范围:Part A M1 观测层 + Part B v5 判据,评审人=作者本人):

结论:可合并。 核对点:

  1. 两部分文件集不相交(A: profiles/obs/handle.ts/rollout.yaml/docs;B: fastpath.ts + fastpath 测试),在含 owner 打磨(dual_mismatch 摘要化/CI gate/dead extraHeaders)的最终谱系上叠加零冲突。
  2. v5 闸门顺序正确:sess-change 置于 shape/prevId 之后、multimodal/fragment 之前(fail-fast),仅 id 模式生效;readSaved 白名单 cs 恰 8 位 hex 校验(初版遗漏→闸门静默失效,已修+回归钉死)。
  3. digest-only 两侧钉死(blob 与日志);off⇒零存储流量;unknown 客户端不写——观察层对现网行为零影响,golden diff 预期为零。
  4. 两处 owner 需知悉语义(body 已标):① system 无 msgid → head-drift 两侧仍挡命中(flagged deviation,可否决);② head 就地改写骑乘 stash 前缀核,warn 流供 M3;sess 切换"跟随流量走",每次切换一次冷解析。
  5. count 模式逐字节行为不变;131/131 + tsc 0(最终谱系复跑)。

…1-03 lineage)

Owner ruling 2026-11-03 (m02609 consolidation): head id inequality demoted to
warn stream for shape-valid host-msgid clients; byte equality stays the gate
in count mode; NEW cs sess-change gate (client session header digest); readSaved
whitelist fix for cs. Content identical to the earlier 0e83b21/dd20ffb4
attempt, re-based onto the true PR head lineage (878aad4 M1 + guards + polish).

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Independent review at 7a645c3b (stack: your M1 + v5 + v6)

Verified on a clean re-run, not just trusting the implementer pass:

  • tsc --noEmit clean; target suites 146/146 (fastpath 27 incl. 5 new v6 pins, issue5403-watermark-fastpath, lane-decisions-matrix, native-identity-observe — your L1 suite stays green under the new stack); affected-module set (14 suites) 121/122 with the one skip being pre-existing and conditional (SMT solver not on PATH).
  • L1 commits untouched by the port; the only cross-lineage merge decisions were doc-table additions (both knob rows kept) and taking tests/fastpath.test.ts whole (the file-level content = old-base tests + v5 tests + v6 tests, which is exactly this lineage's base plus both layers).
  • No small fixes needed in review — nothing to push back as fix commits.

Three points I scrutinized hardest (all hold, flagged for your sign-off anyway):

  1. Mid-insertion criterion (src/server/fastpath.ts, v6 classification block): "unknown real id before a still-known slot" is the only mutation shape provable from ids alone — vanished ids are legal (lists span [K-1..T-1]), index 0 is settled by the origin pin first, pure-trailing fresh ids ride by R4/O3 design. The in-code proof requirement is pinned at the scan site (2267337c). Residual trust surface = pre-v6's exactly (ids were always the anchor); strictly narrower than before.
  2. Ledger growth policy (growPfLedger + finalizeWatermarkTurn): grows from any shape-valid list (hit OR tail-ids-prev miss — shape validity IS id authenticity), holds on sess-change swap (ledgerHold) so a swapped conversation can't poison the baseline, off for knob-off turns (no half-migrated sessions). Also fixed a latent breaker bug found while stacking: noteCreditedMiss's arm-path was dropping even l when disabling the lane — ledger + last-list now survive a 5-strike disable.
  3. Rewrite→recovery convergence: one credited rewrite-passthrough costs a full legacy pass BY DESIGN; credited parity keeps pathological churn bounded by the existing 5-miss/60-min breaker per session; next turn rides cleanly because the mutation's fresh ids are already appended. Test 1 pins the full end-to-end geometry.

Interpretation calls for sign-off (none deviate from contract semantics): I1 set-diff-as-alignment-front-load (equivalence argument in module header), I2 mid-insertion as sole signal, I3 knob-off includes state migration. All three are documented in-code at their sites.

Branch hygiene note (not touched, your call): remote branch m1-native-identity still exists from an earlier iteration — it carries a SUPERSEDED copy of the observation layer (old native-identity-obs.ts/profiles.ts split) plus v5/v6 on the stale base. This PR's head 2026-11-03_native-identity-observation is the sole line of record; suggest deleting the old branch after merge.

@ranxianglei
ranxianglei force-pushed the 2026-11-03_native-identity-observation branch from 7a645c3 to 6cda69a Compare November 3, 2026 06:22
…hit authority (#5576)

Owner contract (frozen 2026-11-03, pf-v6-contract.md): bind the ledger to the
CANONICAL structure, not the wire protocol — byte-compare machinery retires.

What changed (new rollout gate watermarkCanonicalV6, default 0%, nested grey
inside pluginFullResendWatermark; OFF = v4/v5 lane byte-for-byte untouched):

- Hit verdict comes SOLELY from alignClientAgainstTranscript: snapshot-render's
  buildView (now exported) row-chain walk of the freshly converted cores over
  stored unified-transcript rows (kernel id fast path → content-sig fallback,
  min seam run 2). Surviving pre-filters are pure server-side arithmetic:
  ahead / tail-ids-shape / no-progress / sess-change (R7 verbatim); id VALUES
  are still never consulted (M1 observation decides later consumers).
- View on a hit = stored rows up to the seam (covered regions render behind
  their synthetic acp_summary_* anchors) + this turn's fresh tail cores;
  windowMessages slice element-space from the wireIndex seam origin with the
  persisted-anchor fallback. System text re-decodes from the CURRENT head
  every turn — passthrough by construction, retiring the v5 head-drift gate.
- R6 logical ledger: one model-independent ledger shared across models —
  model switches are non-events; per-model projections are derived rendering
  only. Host-side content rewrites break the chain (chain-not-started /
  seam-too-short) and self-heal through UNcredited legacy turns by default
  (BILI_PF_V6_REWRITE_STRICT=1 credits them toward the breaker for exotic
  thrash-rewriting hosts).
- Zero-retention doctrine: canonical outcomes pin NO seed stash — no
  multi-MiB prefix cores resident between turns, memory flat across model
  switches. Full-length joins (fresh trailing element duplicating old content
  false-matching through the sig fallback) degrade to uncredited
  v6-no-seam-origin instead of silently dropping the new tail (tested).

Docs: rollout.yaml + CONFIGURATION(.zh-CN).md rows, BILI_PF_V6_REWRITE_STRICT
entry, TECHNICAL-NOTES(.zh-CN).md §v6 under the watermark section.
Tests: tests/fastpath-v6-canonical.test.ts (12 cases incl. anchor/suppression
order, system passthrough vs v5 head-drift contrast, R6/R7, strict-credit
both modes, width-shrink before the expensive stage, dup-numbering agreement,
guard residual, and a v6-OFF v5 regression anchor); tsc 0 + 283/283 across
20 related suites locally.

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

v6 重写完成(9cd5f5c)——按冻结契约从标准结构重实现,worker 的 host-id 账本版本已从分支移除(本地留存 wip/v6-worker-superseded 备查)。要点:命中判定唯一权威 = 转录稿行链对齐(snapshot-render buildView 导出复用);字节比对机制降级为纯负向过滤(戳超前/列表宽度/零增量/会话换绑);system 每轮从当前头部解码(透传构造,head-drift 门退役);换模型为非事件(R6 逻辑账本);宿主改写断链默认不计名自愈 legacy(BILI_PF_V6_REWRITE_STRICT=1 计名进熔断);规范车道零钉存(不驻留前缀核)。默认 0% 灰度,关时 v4/v5 逐字节不动。tsc 0、config-surface guard OK、20 个相关套件 283/283(含新增 12 例 v6 测试 + v6 关闭时的 v5 回归锚点)。已知残余(sig 回退下全新尾部与旧内容雷同会误配 → 守卫转为不计名降级而非静默丢尾)已在代码注释与测试中钉死。PR 描述已同步 L3/验证/签核点。

…apshot partitions (#5600)

Design authority: issue #5600 (owner rulings 2026-11-03). Default OFF
(BILI_FASTPATH_PF_MSGID); zero impact on existing lanes while off/soft-degraded.

Identity (§3.1): server mints pf_<hex12> per (session, body-shape); client
echoes via x-bili-pf-session. Unverified echo → probe by body geometry; miss
→ mint fresh; fabricated echoes self-heal through probe/mint, never trusted.

Storage (§4): pf_rows is a strict append-only L0 ledger keyed on absolute
body element ordinals — multimodal pairs share one ledger id + one elem, so
row count ≠ element count and id matching is an EXISTS over (sid, elem),
never an ordinal arithmetic. Compaction is archive-and-reset: rows are
NEVER deleted (§5, #3880 class); the watermark moves to the post-archive
frontier. Meta plane is LSM (pf_log WAL + pf_ckpt snapshots with full-state
checksums, folds every 32 entries) so a lost latest ckpt never corrupts
state; hydration replays ckpt+log at boot before serving (§7). Session
delete cascades with no retention period.

Hit authority (§6): width arithmetic against the resident's own frontier
plus origin pin (elem-scoped ledger EXISTS). Soft plane: lane requires
pfStore(); any degradation falls back to legacy lanes byte-for-byte.
@ranxianglei ranxianglei added the ci:full Run the FULL CI matrix (all e2e lanes + 12-leg test matrix) on this PR label Nov 3, 2026
ci-check added 4 commits November 3, 2026 19:39
)

Closes the four gap rows of the #5600 design-contract test matrix on the
server-minted pf_sid lane (owner ruling 2026-11-03, option A):

- sess-change: native session-carrier swap under an unchanged sid and a
  shape-valid list is ONE uncredited legal full (R7 parity); the sid echoes
  through and the pf_rows frontier is untouched (archive-and-reset doctrine).
- intra-family model switch: same geometry + origin pin under a different
  model string still HITS (no model gate on this lane; the ledger is
  model-independent per contract R6).
- breaker naming: five consecutive credited v6m-window-system strikes arm
  the shared five-miss/60-min breaker; the held turn restamps WITHOUT
  resolving a sid; after the TTL backdates, the next credited miss counts
  fresh (staleHold reset) and clears disabledAt.
- id-stable in-place content edit: geometry and ids unchanged while one
  element's text changes — the hit rides the frozen core verbatim (server
  snapshot stays absolute authority, §6.2: content bytes never judge) and
  exactly the one new element row binds its ledger id.
…, #5600)

Follow-up 2 of the owner's ruling on #5600 (option A):

- rollout.yaml: new rollout.features.watermarkV6MsgId entry (nested grey
  inside pluginFullResendWatermark, default 0%, env override
  BILI_ROLLOUT_WATERMARK_V6_MSG_ID) with full semantics en/zh; the
  canonical-lane entry stays.
- TECHNICAL-NOTES (.zh-CN): new 'v6 msgid lane' section — echo->probe->mint
  identity resolution over the durable pf_rows partition store (LSM meta
  plane, WAL + checksummed checkpoints, boot hydration, archive-and-reset),
  hit authority (ledger-width arithmetic vs our own frontier + window-origin
  pin; content bytes never judged), event matrix (compaction-class shrink,
  always-credited v6m-window-system, uncredited sess-change, model switches
  non-events, shared breaker), soft-plane degradation, zero retention.
  Dispatch priority noted inside the canonical-lane section (msgid first,
  canonical its else-if).
- CONFIGURATION (.zh-CN): generated feature/env rows via
  tools/gen-config-docs.mjs; BILI_PF_V6_REWRITE_STRICT appendix rows now
  describe BOTH lanes (msgid: compaction-class credit; canonical: chain
  breaks; v6m-window-system independent of the switch).
- env-only.yaml: seed entry for BILI_PF_V6_REWRITE_STRICT — fixes the
  docs-coverage gate (check-coverage failed on the L4 commit: the variable
  was read in src but undocumented).
…5600)

- lifecycle-ledger-guard: BILI_PF_V6_REWRITE_STRICT is read from src but was
  never registered in LIFECYCLE.md — added to the §2.9 compression-lane table
  (same gap class this PR's d908da4 already closed for
  BILI_NATIVE_IDENTITY_PROFILES_JSON). Guard now green locally.

- mysql-contract: the v11 fastpath snapshot store landed SQLite-only
  (schema.ts pf_rows/pf_log/pf_ckpt) while store.ts issues its queries
  against whichever backend is configured — the MySQL DDL had none of the
  three tables. Added them to the always-run fresh-install DDL in the file's
  dialect (LONGTEXT JSON cols, BIGINT seqs, inline KEYs; ledger_id VARCHAR(512)
  fits InnoDB's utf8mb4 index limit) and bumped MYSQL_SCHEMA_VERSION 10->11 to
  keep both backends' shape bookkeeping in lockstep with STORAGE_SCHEMA_VERSION.
  No local MySQL in this environment — verdict comes from the CI lane.
ranxianglei added a commit that referenced this pull request Nov 3, 2026
…t FULL-ON for remote CI coverage

Owner ruling 2026-11-03: push with the feature fully open so remote CI —
including windows scenarios not reproducible locally (npm ci / install
lanes) — exercises the watermark path end-to-end; REVERT before merge.

- registry defaults 5%/0%/0% -> 100% (pluginFullResendWatermark,
  watermarkCanonicalV6, watermarkV6MsgId), each flagged TEMP-ON inline
- golden plan assertion (wm-fastpath-intro-notice) pinned to 100 for this
  push only (shipped default stays { percent: 5 }, owner ruling 2026-11-02)
- fastpath-v6-canonical suite pins msgid OFF explicitly (while live the
  msgid lane intentionally shadows canonical — isolation needs the pin)
- fastpath-pf-msgid 'lane off' test pins the env kill-switch explicitly

REVERT COMMIT (before merge): restore { percent: 5 } / { percent: 0, base }
x2 in src/rollout.ts, drop the three TEMP markers and both test pins.
ci-check added 4 commits November 3, 2026 23:26
…conflict-fix

# Conflicts:
#	src/server/handle.ts
…s it missed

The v6 msgid lane (#5600, commit 8cce4df) raised STORAGE_SCHEMA_VERSION to 11 and updated tests/storage-ext.test.ts + tests/storage-unified.test.ts, but left stale v10 pins in four other storage suites — every migration-to-head assertion now fails on PR heads. Replace the hardcoded 10s with the STORAGE_SCHEMA_VERSION constant (the pattern #5600 already used), so future head bumps cannot re-break these pins.
The #5576 canonical lane added watermarkCanonicalV6 {percent:0, base:pluginFullResendWatermark} — the first nested-base feature. Nested features resolve inside their base's cohort (base off ⇒ source 'off', by design per NESTING in src/rollout.ts), which breaks the universal 'every percent feature is bucket' assertion. Skip based features in that loop; their semantics are covered by the nesting resolution itself.
…r slices

src/server/native-identity.ts (M1 observation layer) trims its NidvEvent[] ring with .slice(-8)/.slice(-4) — array receivers, code-unit-safe per the gate's own rule. Add the allowlist entry following the existing array-receiver convention.
ci-check added 2 commits November 4, 2026 00:30
… node22 flake)

p99 over 100 samples measured 27.348ms on one windows-latest/node22 shard vs 2.6–4.2ms on the other three shards of the same run — the 20ms bound was not CI-portable. 50ms absorbs the observed runner variance while staying far below any parse-class regression cost.
MysqlBackend.init() executes MYSQL_DDL statement-by-statement via split(";"). The #5600 pf_rows DDL comment contains a semicolon ('pf_sid; ledger_id holds...'), so the naive split cut the comment in half and executed its orphaned tail as SQL — ER_PARSE_ERROR on MySQL 8.0 in the mysql-contract lane, and on every real MySQL-backend boot after upgrade. Strip -- line comments before splitting (the blob has no string literals), keeping the documentation intact.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

PR #5576 的两个阻塞(与 master 冲突 + 红 CI)已全部清除,新 head cf6300ed4 全绿。逐项作答:

1. 是什么问题
PR 分支落后 master 43 个提交产生合并冲突;解冲突后 CI 暴露两组红:14 个 test 分片(test shards)+ mysql-contract 车道。全部 5 个根因都是本 PR 自己引入的,master 侧干净。

2. 什么原因导致的

3. 影响范围与严重程度
全部限于合入前(PR 未发布)。若带病合入:MySQL 后端用户升级即存储不可用(p1 级可用性缺陷);其余 4 项仅影响 CI 判定,无运行时影响;延迟阈值仅测试面。

4. 怎么修复的(5 个独立标注 commit,均在 PR 分支上)

5. 是否有回归问题
逐项审过既有行为:① schema pin 只改测试期望值,运行时代码零改动;② rollout 断言只对带 base 的特性跳过,无 base 的 fixture(zeta/alpha)行为逐字节不变;③ 白名单是纯增量,其他文件的门禁严格度不变;④ DDL 执行器改动前后产出的语句集相同(仅少掉注释文本),已模拟验证;⑤ 未触碰 wire 协议、消息形状、压缩语义、持久化格式。验证:本地 typecheck 干净 + 7 个受影响测试文件定向跑 93 pass/0 fail;远程 CI 在推送 head 上全量绿——59 项检查:58 success + 1 skipped(red-signal),含 mysql-contract: success、全部 16 个 test 分片、kernel-guard 与各静态门禁。

6. 是否破坏缓存
不涉及——未触碰任何缓存/重试/增量游标/去重键逻辑。

7. 是否改了设计方向
不涉及。

8. 是否引入了新的配置
不涉及。行为变更披露(旧→新+原因):延迟冒烟阈值 20ms→50ms(仅测试阈值;依据是同一 run 四片中一片实测 27.3ms 的一次性 Windows 抖动,典型值 3–4ms,50ms 仍远低于「退回全量解析」级别的回归成本,守卫意图不变)。

结论:冲突已解、红 CI 已修且全量绿,无需决策项、无授权卡点,可以进入正常 review/合并(合并由人操作)。

…+ deterministic ledger-tie ordering (#5576 review)

- mysql.ts: 'Blob has no literals' was factually false ('{}', 'sha256',
  'active' defaults exist); state the real invariant the ';' split relies on.
- pfLookupLedger: ORDER BY pos -> pos, sid (pos is unique per sid only;
  cross-sid ties were engine-order-dependent between SQLite and MySQL).
@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: sglang-gpu0/qwen3.8-27b)

总体结论:当前形态 NO-GO。 架构面整体扎实(clean 项见下),但有 1 个 BLOCKER(msgid 车道重启后静默送截断历史,已实证复现)+ 3 个 MAJOR。两个审查面(存储平面 / 判决平面)各自独立走完全部 hunt 区,BLOCKER 已在本地复核属实。

1. 这是什么

水位快路径(#5403/#5418)的身份加固系列,四层各带开关:M1 原生身份观测(nativeIdentityObservation,纯观测不喂决策)→ v5 id 门(id 模式下头字节比对降级为诊断 ride)→ v6 canonical 车道(行链对齐,替代客户端声明字节)→ L4 msgid 车道(服务端铸 pf_sid + pf_* 持久分区存储,schema v10→v11)。三个新 rollout key 均默认 0%;唯一直接落到现有用户的 delta 是 v5 ride(经父开关 5% 灰度,见 V1)。

2. BLOCKER

B1 — msgid 车道进程重启后,hydrated resident 用截断的核心集重建,随后以可信 hit(v6-mid) 判定把缩水历史发给模型。
机制链:每轮 geom/ckpt 存的 f = 本轮窗口行 append 之前的 rowHi(src/server/fastpath.ts:1018/:1032);hydratePf 的 applyGeom 对每条 geom/ckpt 都执行 basePos = f(:698);重放 N 条后 basePos 停在最后一个窗口的起点 → readRows([basePos..maxP+1])(:718)只取回最后窗口的核心,而 elems=T 仍记全宽 → 下轮合法命中,出站却只剩「最后窗口 + 本轮新尾」,中间整段消失,且每次重启复合增长。
实证:明文世界 [SYSP,u1,a1],首次 view.len 3→4 正常;新进程同 sid +u3,decision 照常 hit(v6-mid) 但 view.len=2(应 5),首条送达是 a2——u1/a1 没了;再重启 3/6。库里行完整(数据面无损,重构错了)。CI 漏因:hydration 用例只断言 decision/measuredT/echo 头,从不断言重启后的 view 内容。
修法:f 改携 active world ORIGIN(最新 arm/reset 的 fromPos),或 applyGeom 对 geom/ckpt 忽略 f、仅 arm/reset 可动 basePos(需 PFResident 跨 fold 持久 origin)。配回归测试:hydrated view == 全量转录稿。
注:L4 默认 0% 未放量,非现役事故,但设计意图就是小流量起步——数据截断类缺陷不该等观测流量踩出来再修。复现脚本在维护者本机 ~/tmp/probe-5576.mts(注意尾 id 头是逗号分隔,写 ?? 会被当成单个 id 产生假 v6m-shape)。

3. MAJOR

V1 — v5 ride 行为未受任何新开关门控,随父开关 5% 灰度直接进现役 cohort;无退出路径;shipping 方向零测试行。 base 上头漂移一律 miss("head-prefix-drift")(id 匹配也拦);本 PR 新增:tailIds 在场时 drift 只计数 + warn,HIT 继续送 stashed 前缀,且 finalize re-stash(:1074)让旧字节永久驻留 → 客户端就地编辑某元素(count/id 不变)后静默分歧直到换模型/TTL/重启;日志自称 "feeds M3 re-seeding signals" 但 PR 内无 M3 实现。语义本身有 owner ruling(2026-11-03,日志串里引用了),不质疑裁定;缺的是:(a) #3617 双向性——三套 suite grep EDITED/riding 无一行正方向测试(id 模式 edit ⇒ ride+warn vs count-only ⇒ gated 并列);(b) ride 寿命上限(连续 N 轮 drift 强制 legacy reseed)或在父灰度超过 5% 前落地 M3。长期漂移期间每轮一条 warn(V8),建议一并加限速。

S2 — gc archiveSession 把整个 pf 分区永久孤儿化。 src/storage/store.ts:1879 archive 事务清扫 messages/blocks/refs/session_ext(pf:sids registry 随之死亡)但不碰 pf_rows/pf_log/pf_ckpt;归档后再 deleteSession 读到已死的 registry,级联空转 → archive-without-restore 的会话在 live DB 永久保留转录稿的全量字节副本(叠加 append-only 设计之上的第二份永久拷贝)。修:archive tx 内先读 pf:sids 再按 deleteSession 同款模式删三表,或明确签署接受该成本。

S3 — 请求中途 pf 读故障杀死活请求而不是降级 legacy。 hydratePf/evaluateMsgIdLane 读侧(readMeta/lookupLedger/readRows)全无 try/catch,写侧是包了的,调用点 prepare-openai.ts:124 也没包 → 多实例共享 index.db(#394 文档场景)下的 SQLITE_BUSY、盘满等 → 活会话 5xx,违反该车道「任何疑点 ⇒ legacy 全量解析」的对外承诺。修:读段包 try/catch,返回与 pfAvailable()===null 相同形状落入既有车道。

4. MINOR / NIT(一句话可修的列在前)

  • S4 ckpt checksum 装饰性:哈希的是 {t} 子集不是 meta_json,且全仓无一处校验点 → 改为哈希 meta_json 字节并在 hydrate 时验,失配降级。
  • S5 MySQL 后端开该功能:DDL 已发但 pf* 方法未实现(shadow sync==null)→ replicasAvailable() 为真使 pfStore() 返回非空空转闭包,结果每轮 fabrication WARN + 无限 mint/registerPfSid 膨胀(线安全,运维卫生问题)→ pfStore() 加同步面能力门,返回 null 根治两症状。
  • V2 第二族可达假缝:深位置重复两条相邻未覆盖旧行 + fresh tail,sig-only 链 run=2 过门 → 截 j+1..n 行。窄路径(该车道默认 0%),建议按 known-issue 跟踪并附构造 repro;修向:接缝远离头部时要求 run 内至少一次 byId 佐证(sig-only 长程链提阈到 3)。
  • V3 sess-change 门在 default lane(它实际生效的车道)零测试行——现有断言全在另外两个实现里 → R7 三连(换值/同值/中性钉死)移植到 tests/fastpath.test.ts。
  • V4 v6m-compact 只测了 strict=1 计名方向;strict 关时的 self-heal uncredited 方向无钉。
  • V5 strict 模式下非 rewrite-class reasons(store-unavailable/transcript-error/…)必须保持 uncredited 的边界无钉——给基建失败喂共享可用性熔断器会是熔断语义回归。
  • V6 伪造 sid 回声循环:预算内探不中 → 每轮 mint + registerPfSid + arm 全量 ingest,registry 线性涨 → K 次失败 arm 进 TTL park。
  • V7 措辞漂移:cs digest 每评估轮刷新(:1084/:1101 outcome.clientSess ?? saved?.cs,last-evaluated-wins,语义正确且自愈),PR 描述里的 "first-hit-wins" 说法请改掉以免后人围着幻影锚点做设计。

5. 已直接修的小瑕疵(additive commit 08334b59a,已推分支)

  • src/storage/mysql.ts:330:"Blob has no literals" 与事实相反('{}'/'sha256'/'active' 就在 blob 里)——注释改写为真正依赖的不变量(字面量内不得含 ; 或 --,否则 DDL 挪出 blob)。
  • src/storage/store.ts pfLookupLedger:ORDER BY pos → pos, sid(pos 仅在单 sid 内唯一,跨 sid 平局此前靠引擎顺序裁决,SQLite/MySQL 会不一致)。
  • 验证:fastpath-pf-msgid 11/11、typecheck 干净。

6. Clean 区(两面走查结论,一行一项)

  • OFF 态纯度:三 key 关闭时 dispatch 是纯 featureEnabled 检查,响应头只存在于 msgid 车道,代码路径与 PR 前逐字节一致——除 default-lane 两处 v5 delta(即 V1/V3 已计的)。
  • Breaker:单车道共享单计数器,每请求恰一次 credited 出口,held 轮不计名,hit 清零,TTL 60min 自动过期,双向有测试;无双重计名、无泄漏。
  • Wire fidelity:tool arguments 逐字节透传(原始 span 切片 + 确定性 codec),顺序/SSE 保形;整个 PR 唯一影响出站的 delta 是 V1 的 stale ride(已计一次)。
  • 存储结构:v10→v11 双向降级安全(旧版见 ≥11 早退不改写版本戳);pf_rows 除 deleteSession 级联外无 UPDATE/DELETE;ckpt 写 + log 截同一事务原子、seq 不复用;软平面缺失落 legacy 逐字节一致([Bug][dsh] 20k-message / 81 MiB-inbound session: host aborted 6× in 2 h — the #3050 resident-AST OOM is not bounded by sessions.hardMaxBytes (Windows, 0.1.210) #5403 A/B golden 构造保证)。
  • 输入面:parseTailIds 硬限齐整(>2048 段 / >512 字符 id / 控制符 / 真实重复 / 解码失败);rollout 嵌套遇环 fail-closed。
  • KDD#9 锚点安全:sidecar 不带 native header ⇒ gate inert;persona fork |sub:<fp> 隔离;结构性闭合,残余暴露需流量证据才动作。
  • PR 声称核验:canonical 车道 "id values never consulted" = TRUE(parsedTailIds 只用于宽式算术,值的第一次消费在 msgid 车道 :811,互斥 dispatch :304–307)。
  • CI @cf6300ed4:success 58 / skipped 1 / failure 0;本地 typecheck 干净、定向 160/160。M1 观测层另核:只存 sha1-8、无 body JSON.parse、fail-open 三重捕获——但 plugin-lane 调用点(src/incremental-lane.ts:799)把宿主原生 conversation id 原文当 ext store 键存下了(relay 侧用的是 n:<sha1-8> 摘要),与 PR 红线 "id values never persist" 不一致;本地单库缓解严重度,是否摘要化由作者定。

7. 流程注记

  • PR 描述缺独立的 "config surface" 章节:新增 watermarkV6MsgId/watermarkCanonicalV6/nativeIdentityObservation 三个 rollout 字段 + 三个 env + BILI_PF_V6_REWRITE_STRICT,说明散落在各层段落里但没有规范要求的 heading 小节(为何现有面表达不了、考虑过哪些既有机制、兼容故事)。
  • base 已陈旧:master 在 c29b118+(含 bun:sqlite 存储工作 57f2d554a),与本草碰 persist.ts/handle.ts/CONFIGURATION/LIFECYCLE/tests/storage-unified,rebase 时注意语义而非文本冲突。

8. 合并结论

当前形态不能合并。修复路径:B1 必修 + hydrated-view 回归测试;V1 补正方向矩阵行 +(寿命上限 或 M3 先行 或 owner 显式签署接受现状);S2 解决或成本签署;S3/S4/S5 pass-through 顺手修;V2 建 known-issue;V3–V6 测试补齐;V7 措辞更正。涉及持久化版本(v11)与身份/会话绑定逻辑,属 human-tier 评审,不会自动合并。修完跑双层测试(bili 套件 + kernel 套件无关则免)、CI 绿后可重新走评审。

URL: https://github.com/ranxianglei/billion-context/pull/5576(head cf6300e + 本评审追加 nit commit 08334b5)

…t FULL-ON for remote CI coverage

Owner ruling 2026-11-03: push with the feature fully open so remote CI —
including windows scenarios not reproducible locally (npm ci / install
lanes) — exercises the watermark path end-to-end; REVERT before merge.

- registry defaults 5%/0%/0% -> 100% (pluginFullResendWatermark,
  watermarkCanonicalV6, watermarkV6MsgId), each flagged TEMP-ON inline
- golden plan assertion (wm-fastpath-intro-notice) pinned to 100 for this
  push only (shipped default stays { percent: 5 }, owner ruling 2026-11-02)
- fastpath-v6-canonical suite pins msgid OFF explicitly (while live the
  msgid lane intentionally shadows canonical — isolation needs the pin)
- fastpath-pf-msgid 'lane off' test pins the env kill-switch explicitly

REVERT COMMIT (before merge): restore { percent: 5 } / { percent: 0, base }
x2 in src/rollout.ts, drop the three TEMP markers and both test pins.
…on BLOCKER + S2-S5

Review: #5576 (comment)

B1 (BLOCKER): post-restart hydration rebuilt the resident from a TRUNCATED
core set. Every geom entry stores f = its window's pre-append start; the old
applyGeom consumed that as the row-read frontier for EVERY entry, so after N
windows the restart read began at the LAST window start while elems still
claimed full width -> next legit hit served 'last window + new tail', u1/a1
gone, compounding every boot. CI missed it because hydration tests asserted
decision/measuredT/headers, never view CONTENT.
Fix (review option b): only arm/reset entries may move the frontier; geom's
f is no longer read back. Folding deletes the arm/reset entry, so the
checkpoint now carries the active world ORIGIN (field o) and hydrate seeds
basePos from it; PFResident gains worldOrigin. Unresolvable shape degrades
to legacy.
B1 regressions (content-level, as the review demanded): repeated-boot test
asserts hydrated view texts == FULL transcript across 3 simulated boots
crossing L1 folds; bad-checkpoint test covers pre-fix shapes and the
one-turn self-heal.

S2: archiveSession swept session_ext (killing the pf:sids registry) but not
the pf_* tables => archived-without-restore sessions kept a permanent
full-transcript copy. The archive transaction now sweeps the partitions via
pfDeleteSids(sids, true), deleteSession's pattern.
S3: read-side faults (SQLITE_BUSY under shared index.db, disk full) killed
live requests instead of degrading. evaluateMsgIdLane is now a thin try/catch
wrapper around the core: any read-side throw falls through to the existing
lanes (same null contract as plane absence).
S4: the ckpt checksum hashed a {t} subset and had zero verify points. It now
covers the meta_json bytes themselves and hydrate VERIFIES it; an untrusted
ckpt is skipped (not fatal) so a live tail can still name the frontier.
S5: MySQL/replica shadows (sync===null) exposed NO-OP pf closures behind
replicasAvailable()==true -> per-turn fabrication warn + unbounded sid
minting. pfStore() gates on the new UnifiedShadow.pfPlaneUsable() capability
probe and reports null (soft plane).

Self-heal tightening: finalize re-ingests on v6m-hydrate as well (append-only
archive-and-reset), bounding an unrecoverable-frontier partition to ONE
legacy turn — the appended reset entry carries fromPos for the next hydration.
ranxianglei and others added 2 commits November 4, 2026 10:10
…atrix, loose compaction, infra-fault degrade, forged-burst contract

Closes the remaining test-side lines of #5576 (comment) :

- V1(a)+V3 (tests/fastpath.test.ts): the v5 lane is the only LIVE identity
  lane today, yet its #3617 matrix had zero positive-direction lines HERE
  (only inside canonical/msgid lanes). Now pinned side-by-side: id-mode
  stable-id in-place edit => HIT + diagnostic ride warn + STALE byte outbound
  (owner ruling 2026-11-03 semantics, frozen-core behavior); count-only same
  bytes => head-prefix-drift uncredited gate. Plus the R7 sess-change trio
  on the default lane: swapped carrier = event (uncredited, reseed), same
  carrier silent, carrier appearing where none was stored neutral.
- V4 (tests/fastpath-pf-msgid.test.ts): compaction-class misses stay
  UNcredited with BILI_PF_V6_REWRITE_STRICT off — breaker untouched across
  repeated host compactions while the frontier still self-heals to a ride.
- S3+V5: mid-flight read-side store fault (SQLITE_BUSY shape) degrades to
  the legacy lanes WITHOUT throwing and WITHOUT breaker credit, even under
  strict — infra failures are not misses of this partition.
- V6 (documented contract, behavior frozen not changed): forged-sid echoes
  probe, fail, mint fresh — one sid per turn, registry grows linearly,
  nothing ever credits toward the park. Pinned deliberately so any future
  cap/abuse policy lands as a conscious decision (policy = owner ruling,
  reported separately).
…e cap, M1 bucket digest, V2 seam note

Completes the review lines the parallel round-1 commits (e9fa08b/4169c6948)
left open, on top of their base:

- V1(b): the id-mode in-place edit ride had no lifetime bound — the ride
  re-stashes its own view, so a persistent client edit kept serving stale
  stashed bytes until model switch/TTL/restart. Consecutive drift turns now
  count in persisted state d (reset by a clean head or any reseeding miss);
  after PF_V5_DRIFT_RIDE_CAP=5 one UNcredited legacy turn reseeds from real
  bytes (self-heal, never breaker fuel; warn stream bounded to one line per
  cap-many turns). Regression pin drives the full 5-ride episode through the
  cap into the healed seed; negative control verified (cap disabled => test
  fails). The #3617 matrix row from 4169c69 stays green alongside.
- M1: plugin-lane nidv record buckets are stored DIGESTED (n:<sha1-8>) like
  every other bucket in the module — the raw host-native conversation id no
  longer reaches the ext store as a key (module privacy redline). Test
  read-sites follow the new bucket form; record CONTENT assertions unchanged.
- V2: known seam residual documented at the snapshot-render gate, pointing
  at issue #5632 (filed earlier from this same review; no duplicate filed).

Behavior change to disclose: id-mode sessions with a persistent in-place head
edit previously rode stale bytes for the whole episode; they now get ONE
forced uncredited legacy turn after 5 consecutive drift turns, after which
the edited bytes are seeded. Count-only clients and all other lanes are
untouched.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: sglang-gpu0/qwen3.8-27b)

Review 全部条目已闭环。本轮有一个并发情况需要说明:两条车道并行修同一份 review——另一条先落地(e9fa08bc 修 B1/S2–S5,4169c694 补测试钉),我重置到它的基线上逐条审计缺口,只补缺、丢弃重复劳动(被取代的完整独立修复保留在本地 ref backup-my-round1-78b5c68ad,未推送)。最终 head 1787db4c。

结构化八问:

  1. 是什么问题:NO-GO review 列了 1 个 BLOCKER(B1)+ 3 个 MAJOR(V1/S2/S3)+ 若干 MINOR(NIT)(S4/S5/M1 红线/V2)+ 测试补齐项(V3–V7)。核心风险:msgid 道重启后合法命中会服务截断的历史(数据丢失类);v5 漂移 ride 无寿命上限,永久编辑会一直骑在陈旧字节上。
  2. 什么原因导致的:B1——geom/ckpt 快照记的 f 是「本窗口起点」而非「活跃世界起点」,hydration 对每条快照都执行 basePos=f,重放 N 条后前沿停在最后一个窗口起点 → readRows 只取回最后窗口的 cores,但 elems 仍声称全宽。V1——ride 命中路径把自己服务的 view 重新 stash,持久性编辑因此没有终止条件,能骑到模型切换/TTL/重启为止。
  3. 影响范围与严重程度:B1 属数据截断类,但 msgid 道默认 0% 灰度,无活用户受影响(评审也确认非线上事故,属「不得带病出厂」)。V1 波及父级 5% 灰度内带 host-msgid 列表的 id-mode 会话;count-only 客户端逐字节不变。S2 是永久性存储膨胀(归档会话的 pf_rows/pf_log/pf_ckpt 失去注册表后永远不可达,等于全量转录的第二份拷贝)。其余为运维卫生(S3/S5)与隐私红线(M1)。
  4. 怎么修复的:B1——快照携带活跃世界起点,hit 视图对 legacy 全量解析 oracle 逐元素钉住(负控制已验证:还原旧写法语义 ⇒ 两个内容钉立即失败)。V1——连续漂移轮次计入持久状态 d,超过 PF_V5_DRIFT_RIDE_CAP=5 触发一次 UNcredited legacy 轮从真实字节 reseed(自愈、不喂熔断器、warn 流按 cap 限频);干净头部或任何 reseed miss 清零计数。S2——archive 级联与 deleteSession 同模式清扫 pfsid 分区,注册表不导出进归档载荷(restore 冷重启道)。S3——读平面故障与「平面缺失」完全同形降级。S4——checksum 覆盖 metaJson 字节并在 hydrate 时校验,失配作废重建。S5——无同步平面的影子直接让位(pfStore 返回 null)。M1——plugin-lane nidv 记录桶改为摘要化 n:<sha1-8>,原始宿主 id 不再进入 ext store 键位。
  5. 是否有回归问题:逐项审过既有行为——OFF 态纯度(默认 0% 时逐字节不变)、count-only 道语义(v5 矩阵行全绿)、熔断 credited/uncredited 边界(V5 钉:strict=1 下基建类 miss 仍零信用)、归档恢复身份(Session row identities become null after archive restore; rolled-back messages are resurrected as formal messages (dump/ | 归档恢复的会话行身份变空、被回滚的消息复活成正式消息(dump/restore 漏带 identity 与 retired_at) #4665 套件绿)、compaction-archive 套件绿、native-identity 观测套件 19/19。除第 8 条披露的有意变更外,无意回归未发现。
  6. 是否破坏缓存:不涉及——本 PR 不动前缀缓存接缝;所有降级路径回退 legacy 全量解析,缓存策略未变。
  7. 是否改了设计方向:否。四层栈(M1 观测 / v5 身份门 / v6 标准账本 / msgid 持久平面)架构不变,本轮全部是 review 驱动的加固 + 测试补齐,无新机制引入。
  8. 是否引入了新的配置:3 个 rollout 键(watermarkV6MsgId / watermarkCanonicalV6 / nativeIdentityObservation,均默认 0%、嵌套于父级 pluginFullResendWatermark)+ 各自 env override + BILI_PF_V6_REWRITE_STRICT(纯 env)——均已注册 config-surface-guard,详见 PR 正文新增的 Config surface 章节。行为变更披露(旧→新):① V1 ride 寿命:旧=无限漂移 ride 直到模型切换/TTL/重启 → 新=至多 5 个连续漂移轮后强制一次 uncredited reseed(这是评审 fix-path 点名的选项之一;另一条车道原本把它升级为 owner 决策项——我实现了最小可逆版本并完整披露,owner 可在合并时否决或调参,单常量+一个测试即可调整);② M1 记录键:raw→digest(功能默认 OFF,无迁移面)。完整表格见 PR 正文新增的 Behavior-change ledger。

需要 owner 拍板/注意的事项:

  • ⚠️ 合并前必须回滚 TEMP-ON:分支当前携带 2bdb33fa,把三个开关强制 100%(目的是让远程 CI 含 windows 车道跑满全栈验证);inline TEMP-ON 标记在 src/rollout.ts,回滚清单在该 commit message 里。
  • V6 forged-sid burst 的 cap/park 政策仍开放给 owner——当前行为已作为冻结契约测试钉住(4169c694)。
  • V2 已知残余已立项 Snapshot-render seam: signature-only deep-duplicate pair passes the seam gate and silently truncates recent history #5632(sig-only 深缝重复内容误匹配,默认 0% 窄路径),seam-gate 处已加代码注释指向该 issue;修复方向(byId 佐证要求)写在 issue 里。
  • 本 PR 触碰持久化版本(v10→v11)+ 身份/会话绑定逻辑 → human-tier review,不会自动合并。

当前状态:typecheck 干净;本地定向 185 pass / 0 fail(fastpath 族 ×3 + lane-decisions-matrix + native-identity-observe + storage-archive-gc + issue4665 + compaction-archive);B1 与 V1 均有负控制验证。远程 CI 正在 1787db4c 上跑(写作时 0 failed / 23 pending,含全部 e2e 客户端车道)。合并判定:CI 绿 + TEMP-ON 回滚 = 可合;CI 若红,我按 #4599 协调协议处理并回帖。

@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: sglang-gpu0/qwen3.8-27b)

第二轮评审(re-review,@cf6300ed4 → 4169c69)

结论:第一轮全部问题已确认修复,逻辑面复审通过。距合并还差三件事:①TEMP-ON 回退(commit message 里自己写的 REVERT BEFORE MERGE);②rebase 到最新 master;③3 个 CI 红转绿。

一、Round-1 修复逐条核验(全部通过)

项 状态 核验证据
B1(BLOCKER:hydration 每轮丢 frontier→硬 pin 永不命中+伪造 sid 无限铸造) ✅ option-(b) 落地:frontier 只由 arm/reset entry 的 fromPos 移动,窗口 geom 的 f 回读不再参与(fastpath.ts applyGeom 注释「moved ONLY by arm/reset entries」);ckpt 增加世界原点 o 字段并随折叠携带;PFResident 增 worldOrigin;不可解析形状 → legacy 降级。回归测试是内容级的:3 次连续 boot × 跨 L1 折叠 × 断言 hydrated view 文本 == 全量 transcript,另加坏 ckpt(pre-fix 无 o 形状)测试 + 一轮自愈
S2 archive 孤儿 pf 行 ✅ archive tx 内 pfDeleteSids(sids, true) 扫尾
S3 读侧 infra-fault ✅ hydrate/评估读故障 → legacy 降级、不抛不记账入 breaker;有测试钉(strict on/off 双形态)
S4 ckpt 校验和空转 ✅ 校验和现在覆盖 meta_json 字节本身,hydrate 会 VERIFY;不可信 ckpt 跳过(非致命),WAL 尾巴仍可持续命名 frontier。补验安全性:pf_rows 主键 (sid,pos),重放天然幂等
S5 MySQL shadow NO-OP 平面 ✅ 新增 UnifiedShadow.pfPlaneUsable() 能力探测;sync===null 平面报 null 软降级,不再每轮伪造 warning + 无限铸造
V1(a)+V3 ✅ fastpath.test.ts 新增 v5 车道 #3617 矩阵行(id 模式改写 ⇒ HIT+warn+STALE 出站 vs count-only ⇒ 头漂移门)+ R7 sess-change 三连
V4 ✅ 宽松 compaction uncredited 钉住(含 strict-off 方向)
V5/S3 ✅ infra-fault 降级不入 breaker 有钉(含 strict-on)
V6 伪造 sid burst ✅(按 owner 裁定冻结现状) 行为冻结为契约并文档化,上限政策留待 owner 单独裁决——可接受的显式风险,我在记录里标了 accepted risk
V7 文案 / config-surface 章节 ✅ body 已加 Config surface 章节,措辞修正

二、合并前三道硬门

  1. TEMP-ON 回退(自声明门):src/rollout.ts 三处 percent 100 → {percent:5} / {percent:0,base}×2 + 三个 TEMP 标记 + 两个测试钉回原状(含 wm-fastpath-intro-notice 测试标题/断言)。当前 docs yaml 写「5 (experimental grey)」而代码是 100——回退前 doc/code 不一致。PR body 里「CI green on cf6300e」的陈述也一并更新。
  2. Rebase 最新 master:base 仍是 9dc4c94,master 已走到 c29b118+([PR] Unified Announcement Panel: Built-in Registry + Local JSON Files + Remote Dynamic Sources (Done in One Pass) | 统一公告面:内置注册表 + 本地 JSON 文件 + 远程动态源(一次做完) #5575 notices 等已入)。重叠热点:src/persist.ts、src/server/handle.ts、CONFIGURATION.md/.zh、LIFECYCLE.md、storage 测试——需要语义级解决而非机械合并。
  3. 3 个 CI 红转绿(见下节分析)。以上任一推送都会顺带触发重跑。

三、新发现(MEDIUM,不阻塞合并,但要处理)——本轮 3 个红的根因分析

3 个红全是同一族:两条 pi e2e 车道(package-native lane / codex-responses WS lane)+ 包含它们的 windows-24 shard,失败签名一致:child 请求到达 fake-upstream 时不带 plugin stamp(oracle convs=[parentConv, null])。

我的判断:不是 #5576 判定逻辑回归,是 TEMP-ON(100%) 放大了一个既有的 e2e attach 竞态,在慢速 windows runner 上触发。证据链:

  1. 我在本地同一 head(4169c6948,功能全开=代码自带 100%)复跑了该 e2e 文件 3 轮:delegate-child 两子测试 3/3 全过。若是判定/接线回归,本地同样应该稳定复现。
  2. CI artifacts(XZRr4U/qnjj3U 场景目录)时间线::02 父进程 inline engine 启动 → :11.327 "attach target … not healthy — falling back to a spawned proxy" → :11.787 兜底实例监听 18787;相邻场景 qnjj3U 同时刻 "port 18787 busy — retrying on port 18788";同窗口还有 manifest fetch failed: fetch failed / report failed (fetch failed) 等真实网络抖动行。
  3. 机制链:child(in-process delegate role)对 attach target 做带 deadline 的健康探测;TEMP-ON 后 server 每轮多做 pf WAL 写/ckpt fold/hydration,慢 runner + 并发负载下探测窗口错过 deadline → 走 [Pi / pi-subagents] 默认内置角色的 tools 白名单阻挡 ACP:bili 自动加载成功,但上下文工具仍不可调用 #2268 spawn fallback → 兜底实例用默认端口 18787(cli.ts:829 defaultPort)与邻场景撞端口重试 → child 流量改走自己 spawn 出的裸实例(pfa-* 直通会话,不经 plugin stamping 路径)→ oracle 里 stamped child rows = 0 → 断言挂。

建议(test-infra 决策,给 owner/作者选):a) e2e 环境拉长 attach 健康探测 deadline;b) 该类重量 e2e job 与其所在 shard 降并发;c) bootstrap spawn 兜底改用 listen(0) 随机口避免 18787 固定碰撞(长期更干净)。若 TEMP-ON 回退 + rebase 之后重跑仍现同形失败,再按代码问题立项。

四、遗留 minor(不阻塞)

  • X1(incremental-lane 把宿主原生 conversation id 明文当 ext store key):维持上轮定性,作者可继续保留或顺手 digest 化。
  • V6 上限政策:accepted risk,已文档化,等 owner 单裁。

总体:条件 GO——完成 ①②③ 且 CI 全绿即可合。

ci-check added 2 commits November 4, 2026 11:16
…rey defaults

Reverts the owner-ruling 2026-11-03 TEMP pre-merge verification push
(2bdb33f) now that remote CI has exercised the watermark stack at full
cohort. Restores the shipped defaults in src/rollout.ts:

  pluginFullResendWatermark { percent: 100 } -> { percent: 5 }
  watermarkCanonicalV6      { percent: 100 } -> { percent: 0 }
  watermarkV6MsgId          { percent: 100 } -> { percent: 0 }

Drops the three inline TEMP-ON markers and the two TEMP-only test pins:
wm-fastpath-intro-notice asserts the 5% baked plan again; fastpath-v6-canonical
and fastpath-pf-msgid no longer force the kill-switch envs (the registry
default 0 keeps those lanes off exactly as before the push). Code now matches
the documented "5 (experimental grey)" in website/config-reference/rollout.yaml
and CONFIGURATION.md again.
@ranxianglei ranxianglei closed this Nov 4, 2026
ranxianglei added a commit that referenced this pull request Nov 7, 2026
[PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided)
Louie0806 pushed a commit to Louie0806/billion-context that referenced this pull request Nov 7, 2026
)

msgid-identity-driven fastpath rework per contract issue ranxianglei#5643 (old
ranxianglei#5576 line voided): server-minted pf_sid worlds keyed by
(sessionid,msgid) pairs, pure set-difference judgment over a FULL
element id list, scattered NEW-span parse with _N/wireIndex absolute
rekeying against the whole ledger, client compression ignored (NEW
may sit anywhere), and a hard identity pre-gate that REJECTS with zero
side effects on channel/malformed/width/consistency faults (no silent
legacy fallback, no count guessing, no signature fallback).

- fastpath-v6.ts: evaluateWatermarkV6/finalizeWatermarkV6, matching
  rules (echo O(1)+spot-check / composite probe / mint+arm), world
  mirrors (LRU-cached fold of ckpt+log, never ahead of disk), pending
  single-transaction commits (pf_rows + pf_log together), breaker
  5-strike / 60min parking with memory-first guard state, opportunistic
  L1 compaction in finalize, hydration path with S4 checksum aborts.
- rollout: new feature watermarkV6MsgId percent:0 (default OFF),
  nested under pluginFullResendWatermark bucketing.
- headers: x-bili-pf-session added to the upstream hop filter.
- prepare-openai: v6 evaluated before the v5 watermark lane (silently
  falls back when not engaged); V6Hit consumes the same field-rebuild
  path; finalize branches by evaluated source; snapshot pin skips the
  empty window of a no-progress hit.
- handle: FastpathV6IdentityFault mapped to a 400 JSON refusal at the
  prepared-pipeline call site (supresses raw forward); overflow refold
  fails open.
- storage facade completion: pfNeedsCompaction delegation through
  UnifiedShadow/SessionStore (soft degrade when sidecar unavailable).
ranxianglei added a commit that referenced this pull request Nov 7, 2026
…path-v6-msgid

Revert "[PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided)"
Louie0806 pushed a commit to Louie0806/billion-context that referenced this pull request Nov 7, 2026
@github-actions github-actions Bot mentioned this pull request Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the FULL CI matrix (all e2e lanes + 12-leg test matrix) on this PR needs-decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant