This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch branch-catalog-spi
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-catalog-spi by this
push:
new b8d64260e0c update P5 handoff and fix compile issue
b8d64260e0c is described below
commit b8d64260e0c80776d2b7bc42c2905102e1c36375
Author: morningman <[email protected]>
AuthorDate: Tue Jun 9 17:49:22 2026 +0800
update P5 handoff and fix compile issue
---
.../datasource/maxcompute/MCTransactionTest.java | 54 --------
.../maxcompute/MaxComputeExternalCatalogTest.java | 146 ---------------------
plan-doc/HANDOFF.md | 53 ++++++++
plan-doc/PROGRESS.md | 36 +++--
4 files changed, 75 insertions(+), 214 deletions(-)
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
deleted file mode 100644
index e76f192a858..00000000000
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MCTransactionTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.datasource.maxcompute;
-
-import org.apache.doris.common.UserException;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import java.util.Optional;
-
-public class MCTransactionTest {
- @Test
- public void testBeginInsertRejectsOdpsExternalTable() {
- assertBeginInsertRejectsUnsupportedOdpsTable("mc_external_table");
- }
-
- @Test
- public void testBeginInsertRejectsOdpsLogicalView() {
- assertBeginInsertRejectsUnsupportedOdpsTable("mc_logical_view");
- }
-
- private void assertBeginInsertRejectsUnsupportedOdpsTable(String
tableName) {
- MaxComputeExternalCatalog catalog =
Mockito.mock(MaxComputeExternalCatalog.class);
- MaxComputeExternalTable table =
Mockito.mock(MaxComputeExternalTable.class);
- Mockito.when(table.isUnsupportedOdpsTable()).thenReturn(true);
- Mockito.when(table.getDbName()).thenReturn("default");
- Mockito.when(table.getName()).thenReturn(tableName);
-
- MCTransaction transaction = new MCTransaction(catalog);
-
- UserException exception = Assert.assertThrows(UserException.class,
- () -> transaction.beginInsert(table, Optional.empty()));
- Assert.assertTrue(exception.getMessage().contains(
- "Writing MaxCompute external table or logical view is not
supported: default." + tableName));
- Mockito.verify(catalog,
Mockito.never()).getOdpsTableIdentifier(Mockito.anyString(),
Mockito.anyString());
- }
-}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
deleted file mode 100644
index dfe22f136b5..00000000000
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalogTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.datasource.maxcompute;
-
-import org.apache.doris.common.DdlException;
-import org.apache.doris.common.maxcompute.MCProperties;
-import org.apache.doris.datasource.ExternalCatalog;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class MaxComputeExternalCatalogTest {
- @Test
- public void testSplitByteSizeErrorMessage() {
- Map<String, String> props = new HashMap<>();
- addRequiredProperties(props);
- props.put(MCProperties.SPLIT_STRATEGY,
MCProperties.SPLIT_BY_BYTE_SIZE_STRATEGY);
- props.put(MCProperties.SPLIT_BYTE_SIZE, "1048576");
-
- MaxComputeExternalCatalog catalog = new MaxComputeExternalCatalog(1L,
"mc_catalog", null, props, "");
-
- DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkProperties);
- Assert.assertTrue(exception.getMessage().contains(
- MCProperties.SPLIT_BYTE_SIZE + " must be greater than or equal
to 10485760"));
-
Assert.assertFalse(exception.getMessage().contains(MCProperties.SPLIT_ROW_COUNT));
- }
-
- @Test
- public void testCheckWhenCreatingSkipsValidationByDefault() throws
DdlException {
- Map<String, String> props = createRequiredProperties(true);
- TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
-
- catalog.checkWhenCreating();
-
- Assert.assertNull(catalog.checkedProjectName);
- Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
- }
-
- @Test
- public void testCheckWhenCreatingValidatesProjectWhenValidationEnabled()
throws DdlException {
- Map<String, String> props = createRequiredProperties(false);
- props.put(ExternalCatalog.TEST_CONNECTION, "true");
- TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
-
- catalog.checkWhenCreating();
-
- Assert.assertEquals("mc_project", catalog.checkedProjectName);
- Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
- }
-
- @Test
- public void
testCheckWhenCreatingValidatesSchemaWhenNamespaceSchemaEnabled() throws
DdlException {
- Map<String, String> props = createRequiredProperties(true);
- props.put(ExternalCatalog.TEST_CONNECTION, "true");
- TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
-
- catalog.checkWhenCreating();
-
- Assert.assertNull(catalog.checkedProjectName);
- Assert.assertEquals("mc_project",
catalog.checkedNamespaceSchemaProjectName);
- }
-
- @Test
- public void testCheckWhenCreatingReportsInaccessibleProject() {
- Map<String, String> props = createRequiredProperties(false);
- props.put(ExternalCatalog.TEST_CONNECTION, "true");
- TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
- catalog.projectExists = false;
-
- DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkWhenCreating);
-
- Assert.assertTrue(exception.getMessage().contains("Failed to validate
MaxCompute project 'mc_project'"));
- Assert.assertTrue(exception.getMessage().contains("does not exist or
is not accessible"));
- Assert.assertNull(catalog.checkedNamespaceSchemaProjectName);
- }
-
- @Test
- public void testCheckWhenCreatingReportsInaccessibleNamespaceSchema() {
- Map<String, String> props = createRequiredProperties(true);
- props.put(ExternalCatalog.TEST_CONNECTION, "true");
- TestMaxComputeExternalCatalog catalog = new
TestMaxComputeExternalCatalog(props);
- catalog.threeTierModel = false;
-
- DdlException exception = Assert.assertThrows(DdlException.class,
catalog::checkWhenCreating);
-
- Assert.assertTrue(exception.getMessage().contains("Failed to validate
MaxCompute project 'mc_project'"));
- Assert.assertTrue(exception.getMessage().contains("schema list is
accessible"));
- }
-
- private static Map<String, String> createRequiredProperties(boolean
enableNamespaceSchema) {
- Map<String, String> props = new HashMap<>();
- addRequiredProperties(props);
- props.put(MCProperties.ENABLE_NAMESPACE_SCHEMA,
Boolean.toString(enableNamespaceSchema));
- return props;
- }
-
- private static void addRequiredProperties(Map<String, String> props) {
- props.put(MCProperties.PROJECT, "mc_project");
- props.put(MCProperties.ENDPOINT,
"http://service.cn-beijing.maxcompute.aliyun-inc.com/api");
- props.put(MCProperties.ACCESS_KEY, "access_key");
- props.put(MCProperties.SECRET_KEY, "secret_key");
- }
-
- private static class TestMaxComputeExternalCatalog extends
MaxComputeExternalCatalog {
- private boolean projectExists = true;
- private boolean threeTierModel = true;
- private String checkedProjectName;
- private String checkedNamespaceSchemaProjectName;
-
- private TestMaxComputeExternalCatalog(Map<String, String> props) {
- super(1L, "mc_catalog", null, props, "");
- }
-
- @Override
- protected boolean maxComputeProjectExists(String projectName) {
- checkedProjectName = projectName;
- return projectExists;
- }
-
- @Override
- protected void validateMaxComputeNamespaceSchemaAccess(String
projectName) {
- checkedNamespaceSchemaProjectName = projectName;
- if (!threeTierModel) {
- throw new RuntimeException("schema list is not accessible");
- }
- }
- }
-}
diff --git a/plan-doc/HANDOFF.md b/plan-doc/HANDOFF.md
index 1bb74163a0d..3b46b6cf5b1 100644
--- a/plan-doc/HANDOFF.md
+++ b/plan-doc/HANDOFF.md
@@ -5,6 +5,57 @@
---
+# 🔥 第 19 次 handoff(2026-06-09,覆盖)— 🎉 P4 maxcompute 全部完成并合入;下一 session = P5
paimon 迁移 kickoff
+
+> **本 session**:用户确认「P4(maxcompute)已完成、HANDOFF 中所有 maxcompute TODO
已做完」,要求同步交接文档(PROGRESS + HANDOFF)并为下一 session 启动 **P5 paimon 迁移**做准备。**本
session 仅文档同步,0 产线代码。**
+
+## ✅ P4 完成核实(code-grounded,本 session 亲核)
+- **翻闸已合入**:`max_compute` ∈ `CatalogFactory.SPI_READY_TYPES`(PR **#64253** "P4
maxcompute connector full adoption + live cutover (T01–T06)")。
+- **legacy 已删 + odps-free**:`fe-core/.../datasource/maxcompute/` 不存在;`grep
com.aliyun.odps fe-core/src/main/java`=∅(PR **#64300** "remove legacy subsystem
+ make fe-core odps-free (T07–T09)",HEAD `e96037cf6aa`)。
+- **#64119 校验迁移已合入**:连接器含
`validateMaxComputeConnection`/`checkOperationSupported`;`git log -S
validateMaxComputeConnection` 证其随 **#64300** squash 合入 —— 即上一次(第 18 次)handoff 的
10 文件工作已落地,无悬空。
+- **分支干净**:当前 `branch-catalog-spi`,HEAD=`e96037cf6aa`(#64300);`git status`
仅未跟踪
scratch(`.audit-scratch/`/`conf.cmy/`/`*.bak`/`.claude/scheduled_tasks.lock`)。
+- ⚠️ 仍有遗留 stash `stash@{0}`("WIP on branch-catalog-spi: ... #64253")—— 本
session 未动;如确认无用可由用户 `git stash drop stash@{0}`。
+
+## ✅ 本 session 已完成(文档同步)
+- **PROGRESS.md**:§header(P4 完成→P5 待启动 + 进度统一 ~32%);§一(P4 100%✅ / P5
标「下一阶段」);§二看板(maxcompute 100%);§三(P4 收尾为「已合入 #64253+#64300」+ **新增 P5 kickoff
块**:范围/风险/材料);§四(加 2026-06-09 P4 完成里程碑);§六(决策计数 25→**36**、偏差 12→**22** 纠正,此前严重
stale);§七(session 状态)。
+- **HANDOFF.md**:本第 19 次 + 折叠第 18 次(标注「已随 #64300 合入」)。
+
+## 🎯 下一 session = P5 paimon 迁移 kickoff(用户定)
+> **策略 = full adopter + 翻闸**(复用 P4 样板,非 P3 hybrid)。P4 已交付可复用的**写/事务
SPI**(`ConnectorTransaction`/`ConnectorWritePlanProvider`/`PluginDrivenTransaction`/`PluginDrivenInsertExecutor`)+
full-adopter + cutover 流程范本。
+
+**kickoff 步骤**(沿用 P2/P3/P4:recon → 设计 → 用户签字 → 分批实现):
+1. **code-grounded recon**(多 Agent + 亲核,Rule 8)—— 产
`research/p5-paimon-migration-recon.md`:
+ - 连接器模块 `fe-connector-paimon/` 现状(10 文件:scan/predicate/handle
完整;`ConnectorMetadata` 部分实现;catalog flavor / MVCC / vended / sys-tables 缺)。
+ - fe-core footprint:`datasource/paimon/`(22 顶层 + source/5 + profile/2);**反向
instanceof 10 处**(`PhysicalPlanTranslator` 的 `PAIMON_EXTERNAL_TABLE` 分支等)。
+ - **6 个 catalog flavor**(HMS/DLF/REST/File/Base/Factory)—— 连接器内工厂重组
`PaimonConnectorProvider.create()` 按 properties 实例化 paimon `Catalog`。
+ - **复用面**:P0 已建 `ConnectorMvccSnapshot`(E5) / vended-creds(E6) /
sys-tables(E7) SPI —— **paimon 是首个真正消费 E5/E6/E7 的 adopter**(MC 未用,无先例,须重点核)。BE
经 JNI 调 paimon-reader,序列化 `Table` 经
`ConnectorScanPlanProvider.getSerializedTable` 已支持。
+ - **P1-T02 推迟项**:fe-core 重复 `PaimonPredicateConverter`(**仍在**
`datasource/paimon/source/PaimonPredicateConverter.java:43`,连接器侧另有一份)—— P5 删
fe-core 版。
+2. **写设计 + 批次计划** `tasks/P5-paimon-migration.md`(连接器档约定「P5 待启动时建」)。
+3. **用户签字** → 分批落地、独立 commit、每批守门。
+
+**已知特殊性 / 风险**(master §3.6 line 218 + 连接器档 + risks):
+- **R-004**(classloader 隔离打破 SDK 单例,**paimon 明列**)+ **R-007**(FE/BE 共享 jar
冲突)+ **R-012**(snapshotId 类型)—— P5/P6 触发窗口,recon 须评估(auto-memory
[[catalog-spi-be-java-ext-shared-classpath]] 有共享类路径模型)。
+- **关联决策**:D-005(HMS flavor 走 `tableFormatType`,P3-T08 已细化 per-table
`getScanPlanProvider`)、D-006(cache 放连接器内)。
+- paimon-HMS-flavor 复用 `fe-connector-hms`(P3 已建、稳定)。
+
+**起点材料**:[paimon 连接器档](./connectors/paimon.md)、master plan
[§3.6](./00-connector-migration-master-plan.md)、[P4 task
档](./tasks/P4-maxcompute-migration.md)(full-adopter 样板)、写 SPI RFC
`tasks/designs/connector-write-spi-rfc.md`、[AGENT-PLAYBOOK](./AGENT-PLAYBOOK.md)。
+
+## ⚙️ 操作须知(复用)
+- maven 必绝对 `-f /mnt/disk1/yy/git/wt-catalog-spi/fe/pom.xml` + `-pl
:<artifact> -am` + `-Dmaven.build.cache.enabled=false`;改连接器
`:fe-connector-paimon`、改 SPI `:fe-connector-api`(须 -am 连带 rebuild)、改 fe-core
`:fe-core`。读真实 `Tests run:`/`BUILD`,勿信后台 echo
exit([[doris-build-verify-gotchas]])。
+- 连接器**禁 import fe-core**(import-gate `bash
tools/check-connector-imports.sh`)—— 需 fe Config/session 值经 session-property
透传([[catalog-spi-connector-session-tz-gotcha]])。
+- 连接器测试模块**无 mockito**(纯 seam / child-first
loader,[[catalog-spi-fe-core-test-infra]])。
+- 分支 `branch-catalog-spi`(HEAD #64300);P5 建议 off 最新 upstream 起新分支。未跟踪 scratch
勿提交。
+
+## 🧠 给下一个 agent 的 meta
+- **P4 是 full-adopter + cutover 的完整样板** —— P5 复用其写 SPI + 流程;但 paimon 多了 **6
catalog flavor 工厂** + **首次真正用 E5/E6/E7(MVCC/vended/sys-tables)**,recon
须重点核这两块(MC 无先例)。
+- **live e2e 仍是翻闸真正完成门**(CI 跳)—— P5 翻闸前同样需用户真实 paimon 环境验证。
+- **翻闸时 GSON 三注册须 atomic
齐迁**(catalog+db+table,[[catalog-spi-gson-migrate-all-three]],漏 db 致
ClassCastException);**每个 full-adopter 都要补 FE 分发缺口**(DROP TABLE / CREATE·DROP DB
/ SHOW PARTITIONS / partitions TVF,[[catalog-spi-cutover-fe-dispatch-gap]])。
+- auto-memory:连接器禁 import
fe-core([[catalog-spi-connector-session-tz-gotcha]]);测基建无 fe-core/无
mockito([[catalog-spi-fe-core-test-infra]]);clean-room
对抗复审偏好([[clean-room-adversarial-review-pref]]);构建坑([[doris-build-verify-gotchas]])。
+
+---
+
+<details><summary>📅 历史:第 18 次 handoff(2026-06-09)— PR #64119 MaxCompute 校验迁移
SPI DONE(10 文件已随 #64300 合入)</summary>
+
# 🔥 第 18 次 handoff(2026-06-09,覆盖)— PR #64119(MaxCompute test_connection 校验 +
外表/视图 read·write 拒绝)迁移 SPI DONE,连接器 UT 全绿
> **本 session**:用户要求把 upstream PR apache/doris#64119(`[fix](fe) Improve
> MaxCompute catalog validation`,11 文件/+422)的功能完整迁移到 SPI 框架,并跑通其 3 个单元测试。PR 改的
> fe-core
> 类(`MaxComputeExternalCatalog`/`MaxComputeExternalTable`/`MCTransaction`/`MaxComputeScanNode`)在本
> fork 已于 P4 删除→连接器化,故为真迁移。**用户定夺**:① 范围 = surgical(补 A + 加 C,B/D 已在不动);② 测试
> = fold 进现有连接器测试文件。
@@ -38,6 +89,8 @@
- maven 绝对 `-f .../fe/pom.xml -pl :fe-connector-maxcompute -am test [-Dtest=X]
-Dmaven.build.cache.enabled=false`;**必带 -am**;读真实 `Tests run:`/`BUILD`,勿信后台
echo exit。
- 分支 `catalog-spi-06`。未跟踪 `.audit-scratch/`(本 session 测试
log)/`conf.cmy/`/`*.bak`/`scheduled_tasks.lock`(勿提交)。
+</details>
+
---
<details><summary>📅 历史:第 17 次 handoff(2026-06-09)— 老 MaxCompute 代码移除 DONE(3
commit,全门绿)</summary>
diff --git a/plan-doc/PROGRESS.md b/plan-doc/PROGRESS.md
index 203565b1a13..a5acbbd78dd 100644
--- a/plan-doc/PROGRESS.md
+++ b/plan-doc/PROGRESS.md
@@ -1,6 +1,6 @@
# 📊 项目进度仪表盘
-> 最后更新:**2026-06-09** | 当前阶段:**P4 maxcompute·scope=C(翻闸完成)**——写/事务 SPI RFC
已批准;**W-phase(W1–W7)全部落地** ✅;**P4 adopter 设计已批准**([D-023],5 批/11 task);**Batch
A+B 全完成**(T01–T04,gate 关 dormant);**Batch C 翻闸完成**(T05 image-compat + T06a
写接线/UT + **T06b flip ✅** `CatalogFactory.SPI_READY_TYPES += "max_compute"`,gate
全绿 [D-027]);**Batch D 删除完成 ✅**(2026-06-09,分支 `catalog-spi-06` off upstream
`9ed49571b20`/#64253:删 20 fe-core 文件 + 21 反向引用清理 + MCUtils 下沉
be-java-ext,fe-core 依赖树**彻底无 odps**;`7a4db3511 [...]
+> 最后更新:**2026-06-09** | 当前阶段:**P4 maxcompute 完成 ✅(已合入),P5 paimon 待启动(下一
session)**——P4 full-adopter 迁移 + live 翻闸 + legacy 删除全部完成并合入
`branch-catalog-spi`:**#64253**(T01–T06 连接器全适配 +
`CatalogFactory.SPI_READY_TYPES += "max_compute"`)+ **#64300**(T07–T09 删 20
fe-core 文件 + 清反向引用 + MCUtils 下沉 be-java-extensions,fe-core 依赖树**彻底无 odps**,HEAD
`e96037cf6aa`);upstream PR **#64119**(MaxCompute 连接校验)功能已迁连接器 SPI 并随 #64300
合入。前序 P0/P1/P2(#63582/#63641/#64096)+ P3 hybrid(#64143)均已合入。**下一阶段 = P5 paimon
[...]
> [README](./README.md) · [Master
> Plan](./00-connector-migration-master-plan.md) · [SPI
> RFC](./01-spi-extensions-rfc.md) · [Decisions](./decisions-log.md) ·
> [Deviations](./deviations-log.md) · [Risks](./risks.md) · [Agent
> Playbook](./AGENT-PLAYBOOK.md) · [Handoff](./HANDOFF.md)
---
@@ -13,13 +13,13 @@
| **P1** | scan-node 收口 + 重复清理 | 1 周 | ▰▰▰▰▰▰▰▰▰▰ 100% | ✅ 完成(PR
[#63641](https://github.com/apache/doris/pull/63641) squash-merged
`778c5dd610f`;T1 推迟 P8;T2 推迟 P4/P5)|
[tasks/P1](./tasks/P1-scan-node-cleanup.md) |
| **P2** | trino-connector 迁移 | 2 周 | ▰▰▰▰▰▰▰▰▰▰ 100% | ✅ 已合入
`branch-catalog-spi`(#64096,squash `0793f032662`;T12 回归推迟 DV-003)|
[tasks/P2](./tasks/P2-trino-connector-migration.md) |
| P3 | hudi 迁移 | 2 周 | ▰▰▰▰▰▱▱▱▱▱ 45% | ✅ hybrid(D-019)批 A–D 已合入
`branch-catalog-spi`(**#64143** squash `5c240dc7a34`);批 E(live cutover)并入 P7 |
[tasks/P3](./tasks/P3-hudi-migration.md) |
-| P4 | maxcompute 迁移 | 2 周 | ▰▰▰▰▰▰▰▰▱▱ 80% | 🚧 **W-phase 全落地** ✅;**Batch A+B
完成**(T01–T04 dormant);**Batch C 翻闸完成**(T05 + T06a + **T06b flip ✅**
[D-027]);**Batch D 删除完成 ✅**(legacy 删 + odps
依赖彻底移除,`7a4db351100`+`409300a75b8`,全门绿);剩 push/PR |
[tasks/P4](./tasks/P4-maxcompute-migration.md) |
-| P5 | paimon 迁移 | 3 周 | ▱▱▱▱▱▱▱▱▱▱ 0% | ⏸ 待启动 | — |
+| **P4** | maxcompute 迁移 | 2 周 | ▰▰▰▰▰▰▰▰▰▰ 100% | ✅ 完成并合入
`branch-catalog-spi`(**#64253** T01–T06 适配+翻闸 + **#64300** T07–T09 删
legacy/odps-free;含 #64119 校验迁移)| [tasks/P4](./tasks/P4-maxcompute-migration.md)
|
+| **P5** | paimon 迁移 | 3 周 | ▱▱▱▱▱▱▱▱▱▱ 0% | 🔜 **下一阶段**(本 session
后启动;recon+设计先行)| —(kickoff 时建 tasks/P5)|
| P6 | iceberg 迁移 | 5 周 | ▱▱▱▱▱▱▱▱▱▱ 0% | ⏸ 待启动 | — |
| P7 | hive (+HMS) 迁移 | 6 周 | ▱▱▱▱▱▱▱▱▱▱ 0% | ⏸ 待启动 | — |
| P8 | 收尾清理 | 2 周 | ▱▱▱▱▱▱▱▱▱▱ 0% | ⏸ 待启动 | — |
-**全局进度:12%**(25 周计划中 P0+P1 共 3 周完成)
+**全局进度:~32%**(25 周计划中已完成约 7.9 周:P0+P1+P2+P4 满 + P3 hybrid 45%;统一 header
与本行此前不一致的 38%/12% 旧值,改按 §一 进度条加权)
---
@@ -33,7 +33,7 @@
| **es** | ✅ | ✅ 100% | ✅ | ✅ | ✅ | **100%** | [详情](./connectors/es.md) |
| trino-connector | ✅ | ✅ 100% | ✅ | ✅ | ✅ | **100%** |
[详情](./connectors/trino-connector.md) |
| hudi | 🟡(D-005 区分符 + D-020 模型 dispatch 已设计;实现批 E)| 🟨 55%(读路径 dormant + 批 C
测试基线)| ❌(gate 关)| ❌ | 0/0(寄生 hms)| **25%** | [详情](./connectors/hudi.md) |
-| maxcompute | 🟡 | ✅ 100%(翻闸 + legacy 删除完成)| ✅ **翻闸 T06b** | ✅(Batch D 已删)| ✅
0/0(已清)| **95%** | [详情](./connectors/maxcompute.md) |
+| maxcompute | ✅ | ✅ 100% | ✅ **已合入 #64253** | ✅ **#64300 已删** | ✅ 0/0 |
**100%** | [详情](./connectors/maxcompute.md) |
| paimon | 🟡 | 🟨 50% | ❌ | ❌ | 0/10 | **20%** | [详情](./connectors/paimon.md) |
| iceberg | 🟡 | 🟥 10% | ❌ | ❌ | 0/19 | **5%** | [详情](./connectors/iceberg.md) |
| hive (+hms) | 🟡 | 🟥 20% | ❌ | ❌ | 0/31 | **10%** |
[详情](./connectors/hive.md) |
@@ -44,7 +44,14 @@
> 状态非 ✅ 的项,按阶段聚合。详细见各阶段 task 文件。
-### P4 — maxcompute 迁移(🚧 full adopter;**设计已批准** [D-023],5 批/11 task;Batch
A+B+C ✅(翻闸完成),下一步 Batch D(删 legacy + drop odps 依赖,待 live 验证))
+### P5 — paimon 迁移(🔜 下一 session 启动:recon + 设计先行)
+
+> 策略 = **full adopter + 翻闸**(复用 P4 样板,非 P3 hybrid)。kickoff = code-grounded
recon → 设计 + 批次计划(`tasks/P5-paimon-migration.md`)→ 用户签字 → 分批实现 + 独立 commit。详见
[HANDOFF 第 19 次](./HANDOFF.md) + [paimon 连接器档](./connectors/paimon.md) + master
plan [§3.6](./00-connector-migration-master-plan.md)。
+>
+> **已知范围**(master §3.6 + 连接器档,待 recon 校正):① port
`PaimonMetadataOps`→`PaimonConnectorMetadata`(注意 partitionStatistics /
bucketing);② **6 个 catalog
flavor**(HMS/DLF/REST/File/Base/Factory)连接器内工厂重组(`PaimonConnectorProvider.create()`);③
MVCC(E5 `PaimonMvccSnapshot`)/ vended creds(E6
`PaimonVendedCredentialsProvider`)/ sys-tables(E7 `PaimonSysExternalTable`)承接
P0 新增 SPI —— **paimon 是首个真正消费 E5/E6/E7 的 adopter**(MC 未用);④ 删 fe-core 重复
`PaimonPredicateConverter`(**P1-T02 推迟项,仍在** `datasource/pai [...]
+> **前置风险**:R-004(classloader 打破 SDK 单例,paimon 明列)、R-007(FE/BE 共享 jar
冲突)、R-012(snapshotId 类型)。**关联决策**:D-005(HMS flavor 走
`tableFormatType`)、D-006(cache 放连接器内)。
+
+### P4 — maxcompute 迁移(✅ 已完成并合入:**#64253** T01–T06 适配+翻闸 + **#64300** T07–T09
删 legacy/odps-free;含 #64119 校验迁移)
> 策略 = **full adopter + 翻闸**([D-023],非 P3 hybrid);前置 W-phase(W1–W7)✅。批次计划 + 完整
> task 表见 [tasks/P4](./tasks/P4-maxcompute-migration.md)。
@@ -52,9 +59,9 @@
|---|---|---|---|---|
| A | 连接器 DDL + 分区 parity | 🔒 关 | P4-T01 ✅ / T02 ✅ | ✅ T01 DDL + T02 分区
listing 完成(gate 全绿:compile + checkstyle 0 + import-gate)|
| B | 写/事务 SPI(`ConnectorTransaction`/`WriteOps` +
`WritePlanProvider`→`TMaxComputeTableSink`)| 🔒 关 | P4-T03 ✅ / T04 ✅ | ✅ T03
写/事务 SPI(`MaxComputeConnectorTransaction`+`beginTransaction`)+ T04
写计划(`MaxComputeWritePlanProvider.planWrite`,OQ-2=Approach A)完成,gate 全绿 |
-| C | 翻闸(`SPI_READY_TYPES` + GSON + `getEngine`;含 R-004 防御测)| 🔓 **live** |
P4-T05/T06 | ✅ **翻闸完成**(T05 image-compat + T06a 写接线/UT + **T06b flip**,gate 全绿
[D-027]);R-004 part-2 live 待用户跑 |
-| D | 清 ~30 反向引用 + 删 legacy 子系统(20 文件,收口 P1-T02)+ **drop fe-core odps 依赖** +
**下沉 MCUtils/删 fe-common odps**(方案A §8)| 🔓 live | P4-T07/T08/T09 | ⏳ 方案已
finalize + @HEAD 校验(20 文件全在、linchpin residual=∅,2026-06-09);执行后 fe-core
依赖树**彻底无 odps**;**执行待用户 live ODPS
验证后**([D-027],[设计](./tasks/designs/P4-batchD-maxcompute-removal-design.md))|
-| E | 连接器测试基线 + PR | — | P4-T10/T11 | ⏳ |
+| C | 翻闸(`SPI_READY_TYPES` + GSON + `getEngine`;含 R-004 防御测)| 🔓 **live** |
P4-T05/T06 | ✅ **已合入 #64253**(T05 image-compat + T06a 写接线/UT + T06b flip;+ T06c
FE 分发补接 + T06e 红线 gap campaign G0/G2/G5/G6/G7/GC1/F9 等)|
+| D | 清反向引用 + 删 legacy 子系统(20 文件,收口 P1-T02 的 Mc 部分)+ **drop fe-core odps 依赖**
+ **下沉 MCUtils/删 fe-common odps**(方案A §8)| 🔓 live | P4-T07/T08/T09 | ✅ **已合入
#64300**(删 20 fe-core 文件 + 清反向引用 + MCUtils 下沉
be-java-extensions;`dependency:tree \| grep odps`=∅;含 DV-021/DV-022)|
+| E | 连接器测试基线 + PR | — | P4-T10/T11 | ✅ 连接器 UT 全绿(含 #64119 迁移测,101 run/0
fail/1 skip);PR #64253 + #64300 已合入 |
### P3 — hudi 迁移(🚧 hybrid,批 A–D 全部 in-scope 完成:T02/T04/T05/T07 ✅ + T06/T08
决策;T03→批 E;剩批 E→P7,**P3 已合入 #64143 `5c240dc7a34`**;批 E live cutover 并入 P7)
@@ -140,6 +147,7 @@
> 倒序,新内容置顶;超过 14 天的条目移除(git log 保留历史)。
+- **2026-06-09(阶段里程碑 · P4 完成)** ✅ **P4 maxcompute 迁移全部完成并合入
`branch-catalog-spi`** —— **#64253**(T01–T06 连接器 full 适配 + live 翻闸
`SPI_READY_TYPES += "max_compute"`)+ **#64300**(T07–T09 删 20 fe-core legacy 文件
+ 清反向引用 + MCUtils 下沉 be-java-extensions,`fe-core dependency:tree | grep
odps`=∅,HEAD `e96037cf6aa`)。upstream PR **#64119**(MaxCompute 连接校验)功能已迁连接器
SPI(`validateMaxComputeConnection`/`checkOperationSupported`,连接器 UT
101/0/0/1)并随 #64300 squash 合入(`git log -S` 证)。fe-core **彻底无 odps**(代码 + [...]
- **2026-06-06(实现 ⑧·P4-T05)** ✅ **P4 Batch C 启动 — P4-T05
翻闸接线完成**(dormant、gate-green、**待 commit**,用户定时机):GsonUtils 三 GSON 注册(catalog
`:397` / **db `:452`** / table `:472`)atomic 迁
`registerCompatibleSubtype`→`PluginDriven*` + 删 3 unused `maxcompute.*`
import;`PluginDrivenExternalTable.getEngine`/`getEngineTableTypeName` 加 `case
"max_compute"`(返 `MAX_COMPUTE_EXTERNAL_TABLE.toEngineName()`=null /
`.name()`,**核 legacy 行为等价**);`legacyLogTypeToCatalogType` 仅加注释(默认分支已出
`"max_compute"`,不加 case) [...]
- **2026-06-06(设计 ⑤·Batch C)** ✅ **P4 Batch C 翻闸设计完成 + 用户签字
[D-026]**(design-only,零代码):用户选 "Design Batch C first"。4 路 Explore re-verify
recon 锚点 + 主线核读 executor/txn 生命周期,出
[翻闸设计](./tasks/designs/P4-T05-T06-cutover-design.md)(verified file:line + 5 gap
G1–G5 + 写生命周期顺序 + R-004 两分测 + ordered TODO)。**3 决策签字**:D-1 capability signal=新增
`ConnectorWriteOps.usesConnectorTransaction()` flag(MC=true,否决
writePlanProvider 代理/复用 ConnectorWriteType);D-2 两 commit、flip 末(`[P4-T06a]` 接线
dormant + `[P4-T06 [...]
- **2026-06-06(实现 ⑦·P4-T04)** ✅ **P4 Batch B 收尾 — P4-T04 连接器写计划完成 = Batch A+B
全完成**(gate 关、dormant、零 live 风险):新建 `MaxComputeWritePlanProvider implements
ConnectorWritePlanProvider`,`planWrite` 走 **OQ-2 = Approach A**(finalizeSink
一处:建 ODPS Storage API 写 session →
`session.getCurrentTransaction()`→`MaxComputeConnectorTransaction.setWriteSession`
绑事务 → 盖 `TMaxComputeTableSink` 静态字段 + `static_partition_spec` +
`partition_columns`(ODPS 表列) + `write_session_id` + `txn_id`;**无运行期注入
hook**,lega [...]
@@ -202,8 +210,8 @@
| 类型 | 总数 | 最新条目 | 文档 |
|---|---|---|---|
-| **决策**(D-NNN) | 25 | D-025(P4-T04 写计划 5 决策:OQ-2=Approach A / D-2a seam fill
/ D-3 抽 `getSettings()` / D-4 `supportsInsert` / D-5 静态分区 map);D-024(P4-T03 两
fork)| [decisions-log.md](./decisions-log.md) |
-| **偏差**(DV-NNN) | 12 | DV-012(P4-T04 `partition_columns` 取 ODPS
表列,源不同值同);DV-011(P4-T03 block 上限常量)| [deviations-log.md](./deviations-log.md) |
+| **决策**(D-NNN) | 36 | D-036(P4-T06e FIX-CAST-PUSHDOWN:MC 关 CAST 谓词下推 + 剥壳抑制
source LIMIT,修 F9 静默丢行回归);D-035(FIX-BATCH-MODE-SPLIT 通用 batch SPI
路径);D-034(FIX-POSTCOMMIT-REFRESH swallow)|
[decisions-log.md](./decisions-log.md) |
+| **偏差**(DV-NNN) | 22 | DV-022(P4-T09 fe-common 去 odps 暴露隐藏传递依赖→显式补
netty/protobuf);DV-021(Batch-D 删后 4 条 Tier-3 接受项 GAP3/4/9/10)|
[deviations-log.md](./deviations-log.md) |
| **风险**(R-NNN) | 14 | R-014(thrift sink 选择灵活性) | [risks.md](./risks.md) |
---
@@ -212,9 +220,9 @@
> 当本项目通过 Claude Code 这类 LLM agent 推进时,跟踪当前 session 状态、handoff 状况和 context 健康度。
-- **本 session 已完成**:**P4-T04 连接器写计划**(Batch B 收尾 = A+B 全完成,gate 关、dormant、零
live 风险)——新建 `MaxComputeWritePlanProvider.planWrite`(**OQ-2=Approach
A**:finalizeSink 一处建写 session + `setWriteSession` 绑 txn + 盖
`txn_id`/`write_session_id`,无运行期注入)+
`MaxComputeDorisConnector.getSettings()`/`getWritePlanProvider()` +
`supportsInsert()`=true + fe-core seam(`bindViaWritePlanProvider(insertCtx)` +
`PluginDrivenInsertCommandContext.staticPartitionSpec`)。5 决策 [D-025];偏差
[DV-012](partition_columns 源)。守 [...]
-- **下一个 session 应做**:**Batch C 翻闸**(唯一 live 切点;前置 = A+B 全绿 ✅ + R-004 ODPS
classloader 防御测)——P4-T05 GsonUtils `registerCompatibleSubtype` +
`PluginDrivenExternalTable.getEngine`/`legacyLogTypeToCatalogType` 加
`max_compute`;P4-T06 `SPI_READY_TYPES += "max_compute"` + 删 `CatalogFactory`
case + **executor 接线**(`beginTransaction`→`begin(connectorTx)` + 置
`ConnectorSessionImpl.setCurrentTransaction`)+
`GlobalExternalTransactionInfoMgr` 注册 + binding 期填
`PluginDrivenInsertCommandContext` overwri [...]
-- **是否需要 handoff**:**是**——本场已 rewrite [HANDOFF.md](./HANDOFF.md)(P4-T04 完成 +
Batch C 翻闸首步锚点 + dormant→live 接线清单 + 守门坑沿用)
+- **本 session 已完成**:**交接文档同步(P4 完成里程碑)** —— 核实 P4 全部合入(#64253 T01–T06 + #64300
T07–T09,含 #64119 校验迁移;fe-core 代码 + 依赖树彻底无 odps;分支 `branch-catalog-spi` 干净)后,更新
PROGRESS(§header / §一 P4→100% + P5 标「下一阶段」/ §二看板 maxcompute 100% / §三 P4 收尾 +
**新增 P5 kickoff 块** / §四里程碑 / §六 D-036·DV-022 计数纠正 / §七)+ rewrite HANDOFF(第 19
次)。**无产线代码改动。**
+- **下一个 session 应做**:**P5 paimon 迁移 kickoff** —— code-grounded recon(连接器模块现状 /
fe-core footprint / 6 catalog flavor / MVCC·vended·sys-tables 即 E5/E6/E7 / 10
处反向 instanceof / 复用 P4 写 SPI)→ 写 `tasks/P5-paimon-migration.md`(设计 + 批次计划)→
用户签字 → 分批实现。起点材料见 [HANDOFF 第 19 次](./HANDOFF.md) + [paimon
档](./connectors/paimon.md) + master
[§3.6](./00-connector-migration-master-plan.md)。
+- **是否需要 handoff**:**是**——本场已 rewrite [HANDOFF.md](./HANDOFF.md)(第 19 次:P4
完成确认 + P5 kickoff 起点 + paimon 范围/风险/材料清单)。
- **协作规范**:[AGENT-PLAYBOOK.md](./AGENT-PLAYBOOK.md)(context 预算、subagent
使用、handoff 触发条件)
---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]