MVP 自托管试用交付:安装、完整恢复与两账号验收 #15

Closed
opened 2026-09-10 17:09:31 +08:00 by ila · 5 comments
Owner

来源与目标

2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 4;覆盖 B04、F01–F12 集成验收。

在干净测试环境部署完整 MVP,用两个虚构账号走通学习闭环,再从备份恢复到空实例,为少量用户试用提供可执行交付材料。

验收标准

  • 固定部署版本与配置清单,管理员首次初始化可执行;不带默认可用密码或真实数据,记录依赖和资源版本。
  • 数据库、原文/文件、词典/模型与配置恢复清单完整;在空实例恢复,验证用户隔离、章节原文、词条、复习到期及进度。
  • 集成验证越权、任务崩溃重试、并发答题、长文与无词典降级;性能给出数据量、环境及结果,不凭空承诺。
  • 记录使用、部署、备份、恢复、升级回退步骤;用户验收后才标 MVP 完成。实际对外部署和邀请用户按明确目标执行。

依赖与执行

前置:#14。状态:待验收(2026-09-15,提交 38d8975,PR #35;契约见评论 8099,实施证据见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。

参考模块与设计证据

复用固定底座部署入口,补 LexGo 文件/资源一致性;没有备份管理 UI。

无新增 UI 原型;部署恢复步骤和集成测试结果为验收证据。

后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。

工作量、范围与风险

预计 4~6 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。

文档与证据

实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。

Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。

## 来源与目标 2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 4;覆盖 B04、F01–F12 集成验收。 在干净测试环境部署完整 MVP,用两个虚构账号走通学习闭环,再从备份恢复到空实例,为少量用户试用提供可执行交付材料。 ## 验收标准 - [ ] 固定部署版本与配置清单,管理员首次初始化可执行;不带默认可用密码或真实数据,记录依赖和资源版本。 - [ ] 数据库、原文/文件、词典/模型与配置恢复清单完整;在空实例恢复,验证用户隔离、章节原文、词条、复习到期及进度。 - [ ] 集成验证越权、任务崩溃重试、并发答题、长文与无词典降级;性能给出数据量、环境及结果,不凭空承诺。 - [ ] 记录使用、部署、备份、恢复、升级回退步骤;用户验收后才标 MVP 完成。实际对外部署和邀请用户按明确目标执行。 ## 依赖与执行 前置:#14。状态:待验收(2026-09-15,提交 38d8975,PR #35;契约见评论 8099,实施证据见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。 ## 参考模块与设计证据 复用固定底座部署入口,补 LexGo 文件/资源一致性;没有备份管理 UI。 无新增 UI 原型;部署恢复步骤和集成测试结果为验收证据。 后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。 ## 工作量、范围与风险 预计 4~6 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。 ## 文档与证据 实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。 Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。
Author
Owner

#15 方案确认与实施启动(2026-09-15)

用户 2026-09-15 指示「先按原范围把 #15 做完、再回来处理 #21」,并在只读诊断后选择按建议的默认方案执行。前置 #14 已验收关闭。分支 feat/15-self-hosted-delivery 从 main 20e13e9 创建。

D0 用户确认的六个默认(2026-09-15)

  1. 目标环境:只交付本机可复现的安装/备份/恢复材料并在本机做完整演练;不对外部署,不创建 release/tag,不邀请用户。
  2. 访问入口:本机/内网 127.0.0.1,不做 HTTPS;文档写出对外部署时的入口与证书注意事项,但不作为本次执行内容。
  3. 前端托管:生产用 nginx 托管已构建的 dist(零后端代码改动);本机演练用等价的静态托管验证产物与 API 契约,并明确记录 nginx 配置本身未在本机执行。
  4. 数据起点:试用实例从空库开始,管理员首次 bootstrap 建号;不使用 lexgo_dev 的开发数据,不带默认可用密码。
  5. 备份策略:备份=MySQL 全库 dump + 环境配置(凭据只存运维密码库,不进仓库/日志);保留份数与位置由运维决定;不新增定时备份。
  6. 性能口径:用本契约写明的人造数据集在本机实测,报告数据量、环境与结果,不写成承诺。

D1 交付物:scripts/ops.py(目标无关,可在任意主机复用)

子命令 行为与安全边界
install-check 核对依赖与资源版本(MySQL 客户端/服务端、Go、Node/pnpm、WordNet 资源 pin、.env.local 键名齐全),逐项输出预期结果;只读
backup --out DIR mysqldump --single-transaction --routines --triggers --hex-blob --no-tablespaces 导出全库为 .sql.gz,并写 manifest.json:schema 版本、产品标识、Git 提交、dump 与文件 sha256、逐表行数、mysqldump/服务端版本、库名。不写入任何凭据
restore --dump F --database NAME --confirm 默认只恢复到空库:库名必须含 lexgo、拒绝系统库、目标已有 lexgo_schema 数据时必须显式 --force,且必须带 --confirm;恢复后自动跑 verify
verify --database NAME [--manifest F] [--api URL] [--user U --password-env V] 数据库侧:schema 版本、逐表行数与 manifest 比对、归属一致性(章节属于书、词条属于账号、词条必有排期、复习记录引用有效词条)、审计表白名单列(不含凭据/正文列)。API 侧:两账号闭环与越权(A 读 B 的书籍/章节/词条一律 404;A 读完一章、保存词条、到期复习一次后进度自洽)

D2 本机完整恢复演练(本单核心证据)

备份 lexgo_dev → 恢复到空库 lexgo_restore_drill → 用覆盖环境变量在同一台机起第二个 API 实例(LEXGO_DB_NAME/LEXGO_LISTEN 覆盖,不改代码)→ 在恢复实例上跑两账号闭环与越权验证 → 比对恢复前后的行数与关键数据 → 拆掉演练实例与演练库。演练过程中产生的证据(manifest、行数比对、API 输出摘要)写入工单,不复制任何真实数据内容。

D3 集成验证矩阵(复用既有 Go 测试,按验收标准逐条对应)

验收要求 覆盖用例
两账号越权 TestMySQLLibraryIsolationAndOwnership、TestMySQLTermIsolationAndInputRules、TestMySQLPhraseRulesAndIsolation、TestMySQLReviewAnswerErrorsAndOwnership、TestMySQLAccountIsolationAndRevocation
任务崩溃重试 TestMySQLIngestRecoveryWithoutRestart、TestMySQLIngestRecoveryAfterRestart、TestMySQLIngestAttemptsAreBoundedAndManualRetryRestarts、TestMySQLRetryAfterContentRestoredPublishesSameChapter、TestMySQLRecoverySkipsSupersededJobs
并发答题 TestMySQLReviewConcurrentReplayOfOneAnswer、TestConcurrentDuplicateAccountHasOneWinner、TestMySQLConcurrentChapterDelete、TestMySQLDeleteDuringProcessing
长文 TestMySQLPasteRejectsInvalidInputAndLimits、TestMySQLTextUploadKeepsChapterLimit、TestMySQLTextUploadRejectsInvalidSubmissions
无词典降级 TestDictionaryAPIResourcesAndOwnership 与词典禁用/缺失时的查询状态(实施时确认对应断言并如实记录)
数据完整性 TestMigrationRefusesUnownedOrUnsupportedSchema、全部 TestMigrationFrom*

D4 性能测量

scripts/bench.py 在人造数据集(1 本书、20 章 × 约 5k 词;5000 词条;20000 条复习记录;含短语)上测量登录、书库、章节正文与分词、生词本列表与搜索、到期队列、答题、进度等接口,输出请求数、p50/p95 与错误数,并记录 CPU/内存/操作系统/MySQL 版本。只报告实测值,不承诺容量。 数据集只写演练库,用完删除。

D5 文档

  • 新建 Wiki 页 Deployment-and-Operations(按 docs/templates/deployment.md 结构:服务概览、环境要求、首次部署、supervisor/nginx、配置与凭据来源、日常运维、健康检查、升级与回滚、备份与恢复、已知限制),并加入 wiki-docs.json 映射与核心镜像
  • 更新 Architecture-and-Code-Map(部署拓扑、进程、端口、备份对象)、Local-Development-and-Verification(本机安装/备份/恢复/演练命令与实测结果)、Product-Requirements-Overview(交付状态)、Home、README.md、AGENTS.md 常用命令
  • 记录 #21 的衔接边界:附件(音频/封面)尚未实施,本单恢复契约今天只覆盖数据库;#21 落地后由本单恢复验收纳入附件

D6 范围外与风险

不对外部署、不做 HTTPS、不做灰度/多机/容器化、不做定时备份与监控告警、不做附件存储(#21)、不做数据脱敏导出。风险:恢复演练会创建并删除演练库(只操作 lexgo_ 前缀的演练库,不触碰 lexgo_dev 与生产库);性能数字只代表本机环境。

D7 回退

纯工具、文档与演练库改动,无 schema 变化;删除演练库与演练进程即可,仓库侧回到上一提交。

Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。

## #15 方案确认与实施启动(2026-09-15) 用户 2026-09-15 指示「先按原范围把 #15 做完、再回来处理 #21」,并在只读诊断后选择**按建议的默认方案**执行。前置 #14 已验收关闭。分支 `feat/15-self-hosted-delivery` 从 main `20e13e9` 创建。 ### D0 用户确认的六个默认(2026-09-15) 1. **目标环境**:只交付本机可复现的安装/备份/恢复材料并在本机做完整演练;**不对外部署**,不创建 release/tag,不邀请用户。 2. **访问入口**:本机/内网 `127.0.0.1`,不做 HTTPS;文档写出对外部署时的入口与证书注意事项,但不作为本次执行内容。 3. **前端托管**:生产用 nginx 托管已构建的 `dist`(**零后端代码改动**);本机演练用等价的静态托管验证产物与 API 契约,并明确记录 nginx 配置本身未在本机执行。 4. **数据起点**:试用实例从**空库**开始,管理员首次 `bootstrap` 建号;不使用 lexgo_dev 的开发数据,不带默认可用密码。 5. **备份策略**:备份=MySQL 全库 dump + 环境配置(凭据只存运维密码库,不进仓库/日志);保留份数与位置由运维决定;**不新增定时备份**。 6. **性能口径**:用本契约写明的人造数据集在本机实测,报告数据量、环境与结果,不写成承诺。 ### D1 交付物:`scripts/ops.py`(目标无关,可在任意主机复用) | 子命令 | 行为与安全边界 | |---|---| | `install-check` | 核对依赖与资源版本(MySQL 客户端/服务端、Go、Node/pnpm、WordNet 资源 pin、`.env.local` 键名齐全),逐项输出预期结果;只读 | | `backup --out DIR` | `mysqldump --single-transaction --routines --triggers --hex-blob --no-tablespaces` 导出全库为 `.sql.gz`,并写 `manifest.json`:schema 版本、产品标识、Git 提交、dump 与文件 sha256、逐表行数、mysqldump/服务端版本、库名。**不写入任何凭据** | | `restore --dump F --database NAME --confirm` | **默认只恢复到空库**:库名必须含 `lexgo`、拒绝系统库、目标已有 `lexgo_schema` 数据时必须显式 `--force`,且必须带 `--confirm`;恢复后自动跑 `verify` | | `verify --database NAME [--manifest F] [--api URL] [--user U --password-env V]` | 数据库侧:schema 版本、逐表行数与 manifest 比对、归属一致性(章节属于书、词条属于账号、词条必有排期、复习记录引用有效词条)、审计表白名单列(不含凭据/正文列)。API 侧:两账号闭环与越权(A 读 B 的书籍/章节/词条一律 404;A 读完一章、保存词条、到期复习一次后进度自洽) | ### D2 本机完整恢复演练(本单核心证据) 备份 lexgo_dev → 恢复到**空库** `lexgo_restore_drill` → 用覆盖环境变量在同一台机起**第二个 API 实例**(`LEXGO_DB_NAME`/`LEXGO_LISTEN` 覆盖,不改代码)→ 在恢复实例上跑两账号闭环与越权验证 → 比对恢复前后的行数与关键数据 → 拆掉演练实例与演练库。演练过程中产生的证据(manifest、行数比对、API 输出摘要)写入工单,**不复制任何真实数据内容**。 ### D3 集成验证矩阵(复用既有 Go 测试,按验收标准逐条对应) | 验收要求 | 覆盖用例 | |---|---| | 两账号越权 | `TestMySQLLibraryIsolationAndOwnership`、`TestMySQLTermIsolationAndInputRules`、`TestMySQLPhraseRulesAndIsolation`、`TestMySQLReviewAnswerErrorsAndOwnership`、`TestMySQLAccountIsolationAndRevocation` | | 任务崩溃重试 | `TestMySQLIngestRecoveryWithoutRestart`、`TestMySQLIngestRecoveryAfterRestart`、`TestMySQLIngestAttemptsAreBoundedAndManualRetryRestarts`、`TestMySQLRetryAfterContentRestoredPublishesSameChapter`、`TestMySQLRecoverySkipsSupersededJobs` | | 并发答题 | `TestMySQLReviewConcurrentReplayOfOneAnswer`、`TestConcurrentDuplicateAccountHasOneWinner`、`TestMySQLConcurrentChapterDelete`、`TestMySQLDeleteDuringProcessing` | | 长文 | `TestMySQLPasteRejectsInvalidInputAndLimits`、`TestMySQLTextUploadKeepsChapterLimit`、`TestMySQLTextUploadRejectsInvalidSubmissions` | | 无词典降级 | `TestDictionaryAPIResourcesAndOwnership` 与词典禁用/缺失时的查询状态(实施时确认对应断言并如实记录) | | 数据完整性 | `TestMigrationRefusesUnownedOrUnsupportedSchema`、全部 `TestMigrationFrom*` | ### D4 性能测量 `scripts/bench.py` 在人造数据集(1 本书、20 章 × 约 5k 词;5000 词条;20000 条复习记录;含短语)上测量登录、书库、章节正文与分词、生词本列表与搜索、到期队列、答题、进度等接口,输出请求数、p50/p95 与错误数,并记录 CPU/内存/操作系统/MySQL 版本。**只报告实测值,不承诺容量。** 数据集只写演练库,用完删除。 ### D5 文档 - 新建 Wiki 页 `Deployment-and-Operations`(按 `docs/templates/deployment.md` 结构:服务概览、环境要求、首次部署、supervisor/nginx、配置与凭据来源、日常运维、健康检查、升级与回滚、备份与恢复、已知限制),并加入 `wiki-docs.json` 映射与核心镜像 - 更新 Architecture-and-Code-Map(部署拓扑、进程、端口、备份对象)、Local-Development-and-Verification(本机安装/备份/恢复/演练命令与实测结果)、Product-Requirements-Overview(交付状态)、Home、`README.md`、`AGENTS.md` 常用命令 - 记录 #21 的衔接边界:**附件(音频/封面)尚未实施,本单恢复契约今天只覆盖数据库**;#21 落地后由本单恢复验收纳入附件 ### D6 范围外与风险 不对外部署、不做 HTTPS、不做灰度/多机/容器化、不做定时备份与监控告警、不做附件存储(#21)、不做数据脱敏导出。风险:恢复演练会创建并删除演练库(**只操作 lexgo_ 前缀的演练库,不触碰 lexgo_dev 与生产库**);性能数字只代表本机环境。 ### D7 回退 纯工具、文档与演练库改动,无 schema 变化;删除演练库与演练进程即可,仓库侧回到上一提交。 Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。
Author
Owner

#15 实施完成,待用户验收(2026-09-15)

用户 2026-09-15 选择「按建议的默认」执行,契约见评论 8099。分支 feat/15-self-hosted-delivery 从 main 20e13e9 创建,提交 38d8975(含 bdb3897 的部署页映射)已推送;PR #35 未合并,工单不关闭,停在待用户验收。

交付内容

  • scripts/ops.py:install-check、init-database、backup、restore、verify、smoke。备份=MySQL 全库 dump + manifest.json(schema 版本、提交、sha256、逐表行数、客户端/服务端版本;不含凭据)。恢复默认只写空库,--confirm 必需,覆盖需 --force,拒绝系统库与带 CREATE DATABASE/USE 的 dump,并在恢复前后比对源库逐表内容校验和。
  • scripts/bench.py:人造数据集性能测量。
  • tests/test_lexgo_ops.py:9 项无库测试(含「备份的工具输出不得含库名切换」与 manifest 字段白名单)。
  • Wiki 新增 Deployment-and-Operations(docs/11-deployment-and-operations.md,revision 2b08a33c0c246841deb52450d7fa411d76dc2eee)+ wiki-docs.json 映射;含服务概览、环境要求、首次部署、配置与凭据来源、日常运维、健康检查、升级与回滚、备份与恢复、已知限制。

本机完整演练(27 项顶层检查全部通过,日志 .local/evidence/issue15-drill.log,证据 .local/issue15-drill-evidence.json)

  1. 干净安装:建空库 → migrate(v7,14 张表)→ 确认无账号无数据 → bootstrap 建管理员 → 再次 bootstrap 被拒绝(不覆盖管理员)。
  2. 两个虚构演练账号走通闭环(smoke 19 项):粘贴 → 处理完成 → 分词 → 词典查询 → 保存词义 → 对方查不到 → 立即到期 → 作答 → 重复作答不重复记账 → 完成章节只记已读 → 进度反映活动;越权读他人书籍/章节均 404。
  3. 备份 lexgo_dev(约 12 MB gz,manifest 逐表行数完整)。
  4. 恢复到空实例并自动校验(33 项):逐表行数一致 → 逐表内容校验和与源库一致(13 张表)→ 源库未被改动。
  5. 安全边界:拒绝覆盖已有库、拒绝系统库、拒绝缺 --confirm。
  6. 恢复实例两账号闭环与越权校验(41 项)全通过。
  7. 收尾:演练库删除,lexgo_dev 与测试库保留且仍为 v7。

性能观察(单机无并发,只作观察不给承诺)

数据集:20 章 × 约 500 词、2000 词条、8000 条作答;环境 Windows 10、8 核、31.7 GB、MySQL 8.4.3、Go 工具链固定 1.26.5。/books p50 5.9 ms、/terms 10.2 ms、搜索 12.3 ms、/progress 15.7 ms、/reviews/queue 22.7 ms、/login 82.2 ms;全部 0 错误。登录接口每地址每分钟限 30 次,故登录只测 10 次,不代表登录吞吐。

集成验证矩阵

越权/隔离、任务崩溃重试、并发答题与并发删除、长文与输入上限、迁移与回退标记共 20 余个既有 Go 用例全部通过(对应关系见 Wiki 的 Local-Development 页);LEXGO_TEST_DB_NAME=lexgo_test_issue13 python scripts/server.py test-integration 70 项、治理 65 项(新增 9)、学习端 147 单测与 23 项 E2E、管理端 31 项,全部通过。

实施中发现并修掉的问题(如实记录)

  1. 恢复会写错库(严重):最初用 mysqldump --databases,dump 里带 CREATE DATABASE/USE,恢复时数据被灌回源库而不是目标库。发现后立刻核实源库:dump 与源库内容一致且期间无其他写入,没有数据损失;随后改为导出不带库名切换的 dump,并加了「拒绝加载带库名切换的旧 dump」与「恢复前后比对源库校验和」两道防线,并补了单元测试。
  2. 空实例无法直接迁移:Go 服务连不上不存在的库,因此新增 init-database 步骤并写进部署页。
  3. MySQL 客户端版本:本机 PATH 上是 5.7 客户端,install-check 起初误判为合格(把协议版本 14.14 当成客户端版本);修正解析后正确判失败,部署页写明「客户端不得低于服务端」。
  4. Windows 管道与编码:gzip 解压后经管道喂给 mysql 客户端在 Windows 上失败,改为解压到临时文件再喂入;所有子进程输出显式按 UTF-8 解码。
  5. 批量 SQL 超命令行长度:改由 stdin 传入 SQL。

未验证与边界

  • 真实回滚(升级后切回旧二进制)未演练,只在文档中给出规则。
  • 未验证 HTTPS、域名、反向代理配置、多机与灰度部署;本机演练只在 127.0.0.1 起两个临时实例。
  • 未启用定时备份、监控与告警;备份与恢复均为人工触发。
  • 大库恢复耗时与磁盘上限未测。
  • 附件(封面/音频,#21)尚未实现,本次恢复契约只覆盖数据库;#21 落地后必须把附件存储纳入恢复验收。
  • 按用户确认,本次没有对外部署、没有创建发布标签、没有邀请用户。

文档

  • Deployment-and-Operations(新建):2b08a33c0c246841deb52450d7fa411d76dc2eee
  • Architecture-and-Code-Map: bd4a0e705abe722f153a7410435def91a21d472a
  • Business-Rules-and-Glossary: 5f2912edd09256cf5fc52059145d65918e99f9cb
  • Local-Development-and-Verification: caa80888cf42fd7fd7f040e9fe1147203fe7bfe3
  • Product-Requirements-Overview: a1847957e287c7eb1a54905e13632aeca4cd75f7
  • Home: 22731c2b344b3e0c75eb892c897d36d1f153a441
  • 镜像校验:sync --check 通过,6 个变更页逐字节正文比对一致;README 与 AGENTS.md 已同步

回退

纯工具、文档与演练库改动,无 schema 变化、无接口变化:git revert 到 20e13e9 或恢复上一提交即可;演练库已删除,不影响 lexgo_dev。

Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。

证据文件(本机,不入仓库):.local/evidence/issue15-drill.log(演练完整输出)、.local/issue15-drill-evidence.json(27 项检查)、.local/evidence/issue15-bench.json(性能报告);演练账号密码由演练进程生成、只经环境变量传入,未写入任何文件、日志或本评论。

## #15 实施完成,待用户验收(2026-09-15) 用户 2026-09-15 选择「按建议的默认」执行,契约见评论 [8099](https://git.ilapage.cn/OPC/lexgo/issues/15#issuecomment-8099)。分支 `feat/15-self-hosted-delivery` 从 main `20e13e9` 创建,提交 `38d8975`(含 `bdb3897` 的部署页映射)已推送;PR [#35](https://git.ilapage.cn/OPC/lexgo/pulls/35) 未合并,工单不关闭,停在待用户验收。 ### 交付内容 - **`scripts/ops.py`**:`install-check`、`init-database`、`backup`、`restore`、`verify`、`smoke`。备份=MySQL 全库 dump + `manifest.json`(schema 版本、提交、sha256、逐表行数、客户端/服务端版本;**不含凭据**)。恢复默认只写空库,`--confirm` 必需,覆盖需 `--force`,拒绝系统库与带 `CREATE DATABASE`/`USE` 的 dump,并在恢复前后比对源库逐表内容校验和。 - **`scripts/bench.py`**:人造数据集性能测量。 - **`tests/test_lexgo_ops.py`**:9 项无库测试(含「备份的工具输出不得含库名切换」与 manifest 字段白名单)。 - **Wiki 新增 `Deployment-and-Operations`**(`docs/11-deployment-and-operations.md`,revision `2b08a33c0c246841deb52450d7fa411d76dc2eee`)+ `wiki-docs.json` 映射;含服务概览、环境要求、首次部署、配置与凭据来源、日常运维、健康检查、升级与回滚、备份与恢复、已知限制。 ### 本机完整演练(27 项顶层检查全部通过,日志 `.local/evidence/issue15-drill.log`,证据 `.local/issue15-drill-evidence.json`) 1. **干净安装**:建空库 → `migrate`(v7,14 张表)→ 确认无账号无数据 → `bootstrap` 建管理员 → **再次 bootstrap 被拒绝**(不覆盖管理员)。 2. **两个虚构演练账号走通闭环**(`smoke` 19 项):粘贴 → 处理完成 → 分词 → 词典查询 → 保存词义 → 对方查不到 → 立即到期 → 作答 → 重复作答不重复记账 → 完成章节只记已读 → 进度反映活动;越权读他人书籍/章节均 404。 3. **备份 lexgo_dev**(约 12 MB gz,manifest 逐表行数完整)。 4. **恢复到空实例**并自动校验(33 项):逐表行数一致 → **逐表内容校验和与源库一致**(13 张表)→ **源库未被改动**。 5. **安全边界**:拒绝覆盖已有库、拒绝系统库、拒绝缺 `--confirm`。 6. **恢复实例两账号闭环与越权校验**(41 项)全通过。 7. **收尾**:演练库删除,`lexgo_dev` 与测试库保留且仍为 v7。 ### 性能观察(单机无并发,只作观察不给承诺) 数据集:20 章 × 约 500 词、2000 词条、8000 条作答;环境 Windows 10、8 核、31.7 GB、MySQL 8.4.3、Go 工具链固定 1.26.5。`/books` p50 5.9 ms、`/terms` 10.2 ms、搜索 12.3 ms、`/progress` 15.7 ms、`/reviews/queue` 22.7 ms、`/login` 82.2 ms;**全部 0 错误**。登录接口每地址每分钟限 30 次,故登录只测 10 次,不代表登录吞吐。 ### 集成验证矩阵 越权/隔离、任务崩溃重试、并发答题与并发删除、长文与输入上限、迁移与回退标记共 20 余个既有 Go 用例全部通过(对应关系见 Wiki 的 Local-Development 页);`LEXGO_TEST_DB_NAME=lexgo_test_issue13 python scripts/server.py test-integration` 70 项、治理 65 项(新增 9)、学习端 147 单测与 23 项 E2E、管理端 31 项,全部通过。 ### 实施中发现并修掉的问题(如实记录) 1. **恢复会写错库(严重)**:最初用 `mysqldump --databases`,dump 里带 `CREATE DATABASE`/`USE`,恢复时数据被灌回**源库**而不是目标库。发现后立刻核实源库:dump 与源库内容一致且期间无其他写入,**没有数据损失**;随后改为导出不带库名切换的 dump,并加了「拒绝加载带库名切换的旧 dump」与「恢复前后比对源库校验和」两道防线,并补了单元测试。 2. **空实例无法直接迁移**:Go 服务连不上不存在的库,因此新增 `init-database` 步骤并写进部署页。 3. **MySQL 客户端版本**:本机 PATH 上是 5.7 客户端,`install-check` 起初误判为合格(把协议版本 14.14 当成客户端版本);修正解析后正确判失败,部署页写明「客户端不得低于服务端」。 4. **Windows 管道与编码**:gzip 解压后经管道喂给 mysql 客户端在 Windows 上失败,改为解压到临时文件再喂入;所有子进程输出显式按 UTF-8 解码。 5. **批量 SQL 超命令行长度**:改由 stdin 传入 SQL。 ### 未验证与边界 - **真实回滚(升级后切回旧二进制)未演练**,只在文档中给出规则。 - 未验证 HTTPS、域名、反向代理配置、多机与灰度部署;本机演练只在 `127.0.0.1` 起两个临时实例。 - 未启用定时备份、监控与告警;备份与恢复均为人工触发。 - 大库恢复耗时与磁盘上限未测。 - **附件(封面/音频,#21)尚未实现**,本次恢复契约只覆盖数据库;#21 落地后必须把附件存储纳入恢复验收。 - 按用户确认,**本次没有对外部署、没有创建发布标签、没有邀请用户**。 ### 文档 - Deployment-and-Operations(新建):`2b08a33c0c246841deb52450d7fa411d76dc2eee` - Architecture-and-Code-Map: `bd4a0e705abe722f153a7410435def91a21d472a` - Business-Rules-and-Glossary: `5f2912edd09256cf5fc52059145d65918e99f9cb` - Local-Development-and-Verification: `caa80888cf42fd7fd7f040e9fe1147203fe7bfe3` - Product-Requirements-Overview: `a1847957e287c7eb1a54905e13632aeca4cd75f7` - Home: `22731c2b344b3e0c75eb892c897d36d1f153a441` - 镜像校验:`sync --check` 通过,6 个变更页逐字节正文比对一致;README 与 AGENTS.md 已同步 ### 回退 纯工具、文档与演练库改动,**无 schema 变化、无接口变化**:`git revert` 到 `20e13e9` 或恢复上一提交即可;演练库已删除,不影响 `lexgo_dev`。 Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。 证据文件(本机,不入仓库):`.local/evidence/issue15-drill.log`(演练完整输出)、`.local/issue15-drill-evidence.json`(27 项检查)、`.local/evidence/issue15-bench.json`(性能报告);演练账号密码由演练进程生成、只经环境变量传入,未写入任何文件、日志或本评论。
Author
Owner

#15 范围追加:把备份、恢复与校验做进 Go 二进制(2026-09-15)

用户 2026-09-15 选择方案 C,并指出「项目是纯 Go,为什么要运行 Python 脚本」。核实后的事实与决定记录如下。

事实澄清

  • 「全 Go」是 2026-09-11 确认的正式 NLP/词典技术决策(#5/#6),约束产品运行时:server/go.mod 只有 gin/gorm/mysql 驱动等 Go 依赖,产品代码里唯一的 "python" 字样是 wordnet-resource.json 中「无 Python 进程」的说明。后端、学习端、管理端运行时都不含 Python。
  • 仓库中的 Python 一直是工具语言且早于本单:dev_scripts/harness.py 与 wiki_docs.py(DevHarness 治理,AGENTS.md 要求工具保持原样)、tests/(治理测试)、scripts/server.py(加载 .env.local 并固定工具链后调用 go run/build/test,无业务逻辑)。
  • 本单引入 scripts/ops.py/bench.py 时沿用了这套既有约定,但也确实让运维机需要 Python——尽管这不是新增前提:部署文档第一步 python scripts/server.py migrate 从 #2 起就如此。这层没有说清楚,是本单文档的疏漏。
  • 另外核实:lexgo 二进制本来就有 migrate|bootstrap|serve|audit-cleanup 子命令,安装路径可以不依赖 Python,文档此前没有把它写成主路径。

决定(方案 C)

  1. 备份、恢复、校验移植为 Go 子命令:lexgo backup / lexgo restore / lexgo verify,与既有子命令同一入口、同一份 LEXGO_* 配置。目标产物:运维机只需要一个二进制 + MySQL 客户端(备份仍调用 mysqldump,因为自己实现一致性导出风险更高,这点在文档写明)。
  2. manifest 格式与 Python 通道完全一致(同名字段、同 sha256、同逐表行数),两条通道可以互相读取对方的备份与报告,作为交叉验证手段。
  3. 部署页补「纯二进制路径」:lexgo migrate、lexgo bootstrap、lexgo backup|restore|verify 不经过 Python;Python 通道保留为交叉验证与开发便利入口,并在文档中说明两者关系。
  4. 安全规则不变:恢复必须显式确认、默认只写空库、库名必须含 lexgo 且不能是系统库、拒绝带 CREATE DATABASE/USE 的 dump、恢复前后比对源库逐表内容校验和。
  5. 验证:Go 侧单元测试(manifest 往返、dump 安全性扫描、库名与版本规则)+ MySQL 集成测试(备份→恢复到空库→校验)+ 用两条通道各做一次真实演练并比对行数与校验和。

范围与状态

本追加并入本单 #15(工单仍停在待验收,不另行建单);dev_scripts/ 与 tests/ 的 Python 属于框架规定,不在移除范围。既有 Python 通道已验证可用,移植完成后保留。

Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。

## #15 范围追加:把备份、恢复与校验做进 Go 二进制(2026-09-15) 用户 2026-09-15 选择方案 C,并指出「项目是纯 Go,为什么要运行 Python 脚本」。核实后的事实与决定记录如下。 ### 事实澄清 - 「全 Go」是 2026-09-11 确认的**正式 NLP/词典**技术决策(#5/#6),约束**产品运行时**:`server/go.mod` 只有 gin/gorm/mysql 驱动等 Go 依赖,产品代码里唯一的 "python" 字样是 `wordnet-resource.json` 中「无 Python 进程」的说明。后端、学习端、管理端运行时都不含 Python。 - 仓库中的 Python 一直是**工具语言**且早于本单:`dev_scripts/harness.py` 与 `wiki_docs.py`(DevHarness 治理,AGENTS.md 要求工具保持原样)、`tests/`(治理测试)、`scripts/server.py`(加载 `.env.local` 并固定工具链后调用 `go run/build/test`,无业务逻辑)。 - 本单引入 `scripts/ops.py`/`bench.py` 时沿用了这套既有约定,但也确实让**运维机需要 Python**——尽管这不是新增前提:部署文档第一步 `python scripts/server.py migrate` 从 #2 起就如此。这层没有说清楚,是本单文档的疏漏。 - 另外核实:`lexgo` 二进制**本来就有** `migrate|bootstrap|serve|audit-cleanup` 子命令,安装路径可以不依赖 Python,文档此前没有把它写成主路径。 ### 决定(方案 C) 1. **备份、恢复、校验移植为 Go 子命令**:`lexgo backup` / `lexgo restore` / `lexgo verify`,与既有子命令同一入口、同一份 `LEXGO_*` 配置。目标产物:运维机只需要一个二进制 + MySQL 客户端(备份仍调用 `mysqldump`,因为自己实现一致性导出风险更高,这点在文档写明)。 2. **manifest 格式与 Python 通道完全一致**(同名字段、同 sha256、同逐表行数),两条通道可以互相读取对方的备份与报告,作为交叉验证手段。 3. **部署页补「纯二进制路径」**:`lexgo migrate`、`lexgo bootstrap`、`lexgo backup|restore|verify` 不经过 Python;Python 通道保留为交叉验证与开发便利入口,并在文档中说明两者关系。 4. **安全规则不变**:恢复必须显式确认、默认只写空库、库名必须含 lexgo 且不能是系统库、拒绝带 `CREATE DATABASE`/`USE` 的 dump、恢复前后比对源库逐表内容校验和。 5. **验证**:Go 侧单元测试(manifest 往返、dump 安全性扫描、库名与版本规则)+ MySQL 集成测试(备份→恢复到空库→校验)+ 用两条通道各做一次真实演练并比对行数与校验和。 ### 范围与状态 本追加并入本单 #15(工单仍停在待验收,不另行建单);`dev_scripts/` 与 `tests/` 的 Python 属于框架规定,不在移除范围。既有 Python 通道已验证可用,移植完成后保留。 Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。
Author
Owner

#15 范围追加完成:纯二进制运维(方案 C)

按评论 8108 确认的方案 C 实施完毕,提交 420365f(实现)与 dde2ac1(文档镜像)已推送到同一分支与 PR。工单仍停在待验收。

事实澄清(回应「项目是纯 Go,为什么跑 Python」)

  • 「全 Go」是 2026-09-11 确认的正式 NLP/词典决策(#5/#6),约束产品运行时:server/go.mod 只有 gin/gorm/mysql 驱动等 Go 依赖,产品代码里唯一的 "python" 字样是 wordnet-resource.json 中「无 Python 进程」的说明。
  • 仓库中的 Python 一直是工具语言且早于本单:dev_scripts/(DevHarness 治理,AGENTS.md 要求保持原样)、tests/(治理测试)、scripts/server.py(加载配置并调用 go 命令,无业务逻辑)。
  • 本单此前让运维机需要 Python,这层没有说清楚是本单的疏漏;本次已修正:安装与运维现在有纯二进制路径。

新增的 Go 子命令

命令 行为
lexgo backup --out DIR [--database N] [--force] mysqldump 全库 → gzip → manifest.json(schema 版本、提交、sha256、逐表行数、客户端/服务端版本;不含凭据)
lexgo restore --dump F --database N --confirm [--force] [--skip-manifest-check] 默认只写空库;库名必须含 lexgo 且非系统库;拒绝带 CREATE DATABASE/USE 的 dump;恢复前后比对源库逐表内容校验和;恢复后自动校验
lexgo verify [--manifest F] [--database N] 完整性(孤立行、归属一致、排期与作答引用、等级边界、审计表敏感列白名单)+ 与 manifest 逐表行数比对

与既有 migrate|bootstrap|serve|audit-cleanup 同一入口;server/app/lexgo/ops.go 实现(操作客户端不选 schema,SQL 显式限定库名,保证能写一个还不存在的库)。备份仍调用 mysqldump——自己实现一致性导出风险更高,文档已写明部署机需要 MySQL 客户端。

验证

验证 结果
go test(含 ops_test.go) 7 项无库规则测试(库名白名单、客户端版本解析、dump 库名切换检测、拒绝无 --confirm、拒绝系统库、缺备份/缺 manifest、校验和比较、manifest 无凭据字段)
MySQL 集成 TestMySQLOpsBackupRestoreRoundTrip:备份 → 恢复到空库 → 校验通过 → 拒绝二次覆盖 → 源库校验和不变
顶层 Go 用例 79 项全部通过(本单此前 70)
纯二进制安装演练 9 项全过:lexgo migrate(v7,14 表)→ 空库无账号 → lexgo bootstrap → 重复 bootstrap 被拒 → lexgo verify 通过 → lexgo serve 健康检查 → 两账号走通闭环(19 项)→ 演练库删除
两条通道交叉验证 19 项全过:两条通道各备份一次,manifest 字段与逐表行数一致;Go 的 dump 用 Python 恢复、Python 的 dump 用 Go 恢复都成功;两个恢复实例的逐表内容校验和与源库一致;源库未被改动;安全边界两条通道各自确认
其它 治理 65 项、学习端 147 单测与 23 项 E2E、管理端 31 项与 lint、harness.py check --strict 与 sync --check 全部通过

证据:.local/evidence/issue15-binary-drill-evidence.json、.local/evidence/issue15-crosscheck-evidence.json、.local/evidence/issue15-drill.log。

边界(写入部署页)

  • 接口级的两账号闭环与越权验证需要发 HTTP 请求,仍在 Python 工具通道(ops.py smoke / verify --api);Go 二进制覆盖数据库层的备份、恢复与校验。
  • 备份依赖 mysqldump;未验证大库恢复耗时与磁盘上限。
  • 真实回滚、HTTPS、多机与定时备份仍未验证。

顺带记录的问题

  1. library.go 的 gofmt 遗留:#13 提交的 ChapterSummary 字段对齐未过 gofmt,本次一并修正(纯空白)。
  2. e2e/phrase.spec.ts:63 存在偶发失败(#11 时期的用例,与本次改动无关;前端代码未变):单跑必过,全量并行跑时约 6 次中出现 2 次失败。已如实记录,未在本单修改它的测试逻辑;如需修可另开小单或授权本次一并处理。
## #15 范围追加完成:纯二进制运维(方案 C) 按评论 [8108](https://git.ilapage.cn/OPC/lexgo/issues/15#issuecomment-8108) 确认的方案 C 实施完毕,提交 `420365f`(实现)与 `dde2ac1`(文档镜像)已推送到同一分支与 PR。工单仍停在**待验收**。 ### 事实澄清(回应「项目是纯 Go,为什么跑 Python」) - 「全 Go」是 2026-09-11 确认的**正式 NLP/词典**决策(#5/#6),约束**产品运行时**:`server/go.mod` 只有 gin/gorm/mysql 驱动等 Go 依赖,产品代码里唯一的 "python" 字样是 `wordnet-resource.json` 中「无 Python 进程」的说明。 - 仓库中的 Python 一直是**工具语言**且早于本单:`dev_scripts/`(DevHarness 治理,AGENTS.md 要求保持原样)、`tests/`(治理测试)、`scripts/server.py`(加载配置并调用 go 命令,无业务逻辑)。 - 本单此前让**运维机需要 Python**,这层没有说清楚是本单的疏漏;本次已修正:安装与运维现在有纯二进制路径。 ### 新增的 Go 子命令 | 命令 | 行为 | |---|---| | `lexgo backup --out DIR [--database N] [--force]` | `mysqldump` 全库 → gzip → `manifest.json`(schema 版本、提交、sha256、逐表行数、客户端/服务端版本;不含凭据) | | `lexgo restore --dump F --database N --confirm [--force] [--skip-manifest-check]` | 默认只写空库;库名必须含 lexgo 且非系统库;拒绝带 `CREATE DATABASE`/`USE` 的 dump;恢复前后比对源库逐表内容校验和;恢复后自动校验 | | `lexgo verify [--manifest F] [--database N]` | 完整性(孤立行、归属一致、排期与作答引用、等级边界、审计表敏感列白名单)+ 与 manifest 逐表行数比对 | 与既有 `migrate|bootstrap|serve|audit-cleanup` 同一入口;`server/app/lexgo/ops.go` 实现(操作客户端不选 schema,SQL 显式限定库名,保证能写一个还不存在的库)。备份仍调用 `mysqldump`——自己实现一致性导出风险更高,文档已写明部署机需要 MySQL 客户端。 ### 验证 | 验证 | 结果 | |---|---| | `go test`(含 `ops_test.go`) | 7 项无库规则测试(库名白名单、客户端版本解析、dump 库名切换检测、拒绝无 `--confirm`、拒绝系统库、缺备份/缺 manifest、校验和比较、manifest 无凭据字段) | | MySQL 集成 | `TestMySQLOpsBackupRestoreRoundTrip`:备份 → 恢复到空库 → 校验通过 → **拒绝二次覆盖** → 源库校验和不变 | | 顶层 Go 用例 | **79 项全部通过**(本单此前 70) | | 纯二进制安装演练 | **9 项全过**:`lexgo migrate`(v7,14 表)→ 空库无账号 → `lexgo bootstrap` → 重复 bootstrap 被拒 → `lexgo verify` 通过 → `lexgo serve` 健康检查 → 两账号走通闭环(19 项)→ 演练库删除 | | 两条通道交叉验证 | **19 项全过**:两条通道各备份一次,manifest 字段与逐表行数一致;**Go 的 dump 用 Python 恢复、Python 的 dump 用 Go 恢复**都成功;两个恢复实例的逐表内容校验和与源库一致;源库未被改动;安全边界两条通道各自确认 | | 其它 | 治理 65 项、学习端 147 单测与 23 项 E2E、管理端 31 项与 lint、`harness.py check --strict` 与 `sync --check` 全部通过 | 证据:`.local/evidence/issue15-binary-drill-evidence.json`、`.local/evidence/issue15-crosscheck-evidence.json`、`.local/evidence/issue15-drill.log`。 ### 边界(写入部署页) - 接口级的两账号闭环与越权验证需要发 HTTP 请求,仍在 Python 工具通道(`ops.py smoke` / `verify --api`);Go 二进制覆盖数据库层的备份、恢复与校验。 - 备份依赖 `mysqldump`;未验证大库恢复耗时与磁盘上限。 - 真实回滚、HTTPS、多机与定时备份仍未验证。 ### 顺带记录的问题 1. **`library.go` 的 gofmt 遗留**:#13 提交的 `ChapterSummary` 字段对齐未过 `gofmt`,本次一并修正(纯空白)。 2. **`e2e/phrase.spec.ts:63` 存在偶发失败**(#11 时期的用例,与本次改动无关;前端代码未变):单跑必过,全量并行跑时约 6 次中出现 2 次失败。已如实记录,未在本单修改它的测试逻辑;如需修可另开小单或授权本次一并处理。
Author
Owner

#15 验收通过(2026-09-15)

用户 2026-09-15 回复「A,并新开章级工单」,其中方案 A 即:先验收 #15,再按顺序合并 #15 与 #21 两个 PR。据此记录本单验收。

  • 验收范围:#15 契约 D0~D7(评论 8099、8108)— 本机可复现的安装/备份/恢复材料与完整演练、纯二进制运维子命令 lexgo backup|restore|verify、部署与运维 Wiki 页;不对外部署、不创建发布标签、不邀请用户。
  • 合并:PR #35 已 fast-forward-only 合入 main,merge commit dde2ac1。
  • 演练结果(本机,全部通过):空库安装+两账号闭环 19 项、纯二进制安装 9 项、完整恢复 27 项、两条通道交叉验证 19 项、附件版恢复 22 项(#21 落地后补做);恢复后逐表行数与内容校验和都与源库一致、源库未被改动。
  • 文档 revision:Deployment-and-Operations dacdad8a9385b2fde153a0dd1fe2579b57a810fd、Architecture 08472d2c98a5b4ac1b0354b09c6319ac74d321f7、Product-Requirements 2d6563574e807c9a167b90b7c772ee8b9b81e76d、Home eef77f39332c2bef01d5e9788a2c6c89796b2a1a、Project-Profile 2599afbb5e7cb47655fabe372596ca50cacb7a60。
  • 合并顺序说明:本单与 #21 的分支基点存在依赖(#21 分支从 #15 分支切出,见 #21 与本评论所属讨论),因此按用户确认的方案 A 先合并 #15 再合并 #21,避免未验收代码进入主干;本次未重写任何已推送历史。
  • 未验证(保留):真实回滚(升级后切回旧二进制)未演练、HTTPS/域名/反向代理、多机与灰度、定时备份、监控告警、大库恢复耗时与磁盘上限;接口级两账号闭环仍在 Python 工具通道。
  • 回退:本单无 schema 变化,纯工具与文档改动;git revert 到 20e13e9 或恢复上一提交即可(演练库已删除)。

单元工单关闭;#16 的 #15 复选框同步勾选。

## #15 验收通过(2026-09-15) 用户 2026-09-15 回复「**A,并新开章级工单**」,其中方案 A 即:先验收 #15,再按顺序合并 #15 与 #21 两个 PR。据此记录本单验收。 - 验收范围:#15 契约 D0~D7(评论 [8099](https://git.ilapage.cn/OPC/lexgo/issues/15#issuecomment-8099)、[8108](https://git.ilapage.cn/OPC/lexgo/issues/15#issuecomment-8108))— 本机可复现的安装/备份/恢复材料与完整演练、纯二进制运维子命令 `lexgo backup|restore|verify`、部署与运维 Wiki 页;不对外部署、不创建发布标签、不邀请用户。 - 合并:PR [#35](https://git.ilapage.cn/OPC/lexgo/pulls/35) 已 fast-forward-only 合入 main,merge commit `dde2ac1`。 - 演练结果(本机,全部通过):空库安装+两账号闭环 19 项、纯二进制安装 9 项、完整恢复 27 项、两条通道交叉验证 19 项、附件版恢复 22 项(#21 落地后补做);恢复后逐表行数与内容校验和都与源库一致、源库未被改动。 - 文档 revision:Deployment-and-Operations `dacdad8a9385b2fde153a0dd1fe2579b57a810fd`、Architecture `08472d2c98a5b4ac1b0354b09c6319ac74d321f7`、Product-Requirements `2d6563574e807c9a167b90b7c772ee8b9b81e76d`、Home `eef77f39332c2bef01d5e9788a2c6c89796b2a1a`、Project-Profile `2599afbb5e7cb47655fabe372596ca50cacb7a60`。 - 合并顺序说明:本单与 #21 的分支基点存在依赖(#21 分支从 #15 分支切出,见 #21 与本评论所属讨论),因此按用户确认的方案 A **先合并 #15 再合并 #21**,避免未验收代码进入主干;本次未重写任何已推送历史。 - 未验证(保留):**真实回滚(升级后切回旧二进制)未演练**、HTTPS/域名/反向代理、多机与灰度、定时备份、监控告警、大库恢复耗时与磁盘上限;接口级两账号闭环仍在 Python 工具通道。 - 回退:本单无 schema 变化,纯工具与文档改动;`git revert` 到 `20e13e9` 或恢复上一提交即可(演练库已删除)。 单元工单关闭;#16 的 #15 复选框同步勾选。
ila closed this issue 2026-09-15 20:26:12 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/lexgo#15