姚章浩
|
ca51cbe202
|
docs(release): 台账补记 0.1.131–0.1.132 与候选验收报告
build / build (push) Successful in 1m17s
为什么:版本→SHA→CI→是否部署要可审计,候选 E2E 证据要指向固定路径。
|
2026-10-28 17:58:42 +08:00 |
|
姚章浩
|
8a68ea2da2
|
docs(release): 台账补记 0.1.129–0.1.130
build / build (push) Successful in 1m21s
为什么:候选 SHA、CI 结论与真实服务验收事实要落台账。
|
2026-10-28 16:30:08 +08:00 |
|
姚章浩
|
6ca8481e8e
|
docs(release): 台账补记 0.1.126 与真实服务验收结论
build / build (push) Successful in 1m11s
为什么:候选 SHA 与 CI/验收结论要落在台账里,便于父审独立核对。
|
2026-10-28 16:00:16 +08:00 |
|
姚章浩
|
8da4666e76
|
test(library): 端到端编排在本机真实 PG/ES 上跑通
build / build (push) Successful in 1m14s
为什么:只验证单阶段写入还不够,完整链路(授权→预备份→四类写入→校验)也要在真实服务上跑。
本机 WeKnora 测试栈一次性库与随机索引已通过,CI 无这些服务故在 test-scope 声明为可选。
|
2026-10-28 15:58:06 +08:00 |
|
姚章浩
|
281699a431
|
feat(library): 生产整库真实读写/校验/恢复与本机真实服务验收
build / build (push) Successful in 1m21s
为什么:生产目标此前是"无条件失败"的占位,编排再完整也不能落地;本轮把它做成真实实现,
并在本机 WeKnora 测试栈的真实 PG/ES 上跑通导入、撤销、预备份与故障恢复。
- ProductionLibraryTarget:Current 读行数+身份摘要;Apply 按阶段真实写入(database/wiki
同事务先删本库再插、resources 传对象、index 搬运原始文档与向量);Verify 比对身份摘要;
Restore 按预备份快照回放。
- 撤销真正生效:索引阶段写入后 PruneScope 删除快照里没有的文档。
- ProductionBackupStore:导出前独立完整预备份,导出前后行数不一致即失败。
- worker 用注入配置装配目标与预备份;缺项把变量名写进阶段并失败,不再有占位对象。
- capacity 安全加法防溢出;保留策略组合语义明确(各维度都超限才候选)。
- 新增本机真实服务集成测试(一次性 kg_library_test_* 库 + 随机 ES 索引),
覆盖导入/校验/撤销/预备份/故障注入/恢复。
|
2026-10-28 15:54:01 +08:00 |
|
姚章浩
|
444b820210
|
docs(release): 台账补记 0.1.123 与 run164 失败说明
build / build (push) Successful in 1m10s
为什么:run164 的失败原因与修复要留在台账里,不能让失败消失。
|
2026-10-28 15:32:52 +08:00 |
|
姚章浩
|
7e3075f0fc
|
docs(release): 台账补记 0.1.121–0.1.122 与候选说明
build / build (push) Failing after 48s
为什么:每个开发版本的 SHA 与 CI 结论要能独立审计,不留在交付报告里。
|
2026-10-28 15:17:48 +08:00 |
|
姚章浩
|
2038462dbb
|
feat(library): Wiki 页面级差异与页面展示
build / build (push) Successful in 1m24s
为什么:撤销文档后 Wiki 变化此前只有"快照保存"证据;页面级差异能给出增/改/撤,
但必须写明它不等于实体、概念、边与引用的语义重算。
- overview 差异新增 wiki 字段:读两份快照的 wiki_pages 行数组比较,缺部件时 unknown。
- 发布管理"本次变更"显示 Wiki 新增/更新/撤销页数与页面级声明。
- 真实归档验证:对内 vs 对外 = 新增 31 / 撤销 1,反向镜像一致。
|
2026-10-28 15:15:33 +08:00 |
|
姚章浩
|
7b8cc0384b
|
feat(library): 生产发布授权与同步/恢复编排,worker 接线
build / build (push) Successful in 1m19s
为什么:同步入口此前只会拒绝;授权、预备份、四类写入、验证与失败恢复都没有代码。
本轮把编排与授权实现出来,真实生产执行仍按授权闸口关闭。
- internal/libraryrelease:预备份 → 数据库/资源/索引/Wiki → 验证 → 失败恢复;
授权过期/目标不符/快照不符/参数变化在动生产前拒绝;恢复失败单独上报。
- 迁移 000067 library_release_authorizations(目标+快照+参数摘要+有效期,可撤销)。
- POST/GET /api/v1/library/authorizations 与 /{id}/revoke,仅管理员签发,5–1440 分钟。
- worker library.sync 接编排:先闸口再授权,阶段落库,只有编排成功才标成功。
- 生产目标适配器未配置时显式失败(不返回零值状态),预备份存储同。
- overview 返回授权状态,页面"生产保护与恢复"显示签发人与有效期。
- 验收矩阵区分"已实现·隔离测试通过"与"真实执行未授权"。
|
2026-10-28 15:11:27 +08:00 |
|
姚章浩
|
12bb839d8a
|
docs(release): 台账补记 0.1.116–0.1.118 的 CI 结论
build / build (push) Successful in 1m15s
为什么:版本台账要能独立审计每个版本的 SHA 与 CI 结论,不能只留在交付报告里。
|
2026-10-28 14:43:22 +08:00 |
|
姚章浩
|
e313ae12f2
|
feat(library): 真实差异比对 + 孤儿作业回收 + 验收矩阵与台账
build / build (push) Successful in 1m18s
为什么:发布管理的差异一直显示"未接入",业务作业也可能因队列丢作业而永久占锁;
本轮把这两件做成真实实现,并把 30 个验收项与 CI/版本身份落成可审计文档。
- internal/librarydiff:稳定文档 ID + 排除易变列的整行摘要做增改撤销;overview 在
生产权威版本与测试封存都在时给出 computed 差异并标注两侧快照,缺一侧仍是 unknown。
- 发布管理"本次变更"列文档身份与比对版本;无差异时明确写"没有文档差异"。
- ReconcileLibraryJobs:worker 启动清理队列已无对应作业的孤儿,避免永久互斥。
- docs/library-acceptance-matrix.md 与 docs/release-ledger.md 固定证据与版本事实。
|
2026-10-28 14:39:17 +08:00 |
|
姚章浩
|
58d0483d44
|
feat(release): 按确认稿重做发布管理(两库页签 + 单作业区 + 版本抽屉)
build / build (push) Failing after 19s
- 顶部只有对内/对外两个知识库页签,切换只渲染选中库的一个作业区
- 同步前:生产当前→拟发布、新增/更新/删除与 Wiki 完整快照、准备清单、
版本与快照/启动同步、本次变更 + 生产保护与恢复、五段作业阶段
- 同步中:作业阶段/版本/已用时 + 四类数据卡 + 同步明细与异常,未接入项
只显示状态、不编百分比
- 版本与快照抽屉按 scope 列全部封存记录与分项摘要,恢复入口在真实演练前禁用
- 存储口径移到系统设置→存储管理只读区;保留/清理/自动清理标未接线
- 生产段无真实数据一律"未接入/尚无记录",启动同步禁用并说明
|
2026-10-28 13:23:55 +08:00 |
|
姚章浩
|
910c0fcd76
|
feat(library): 页面发起封存的最小权限主机侧执行边界
build / build (push) Failing after 16s
- libraryagent:0700 目录内 0600 unix socket + SO_PEERCRED 同 uid,
固定 binary/归档/日志/项目/写入者声明,请求只能选范围与作业号
- API:POST/GET /api/v1/library/captures(入队 library.capture + 读队列状态)
- worker:library.capture handler 走 socket;启动先 recover;不挂 Docker socket、
不持有来源凭据
- web:整库版本页显示真实作业状态并可发起封存(未接线/无权限给出原因)
- scripts/library-agent-install.sh:构建、安装 systemd user 服务并读回权限
|
2026-10-28 12:11:08 +08:00 |
|
姚章浩
|
c5e033dd0e
|
fix(library): 幂等重放、跨版本去重用量与契约复核
build / build (push) Failing after 15s
- 同作业号重跑读持久日志+已封存清单按首次请求重放(source_read=false,
writers_stopped=false),换范围/绑定库或清单校验失败即拒绝
- 归档用量按跨版本去重统计内容字节,清单/未引用 blob/实际分配单列,
不再用各版本 unique 之和冒充归档占用
- 冻结窗口内复核来源契约,不一致即中止;拒绝组外同镜像运行容器
- 补齐整库只读接口的 OpenAPI 契约
- 按用户确认取消 A06:文档/页面/接口不再把效果测试列为封版门槛
|
2026-10-28 12:01:09 +08:00 |
|
姚章浩
|
045fc44f0e
|
feat(library): 接通整库封存真实入口与只读版本页
build / build (push) Failing after 19s
- libraryctl:status/preflight/capture/list/verify/recover,只读来源会话、
结清检查、契约推导、维护窗口内停写者、导出十表+索引+对象+Wiki、封存候选后恢复
- libraryfreeze.ProjectController:按 Compose 项目逐服务声明固定身份,
未声明服务/容器重建即拒绝,仅 SIGTERM,恢复后必须 healthy
- httpapi:GET /api/v1/library/snapshots[/{id}] 只读列出封存产物
- web:「整库版本」页(只读、未接线显示原因、无假按钮)
- api:LIBRARY_ARCHIVE_ROOT + 归档根只读挂载
- docs/library-capture.md:运维手册与 2026-10-28 两次真实封存实测
不代表整库业务验收通过:内容/问答/性能验收、跨系统切点、Wiki 删除语义重算、
生产预备份/恢复演练/双闸/同步协调仍未完成。
|
2026-10-28 11:39:50 +08:00 |
|
姚章浩
|
864a1632e0
|
test(snapshot): 增加真实测试源只读诊断并记录孤立索引阻塞
build / build (push) Successful in 1m11s
|
2026-10-28 08:32:23 +08:00 |
|
姚章浩
|
9f990158b9
|
test(snapshot): 联合验证真实隔离存储与暂停恢复链
build / build (push) Successful in 1m8s
|
2026-10-28 08:22:21 +08:00 |
|
姚章浩
|
76f687b52d
|
feat(snapshot): 按已确认口径保留索引产物并标记验收策略
build / build (push) Successful in 1m12s
|
2026-10-28 08:01:46 +08:00 |
|
姚章浩
|
bf049cee1f
|
fix(snapshot): 暂停前后强制检查共享源全库任务
build / build (push) Successful in 1m12s
|
2026-10-28 01:05:44 +08:00 |
|
姚章浩
|
2c5ecdf0f3
|
fix(version): 补齐整库基础版本的独立快照说明
build / build (push) Successful in 1m11s
|
2026-10-28 00:34:20 +08:00 |
|
姚章浩
|
9105f8316c
|
feat(snapshot): 增加整库独立快照及测试停写恢复基础
build / build (push) Successful in 1m20s
|
2026-10-27 23:44:12 +08:00 |
|
姚章浩
|
c1d49adb62
|
docs(agents): 补三Agent交接闭环工作流(状态机、快照tag与验收模板)
build / build (push) Successful in 53s
工单 #6。三个会话(架构/开发/验收)在同一仓库串行协作时缺一份可核对的
书面契约,口头约定会漂移:状态标签命名不统一(仓里还留着 status/working)、
快照 tag 被当正式版本用、验收拿开发总结当结论。
本文件把契约写死:角色边界、main 单线串行、六个状态名与 blocked 要素、
快照 tag snapshot/vX.Y.Z 与正式版本 vX.Y.Z 分线、不可变与回退规则、
开发与验收交接模板、关单条件、安全边界。
为什么快照不能沿用 vX.Y.Z:make verify 里的 check_changelog --tags 会对每个
正式 tag 断言其提交内 CHANGELOG 顶部版本一致;在临时仓库实测正式 v0.1.1 与
v0.1.2 都判红,而 snapshot/v0.1.1 被归为非正式 tag 通过。故快照改用
snapshot 前缀,正式版本仍走单独批准与 CHANGELOG 流程。
范围:仅新增这一个文档,不改 CHANGELOG 与 CI。
验证:make verify 15 项全 success(档案 local,退出码 0)。
|
2026-10-14 17:33:22 +08:00 |
|
姚章浩
|
64b32c2da6
|
feat(settings): 数据源配置默认只列 PP 资料 + 「可加入的来源」
build / build (push) Successful in 53s
主人要求:AList 已由钉盘文件替代、钉钉知识库改为按当前账号发现 ⇒ 这两类不再出现在
数据源配置里,只保留 PP 资料与「可加入的来源」(按当前钉钉账号列出可访问的知识库与钉盘空间)。
实现(非破坏、可逆):
- 新增纯函数 splitSourceConnections(connections, showLegacy):把 alist 与 dingtalk 归为
legacy,默认只返回 PP/手工等其余来源;showLegacy=true 时原样返回(顺序不变、一条不少)。
- 「数据源配置」新增一行折叠开关「显示 AList/钉钉知识库来源(N)」:默认收起,只显示
PP 资料(+手动导入);展开后这 N 个来源照旧可改刷新周期、启停、看修订历史。
**没有删除任何来源,也没有动它们的调度与目录快照。**
- 区块文案说明登记路径:新来源只从「可加入的来源」勾选登记(钉盘文件已替代 AList)。
- 测试:splitSourceConnections 直测(默认折起 a/d、展开 a/b/c/d)+ SSR 断言默认视图只含 PP、
折叠项不在默认视图(原断言的 dingtalk 卡片标记改为折叠后的期望)。
验证:make verify 15/15;SystemSettings 用例 7/7。
|
2026-10-14 12:01:47 +08:00 |
|
姚章浩
|
0974d8dfa2
|
feat(version-history): 「版本记录」页 —— 追踪远端 main 全部提交(只读 + 管理员手动同步)
build / build (push) Successful in 57s
按已确认的契约实现(口径见 docs/VERSION_HISTORY.md):
- **版本号口径(只给有证据的)**:注释 tag + tag 指向该提交 + 该提交内 CHANGELOG 顶部三者一致 ⇒ 正式版本;
tag 之后的提交按 `<主>.<次>.<自该 tag 的提交数>` 显示开发号(与 scripts/version.py **同规则**);
证据不足 ⇒ 「历史提交 · 短SHA」+ 原因码,**不补造版本号**。完整 SHA 是唯一身份、版本号不是唯一键
(tag 之后两条并行分支各自的第 1 个提交都算 0.1.1 ⇒ 两条都保留,用短 SHA 区分)。
- **迁移 000046**:version_history_commits(提交记录,主键 repo_key+commit_sha)+ version_history_sync_runs
(同步状态)。快照 = 一次同步:抓完并与 X-Total-Count 对账通过才切换;失败不切换快照、不清空历史、
last_success_at 不动(页面显示"上次同步失败(原因)· 仍展示上次成功数据");「同步成功」≠「历史完整」。
- **只读客户端(匿名,不使用任何凭据)**:白名单 origin + 固定仓库、拒绝任意 URL 与跨主机重定向、
响应上限 5MB / 超时 15s、仅 5xx/429 退避重试(最多 3 次);逐页抓到短页为止;每次全量扫 tag
⇒ 旧提交后补的 tag 会更新既有记录(不新增第二行)。
- **接口**(三个都登记进 api/openapi.yaml):GET /api/v1/build-info(viewer)、
GET /api/v1/version-history(viewer;游标绑定快照,过期返回 409 cursor_expired;不返回伪造 total)、
POST /api/v1/version-history/sync(admin;并发同步复用同一作业,靠 IdempotencyKey)。
- **「当前运行」只认精确匹配**:产物注入的完整 SHA 命中某条记录才标该条;开发构建显式标注"开发构建";
没有可用标识 ⇒ "当前运行版本未知";**不拿最新 main / 最新 tag 顶替**,CI 成功不等于已部署。
- **前端**:一级菜单第 5 项(版本记录)+ 时间线页面(全部/正式/开发/历史四段筛选、正文展开、
加载更多、760px 单列无横向溢出、提交正文与变更记录按纯文本渲染);无打 tag / 发布 / 部署入口。
新增配置(留空即未接线,页面降级):VERSION_HISTORY_GITEA_BASE_URL / _REPO / _ALLOWED_ORIGINS /
_HTTP_TIMEOUT / _MAX_PAGES。
验证:`make verify` 15/15 success(tests-go 578 通过 / 0 失败;tests-web 209 通过 / 0 失败);
新增 Go 用例 30(版本口径与图遍历 12、客户端守卫 6、同步编排 5、接口 7);前端新增 18(组件 10 + 客户端 8);
真实仓库匿名快照拉取(`VERSION_HISTORY_LIVE_BASE_URL=… go test -run TestLiveSyncAgainstRealRepository`):
抓到 113 条与 X-Total-Count 一致、v0.1.0 是注释 tag 且目标与 `git rev-parse v0.1.0^{commit}` 一致、
开发号逐个等于 `git rev-list --count v0.1.0..<sha>`(正式 1 / 开发 22 / 历史 90)。
|
2026-10-13 19:40:19 +08:00 |
|
姚章浩
|
ad9c5d20d4
|
Merge remote-tracking branch 'origin/main'
build / build (push) Successful in 49s
|
2026-10-13 19:08:54 +08:00 |
|
姚章浩
|
3a1d32da8f
|
docs(readme): 重写平台定位与能力边界并归档原说明
build / build (push) Successful in 49s
|
2026-10-13 17:53:23 +08:00 |
|
t
|
950c1b429b
|
feat(release): 抬档门禁(破坏性 ⇒ 0.x 抬次 / ≥1.0.0 抬主)+ 1.0.0 前置(稳定契约承诺)
原来预检只"打印破坏性条数",抬哪一档靠人自觉 ⇒ 改成硬门禁:
- **抬档门禁**:破坏性条数取自**目标提交里候选版本那一段**(发版事实看提交,不看工作区)。
`0.x` 阶段有破坏性 ⇒ 必须抬**次版本**(或主版本),只抬修订 ⇒ 阻断并报出该抬到哪一档;
`≥1.0.0` 之后有破坏性 ⇒ 必须抬**主版本**,抬次/修订都阻断。
另加"候选号必须大于上一个正式版本"(版本只增不减)。
- **1.0.0 前置**:上一版本是 `0.x` 时,候选 `1.0.0` = 对外承诺契约稳定 ⇒ 必须先有写实的
《稳定契约承诺》(覆盖 接口 / 数据模型 / 配置 / CLI 输出与退出码,不留 `待填`/`TODO`/`TBD`),
**且候选发布记录里链接它**,缺任一条 ⇒ 阻断;`1.x → 2.0.0` 不重复要求。
- 预检新增"版本走向"事实行(上一版本 → 候选 / 抬哪一档 / 破坏性 N 条 ⇒ 要求哪一档 ✅⛔);
`docs/RELEASE_RUNBOOK.md` 新增"抬哪一档"对照表与《稳定契约承诺》段(故意留占位)。
验证:release_preflight --self-test 32 分支全过(含新增 9 条);反向夹具新增 §24 六条真实临时仓库用例
(0.x 只抬修订 ⇒ 阻断、0.x 抬次 ⇒ 放行、≥1.0.0 抬次 ⇒ 阻断、1.0.0 留占位 ⇒ 阻断、写实+链接 ⇒ 放行、
写实但没链接 ⇒ 仍阻断)⇒ 夹具 91/0;make verify 15/15。
于是 0.1.0 之后的第一个提交(本提交)开发号 = 0.1.1。
|
2026-10-13 17:13:44 +08:00 |
|
t
|
6de5d52363
|
feat(version): 开发号随提交自动递增 + 首个正式版本 0.1.0
build / build (push) Successful in 51s
按使用者要求定的版本规则(自动升的是**开发标识**,发布版本与 tag 仍由人批准):
- **开发号自动递增**:display_version(development) = `<正式版本的主.次>.<自 v<正式版本> 以来的提交数>`
(正式 0.1.0 之后第 1 个提交 0.1.1、第 12 个 0.1.12;恰在发布提交上 = 正式号)。
它**不写进 CHANGELOG**(发布记录只在发版时动),由 git 算出来 ⇒ 每个提交都有自己的号、数字只增。
- **浅克隆不猜号**:`--depth` 会把条数算少 ⇒ 浅仓库里拒绝算号,退回 `<版本>-dev+g<短SHA>`;
检出步骤在仓库有 tag 时 `--unshallow` 补全历史。
- 接线三处齐全:`version.py --identity` → 门禁 `-X …CommitsSinceRelease=<n>`;Makefile 的
`COMMITS_SINCE_RELEASE`;Dockerfile 同名 build-arg;Go 侧新增 `CommitsSinceRelease` 与
DisplayVersion() 新规则;契约测试**交叉核对**"注入的提交数 == git 算出的"(防注入错号)。
- **首个正式版本 0.1.0**:CHANGELOG 的 `[Unreleased]` 提成 `## [0.1.0] - 2026-10-13`;
头部补"版本怎么走"两行;RELEASE_RUNBOOK 补递增规则与"下一次发布把次版本加一"。
- 发版预检新增:打印**当前开发号**,并挡住"候选正式版本 <= 当前开发号"(会把开发号当正式号;建议次版本加一)。
验证:version.py --self-test(含 tag 后第 2 个提交 = 0.2.2、恰在 tag 上 = 0.2.0、无 tag 不猜号);
release_preflight --self-test(21 分支,含开发号两条);go test 本地三态 + 临时仓库 tag+2 提交实测
(Python 与 Go 都得出 0.2.2);反向夹具 85/0;make verify 15/15 success。
|
2026-10-13 16:45:56 +08:00 |
|
姚章浩
|
97f4b29661
|
fix(version): 就绪看目标提交的顶部版本 + 禁用自动发布路径
build / build (push) Successful in 52s
补两处残余(本轮不推、不打真实 tag、不部署;全部用临时仓库与 spy 验):
1) version_in_commit 必须比"目标提交 CHANGELOG 的**顶部**已发布版本",不是"历史里出现过":
- 新增 top_version_in_commit(),version_in_commit() 直接比它;预检输出把该提交的顶部版本打出来
(诊断可审计:例如"顶部是 `## [0.3.0]`,不是 0.2.0"),阻断信息里也带上真实顶部版本。
- 顺带兜住"最新在最上面 / 版本只增不减"的排序要求。
- 负例(自检 + 夹具各一遍):顶部 0.3.0、历史里 0.2.0 ⇒ 候选 0.2.0 拒绝;候选 0.3.0 通过。
2) 按只读约定**禁用 --execute 自动发布路径**:
- 删掉写路径(打 tag / 推 tag / 建 Release 的代码整段移除),`--execute` / `--approve-version` /
`--approve-sha` 只保留参数兼容(不报 unknown argument),传了就**明确拒绝**(rc=2)。
- 拒绝发生在收集事实之前 ⇒ **零写操作、零 API 调用**;自检用 spy 断言拒绝路径
"一个子进程都没跑、一个 API 都没发",并扫描生产路径不许出现直接执行 git 写命令的行。
- 输出里也不再推荐自动路径;RELEASE_RUNBOOK 第 4 步改为由人执行。
验证:release_preflight --self-test 绿(就绪 20 分支 + 顶部/历史两态 + --execute 拒绝零写 +
源码写路径扫描);反向夹具 84/0(含 --execute rc=2 且跑完仓里 tag 不变);make verify 15/15 success。
|
2026-10-13 15:48:50 +08:00 |
|
姚章浩
|
7a9d51cc70
|
fix(version): 正式构建核证据 + 预检分"建议/就绪" + CI 就绪按必需 context
按要求补三项(本轮不推、不打真实 tag、不部署;全部用临时仓库与假对象验):
1) 正式构建身份不能只认 --release:
- 新增 release_evidence():核①完整 40 位 SHA ②**指向该提交的注释 tag** v<版本号>
③该提交里 CHANGELOG 顶部版本一致。缺任一条 ⇒ rc=2,身份退回 development 并把
release_blocked 的原因写进 JSON(给机器读,也给人看)。
- version.py --self-test:六条负例(有版本无 tag / unknown SHA / 短 SHA / tag 指错提交 /
轻量 tag / 版本不一致)+ 证据齐正例,**tag 全部在 mktemp 临时仓库里创建**。
- Go 侧新增 TestReleaseBuildRequiresEvidence:release 构建必须 CommitSHA 完整且
v<ReleaseVersion> 是**注释 tag** 并指向该提交(独立于 Python 的二次复核)。
2) 发布预检区分"准备建议"与"发布就绪":
- 新增纯函数 readiness(facts) → (是否就绪, 阻塞项, 建议);输出分两段。
- **就绪要求候选版本已写进目标提交**(version_in_commit:查 git show <sha>:CHANGELOG.md,
工作区写了没提交不算);首发按**显式指定版本**处理,**不把"记录里有这个版本"当已发布**
(已发布的证据是 tag,不是记录条目)。
- 预检**不执行、也不在输出里推荐自动发布路径**(正式发版由人按 docs/RELEASE_RUNBOOK.md)。
3) CI 就绪判据:必需 context 集合来自 .gitea/required-contexts.txt(缺失/为空 ⇒ 没有策略 ⇒
阻断,不用观察到的状态顶替);**全部 success 才通过**,失败/缺项/pending/查询异常一律阻断。
Release 查询加 release_state():**只有 HTTP 404 才算不存在**,403/5xx/超时算查询异常 ⇒ 阻断。
验证:version.py --self-test 绿;release_preflight --self-test 绿(就绪判定 19 个分支 +
临时仓库验证 git show 语义 + 五个 HTTP 码语义);go test 三态(未注入 SKIP / 开发 PASS /
自称正式 RED);反向夹具 83/0(含临时仓库 go test 六例、预检"记录未进提交"两态);
make verify 15/15 success。
|
2026-10-13 15:26:49 +08:00 |
|
姚章浩
|
4f8ee0a8c5
|
feat(version): 变更记录改固定四类,破坏性变化带发布文档链接
按项目方给的规则重做 CHANGELOG 与检查器(本轮不推、不打 tag、不部署):
- 条目形状:四个自定义必填节(改了什么/兼容性与迁移影响/怎么验收/已知问题)
→ 固定四类 Added/Changed/Fixed/Security;分类可省略,**不许空栏目**;每个版本块
至少一个非空分类;`[Unreleased]` 段不得写日期。
- 破坏性变化:固定写在 Changed 里、以 `**破坏性**` 开头,**必须链接发布文档**;
仓内 `docs/….md` 链接**对账**(不存在 ⇒ 红)。写在别的分类里也判红。
- 结构判据补强:非法日期、重复版本、顺序必须严格递减、前导零;围栏代码块里的
`##`/`###` 不算标题;**块正文以任意二级标题为界**(「## 能力基线(未发布)」这类
不带方括号的标题原先不是边界,会把后文算成上一节的内容 ⇒ 空栏目被兜成"有内容",
夹具真的抓到了这个假绿)。
- tag 一致性:远端专属清单 `.ci-remote-tags` → `ls-remote` → 本地 refs 三级来源;
**没核对远端就不许说校验成功**(CI/预检用 `--require-remote`,拿不到清单即红),
非正式 tag(如本地 `x`)不当作发布版本、不判红,没有 tag 不判红。
- `0.1.0` 定为**未发布的能力基线**(远端无 tag、无 Release):改成不带方括号的
「## 能力基线(未发布)」,不补造 tag/发布日期/发布事实。
- 过程记录迁出:审查轮次与命令输出 → `docs/archive/CI_接入留档.md`(原文保留);
未合并事项 → `docs/BACKLOG.md`;补 `docs/RELEASE_RUNBOOK.md`(破坏性变化的链接目标,
同时修掉 CHANGELOG 里指向不存在文档的悬空引用)。
- 发版预检:无版本基线时把「首个正式版本号由人指定」列成阻塞项(不再要求先有基线才能跑);
打印破坏性变化条数;远端 tag 查不到时明说未核对并阻塞;不再硬读已删除的『已知问题』节。
- traps trap-5 口径修正:不是"不用 tag",而是"构建时不要用 git describe 取版本号"。
验证:check_changelog --self-test 全过;反仓夹具 80/0(含五条真改文件的结构负例、
六条只在临时仓库里造 tag 的场景);make verify 15/15 success。
|
2026-10-13 14:59:35 +08:00 |
|
姚章浩
|
9ad13a8c62
|
docs(agents): 留档短命试验分支的真实 CI 运行记录(run #16 失败 / #17 通过)
build / build (push) Successful in 48s
记录真实 run 链接、完整 SHA、14 项必需检查、预览 URL 与探测结果、通知入队与 ret=-2 的送达状态、run #16 暴露的 total_commits=0 缺陷,以及未验证项。分支 ci-trial-20261012 已在试验后删除,远端只剩 main。
|
2026-10-12 17:00:21 +08:00 |
|
姚章浩
|
257a8a187a
|
fix(gate): total_commits<=0 视为未声明,范围以 Git 为准(真实新分支事件形状)
build / build (push) Successful in 1m22s
真实 Runner 首跑(run #16, ci-trial-20261012)发现:新分支推送时 Gitea 给 total_commits=0、commits 列表被截断(5 条),而 Git 范围 12 条;原先'声明条数 != Git 范围就拒绝'让门禁第一次真实运行就红,且与代码质量无关。改成 Git 范围是唯一权威:total_commits>0 才交叉核对(保留'声明6/列表1/Git2 ⇒ 拒绝'的判据),<=0 或缺失视为未声明并以 Git 范围为准,同时把'负载条数不可信、列表被截断'写进来源说明。--self-test 增加该形状(15 分支);traps 22 记录教训:负例要照真实负载的形状造。
|
2026-10-12 16:55:41 +08:00 |
|
姚章浩
|
91b674f278
|
docs(agents): 清掉 traps.md 文件末尾的多余空行(git diff --check 报的最后一处)
build / build (push) Failing after 4s
|
2026-10-12 16:52:44 +08:00 |
|
姚章浩
|
d167a2b937
|
fix(ci): 第一步改最小 bootstrap(空工作区可启动),新分支范围以默认分支为基准
空工作区启动:workflow 第一步不再调用仓内脚本(此时它还不存在,实测 rc=127),改成只用 runner 环境变量的最小 bootstrap:校验协议/凭据 → git init+remote add → 取事件完整 SHA → checkout → 断言 HEAD==事件 SHA;检出后才调用 ci_checkout.sh --post-checkout 做再断言与补取(默认分支引用、事件 before)。按任意 SHA fetch 在服务端默认不可用(服务器不允许请求未公开的对象),改成取分支历史 + --deepen 再核事件 SHA。新分支范围:after --not --remotes 会把刚 fetch 的同名远端分支(=after)当排除集、排除自身得到 0 条;改为以远端默认分支为基准 refs/remotes/origin/<default>..<after>,取不到基准就明确失败。新增 scripts/ci_chain_fixture.py:本地 HTTP git 服务 + 把 workflow 的 bootstrap run 块原样抽出来在空目录执行,正/负例 12 项断言。
|
2026-10-12 16:45:10 +08:00 |
|
姚章浩
|
75a6085844
|
docs(agents): traps 14-18(假检查/预览顺序/观察到的 context/协议降级/范围退化)
|
2026-10-12 11:15:18 +08:00 |
|
姚章浩
|
96ac67e744
|
docs(agents): traps 补 5 条、CHANGELOG 记这批 CI 改动的改了什么与怎么验收
新增陷阱(只追加、不复用旧号):
trap-8 gofmt -l 列出文件时退出码仍是 0(只看退出码=假绿);
trap-9 tar -C dir . 产生 . 根成员 ⇒ 预览 404 而流水线显示成功;
trap-10 依赖清单被静默改写(-mod=mod、缺锁回落 npm install);
trap-11 汇总把"未运行/被跳过"当"通过";
trap-12 事件 SHA 与检出 SHA 不一致;
trap-13 密钥扫描规则过宽 ⇒ 永远的假红,最后被人整条注释掉。
(trap-13 来自实做:第一版规则用很宽的字符类抓口令段,把 postgres://{u.quote(...)} 这类
模板表达式和 *** 脱敏也当成密钥,四条全是假阳性。收窄口径并把这些形状钉进良性对照防回归。)
AGENTS.md 的现状表需要同步(写着"main 已启用分支保护",实测 GET /branch_protections = [])——
该文件受写入保护,本次未改,修正稿另存待批准后应用。
验证:python3 scripts/check_changelog.py 结构自检通过;make verify 全绿。
|
2026-10-12 00:11:10 +08:00 |
|
姚章浩
|
5f3a71cade
|
feat(version): 版本号唯一来源 = CHANGELOG.md,并要求写清改了什么与怎么验收
build / build (push) Successful in 26s
背景:本仓此前没有任何版本/构建元信息 —— 没有 ldflags 注入、也没有产物可读的
版本号,"线上跑的是哪个提交"答不出来;"这次改了什么、怎么验收"也没有载体。
落地:
- CHANGELOG.md:**版本号的唯一来源**(正本 §6.1:版本号只准有一处)。刻意不放
VERSION 文件、也不靠 git tag —— CI 是 `git fetch --depth 50`,取不到 tag,
`git describe` 会静默退化。每个已发布版本必须有两节:### 改了什么 与 ### 怎么验收。
- scripts/version.py:从 CHANGELOG 顶部解析版本号;解析不到即非 0 退出(构建据此失败)。
- scripts/check_changelog.py:结构自检(两节齐、带日期、版本号不重复且严格递减、
小节不为空),带 --self-test 反向自检。
- internal/version:三个构建期注入变量 + 契约测试(注入的号必须等于 CHANGELOG 顶部)。
- Makefile:build 带 -ldflags 注入;verify 增加 changelog-check 与 version-contract。
- Dockerfile:ARG VERSION/COMMIT_SHA/BUILD_TIME + ldflags(未透传时落 dev —— 故意显眼,
好过看起来正常的假版本号)。
- CI:新增「版本与变更记录契约」步,并显式断言契约测试真的 PASS(被跳过的断言等于没有断言)。
- docs/提交规范.md(ci_gate.py 的报错文案一直在指它)、docs/agents/traps.md(7 条实测陷阱)。
验证(都真跑过):
- make version → 0.1.0;make changelog-check → 合规
- make version-contract → PASS;注入 9.9.9(CHANGELOG 里没有)→ FAIL(反向自检)
- 删掉真实 CHANGELOG 的「怎么验收」小节 → 报红(对真实文件做,不只是夹具)
- go build ./... 与 go vet ./internal/version/... 通过
未做(会与在审 PR #2 冲突,待其合并后在 main 上补):
- GET /version 端点(internal/httpapi/server.go)与 cmd/api 的 -version 开关
- compose.yaml 透传 build args(当前由 compose 构建的镜像会报 dev)
⚠️ 未跑 make verify 全量(含 go test ./... 与前端),CI 是本次的测试证据。
|
2026-10-10 18:13:24 +08:00 |
|
姚章浩
|
ed60b20790
|
docs(acceptance): 补 C9 数据源配置(列出来→勾选→变成来源)实测记录
|
2026-10-10 16:47:06 +08:00 |
|
姚章浩
|
f8faed0b21
|
feat(release): 发布到生产一键完成(建批+锁定+授权合成一个动作)
用户的反馈是对的:上一轮只砍掉了"冻结/锁定"两个按钮,但一条文档从"已批准"到"发出"实际仍要
~9 次交互(找条目→勾选→填名→建批→滚到清单→找批次→授权→输语句→提交),因为"批次仪式"本身
还留在路径上。
- 新端点 POST /api/v1/release-batches/publish-now:在同一操作里先建批(SealImmediately,冻结
即锁定)再授权生产发布,返回 {batch, execution}。
- 不放松任何约束:请求门禁(403)、备份恢复验证门禁(412)、管理员身份(401)、固定确认语句(400)、
发布前快照硬门禁(409)、建批门禁(422) 全部沿用既有实现,无旁路;名称可省(服务端固定回退名,
保证重放指纹一致)。
- 界面:审核行上直接「发布到生产」(管理员 + 门禁开启时显示),工具栏支持选中多条一次发布;
复用既有确认弹窗(固定语句)。批次名不再是必经步骤。
- 实测(面板):点行级按钮 → 输 `publish-to-production` → 提交 → 批次 rb-bee80550…(sealed)
+ 执行 rx-3d831129…(completed, 项级 verified) → 页面回滚 rx-43835fac…(rolled_back, absent)。
测试:publish_now_test.go(四道关卡 + 组合调用 + 名称回退)与 reviewRelease.test.ts(请求体/回传/错误原因);
Go 26 包、前端 183 条全过。
|
2026-10-10 15:48:30 +08:00 |
|
姚章浩
|
70131c6161
|
feat(release): 批量审核 + 建批即锁定 —— 发布管理单文档交互降到 3~4 次
P0-3:
- 批量审核:新增 POST /api/v1/review-candidates/batch-decision,逐条复用单条审核的写入
路径(同一套合法性校验与"最新验收轮次"绑定),逐条回报 decided/skipped/skipped_ids;
不可审核的条目只计入 skipped,不打断整批,其他错误整批回滚(不留半成品)。
界面新增「全选可批准」「批量批准选中」「批量驳回选中」。
- 建批即锁定:建批请求加 seal 字段,服务端在创建后立即执行既有的密封(仍逐项复核门禁,
失败整批回滚),草稿态不再单独占一步;界面按钮改为「创建并锁定清单」,流程说明从 8 步改 7 步。
- 判据修正:「可批准」原先把已驳回的算进去(review_state !== 'approved'),改为只含 pending + 门禁通过。
语义边界(写进测试):批量批准按人工身份记录,人工可推翻自己先前的驳回;system:auto 发起的
批量批准对人工驳回过的那条必须跳过(Decided=0/Skipped=1)——机器永远不覆盖人工。
测试:review_batch_integration_test.go(批量决定/跳报/重复 id 拒绝/机器不覆盖人工、
建批即锁定)、review_batch_test.go(幂等键、400/409/500/501 映射、服务端盖操作人)、
reviewRelease.test.ts(批量请求体与逐条回报、建批带 seal)。前端 181 条通过。
|
2026-10-10 15:29:31 +08:00 |
|
姚章浩
|
c83a6c8086
|
docs(runbook): 发布准备改为「勾选 → 建批 → 锁定」(建批时冻结 + 对内自动批准),并补 C6 实测
|
2026-10-10 15:06:44 +08:00 |
|
姚章浩
|
a1b46d2b7c
|
feat(monitor): 需下架车道可逐条移除测试库知识 —— 补齐最后一个没有页面入口的流程
背景:来源侧被判「禁止导入」后,已建好的测试库知识不会自动消失;此前只有变更集
删除路径会入队 test.remove,页面既列不出条目也没有按钮,运维无法闭环(车道只有按
库计数)。
新增:
- GET /api/v1/test-publications?removal=required:条目级列表,判据与车道计数同源
(superseded_at IS NULL / 有 knowledge_id / completed / retrieval_state NOT IN
(disabling,disabled) / policy_state='blocked'),过滤是叠加而不是替换。
- POST /api/v1/test-publications/{id}/removal:engineer 级写路由,要求 Idempotency-Key,
按条目幂等(operator-remove:<id>);置 disabling 并交既有 test.remove 工作流去删除
远端知识并读回校验。错误映射 404/409(已移除)/409(不可移除)/501(未接线)。
- 界面:需下架车道逐条显示条目 + 「下架(从测试库移除)」,页内二次确认,成功提示,
完成后计数归零。
修掉过程中踩到的两个真问题:
1. 二次确认的确认态原先经容器 props 传给视图,一次容器改动把三个 props 丢了 ——
视图永远渲染原按钮、确认步骤静默消失,而所有静态单元测试仍然通过。改为把确认态
放在视图内部;并把「取消」放在原按钮位置(真实指针连点两下只会落到取消)。
2. jobs 上有部分唯一索引 UNIQUE (business_change_set_id, business_version_id,
business_target_kb_id, business_action) WHERE business_change_set_id IS NOT NULL。
本路径给这三列写空串(非 NULL),('','','','remove') 对所有条目是同一个键 ——
第一条之后每次 INSERT 都撞唯一索引、被 ON CONFLICT DO NOTHING 静默吞掉,留下
「状态已 disabling、没有任务」的永久卡死条目,而车道恰好隐藏 disabling,运维也
看不到。改为写 NULL(语义:无变更集身份)+ 冲突目标收敛到 idempotency_key +
校验 RowsAffected()(0 行回查既有任务;查不到就报错,不提交无任务的 disabling)。
卡死状态在重试时可自愈。
测试:internal/platform/postgres/test_publication_removal_integration_test.go(两条发布
各自入队、business_* 为 NULL、卡死自愈;把修复退回旧写法该测试即 FAIL,已实测)、
internal/httpapi/test_publication_removal_test.go(权限/幂等键/错误映射/未接线 501/列表
过滤)、前端 testPublications.test.ts + WeKnoraMonitor.test.tsx。
验收(纯界面,两条都走完):解析监控 → 需下架(2)→ 逐条「下架」+ 二次确认 →
retrieval_state=disabled(PDF 03:57:03Z、md 04:08:55Z),jobs completed(attempt 2,
首次 test_remove_pending=远端仍在处理,重试通过;工作流以 GetKnowledge 读回 404 判
成功)→ 车道需下架(0)。核验「确认前不执行」:首次点击后仍 unpublished、移除任务数仍 1。
|
2026-10-10 12:10:46 +08:00 |
|
姚章浩
|
e9a643cc33
|
fix(release): 禁止导入未被算进期望策略 —— 生产知识下不了架(计划与建批两处同源缺陷)
界面验收实测(2026-10-10):把已发布到生产的 PDF 改为「禁止导入」后,发布通道既给不出
delete、也建不了 delete 批次。
根因:禁止导入只写 source_items.policy_state='blocked',而"期望策略"的解析只看
source_item_scope_overrides / directory_scope_rules / source_items.visibility——
两处实现都不看 policy_state:
1) release_plan.go 的 source_truth:被禁止且生产侧存在的条目被算成 unchanged/present、
can_release=false → 永远不会出现 delete 动作;
2) release_batches.go 的 releaseDeleteReadyCTEs.source_truth:同样口径 → 计划即使给了
delete,创建封批仍被拒 422(实测原文「创建封批失败(HTTP 422)」)。
修复:两处都把 policy_state='blocked' 算进期望策略(各一行,注释写明成因)。
新增集成测试 release_plan_policy_state_integration_test.go:用 policy_state(真实路由的写法)
造"生产存在 + 已禁止"的条目,断言①计划给出 action=delete/can_release、②delete 批次可创建;
分别回退任一处修复,该测试即 FAIL(已实测两种回退都 FAIL)。
实测闭环:重新发布使生产存在(enable_status=enabled)→ 禁止导入 → 计划 delete(present/
can_release=true)→ v8 delete_count=1 → 批次 rb-8c1ad1c9…(sealed, action=delete) → 留档
20261010T033100Z + 门禁 PASS → 执行 rx-6c19232a… completed(项级 verified/delete、
production_revision=absent)→ 目标库该行 enable_status=disabled(行保留、检索停用、可恢复)。
附带:从未导入却被标为禁止的 82 条"等待测试"噪音不再占发布计划(195 → 113 项)。
证据与说明补进 docs/USER_FLOWS_ACCEPTANCE.md(C2b + F.3h)。
|
2026-10-10 11:36:08 +08:00 |
|
姚章浩
|
fa244c447c
|
fix(deploy): 重建 api 会静默关掉生产门禁 —— 加前置保护 + 门禁状态回显
界面验收第三遍(PDF)踩到:授权发布被回绝 "production release requests are disabled"。
根因:scripts/deploy-api-web.sh 的 COMPOSE_FILES 默认只叠 compose.yaml,重建 api 时没叠
compose.release-gates.yaml → PRODUCTION_RELEASE_REQUESTS_ENABLED / PRODUCTION_BACKUP_RESTORE_VERIFIED
变 false,生产授权接口被静默关闭(页面只在点击那一刻提示一句,极易误判成功能坏了)。
- 前置保护:正在运行的 api 已开闸、而本次 COMPOSE_FILES 不含门禁文件时直接拒绝
(REFUSED_WOULD_CLOSE_PRODUCTION_GATES,并打印保留门禁的正确命令;确要关闸用 ALLOW_GATE_OFF=1)
- 结尾新增 === 7b 打印重建后的两道门禁状态,避免"以为开着"
- 已用同一段判定逻辑覆盖三种情形(已开闸+不叠门禁→拒绝 / 已开闸+叠门禁→放行 / 显式 ALLOW_GATE_OFF→放行)
验收第三遍同时确认:PDF→MinerU 解析链路是通的(入库 completed、验收"内容处理:通过"),
发布首轮 completed/verified(in_scope=8 foreign=8 降级保留正常),回滚 rolled_back、
目标库 enable_status=disabled。证据补进 docs/USER_FLOWS_ACCEPTANCE.md。
|
2026-10-10 11:10:51 +08:00 |
|
姚章浩
|
d0a45d563f
|
fix(monitor): 需下架车道恒为 0(判据用了没人写的状态)+ 隔离会改线上设置的集成测试
界面验收第三遍(禁止导入 → 需下架)暴露两处真问题:
1) 需下架车道死掉:判据 `retrieval_state='enabled'`,而 retrieval_state 在这套状态机里
描述「是否发布到生产」(unpublished/disabling/disabled/failed),全仓没有任何代码写过
'enabled',线上 5/5 发布单元都是 unpublished → 车道恒 0,界面「仍在知识库里的文件会
出现在这里」的承诺不成立。改为与设计注释一致的口径:仍在测试库存活(completed + 有
knowledge_id + 未 disabling/disabled)+ 来源项 policy_state='blocked'。
线上对照:旧判据 0 → 新判据 1,命中被禁止导入的 DH-AG95夹爪适配-指令协议.md;
修后页面显示「需下架(1)· 对内知识库 · 1 份仍在检索中」。新增集成测试覆盖
存活/未禁止/移除中/已移除/未上传五种情形(真实 Postgres + 独立 schema)。
2) 集成测试改到线上设置(直接踩到并已恢复):ui_settings_integration_test.go 只判断
TEST_DATABASE_URL 是否存在、无 schema 隔离,而它「创建候选并激活」——跑在共享库上会把
真实 active 设置挤成 retired。已先备份(backups/ui-settings/…pre-restore.jsonl),再用
单事务(先 retire 再 activate,uq_ui_setting_active 只允许一条 active)恢复
uis-d40ea1fc…(15/30/1800/7200 + https://weknora-test.dobot.cn/),并复核线上值。
根因修复:给该用例加 per-test schema 隔离,复跑后线上设置不再被改动。
同时把两处与事实不符的文案改实话(WeKnoraMonitor.tsx 需下架说明、SourceCatalogBrowser.tsx
禁止导入说明):移除走 test.remove 工作流(删除测试库知识条目,可再入库),入口当前由
变更集删除路径触发,页面尚无独立按钮——条目级列表与下架按钮列为待排期。
|
2026-10-10 10:55:03 +08:00 |
|
姚章浩
|
6a8db9ca98
|
docs(acceptance): 补第二遍界面验收(.md / drive 直下路由)
- A1:第二遍取件(DH-AG95夹爪适配-指令协议.md,3513 B)与内容级 sha256 去重的核对方法
(content_objects 命中已有行时只更新 updated_at,不更新 created_at;必须走
source_item_versions.content_object_id 关联,不要按 created_at 过滤)
- B1:tp-466164a074cb22efb → completed(polls=8,测试库 0c84a098…)
- C1:v4 rcs-2b22276e…(新增3/阻断193)+ 批次 rb-f1819fb0…(sealed、1 项)→ 再证「批准后才生成」顺序规则
- C2:留档 20261010T023538Z-0b217e8a + guardcheck PASS + 执行 rx-bc714172… 首轮 completed/verified
- C3:回滚 rolled_back + 独立核对目标库 enable_status=disabled(行不删)
- F:新增待办 3e——发布结果页不自动刷新(worker 已完成仍显示待执行,需手动刷新)
|
2026-10-10 10:41:49 +08:00 |
|
姚章浩
|
134da985fa
|
docs(acceptance): 补 2026-10-10 界面端到端验收结果(含三处修复与顺序约束)
- A1:记录白名单环境漏传 dws 变量这一缺陷与修复后的真实产物证据(d29e04e)
- A3/C1:写明生成即固化的顺序约束——处理完成 → 批准 → 生成新版本 → 确认冻结(冻结不重算)
- B1/C1/C2/C3/C4:补本期实测(tp-c3412382… / rb-d6eb1c91… / rx-63b81560… / rx-71d13453…)
- C2:记录首个真实跨环境 wiki 发布与「写入保留外来源页 vs 校验要求集合相等」的口径冲突(eabe55b)
- F:wiki 跨环境发布不再列为未跑;新增健康探测误报、测试端 404、snapshot_verification_id 空 三项待办
|
2026-10-10 10:23:51 +08:00 |
|
姚章浩
|
a1d04f07ec
|
docs(runbook): 现行用户操作流程(含本期新增/变化速查)
按实际干活顺序:开工自检(含 dws 凭据续期)→ 取件 → 标注 → 发布准备 → 待入库处理 →
发布前留档 → 授权发布 → 回滚/重排 → 系统设置维护项 → 备份恢复运维 → 按事故恢复。
末节给出 7 条与旧流程的差异对照。
|
2026-10-09 14:44:45 +08:00 |
|
姚章浩
|
32b480ce85
|
docs(acceptance): A1 补钉钉取件走 dws 的实现与复核结论
- 记录开关/路由/平台侧判定保留、凭据共享与续期 runbook 依赖
- 本人复核:worker 内 dws v1.0.63 接线、鉴权(须 HOME=DWS_HOME,否则误报未登录)、
真实调用 ok、回归测试 18 项 + 19 断言、CI #6/#7/#8 全 success
|
2026-10-09 14:41:55 +08:00 |
|