Repository navigation
Inbound markers: one declarative strip engine for all four wires (#2789, #2798, #2811 plan B) - #2815
Conversation
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g billion-context@0.0.3379-pr.2815.e60bde1This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr2815.tgz
npm install -g packageInstall instructions are refreshed on each push. |
ae702d6 to
9b480c9
Compare
The lane-coverage contract wrote complete well-formed ACP/bili-chain tags as literal angle brackets in source. KDD#2 requires \x3c/\x3e escapes because tooling strips well-formed tags: if that ever touches these files, the RENDER_TAG_PROSE pin silently degrades to plain-prose (a tautology — render-tag stripping regression would go undetected) and the CHAIN_CARRIER fixture breaks its carriers>=1 assertion. Convert the four occurrences (test fixtures + spec.ts render_tag note) to hex escapes; runtime strings are byte-identical (verified by re-running marker-lane-coverage.test.ts, still 4/4 green).
[bot] 🏷 Review 结论:#2815 声明式 inbound marker 引擎(plan B)— 可合(人合) 先说结论:方向和实现都对,我把分支 rebase 到当前 master 后独立跑了定向测试 + typecheck,并顺手修了一处 KDD#2 违规(已推独立 commit)。下面是结构化八问。 ① 是什么问题 ② 什么原因导致的 ③ 影响范围与严重程度 ④ 怎么修复的 ⑤ 是否有回归问题 —— 我审过的既有行为,逐条结论:
⑥ 是否破坏缓存 ⑦ 是否改了设计方向 ⑧ 是否引入新配置 验证(rebase 到当前 master@9fb91641b 之上):
我顺手修的一处(小问题直接修,已推): 两处非阻塞 nit(供合并时定夺,我没动): 新增 parity-gate 测试里 判定:可合(人合)。 非 auto-merge 候选(wire/message-shape 变更、双模式影响,§7.4 必须人合)。rebase 干净、定向测试绿、行为变更均已披露。请 owner 确认 ⑤ 第一条(inbound render-tag span 现在也被剥)符合预期后合并即可。 |
…f-download (#2833) Engine acquisition no longer depends on host install-time build-script approval (the strictDepBuilds gate behind #2823/#2825): - detectEngine order: built-in node:sqlite (Node >= 22.5) -> host better-sqlite3 require probe -> registered self-downloaded loader -> none (legacy-only per the #2825 contract) - new src/storage/engine-bootstrap.ts: one-time download of the pinned better-sqlite3 13.0.3 npm tarball (in-tarball N-API prebuilds for all 8 platform-arch targets, no build scripts), sha512-pinned in-repo, extracted via a dependency-free gunzip+ustar reader into <cache>/sqlite/better-sqlite3-<version>, atomic publish, 6h cooldown after failure, proxy-aware via the existing network.proxy chain - storage.sqliteAutoDownload (default true) / BILI_SQLITE_AUTO_DOWNLOAD gate the network fetch only; a cached copy is used even when false - wired into bili start before the first store open (bounded ~10s); enablement log now records engine/source for field diagnosis
… notes, changelog (#2833)
…unpassable
assert.equal from node:assert/strict is strictEqual: comparing the fake
driver's get() result against a fresh { ok: true } literal always fails on
reference equality, so the test could never pass. Use deepEqual to assert
the actual value (the point: the registered self-downloaded loader drives a
real open through the driver).
Review fix for PR #2845 (found by local run of the suite: 20/21 with this
line failing).
downloadAndInstall published via fsp.rename(tmpDir, finalDir) only. When a stale/partial final dir already exists (killed run, local tampering), the rename fails ENOTEMPTY over the non-empty dir, so every retry re-downloads and fails at publish, re-arming the 6h cooldown indefinitely — contradicting the documented 'corrupt cache dir is skipped' contract. Before publishing: a usable existing dir means a concurrent process already published the same pinned artifact (treat as success); an unusable one is removed and replaced. Adds the hermetic regression test (stale dir -> downloaded, complete cache, no cooldown marker). Review fix for PR #2845.
…xports gate OpenedDatabase (driver.ts) and EngineBootstrapSpec/DEFAULT_ENGINE_SPEC/ BootstrapStatus/EnsureSqliteEngineOptions (engine-bootstrap.ts) have no references outside their declaring files and tsup emits no d.ts, so the exports are pure surface bloat. Unexport them; behavior unchanged. Review fix for PR #2845 (CI unused-exports job).
…blocks The PR hand-edited the generated param-ref/env-map blocks instead of adding a seed entry, which broke docs-sync/docs-coverage/config-surface-guard. Add the seed to website/config-reference/process.yaml and regenerate (also fixes the env-map row ordering the generator sorts by name). Sync the static zh long-form BILI_STORAGE_UNIFIED entry to the new engine-resolution wording. Review fix for PR #2845.
|
KDD #10 follow-up from the #2811 matrix review (comment 6110433698) is in: the google inbound walk did strip |
[bot] 🏷 Upstream conflict resolved & re-verified — no push needed from me The
Re-review of the two fix commits added since my first pass:
The Google storage-render golden change (the one item I wanted proven safe): only 中文结构化结论(八问)
判定:分支现状(远端 |
Single table (src/marker/spec.ts) for the ten inbound marker classes; raw-stage engine (src/marker/engine.ts) walks anthropic/openai/google/ responses wire shapes through one ordered pipeline: per-slot status-body consumer (#2789) + stripAcpTags, whole-message panels/nudge echoes/ carriers. Google walk is new — the old generic walk could not see content.parts objects (#2798). Integrity note + silence clause moved to the leaf src/marker/anchors.ts so the inbound nudge-echo matcher shares the emitter bytes (single-source); compress-tool.ts re-exports. Pure addition: no prepare wires the engine yet (next commit).
…tion Every raw-stage consumer now runs one engine instead of per-protocol ad-hoc sequences: prepare-anthropic/openai/responses replace their three-step loops with logRawStripCounts(stripRawStage(parsed, wire)); prepare-google gains the full stage (fixes #2798: panels/status/markers were never stripped there — the generic walk was blind to content.parts objects); fork adoption paths (fork-adoption.ts responses/google/messages, agent/fork-adopt.ts openai/anthropic/responses) strip through the same engine, fixing #2789's head-only consumption (whole status bodies are now eaten by the block consumer while prose lines survive). Two orderings preserved by construction: - carriers FIRST: chain-checkpoint's whole-PART exact stripper must run before the lenient tag walk, or whole carriers degrade into whitespace zombies instead of being spliced (#1542's log line would starve). - keepBiliArtifacts on the inbound walk: the #1634 artifact family (chain tags, forged handoff headers, captured summary blocks) is model-OUTPUT stripping; inbound history keeps user-data semantics (#1039/#1395) — strict carriers and state-layer anchors own those shapes.
Pins the #2811 leak matrix: every raw-stage marker class (panel message, acp_status report body incl. contiguous sections, confirmation/failure marker lines, render-tag spans, chain carriers, nudge echoes) is stripped on anthropic/openai/responses/google through the one engine, while downstream-owned shapes (summary anchors, codex handoff) and surrounding prose are preserved. Fixes a latent engine bug the contract caught immediately: nudge splices in stripMessagesArray ran inside a forward for..of, so removing a message skipped the next one entirely (a multi-part message after a nudge echo was never walked). Reverse index now, matching the google/responses walks. The responses nudge splice covers string-content messages; array-content user messages keep their shape (text slots cleaned) — the wire-realistic form, and the dogfood corpus join (issue #2811) found zero user-role nudge echoes in 440+ sessions.
…ts spec/engine parity The unused-exports gate flagged MARKER_SPECS as DEAD and the marker types as INTERNAL_ONLY. Instead of waiving, the coverage test now imports the declarative table and pins both directions: every raw-stage id declared in the spec is one this file proves behaviorally, and the engine's counts shape is unchanged (no silently-added class). engine.ts annotates its consumeAcpStatusBody result with StatusBodyResult.
The lane-coverage contract wrote complete well-formed ACP/bili-chain tags as literal angle brackets in source. KDD#2 requires \x3c/\x3e escapes because tooling strips well-formed tags: if that ever touches these files, the RENDER_TAG_PROSE pin silently degrades to plain-prose (a tautology — render-tag stripping regression would go undetected) and the CHAIN_CARRIER fixture breaks its carriers>=1 assertion. Convert the four occurrences (test fixtures + spec.ts render_tag note) to hex escapes; runtime strings are byte-identical (verified by re-running marker-lane-coverage.test.ts, still 4/4 green).
…oundary) The CI battery caught the overreach: anthropic-pck-verbatim T2 pins that a FOREIGN literal <acp> tag in user text survives advisory processing byte-intact — it is user data. stripTextSlot now runs the marker-LINE stripper only (same semantics as the old stripAcpStatusMarkers wiring); tag-echo-filter.ts is back to byte-identical with master (the short-lived keepBiliArtifacts param is gone with its only caller). spec.ts moves render_tag to a new 'render' stage with the boundary note; the coverage contract pins both directions (raw ids exclude render_tag; the literal tag survives raw on every wire). Google storage goldens regenerated: they were committed snapshots of the storage-render/golden-storage-render/engine-proofs + the full marker and fork families green.
…k (KDD #10) Review of the leak matrix (issue #2811 comment 6110433698) pinned the fatality class before implementation did: any rewrite of signed text desyncs it from its signature and bricks replay (#1882/#1960). The google inbound walk DID strip p.text on thought parts — a resent {text, thought:true} / {text, thoughtSignature} part whose thinking echoed a marker line would have been rewritten. Now gated explicitly: - google: parts with thought===true or thoughtSignature are skipped - anthropic/openai: thinking/redacted_thinking content blocks are skipped (structurally safe — their text lives in .thinking — but the gate pins the shape against future drift) - responses: thinking/redacted_thinking/reasoning content parts skipped (top-level reasoning items were already type-gated out) Coverage gains a byte-invariance fixture per signed channel: marker-shaped text inside every signed slot, JSON.stringify-equal before/after the walk, with non-signed control slots still stripping on the same body.
…d strips shrink resent history ~268 B/turn)
311e54b to
b6da1cd
Compare
…section heads), latest-user paste guard, spec note for array nudges
- tests/marker-render-contract.test.ts drives the REAL handleAcpStatus
renderer over six report variants and asserts consumeAcpStatusBody eats
each whole. It immediately caught three section heads missing from
SECTION_HEADS ('Compressible ranges (', 'COMPRESSED — ', 'Sorted by
size/time') — hand-maintained whitelists drift; the render contract
cannot.
- status-body consumption now skips the LATEST user message on every wire
(#2815 review pt 3): the current turn is not an echo; a user pasting an
acp_status report to report a bug keeps it. Marker head lines still
strip (review acknowledged). Resent positions consume as before.
- spec.ts: array-content nudge echoes documented as not whole-message
spliced on anthropic/openai/responses (google parts walk covers all).
|
Review round 2 — all four points addressed in d4032e0:
Local: marker families + goldens + wire-contract + #1542 all green; tsc clean. |
#2821 replay: a mid-session model switch re-minted every tool-call id on re-projection (content byte-identical). Both Pass 0 flank scans died at their FIRST cell (changed preamble at the head, appended turn at the tail): byPos=0, 3289 covered ids missing, three drift passes -> "substrate destroyed" -> total unfold -> ~4MB raw out -> doomed-probe 502. The order was intact the whole time; only its evidence was id-gated. Owner rule (2026-10-12): 顺序为中心, hash 为辅助 — order is the carrier, content the per-cell gate, the id a fast path; no single dimension's miss may cascade into total unfold. - Pass 0 resync: a fingerprint mismatch is a gap, not a wall — scans resync at the next run of MIN_RESYNC_RUN consecutive same-index agreements (gaps bounded by MAX_RESYNC_GAPS) and keep claiming verified spans behind the break; order breaks are observable ("N order break(s) resynced" in the drift line). - Pass 1.5 (#2396 detection promoted to claiming): re-minted tool-call ids with byte-identical normalized content are claimed k-th-to-k-th with the byNorm length guard — the fallback when no stored positional copy exists. After one churn pass the self-saved {ids, canon} copy upgrades recovery back to the positional path. - Escalation semantics: "substrate destroyed" only counts gaps that survived resync AND the content passes. - unchanged: "never fuzzy similarity" — the hash stays a HARD per-cell gate (mis-attribution discipline); genuinely edited cells stay honestly unmatched and re-enter the wire. AGENTS.md §2 gains the order-centric principle as design decision #11. Tests: tests/issue2915-order-centric-reconcile.test.ts (2821 replay, mid-island resync, insertion offset, twin claiming incl. rerun-twin rejection + k-th families, three-generation escalation lifecycle).
[bot] 🏷 Round 2 fixes verified — all four points hold, empirically Re-cloned the branch tip ( Empirical checks
Per point
Behavior changes flagged (§Deliverables #4)
No new issues found while reviewing — the four facets are one mechanism, handled together. 中文结构化结论(八问)
判定: |
…twin-claim pass Review supplement for #2939: the comment claimed 'both claim passes key on the toolCallId itself', which stopped being true once Pass 1.5 (#2915) promoted content-identical twins from detection to claiming. Reworded to state what the counter actually reports now: suspects that survived EVERY claim pass (length-guard rejects, exhausted duplicate families, real edits) — detection evidence only, never a repair target.
|
Proof-angle review (independent verification, additive; nothing pushed to this branch) Verified green in a clean worktree: marker-lane-coverage 4, marker-render-contract 2, marker-echo 23, bili-artifact-strip 16, e2e-tag-echo 2 — plus code-order checks that The PR proves its own axis thoroughly. One axis is missing, and it is the conjunctive one (same class as the #2807 review gap): fold-state continuity across the strip transition. Mechanism: ids are minted by Probe (unit-level, real engine + real adapter, repair mode, 12 marker-laden assistant turns + 12 user turns, block covering all 24): Findings:
Suggested additions (happy to follow up with the test if wanted):
Two boundary notes (not blockers): non-latest user positions carrying a pasted report still get consumed (marker-lines already had this policy — fine, just documenting); affinity pre-strip ordering is currently load-bearing and unpinned — one cheap test (resolve before/after strip → same session) would keep it that way. |
[bot] 🏷 Fold-state continuity: verified real — and I found one more concrete harm than the list Re-verified the mechanism in a clean worktree (not just your probe). It holds, and I traced the blast radius further than the writeup. Mechanism confirmed (code-level)
Blast radius — one harm beyond the list. Not just the error log. Once latched, Your findings 1 & 2: agree with both; both should become pins (no-reap under strip-churn; bounded-window convergence via #2741/#2755 nesting/retirement), not behavior changes. Decision on finding 3: FIX, in this PR, before merge — not document-and-accept. Shipping #2815 alone introduces a false ERROR + model-misdirection on exactly the sessions it exists to help. A scary-but-wrong "substrate destroyed" also erodes trust in the real destruction alert. Proposed fix (Tier 1, minimal, mirrors the existing carve-out):
If you'd rather go deeper (Tier 2): re-anchor strip-churned ids onto their same-slot candidate by normalizing both sides through the strip before identity-compare — then churn stops accruing at all (also closes finding 2 faster). Bigger blast radius (id assignment); better long-term; fine as a follow-up issue if so. Tests I'd add: continuity (existing fold + marker-laden resend → assert no reap, no escalation/latch, re-fold heals, old block retires, churn stops warning, Give me the nod on Tier 1 (+ the anti-masking predicate) and I'll implement in this PR with the tests; or say Tier 2 / split-to-follow-up and I'll route accordingly. 中文结构化结论(八问)
判定:发现 #3 实证成立且可修;建议本 PR 内修(Tier 1),反掩盖谓词待你点头后我落地(含测试);#1/#2 转 pin;边界注记采纳。此轴未闭合前不合——这是本 PR 在其自身目标群体上引入的回归。 |
…es that exercise it (#2989) The #2815 stack rewired production session identity to personaConversationOrder (src/session-resolve.ts) and retired src/persona-anchor.ts from the wiring, but the proof surface kept driving the retired module: three suites pin its ladder, six suites reset only its (now inert) anchor map while the LIVE order skeletons never reset, and nothing pinned the new resolver's contract directly. - tests/session-resolve-twins.test.ts: live twins for the full ladder (claim/shallow tag claim/|sub:aux, match/ride, fork-lane byte continuity vs a locally computed sha256-16 so persisted pre-upgrade lanes keep their keys, grown/compacted reanchor, line-confined model switch migration, post-restart chain-race rescue + control, head truncation, #150 task lane) plus the two DESIGNED divergences from the retired ladder pinned explicitly: (a) header-corroborated absorption is looser (any persona change + declared model switch), (b) tag-less shallow first sight derives |sub:aux. - Old-vs-new parity was probed exhaustively first: every scenario the retired pins cover agrees at the key level except (a)/(b). - Mark the three retired-module suites as retired pins; do not extend. - resetSessionOrderForTest() beside every resetPersonaAnchorsForTest() call site (incl. dsh-persona-fingerprint's startRig) so test isolation covers the live state. Refs #2989
…es that exercise it (#2989) The #2815 stack rewired production session identity to personaConversationOrder (src/session-resolve.ts) and retired src/persona-anchor.ts from the wiring, but the proof surface kept driving the retired module: three suites pin its ladder, six suites reset only its (now inert) anchor map while the LIVE order skeletons never reset, and nothing pinned the new resolver's contract directly. - tests/session-resolve-twins.test.ts: live twins for the full ladder (claim/shallow tag claim/|sub:aux, match/ride, fork-lane byte continuity vs a locally computed sha256-16 so persisted pre-upgrade lanes keep their keys, grown/compacted reanchor, line-confined model switch migration, post-restart chain-race rescue + control, head truncation, #150 task lane) plus the two DESIGNED divergences from the retired ladder pinned explicitly: (a) header-corroborated absorption is looser (any persona change + declared model switch), (b) tag-less shallow first sight derives |sub:aux. - Old-vs-new parity was probed exhaustively first: every scenario the retired pins cover agrees at the key level except (a)/(b). - Mark the three retired-module suites as retired pins; do not extend. - resetSessionOrderForTest() beside every resetPersonaAnchorsForTest() call site (incl. dsh-persona-fingerprint's startRig) so test isolation covers the live state. Refs #2989
…session-resolver (ranxianglei#2989) The ranxianglei#2815 stack swapped production session-identity wiring to personaConversationOrder (src/session-resolve.ts); persona-anchor.ts is retired from production but at least seven suites still pinned it. - issue2601-model-drift-absorption: 7 live-twin tests over the same corpus — shared expectations where OLD and NEW agree (absorption keeps the raw key, fork keys byte-identical), designed divergences marked: v2 folds model-switch absorption into the reanchor branch (no separate action), requires a deep main-shaped history (shallow switches fork), and never parses system line-diff (drift + header change rides raw). - dsh-persona-continuity: twin unit block with one shared key expectation per old-ladder row; e2e rigs already run through live wiring and pass unchanged. - issue2601-persona-fork-lineage: twin for the resolvePersonaKey migrate row — the re-serialized switch rides raw via the continuation branch on order+fragment evidence; control arm proves unproven switches still fork. Part-A chainContinues rows kept: prefix-affinity stays LIVE (server.ts anonymous-ladder). - Category B (fingerprint/durable-tool-identity/issue2419/2446/2447/ 2481/responses-instructions-drift): rig hygiene now resets the live session-order registry instead of the retired anchor ladder (dsh-persona-fingerprint's import was dead — its absence leaked skeletons across rigs; now reset in startRig like every sibling). - issue2944-neutral-skeleton / session-continuity-proof: label stale references to the retired module. Targeted verification: 12 suites, 91 tests green; typecheck clean; new import-graph gate passes.
…ows EBUSY) The full-mode leg leaked the sidecar handle (cancelAll does not close index.db) and used plain rmSync — EBUSY on the windows runners. Same fix pattern as #2815's export-jsonl legs.
…l full-suite runs Local full-suite runs are environment noise (firewalled live lanes, port collisions with a concurrently running bili — claude-native on 18787, ranxianglei#394 — cross-file interference): the ranxianglei#2815 review session saw ~20 env-failure false positives locally while the CI test lanes (scripts/run-ci-tests.mjs, ranxianglei#2816) were the ground truth — including catching the real codex-turn-isolation regression. Codify: targeted suites locally, full-suite green/red from the pushed head's CI test lanes (§7.2, §7.4 item 3, §3 command table).
…eanups (ranxianglei#3818) - resolveStorageMode: absent-everywhere default shadow -> full (ranxianglei#3818; the shadow dry-run reconciled cleanly since ranxianglei#2815 - JSON envelopes keep being written, legacy remains the one-line escape hatch) - writerOff saves: a mid-build 3-strike sidecar disable now lands one synchronous JSON envelope write in the same tick (ranxianglei#3135 1) - persistence disabled (BILI_PERSIST=0 / enabled:false) is recorded as an intentional opt-out - no fabricated storage-degraded banner (ranxianglei#3135 2) - the storageMode stamp follows the live instance: a dead/absent sidecar stamps legacy so records describe the copy that actually holds data (ranxianglei#3135 3) - verifyDrift + driftedSessions on the /__bili/status wire; drifted sessions serve from the JSON envelope until a clean sample (ranxianglei#3135 4) - self-bootstrap: an unloadable cached engine copy is removed and one pinned sha512 download retried instead of warn-forever-stuck (ranxianglei#3135 5) - bounded boot unions index-only sessions so jsonWriter=off sessions stay enumerable after restart (ranxianglei#3135 6)
What
Implements plan B (marker 声明化) from #2811 for the raw (inbound) stage: one declarative engine,
stripRawStage(parsed, wire), replaces the per-prepare wiring of panel → status-marker → chain-carrier strippers, and closes the two leaks the #2811 leak-matrix audit pinned:content: string | part[], and google'scontent.parts[].textobject shape was invisible to it. Panels, status bodies, marker lines, render tags, nudge echoes all rode the rebuild.acp_statushead line was removed; the contiguous report body (ACTIVE SURFACE / CONTEXT BREAKDOWN / COMPRESSED BLOCKS / BILLED INPUT sections) stacked 0.5–1.5 K per resent turn.consumeAcpStatusBodyeats the head plus only whitelisted section shapes; surrounding prose survives.Structure
src/marker/spec.ts— the class table (10 ids): what exists, who strips it, at which layer.src/marker/engine.ts— the walk. Order matters and is documented in-code:src/marker/status-body.ts— the block consumer (head regex + 26-prefix section whitelist + continuation rules; stops at unknown lines, empty-slot degrades to one space sotool_callsare never orphaned).src/marker/anchors.ts— single home forMARKER_INTEGRITY_NOTE/MARKER_SILENCE_CLAUSE+isNudgeEchoText(compress-tool.ts re-exports).prepare-anthropic/openai/responses/google) call one line each; both fork-adoption paths (fork-adopt.ts,fork-adoption.ts) get the same engine — adopted children were another leak vector.tests/marker-lane-coverage.test.ts— the leak matrix as a contract: every raw-stage class stripped on every wire, downstream-owned shapes (summary anchors → state layer, codex handoff → absorb) preserved, plugin-mode sessions: #1421 outbound chain stamps accumulate in the model-visible transcript (+1 user message per request) #1542 zombie guard pinned.Behavior notes
<acp …>spans) are deliberately NOT raw-stage (bug(chain): ACP tag literals in normal history can permanently force fresh proxy sessions into passthrough #1357 user-data boundary, enforced byanthropic-pck-verbatimT2): a foreign literal tag in user text survives byte-intact at this layer; bili's own echoes are handled at the projection layer andtag-echo-filter.tsstays byte-identical to master. An interimkeepBiliArtifactsparam onstripAcpTagswas superseded by this stricter split (the parameter no longer exists).for..of, silently skipping the message after a splice. Fixed with a reverse-index walk (matching the google/responses walks).Review round 2 fixes
thought:true/thoughtSignatureparts (google),thinking/redacted_thinkingblocks (anthropic/openai, and responses parts),reasoningitems (responses type-gated already). Byte-equality fixtures per wire pin the invariance (tests/marker-lane-coverage.test.ts).tests/marker-render-contract.test.ts): drives the REALhandleAcpStatusrenderer over six report variants and asserts the section whitelist consumes each whole — adding/renaming a report section now fails CI instead of silently re-leaking. This test immediately caught three missing section heads (Compressible ranges (,COMPRESSED —,Sorted by size/time) that hand-maintenance had missed.Tests
All green locally: marker-echo 23, acp-panel 26, e2e-tag-echo 2, bili-artifact-strip 16, adapter-google 12, e2e-google-compress 4, issue1542 13, issue1086 21, issue1029 5, issue2658 6, issue2407 ×2 5, preflight-google 2, issue1204 2, fix-1117 3, 2260-inert 4, 2709 ×2 11, decode-fail 4, advisory-panel 1, marker-lane-coverage 4, fork family 129/129.
The only reds in the full fork family are the two pre-existing master regressions tracked in #2814 (
fork-adoption-wires.test.ts:477,issue2601-persona-fork-lineage.test.ts:125) — red on origin/master@525b4f51 before this branch, unaffected by it.Out of scope (deliberate)
The audit's step "prepare-shared orchestrator" is descoped from this PR: on inspection the four prepares' stage-level code interleaves protocol quirks throughout (codex gates, cache-control, hardenOpenaiAssistantContent, …) — the 80% clone is the import block and call shape, not movable stage bodies. Extracting an orchestrator would be a rewrite of 1.8 K lines, not a move; it belongs in its own PR under #2811 once this engine has soaked. State-layer classes (summary anchors, absorb) and the outbound stripper are untouched by design.
Fixes #2798
Fixes #2789
Refs #2811
prepared by an agent under the local git identity (ranxianglei), human merge required
Rollout step: unified storage defaults to
shadow(5aced73)resolveStorageModenow lands on shadow when neitherstorage.unifiednorBILI_STORAGE_UNIFIEDis set — the JSON envelope stays the sole source of truth (zero behavior change), every session write mirrors intoindex.dbwith digest reconciliation, and drift surfaces as[storage] DIGEST DRIFTlogs: fleet-wide parity telemetry before the full-mode default flip. Explicitlegacyopts out; garbage still degrades to legacy; engine-less lanes stay legacy-only (#2825 contract). The repo test corpus runs on an explicit legacy baseline (tests/preload-storage-baseline.mjsinnpm test+scripts/run-ci-tests.mjs); the storage family pins/overrides its own modes and theresolveStorageModematrices + web-sessions stamp test pin the new default.Note on history: the dev-build version bump (0.1.197-dev.1) was dropped to satisfy version-guard — releases bump versions, dev branches don't. Machine installs are self-contained tarballs with
autoUpdate: false, unaffected.