Skip to content

[PR] feat(storage): support disabling JSON envelope on MySQL backend and add migration tool - #4936

Open
fathonix wants to merge 16 commits into
ranxianglei:masterfrom
fathonix:feat/storage-mysql-writer-off
Open

fathonix wants to merge 16 commits into
ranxianglei:masterfrom
fathonix:feat/storage-mysql-writer-off

Conversation

@fathonix

Copy link
Copy Markdown
Contributor

PR 3: feat(storage): support disabling JSON envelope on MySQL backend and add migration tool

Problem / Background

When running Billion-Context with network storage backends like MySQL/MariaDB (BILI_STORAGE_BACKEND=mysql), the server operates in unified full mode (storage.unified=full). However, src/persist.ts:508 previously locked jsonWriterOff exclusively to the sqlite backend:

this.jsonWriterOff = wantJsonWriterOff && storageMode === "full" && !unifiedBlockedByEncryption && resolveBackendName(process.env, fileStorageBackend()) === "sqlite";

If storage.jsonWriter=off was specified on a MySQL backend, it logged a warning and forced JSON files to continue being written to disk under share/sessions/openai/*.json.

In containerized, multi-instance, or cloud-hosted deployments where MariaDB is the authoritative single source of truth, perpetual double-writing to local JSON files causes:

  1. Unnecessary disk space consumption and file descriptor churn.
  2. High I/O overhead on network/virtual filesystems (such as VirtioFS or NFS).
  3. Drift risks between filesystem envelopes and relational records.

Additionally, existing users transitioning from local SQLite installations to MySQL lacked an official, end-to-end verified migration utility.

Changes

  • src/persist.ts:
    • Broadened jsonWriterOff check to allow backendName === "sqlite" || backendName === "mysql" when operating in full mode.
    • Updated configuration warning to reflect (sqlite or mysql).
  • src/storage/shadow.ts:
    • Imported resolveJsonWriterOff from ../knobs.ts.
    • Updated MySQL backend initialization log to accurately report writerOff status (json envelopes off (writerOff enabled) vs JSON envelopes keep being written).
  • scripts/migrate-storage.ts:
    • Added standalone CLI migration tool:
      node --import tsx scripts/migrate-storage.ts --from <index.db> --to <mysql://user:pass@host:port/db> [--dry-run]
    • Initializes schema via openBackend("mysql", to).
    • Implements batch replication (200 rows or 8 MB string budget) for content, messages, blocks, dead_refs, refs, session_runs, and conversations.
    • Normalizes SQLite BLOB buffers to UTF-8 strings before parameter handoff to avoid mysql2 buffer serialization edge cases.
    • Includes end-to-end parity checks: validates row count parity, content byte lengths, session views, and projections against source SQLite.

Verification

  • Backward Compatibility:
    • storage.jsonWriter remains enabled by default (off is strictly opt-in).
  • Migration & Parity Testing:
    • Tested scripts/migrate-storage.ts against a live production database snapshot (33 sessions, 31,800+ content rows, 27,000+ messages).
    • Row counts, byte lengths, and session projections tied out with 100% parity.
  • Runtime Testing:
    • Ran Billion-Context against MariaDB 11 with BILI_STORAGE_BACKEND=mysql and BILI_STORAGE_JSON_WRITER=off. Verified multi-turn conversations persist cleanly into MariaDB tables with zero writes to share/sessions/openai/.

…dd migration tool

- Allow storage.jsonWriter=off when backend is mysql
- Add scripts/migrate-storage.ts to migrate SQLite sessions to MySQL/MariaDB
@ranxianglei ranxianglei changed the title feat(storage): support disabling JSON envelope on MySQL backend and add migration tool [PR] feat(storage): support disabling JSON envelope on MySQL backend and add migration tool Oct 27, 2026
ci-check added 4 commits October 27, 2026 16:40
…ronous read facade

Reverts the writerOff broadening from this PR's first commit: honoring storage.jsonWriter=off on the mysql backend loses every session at every process restart, because the mysql facade has no synchronous read path (UnifiedShadow.viewFor returns null and listSessionIds returns [] there), so with the envelope off both loadSync and boot enumeration find nothing. The P1 aspect is tracked in issue ranxianglei#4942; until a synchronous read facade (or an async boot pre-warm) lands, mysql full mode keeps writing envelopes and the config warns, exactly as before this PR.
…ls identities

The hardcoded user_version == 7 gate rejected every current-gen index.db (v8 since ranxianglei#4390) and its retry hint was actively misleading — opening the store with this build bumps it to 8. Accept MIN_SOURCE_VERSION(7)..STORAGE_SCHEMA_VERSION and refuse unknown-newer versions instead. Backfill empty message identities on the target from CAS bytes using the exact formula of the mysql init backfill; without it every cross-save identity join on migrated rows misses. Also fixes the SessionRow|null type error in the parity section and closes the raw sqlite handle.
scripts/ was outside the tsconfig include, so a real TS2322 in migrate-storage.ts shipped invisible to CI. Including the directory also surfaced stale code in update-storage-corpus.ts: a Session import from a module that never exported it, StoredEntry literals predating the kernel CCR re-key (ranxianglei#4733), and non-wire "chat" protocol labels the committed golden fixtures deliberately carry. Fixed in place so the whole tree typechecks clean.
…ntract lane

Hermetic gate tests (version refusal, missing-table refusal — both exit before any mysql contact, so they run against an unreachable DSN) always run; DSN-gated cases prove the full migration against a real MySQL: row count, content byte-length and read-back view parity, dry-run stopping after schema ensure, and v7 identity backfill landing on every row. Runs in the existing mysql-contract job, each case on a fresh target database.
@ranxianglei

ranxianglei commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

查重:不重复。 最接近的条目:#3020(已关闭 PR,sqlite-only storage.jsonWriter=off 的最初实现,是本 PR 的背景);#3931/#3946/#3955(MySQL backend 系列,已合并)。无任何既有 issue/PR 请求 mysql writerOff 或 SQLite→MySQL 迁移工具。

标签: pr + scope/storage + p3(功能/工具类、纯 opt-in;其中 p1 数据丢失面已单独立项 #4942)。

审核结论:首版不可按原样合并——已直接在你的分支上对齐重构

按外部提交审查规则,我在你的分支上直接重构(additive commits,保留你的作者署名),已推送 feat/storage-mysql-writer-off,新 head 3947c8e19(你的原始 commit da6c10de0 原样保留在历史里)。

核心功能为什么被回滚(P1)

MySQL 上开 jsonWriter=off = 每次进程重启后所有会话读不回来:

  • mysql full 模式没有任何同步读路径:UnifiedShadow.viewFor() 在 sync===null 时直接返回 null(src/storage/shadow.ts:520)、listSessionIds() 返回 [](src/storage/shadow.ts:666);
  • 于是 loadSync()(src/persist.ts:1439 起)unified-first 拿不到东西 → 回退读 envelope → writerOff 下没有 envelope → 返回 null。plugin/session/handle/decompress/web 全部调用点拿到空;
  • boot 枚举循环同样枚举到零行;全链路没有任何异步预热路径(viewForAsync/listSessionIdsAsync 只被 admin 详情页使用,persist.ts:2094)。

你的运行时验证证明了「写入会落到 MariaDB」,但没有覆盖「重启后能否读回」——断点正好在后半段。修复方向已立项 #4942(bug/p1/scope/storage):A 异步 boot 预热 + 热路径持有、B 本地同步读镜像、C 维持现状(近期推荐)。在该机制落地前,mysql full 模式必须继续写 envelope。

迁移脚本:保留并修好(首版对当前代库实际不可用)

  1. 硬编码 schema 门 user_version == 7:master 的 sqlite 已是 v8(Four storage-layer defects: identity hash contaminated with positional metadata (truncation triggers identity swap) / sw | 存储层四缺陷:身份哈希掺位置元数据(截断即换血)/清扫删除回退历史/渲染接缝图片只比长度/fork 谱系死列 #4390,2026-10-23 合入),脚本拒绝每一个当前代 index.db,且提示「用本构建打开一次再重试」有误导(打开会把版本 bump 到 8)。改为接受 7..STORAGE_SCHEMA_VERSION、拒绝未知更新版本;
  2. 缺 identity 回填:v7 源库 messages.identity 为空串,而 mysql 目标的跨保存身份 join 依赖它(WHERE … AND identity = ?),不回填则迁移后的行永远 miss。补了与 mysql init 回填完全同式的回填(从 CAS 字节重算);
  3. 真实类型错误 SessionRow | null 不可赋值(TS2322)——因为 scripts/ 不在 tsconfig include 内,CI 从未对它做过 typecheck;
  4. 裸 sqlite 句柄未关闭;
  5. PR 描述小勘误:DDL 里没有 session_runs 表(实际表共 12 张)。

顺手修的小问题(独立标注 commit)

新增测试

tests/storage-migrate-script.test.ts:hermetic 的版本拒绝/缺表拒绝测试恒跑(均在任何 mysql 连接前退出,DSN 不可达也安全);DSN-gated 的全量迁移测试进 mysql-contract job——行数/content 字节长/读回视图三重 parity、dry-run 在 schema ensure 后停止、v7 identity 回填逐行验证。

本地定向验证:整树 typecheck 绿;新套件 2 pass / 3 skip(本地无 DSN);tests/storage-json-writer-off.test.ts 3/3 绿(钉住回滚后的行为)。全量回归以远端 CI 为准。

八问

  1. 是什么问题:PR 想让 mysql 后端支持 jsonWriter=off(停写 JSON envelope 双写)并提供 SQLite→MySQL 迁移工具。
  2. 什么原因导致的:功能部分撞上架构缺口——mysql facade 设计为「异步只写 + envelope 暖缓存」,没有任何同步读路径,关掉 envelope 等于切断唯一热路径读源;脚本部分是硬编码 schema 版本 + 类型检查覆盖缺失。
  3. 影响范围与严重程度:按提交状态是 p1——任何开启 BILI_STORAGE_JSON_WRITER=off + mysql 的用户,重启后所有会话读不回(数据在库里没丢,但 bili 看不见)。重构后剩余范围是 opt-in 离线工具 + 测试覆盖,无运行时行为变化。
  4. 怎么修复的:功能部分回滚(行为恢复 master:warn+ignore),根因修复立项 MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942 等方向拍板;脚本部分改版本区间接受 + identity 回填 + 类型修正 + 句柄关闭;tsconfig 纳入 scripts 并用测试把全流程钉住。
  5. 是否有回归问题:逐项过触碰路径的既有行为——sqlite writerOff(storage-json-writer-off.test.ts 钉住,3/3 绿)、shadow 模式忽略、file tier Identity pipeline: key sessions by (agent, conversation id) in the unified store — decouple fold ledgers from protocol/host origin (#2938 / #2847 / #2671 defect-1) #2960、mysql contract/knob lanes(未动)、boot 枚举(代码逐字恢复 master)。无回归。
  6. 是否破坏缓存:不涉及(不触碰前缀缓存/压缩/账本逻辑)。
  7. 是否改了设计方向:没有。persist.ts 注释明确记录「mysql writerOff 保持封禁直到 MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942 落地」,防止将来被顺手重开。
  8. 是否引入新配置:无。复用现有 storage.jsonWriter / BILI_STORAGE_JSON_WRITER;CI 侧仅在既有 mysql-contract job 里多跑一个测试文件(无新 job)。

行为变更披露(旧值→新值)

项 首版 PR 重构后 原因
jsonWriter=off + mysql full mode 生效(停写 envelope) warn+ignore,继续写 envelope 无同步读路径,关掉=重启读不回(#4942)
迁移脚本 schema 接受 仅 user_version==7 7..current(现为 8),拒绝未知新版本 #4390 使当前代库为 v8,首版全拒
scripts/*.ts 类型检查 不在 include,未查 纳入 npm run typecheck 真实 TS2322 漏网证据

判定:首版不合。重构后剩余部分 = 加固过的迁移工具 + typecheck 覆盖 + 回归钉,自洽且零运行时影响——我的建议是工具部分可以先合(CI 绿即可),writerOff 功能等 #4942 拍板后另走。合并由你执行:#4936

@ranxianglei

Copy link
Copy Markdown
Owner

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

Status note from the #4942 lane: the writerOff extension for mysql was reverted in d5a3950 (jsonWriter=off stays sqlite-only until mysql has a synchronous read facade). The gap is tracked as decision request #4942 — options A (async boot pre-warm + eviction hold) / B (local read mirror) / C (status quo); C is in effect right now, owner decision on direction pending. This PR's remaining diff (scripts/migrate-storage.ts + tests) is independent of that decision. Note: the branch currently conflicts with master (mergeable_state=blocked) — a rebase is needed before further review.

ci-check added 3 commits October 27, 2026 17:03
…ss lines

CI ran the v8 end-to-end case against real MySQL: the migration itself was fully green (row parity, content bytes, read-back view identical), only my assertion regex missed the colon in the "<table>: N rows ok" success line.
…anglei#1248 tripwire)

The runner's SPAWN_RE tripwire requires every process-spawning suite to be registered in scripts/live-files.mjs or all shards fail at startup. The suite only spawns one-shot migrate-storage.ts children with no listening sockets, so the entry is tripwire-only like ranxianglei#3890's.
EMPTY is a MySQL reserved word: the post-migration verification query used "AS empty" and ER_PARSE_ERROR killed the v8 end-to-end case after the migration itself had passed. Renamed the alias to n_empty.
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b) CI 已全绿,收工状态更新(head 30dac9770,49 项检查 36 success / 13 skipped / 0 fail):

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b) 收到重复唤醒,已核对现状:无新提交、无新评论,head 仍为 30dac9770(CI 49 项全绿)。本 PR 处理已闭环:审查结论(主评论)、P1 数据丢失问题(#4942,等方向决策)、工具部分可合的判定均已就位。等你拍板:① #4942 的 A/B/C 方向;② 迁移工具部分直接合入还是拆小 PR。在此之前无需进一步动作。

ci-check added 8 commits October 27, 2026 18:17
# Conflicts:
#	.github/workflows/ci.yml
#	scripts/live-files.mjs
…on, ranxianglei#4936)

The 3 red shards fail one master-level test - plugin-fork ranxianglei#5140 cold-restored
non-retained parent returning 409 instead of 200 - which this storage/migration
PR never touches. It surfaced because the branch had merged a stale master base
(110 commits behind dcf7607); master itself tracks ranxianglei#5140 as a known cold-tail
flake (b5385a7). Per CI-coordination policy, converge onto the sentinel-maintained
ci-fixes branch rather than patching a master-level flake on this branch.
# Conflicts:
#	scripts/live-files.mjs
 is resolved by ranxianglei#5213's async reload seam, which is on master; the gate stays sqlite-only as a separate decision (ranxianglei#4936 sync)
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

Conflict resolved and synced to current master. What I did this run:

  1. Merged master 33104b1f95 into fathonix:feat/storage-mysql-writer-off (merge, not rebase — matches the branch's established sync history; fast-forward push, no force-push). New head be857db6a1, 16 ahead / 0 behind master (verified with git rev-list --left-right --count).
  2. One conflict, union-resolved — scripts/live-files.mjs: both sides added distinct tripwire entries at the same spot; kept both in numeric order ([PR] feat(storage): support disabling JSON envelope on MySQL backend and add migration tool #4936 storage-migrate-script.test.ts before [Bug][dsh] Recovery race: after a stuck twin dies, concurrent re-pull causes the substitute child process to self-termin | [Bug][dsh] 恢复竞态:卡死孪生死后并发重拉,替补子进程在端口仍被僵尸占据时按 twin-collision 自杀(code 3)→ 全体客户端同时放弃、裸历史直连撞上游 1M token 上限;并触发 index.db 双写者互斥(DIGEST DRI… #4977 issue4977-present-twin-persist-gate.test.ts).
  3. Auto-merged files verified semantically — .github/workflows/ci.yml: the mysql-contract lane still runs this PR's tests/storage-migrate-script.test.ts alongside master's --test-concurrency=1 set; src/persist.ts: the PR's sqlite-only gate and comment survived intact amid master's 47 commits of storage evolution.
  4. Verified on the merged tree — full typecheck green (kernel + pi-subagents pre-builds included); targeted suites tests/storage-migrate-script.test.ts + tests/storage-json-writer-off.test.ts: 6 pass / 3 skip (DSN-gated e2e, no local MySQL) / 0 fail. Full-suite verdict is the remote CI on the new head.
  5. Small in-pass fix (own labeled commit be857db6a1) — the PR's gate comment in src/persist.ts said "sqlite-only by design until MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942 lands … an envelope-less mysql store would lose every session at every restart". That premise is stale: MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942 was resolved by the async reload seam (PR [PR] [storage] Degradation Semantics Bundle: Seven accepted fixes consolidated into one branch — a single merge suffices (inc | [storage] 降级语义全家桶:七个已验收修复合成一个分支,合并一次即可(含撤回损坏库自动改名) #5213, merge 7c9e65b9, verified as a master ancestor), so the restart data-loss conclusion no longer holds. Comment now reads: the extension was reverted pending MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942, which [PR] [storage] Degradation Semantics Bundle: Seven accepted fixes consolidated into one branch — a single merge suffices (inc | [storage] 降级语义全家桶:七个已验收修复合成一个分支,合并一次即可(含撤回损坏库自动改名) #5213 has since resolved — extending the gate to mysql is a separate decision. Comment-only, zero behavior change; the gate itself remains byte-identical to master (sqlite-only).
  6. Live state after push — GitHub: mergeable: true (the "dirty" conflict is gone); mergeable_state currently shows "behind" transiently while GitHub recomputes — the API base SHA is exactly 33104b1f95, the commit I merged, and git confirms 0 behind, so this will converge on the next recompute/CI registration. CI re-ran on the new head; if any shard goes red, the CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599 coordination flow applies (master red → merge ci-fixes; branch red → targeted fix).

八问

  1. 是什么问题:PR 分支落后 master 1334 个 commit 且产生文本冲突(merge state dirty),阻断合并。
  2. 什么原因导致的:分支上次同步停在 2026-10-30 的 master(44067a5bc),此后 master 大幅演进(存储层 schema v11、jsonWriter=off 域多个 PR、CI 三层化改造等);唯一文本冲突在 scripts/live-files.mjs——双方在同一位置各加了一条 tripwire 登记。
  3. 影响范围与严重程度:仅本 PR 的合并阻断;无运行时/用户面影响。
  4. 怎么修复的:merge master 进分支(与分支既有同步方式一致);冲突按 union 解(两条 tripwire 登记都保留、按编号排序);顺手把 persist.ts 里因 MySQL-backed storage loses all sessions after a restart when JSON envelopes are off (no synchronous read facade) #4942 已被 [PR] [storage] Degradation Semantics Bundle: Seven accepted fixes consolidated into one branch — a single merge suffices (inc | [storage] 降级语义全家桶:七个已验收修复合成一个分支,合并一次即可(含撤回损坏库自动改名) #5213 解决而过期的注释改对(独立标注 commit,纯注释、零行为变化)。
  5. 是否有回归问题:逐项过触碰路径既有行为——sqlite writerOff 门控(代码逐字保留 master 形态,storage-json-writer-off 套件 3/3 绿)、mysql-contract lane 的测试清单(PR 测试文件在)、LIVE_FILES 只增不删、ci.yml 其余变更全部来自 master 自身。无回归。
  6. 是否破坏缓存:不涉及(不触碰前缀缓存/压缩/账本逻辑)。
  7. 是否改了设计方向:不涉及。
  8. 是否引入新配置:不涉及。

判定:冲突已解除(mergeable=true),分支 0 behind,CI 在新 head be857db6a1 上重跑中;全量绿后合并由你执行。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[ework] CI fix verified green ✓

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

No new sync needed — this "dirty" signal is a stale snapshot from before my previous push (same pattern as the earlier "behind" false alarms in this thread). Verified against live sources in this run:

  • PR head be857db6a1 = exactly my last push (the merge of master 33104b1f95 into the branch, + the comment-refresh commit); nobody else pushed to the branch since (fork head re-fetched, unchanged).
  • Base is still 33104b1f95 — the very commit I merged; git rev-list shows the branch 16 ahead / 0 behind master, base fully contained in head.
  • GitHub API: mergeable: true — the conflict is resolved; mergeable_state still shows the transient "behind" while GitHub recomputes, which the containment check above disproves as a real drift.

No changes made this run; nothing to rebase or re-push. CI is running on the new head — its verdict (and any red, via the #4599 flow) is the next actionable event.

八问

  1. 是什么问题:系统再次转发「PR 与 base 冲突(dirty)」信号,需核实是否仍需处理。
  2. 什么原因导致的:信号来自我上一轮推送前的旧快照(GitHub 状态重算滞后),非真实冲突——live 核验 mergeable=true。
  3. 影响范围与严重程度:无实际影响;分支 0 behind、冲突已解除,仅状态显示滞后。
  4. 怎么修复的:无需修复——本轮只做 live 核验(API mergeable/base/head + fork 分支 re-fetch + rev-list 前后向计数),未做任何改动。
  5. 是否有回归问题:不涉及(零改动)。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入新配置:不涉及。

判定:无动作可做的空转信号,已核实并留痕;等 CI 在新 head be857db6a1 上的判决。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

Conclusion for this wake (full evidence in my previous comment): the repeated "dirty" blocker signal is a stale snapshot, not a real conflict — no action was needed and none was taken.

Live-verified in this run:

  • PR head be857db6a1 = my previous push (master 33104b1f95 merged into the branch + comment-refresh commit); fork head re-fetched, unchanged since.
  • Base still 33104b1f95 — the exact commit already merged; git rev-list shows 16 ahead / 0 behind, base fully contained in head.
  • GitHub API: mergeable: true (conflict resolved); the transient "behind" state is disproven by the containment check.

Status: conflict resolved, branch in sync, CI running on the new head — its verdict is the next actionable event (any red goes through the #4599 coordination flow). Nothing else pending from this lane.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[ework] CI fix verified green ✓

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

Third "dirty" signal in ~20 min — again a stale/transient state, not a real conflict. Live-verified in this run, no action needed:

  • Merge state: GitHub API mergeable: true; head be857db6a1 and base 33104b1f95 both unchanged since my sync push (fork head + master re-fetched this run, same SHAs). Branch is 16 ahead / 0 behind master — the "behind" state GitHub shows is the transient post-merge recomputation, disproven by the containment check.
  • CI on the new head: fully green. Mirror cache (fetched minutes ago, sha be857db6a1): 30 checks, 0 failed, 0 pending — all test shards (ubuntu/windows × node 22/24), static-gates, mysql-contract (the lane running tests/storage-migrate-script.test.ts), and all 3 gates pass; the remaining lanes are env-gated skips (e2e/canary/registry — expected, not failures).

So the PR is conflict-free and CI-clean; it is ready for human review/merge. Nothing further for this lane unless a new real blocker appears.

八问

  1. 是什么问题:系统第三次转发「PR 与 base 冲突(dirty)」信号。
  2. 什么原因导致的:GitHub 对我上一轮 merge push 后的 mergeable_state 重算仍停留在瞬态 "behind",触发器据此误报;live 核验 mergeable=true、base 完全包含在 head 内,无真实冲突。
  3. 影响范围与严重程度:无实际影响——CI 已在新 head 上全绿(30/30,0 失败 0 pending),仅状态显示滞后。
  4. 怎么修复的:无需修复——本轮只做 live 核验(GitHub API + fork/master re-fetch + 镜像缓存 check 全量清点),零改动。
  5. 是否有回归问题:不涉及(零改动)。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入新配置:不涉及。

判定:空转信号,已核实并留痕;PR 现处于无冲突 + CI 全绿状态,等待人工 review/merge。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[ework] CI fix verified green ✓

1 similar comment
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[ework] CI fix verified green ✓

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants