From 80a8b7a3553a9eaaaba60c379aa943203b28cf47 Mon Sep 17 00:00:00 2001 From: whitelonng Date: Thu, 23 Jul 2026 03:30:13 +0800 Subject: [PATCH] fix: prepare 0.4.2 release --- README.en.md | 27 ++- README.md | 19 +- docs/12-lifecycle.md | 6 +- docs/architecture.md | 7 + docs/engineering.md | 9 +- docs/planning-governance-evolution.md | 99 ++++++--- docs/release-acceptance.md | 49 +++-- docs/workflows.md | 6 + package-lock.json | 218 +++++++++---------- package.json | 5 +- scripts/release-check.mjs | 8 +- src/installers/adapter-upgrade.ts | 21 ++ src/installers/v3-adapter.ts | 2 +- src/team/git-ref-coordination.ts | 25 ++- tests/adapter-upgrade-contracts.test.ts | 17 ++ tests/git-ref-coordination-contracts.test.ts | 20 ++ tests/git-ref-cross-clone-e2e.test.ts | 118 ++++++++++ tests/release-check-contracts.test.ts | 4 + tests/v3-adapter-contracts.test.ts | 3 + website/docs.html | 2 +- website/docs.zh-CN.html | 2 +- website/index.html | 2 +- website/index.zh-CN.html | 2 +- 23 files changed, 474 insertions(+), 197 deletions(-) diff --git a/README.en.md b/README.en.md index 5c2f182..a03de3c 100644 --- a/README.en.md +++ b/README.en.md @@ -17,7 +17,7 @@

License: AGPL-3.0 npm version - Status: mancode Continuity v0.4.1 + Status: mancode Continuity v0.4.2 Platforms: Claude Code, Cursor, Codex in ChatGPT desktop and CLI, GitHub Copilot, ZCode

@@ -137,6 +137,13 @@ the code baseline, then run `MANCODE_GIT_REF_DEFERRED_SYNC_REQUIRED`; cross-clone synchronization is complete only after the push returns a receipt. +Atomic git-ref mutations that explicitly require `--sync`, such as +`workflow update`, complete the remote CAS before materializing the local +projection. If a resumable `in_progress` or `blocked` task leaves tracked +`.mancode/shared` changes, commit that projection and run the same +`team sync push` with the unchanged task revision to rebind the remote code +head. Another clone must not resume until this push returns a receipt. + For a new project, start with one platform you actually use: ```bash @@ -374,7 +381,7 @@ it should behave, and why previous decisions were made. ## Installation -**Status**: mancode Continuity v0.4.1. Claude Code, Cursor, Codex in the ChatGPT +**Status**: mancode Continuity v0.4.2. Claude Code, Cursor, Codex in the ChatGPT desktop app and CLI, GitHub Copilot, and ZCode adapters are included. Requires Node.js 20 or newer. macOS, Linux, Windows CMD, PowerShell, and Git Bash @@ -481,7 +488,7 @@ mancode version Simplified output: ```text -mancode v0.4.1 +mancode v0.4.2 Project: my-app Runtime: ready @@ -628,14 +635,16 @@ mancode/ - Complete real-host session acceptance for Claude Code, Codex, Cursor, GitHub Copilot, and ZCode on one release candidate; verified host sessions and isolated explicit sessions are both valid evidence paths. -- Run `npm run release:check -- --candidate ` for the clean - checkout, automated two-clone/legacy checks, tarball SHA-256, and install - smoke; complete cross-host recovery separately. +- Merge the final candidate into `main`, then run + `npm run release:check -- --candidate ` from that same + `origin/main` commit for the clean checkout, automated two-clone/legacy + checks, tarball SHA-256, and install smoke; complete cross-host recovery + separately. - Confirm ZCode project-skill discovery and workspace-command paths; keep the adapter provisional until then. - Evaluate Windsurf, Cline, and Roo Code adapters based on real demand. -See [0.4.1 Continuity Release Acceptance](./docs/release-acceptance.md) for the complete gate. +See [0.4.2 Continuity Release Acceptance](./docs/release-acceptance.md) for the complete gate. ## Troubleshooting @@ -660,7 +669,9 @@ hook architecture still uses `mancode init --legacy --force`. This means the platform's target files are missing or their digest is stale. Preview `mancode adapter upgrade --platform --dry-run`, inspect the staged result, then run it with the returned `--operation-id`, an active session, -and `--confirm`. For managed-block +and `--confirm`. A successful confirmation removes that operation's staging +preview so internal temporary files cannot make a later Git sync report a dirty +worktree. For managed-block platforms (Codex, ZCode, Copilot), the managed block in `AGENTS.md` or `.github/copilot-instructions.md` may have been manually edited or deleted. diff --git a/README.md b/README.md index 4b86d84..c24b621 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@

许可证:AGPL-3.0 npm 版本 - 状态:mancode Continuity v0.4.1 + 状态:mancode Continuity v0.4.2 平台:Claude Code、Cursor、ChatGPT 桌面端 Codex、Codex CLI、GitHub Copilot、ZCode

@@ -116,6 +116,12 @@ git-ref 下的 workflow create、requirements、plan、review 和 verification `--sync` 会返回 `MANCODE_GIT_REF_DEFERRED_SYNC_REQUIRED`;只有拿到 push receipt 才表示跨 clone 同步完成。 +`workflow update` 等明确要求 `--sync` 的原子 git-ref mutation 会先完成远端 CAS, +再 materialize 本地投影。如果仍需 resume 的 `in_progress` 或 `blocked` 任务因此产生 +tracked `.mancode/shared` 变更,应先提交这些投影,再用不变的 task revision 执行同一条 +`team sync push`,把远端 code head 重绑到新提交;另一个 clone 只能在这次 push 返回 +receipt 后 resume。 + 在全新项目中,从一个实际使用的平台开始: ```bash @@ -329,7 +335,7 @@ src/components/ ## 安装 -**状态**:mancode Continuity v0.4.1。Claude Code、Cursor、ChatGPT 桌面端中的 +**状态**:mancode Continuity v0.4.2。Claude Code、Cursor、ChatGPT 桌面端中的 Codex、Codex CLI、GitHub Copilot 和 ZCode adapter 均已接入。 需要 Node.js 20 或更高版本。原生支持 macOS、Linux、Windows CMD、 @@ -434,7 +440,7 @@ mancode version 以下是简化输出示例: ```text -mancode v0.4.1 +mancode v0.4.2 Project: my-app Runtime: ready @@ -570,11 +576,11 @@ mancode/ ## 仍在推进 - 在同一发布候选上完成 Claude Code、Codex、Cursor、GitHub Copilot 和 ZCode 的真实宿主 session 验收;宿主自动 session 和显式双 session 都是合法证据路径。 -- 使用 `npm run release:check -- --candidate <完整提交 SHA>` 完成干净 checkout、自动双 clone/legacy、tarball SHA-256 和安装 smoke;另完成跨真实宿主恢复。 +- 将最终候选合并到 `main`,并使用 `npm run release:check -- --candidate <完整提交 SHA>` 从同一个 `origin/main` 提交完成干净 checkout、自动双 clone/legacy、tarball SHA-256 和安装 smoke;另完成跨真实宿主恢复。 - 确认 ZCode 项目级 skill 发现和 workspace command 路径;完成前继续标记为 provisional。 - 根据真实需求评估 Windsurf、Cline 和 Roo Code adapter。 -完整发布条件见 [0.4.1 Continuity 发布验收](./docs/release-acceptance.md)。 +完整发布条件见 [0.4.2 Continuity 发布验收](./docs/release-acceptance.md)。 ## 故障排查 @@ -596,7 +602,8 @@ mancode/ 该平台的目标文件缺失或 digest 不匹配。先运行 `mancode adapter upgrade --platform --dry-run`,确认 staging 结果后再用 -该预览返回的 `--operation-id` 和 active session 执行 `--confirm`。 +该预览返回的 `--operation-id` 和 active session 执行 `--confirm`。确认成功后会删除 +该 operation 的 staging 预览,避免内部临时文件让后续 Git 同步误判工作区不干净。 对于 Codex、ZCode 和 Copilot,`AGENTS.md` 或 `.github/copilot-instructions.md` 中的受控区可能被手动编辑或删除了。 diff --git a/docs/12-lifecycle.md b/docs/12-lifecycle.md index 0f3f5c1..bfc1b26 100644 --- a/docs/12-lifecycle.md +++ b/docs/12-lifecycle.md @@ -56,6 +56,10 @@ session 是本地便利状态。关闭一个 session 不会关闭任务,也不 `context session spike` 记录真实宿主的窗口隔离、子命令传播、子 agent 继承和 hook approval,但不保存原始宿主 session key 或显式 session ID。证据模式为 `host` 或 `explicit`:前者通过后可授权受信宿主身份,后者只证明两个已存在、active、client 匹配的显式 session 隔离,不改变运行时的 `explicit_required` 策略。内部 `context beta` 接受与平台能力匹配的任一路径,并要求所有证据绑定同一个 immutable release candidate。 -`npm run release:check -- --candidate <完整提交 SHA>` 从 `origin/develop` 创建干净 checkout,运行完整自动化、真实双 clone/legacy fixture、audit、pack 与 tarball 安装 smoke,并把报告和候选 tarball 保存在 `.mancode/local/release-evidence/`。该命令不会执行 `npm publish` 或修改 dist-tag。 +`npm run release:check -- --candidate <完整提交 SHA>` 从最终 `origin/main` 候选创建干净 +checkout,运行完整自动化、真实双 clone/legacy fixture、audit、pack 与 tarball 安装 +smoke,并把报告和候选 tarball 保存在 `.mancode/local/release-evidence/`。候选必须同时 +等于本地 HEAD 和 `origin/main`,检查期间 main 不得变化。该命令不会执行 `npm publish` +或修改 dist-tag。 尚未完成的验收见 [release-acceptance.md](./release-acceptance.md)。 diff --git a/docs/architecture.md b/docs/architecture.md index d164856..9f68db1 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -77,4 +77,11 @@ mancode team sync push shared: --expected-task-revision N --session `team sync push`。直接传入 `--sync` 会稳定返回 `MANCODE_GIT_REF_DEFERRED_SYNC_REQUIRED`,防止未发布的本地成功被误报为跨 clone 成功。 +明确要求 `--sync` 的原子 git-ref mutation 会在一次 CAS 中更新远端 bundle/fence,随后 +materialize 本地投影。若仍可 resume 的 `in_progress` 或 `blocked` 任务留下 tracked +`.mancode/shared` 变更,owner 提交该投影后必须用不变的 task revision 再执行 +`team sync push`。这个受限的 same-revision 操作只能把 code head 快进重绑到新提交; +task revision、aggregate digest、owner 和 ownership epoch 都不得变化。另一 clone 应在 +该 receipt 到达后同步 Git、pull transport 并 resume。 + 远端不会自动同步业务代码。bundle、ownership fence 和 remote revision 只协调 mancode 权威;调用者仍需自行同步 Git 分支。 diff --git a/docs/engineering.md b/docs/engineering.md index e3d6cbd..54219e7 100644 --- a/docs/engineering.md +++ b/docs/engineering.md @@ -36,7 +36,14 @@ npm run build npm run test:dist ``` -发布候选先运行 `npm run prepublishOnly`。提交并推送最终 `develop` 后,运行 `npm run release:check -- --candidate <完整提交 SHA>`,由远端候选的干净 checkout 重跑完整门禁、跨 clone、legacy、audit、pack 和 tarball 安装 smoke,并生成本地 SHA-256 证据。涉及 Windows 原子文件行为时追加 `npm run test:windows-smoke`;涉及网站时运行对应网站测试和浏览器检查。 +发布候选先运行 `npm run prepublishOnly`。开发集成通过后把最终变更合并并推送到 +`main`,等待该 main 提交的 Quality/Windows checks 成功,再运行 +`npm run release:check -- --candidate <完整提交 SHA>`。脚本必须从同一个 +`origin/main` 提交创建干净 checkout,重跑完整门禁、跨 clone、legacy、audit、pack +和 tarball 安装 smoke,并生成本地 SHA-256 证据。涉及 Windows 原子文件行为时追加 +`npm run test:windows-smoke`;涉及网站时运行对应网站测试和浏览器检查。只有所有真实 +宿主与 Beta 证据也绑定该 main SHA 后才允许发布;npm `gitHead`、tag 和 GitHub Release +必须继续指向同一个提交。 不要把历史测试数量写入长期文档。报告当前命令、退出码和失败原因即可。 diff --git a/docs/planning-governance-evolution.md b/docs/planning-governance-evolution.md index 0eced37..259b94d 100644 --- a/docs/planning-governance-evolution.md +++ b/docs/planning-governance-evolution.md @@ -1,6 +1,9 @@ # 规划治理演进与安全发布契约 -本文是 mancode 0.4.0 的规划治理实施与发布契约。它描述目标行为、兼容边界、验证证据和停止条件。`4dc2e7e` 是当前已验证的开发集成候选;后续契约修复必须进入新的唯一候选。在最终发布门禁和 npm 发布完成前,本文的“已完成”只表示代码与自动化验证完成,不表示已经发布。 +本文记录 mancode 0.4.0 的规划治理实施基线,以及 0.4.1 发布后发现的契约偏差和 +0.4.2 修正。第 4–13 节保留 0.4.0 的能力设计与不变量;“当前状态”和第 14 节使用 +0.4.2 的现行发布契约。历史候选与勾选项只能说明当时的开发证据,不能替代最终 +`origin/main` 候选的发布验收。 ## 1. 决策摘要 @@ -8,20 +11,22 @@ | --- | --- | --- | --- | | 0.4.0 | additive advisory、adapter digest/upgrade、policy parser/capability gate、显式 project upgrade、已升级项目的 Policy 2 默认值,以及 local transport 的原子 `reframe` | 不强制 `solo -> /man`;不批量重写旧 workflow;不把项目升级伪装成普通 `refresh`;不自动降级 policy;git-ref transport 不执行 reframe | A–F 工作包、完整测试、真实宿主验收和 npm 发布前检查全部通过;只有完成 project upgrade 的项目启用 Policy 2 | -这是唯一对外版本。工作包可以分 PR、独立合并和独立评审,但不产生中间发布。任何能力都必须一起通过 0.4.0 release gate;在此之前不得通过 feature flag、环境变量、手工 metadata 或 npm 预发布提前启用。 +这是 0.4.0 原计划的单版本决定。0.4.1 已作为发布修复存在,0.4.2 继续修复 +git-ref code-head rebind 和发布候选身份;补丁版本不得降低原 release gate,也不能用 +历史版本的证据替代新候选。 -### 当前状态(2026-07-22) +### 当前状态(2026-07-23) | 类别 | 状态 | 证据 | | --- | --- | --- | -| A–F 实现工作包 | 工作树生产加固完成 | Policy 2、adapter recovery、reframe、旧 CLI 黑盒、decision-readiness、requirements draft 和 Continuity 命名已经完成;本轮继续修正平台发布证据与最终 release-check | -| 本地发布前检查 | 新候选待重跑 | 最终候选必须通过 `npm run prepublishOnly`,并由 `npm run release:check -- --candidate ` 从远端干净 checkout 重跑跨 clone、legacy、audit、pack 和 tarball 安装 smoke | -| GitHub Quality gate | 历史候选通过 | `2c9d697` 的 [Quality gate run 29930349142](https://github.com/whitelonng/mancode/actions/runs/29930349142) 成功;本轮形成新候选后必须重跑 | -| GitHub Windows gate | 历史候选通过 | `2c9d697` 的 [Windows gate run 29930353690](https://github.com/whitelonng/mancode/actions/runs/29930353690) 在 CMD、PowerShell、Git Bash 全部成功;本轮形成新候选后必须重跑 | -| `develop` 远程一致性 | 新候选待形成 | `2c9d697` 当前与 `origin/develop` 对齐;本轮工作树形成新候选后需重新推送和对齐,`main` 不得修改 | -| Claude Code 条件式澄清实测 | 工作树通过 | Claude Code 2.1.142 使用本地 0.4.0 tarball:清晰请求直接执行,需求不清晰时提问等待,明确但与证据冲突的请求被拦截;真实测试同时发现并修复了隐藏 bootstrap skill 未稳定加载的问题,最终改为 `CLAUDE.md` 受控区,候选形成后仍需重跑 | -| 最终发布验收 | 未完成 | 五平台真实宿主与跨宿主恢复、自动 release-check、最终 Beta gate 和候选 tarball 验收仍待完成 | -| npm 发布 | 未执行 | 在上项全部完成前保持禁止 | +| A–F 实现工作包 | 已随 0.4.0 发布 | Policy 2、adapter recovery、local reframe、旧 CLI 拒绝与 decision-readiness 基线保留;补丁版本不改这些语义 | +| 0.4.1 hotfix | 已发布但证据未闭合 | npm `gitHead` 为 main 合并提交 `8cc8b24`,而旧 release-check 只接受 `origin/develop` 的 `aaa8d6c`;仓库内没有绑定已发布提交的完整 release-check/Beta 证据 | +| git-ref publication | 0.4.2 修正中 | 0.4.1 已为 create/requirements/plan/review/verification增加 deferred boundary;真实双 clone 又发现原子 mutation 投影提交后无法为 blocked task 重绑 code head,0.4.2 增加受限 same-revision fast-forward rebind | +| adapter upgrade staging | 0.4.2 已修正 | 真实 tarball 测试发现确认成功后残留 `.mancode/staging/adapters/upgrade/` 会让 git-ref clean-worktree gate 拒绝同步;确认成功现在只清理该 operation 的预览目录,并由 contract 验证 live target 已发布且预览已删除 | +| 依赖审计 | 工作树通过 | [GHSA-g7r4-m6w7-qqqr](https://github.com/advisories/GHSA-g7r4-m6w7-qqqr) 覆盖 esbuild `0.27.3–0.28.0` 的 Windows dev-server 低危问题;tsup 尚不接受 0.28.1,因此 0.4.2 暂时精确约束到未受影响且兼容的 0.27.2,保持 `npm audit` 零漏洞门禁 | +| GitHub 自动门禁 | 0.4.1 历史候选通过 | `8cc8b24` 的 [Quality gate run 29943330958](https://github.com/whitelonng/mancode/actions/runs/29943330958) 和 [Windows gate run 29943330982](https://github.com/whitelonng/mancode/actions/runs/29943330982) 成功;0.4.2 最终 main 候选必须重新执行 | +| 最终发布身份 | 已重新定稿 | `develop` 只作集成;最终候选必须是 `origin/main` 的单个提交,release-check、CI、真实宿主、Beta、npm `gitHead`、tag 和 GitHub Release 全部绑定该 SHA | +| 0.4.2 发布验收 | 未完成 | 最终 main 合并提交、五平台真实宿主、跨宿主恢复、release-check、Beta gate、npm/tag/Release 仍待完成 | ## 2. 目标、不变量与非目标 @@ -206,7 +211,7 @@ mancode adapter status --json 1. 先读取 project manifest、实际 adapter inventory、profile 和当前 writer capability;stale、路径冲突、未完成 operation 或版本门禁失败时只报告,不写文件。 2. 在 staging 目录渲染所有目标,展示变更 target、digest 和托管区域差异;用户确认后才进入 journal。 3. 在 adapter locks 下按目标写入,使用 before/target digest recovery action;中断后由 `operation repair` 继续或在无业务写的前提下 abort。 -4. 写完重新读取并验证每个 target;仅在 renderer version 变化时更新 manifest 的 adapter version/inventory,不写 content digest。任何一个 target 失败都不能报告整体成功。 +4. 写完重新读取并验证每个 target;仅在 renderer version 变化时更新 manifest 的 adapter version/inventory,不写 content digest。任何一个 target 失败都不能报告整体成功;成功后只删除该 operation 的 staging 预览,不能让已消费的临时文件污染后续 Git clean-worktree gate。 5. 不修改 task、requirements、plan、policy 或 step;adapter 升级与 workflow 语义升级是两个 operation。 `refresh-project` 可以发现并报告 stale,但不能悄悄完成 adapter upgrade。`install --force` 是否复用底层 writer 由实现决定,但必须保留一个语义明确、可审计的显式 upgrade 入口。 @@ -318,10 +323,27 @@ mancode project upgrade --policy 2 --operation-id --session - | 0.4.x + 已升级项目 | 读写且保留 provenance | 读写,要求 digest/capability | 写 2 | 目标 Policy 2 路径 | | 0.3.x + V2 已升级项目 | 不允许写入 | 不允许读取后执行 | 不允许创建 | 0.3.18 在 manifest parser 边界拒绝;能解析 V2 的旧 reader/writer 返回 version-too-old failure | | 任意 CLI + stale adapter | 读诊断 | 拒绝 mutation | 拒绝创建 | 先执行显式 adapter upgrade | -| 任意 CLI + git-ref transport | 正常既有 transport contract | Policy 2 仍可按 transport contract 运行 | 不能 reframe | `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` | +| 任意 CLI + git-ref transport | 使用下述显式 publication contract | Policy 2 按相同 publication contract 运行 | 不能 reframe | `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` | “读”不等于“执行”:旧 CLI 只能在 V1/Policy 1 的兼容范围内展示安全诊断;遇到 V2 manifest 必须先由 manifest parser 或 reader gate 阻断,不能生成执行指令或写入任何 authority。 +### 8.1 0.4.2 补充:git-ref publication 与 code-head 矩阵 + +0.4.0 将非 reframe 的 git-ref 行为概括为“正常既有 transport contract”,粒度不足。 +从 0.4.2 起,所有公开 writer 必须落入以下明确边界之一: + +| mutation 类别 | 本地/远端顺序 | Git 提交后的动作 | 跨 clone 完成条件 | +| --- | --- | --- | --- | +| create、requirements、plan、review、verification | 不带 `--sync` 写本地 shared authority | 提交匹配的 `.mancode/shared` 与代码,再执行 `team sync push` | push 返回 receipt,另一 clone 同步 Git 后 pull/resume | +| 明确要求 `--sync` 的原子 lifecycle/scope mutation | 单次远端 CAS 成功后 materialize 本地投影 | 若仍可 resume 的 in-progress/blocked task 的 tracked 投影被提交,用不变 revision 再执行 `team sync push` | same-revision、same-aggregate、owner-only、fast-forward rebind 返回 receipt | +| claim、handoff 等远端协调 mutation | 只走各自显式 CAS/repair contract | 不允许用普通 Git 提交伪造 ownership 或 receipt | 远端 receipt 与本地 recovery/materialization 都完成 | +| reframe | git-ref 下拒绝 | 无 | `MANCODE_REFRAME_GIT_REF_UNSUPPORTED` | + +`.mancode/shared` 是可提交的共享 authority 表示,git-ref bundle/fence 是跨 clone 协调 +authority;二者必须通过 task revision、aggregate digest 和 codeRef 唯一绑定。任何 writer +若不能说明本地文件、remote CAS、Git commit、code-head rebind 和 session projection 的 +先后关系,必须触发第 12 节的重新对齐条件,不能继续沿用“既有 contract”作为证明。 + ## 9. 验证矩阵 ### 9.1 单元和 contract @@ -342,7 +364,7 @@ mancode project upgrade --policy 2 --operation-id --session - - 五个平台生成、status、stale 编辑、dry-run、确认升级、升级后重新读取。 - adapter upgrade 在每个 target 写入前、写入后和中断点恢复;共享 `AGENTS` target 不能被两个平台重复覆盖。 - local transport 下的 Policy 2 create/plan/review/verification 与旧 workflow 并存。 -- 两个 clone 的 git-ref 兼容门、旧 writer 拒绝、receipt recovery;所有 git-ref reframe 请求必须确认硬拒绝。 +- 两个 clone 的 git-ref 兼容门、旧 writer 拒绝、receipt recovery,以及 deferred publish 和原子 mutation 后“提交 tracked 投影 → same-revision code-head rebind → 第二 clone pull/resume”的完整链路;所有 git-ref reframe 请求必须确认硬拒绝。 - active child、open handoff、active solo assignment 的并发 race:先取得锁的一方决定,另一方得到 expected-revision 或明确 reframe error。 ### 9.3 真实宿主和跨平台 @@ -366,7 +388,8 @@ mancode project upgrade --policy 2 --operation-id --session - ### 10.2 0.4.0 gate -当前 gate 结果如下。`[x]` 仅表示实现和自动化证据完成;真实宿主或发布验收未完成时,仍不得发布 npm。 +以下保留 0.4.0 发布前记录。`[x]` 仅表示当时的实现和自动化证据;它不是 +0.4.2 的发布状态,也不能证明后来发布的 npm 提交已经通过相同 gate。 - [x] 模板和文档 contract 通过;advisory 不直接执行 schema migration、policy 写入或自动 step 变更。 - [x] 旧 layout-version-3 fixture、legacy fixture、已有 adapter 和历史 workflow 通过原有测试。 @@ -385,6 +408,11 @@ mancode project upgrade --policy 2 --operation-id --session - - [x] 按开发集成要求将候选 `4dc2e7e` 推送到远程 `develop`,且 Quality 与 Windows gate 均通过;这不等同于 release gate 通过。 - [ ] 完成剩余发布验收后才允许进入 npm 发布检查;任何条件失败都不得发布 npm。 +0.4.0 与 0.4.1 后来已经发布,但仓库内的未完成列表和外部 gate 证据没有在发布前闭合, +且 0.4.1 的 npm `gitHead` 不是旧 release-check 所要求的 `origin/develop` 提交。该偏差 +不通过事后勾选消除;0.4.2 按 [`docs/release-acceptance.md`](./release-acceptance.md) 的 +main-candidate 契约重新建立可审计证据。 + ## 11. 发布回滚与停止策略 | 发现的问题 | 立即动作 | 禁止动作 | 恢复方式 | @@ -400,15 +428,14 @@ mancode project upgrade --policy 2 --operation-id --session - ## 12. 实施顺序与停止/重新对齐条件 -截至 `4dc2e7e`,步骤 1–4 是已验证的开发集成候选;本轮生产加固修复形成新候选后,受影响的自动化证据和步骤 5、7 仍需重新完成。 +A–F 是已经发布的 0.4.0 能力基线。0.4.2 的修复和发布按以下顺序重新建立证据: -1. [x] 冻结本文件中的错误码、字段语义、digest 规范和兼容矩阵,并复核 public workflow create 的 Policy 1 基线。 -2. [x] 完成 A–F 工作包;工作包可以独立合并,但不发布中间 npm 版本。 -3. [x] 完成 adapter digest/upgrade 和 parser/capability gate;当前工作树已通过 0.3.x + V2 manifest reader/writer fixture,新候选仍需重跑。 -4. [x] 完成 project upgrade 和 local reframe 的独立 operation/recovery;只在 upgraded marker 下打开 Policy 2 create default。 -5. [ ] 在同一个 release candidate 上通过第 10.2 节和 [`docs/release-acceptance.md`](./release-acceptance.md) 的全部真实宿主、release-check、Beta gate 和 tarball 检查。 -6. [ ] 将本轮加固后的唯一候选提交推送到远程 `develop`;`4dc2e7e` 的历史推送不替代新候选,且禁止推送、合并或创建以 `main` 为目标的发布操作。 -7. [ ] 确认远程 `develop` 与完整验收证据完全一致后,才允许发布唯一的 npm 版本 0.4.0。git-ref reframe 始终拒绝,不进入本计划范围。 +1. [x] 记录 0.4.1 的 git-ref publication 与发布候选偏差,不把历史 CI 当作当前证据。 +2. [x] 为原子 mutation 的 tracked 投影提交增加 same-revision、same-aggregate、owner-only、fast-forward code-head rebind,并加入第二 clone resume 回归测试。 +3. [x] 将 release-check 改为要求 candidate 同时等于本地 HEAD 与 `origin/main`,并从 main 创建干净 checkout。 +4. [ ] 在 `develop` 完成实现、测试和文档评审后合并到 `main`,形成唯一 0.4.2 candidate。 +5. [ ] 在该 main SHA 上通过 [`docs/release-acceptance.md`](./release-acceptance.md) 的 Quality/Windows、release-check、真实宿主、跨宿主恢复、Beta 和 tarball 检查。 +6. [ ] 从同一 main checkout 发布 0.4.2,验证 npm version/integrity/`gitHead`,再为同一 SHA 创建 `v0.4.2` tag 与 GitHub Release。 任何阶段出现下列情况,都回到“证据和契约评审”,而不是继续编码: @@ -431,19 +458,25 @@ mancode project upgrade --policy 2 --operation-id --session - 3. **升级命令的公开名称:** 以现有 `adapter status/upgrade` 命令注册、JSON 输出和 shell 退出码测试确定名称;文档和实现必须只保留一个正式入口。 4. **Capability 的编码:** 默认由 CLI 内置 capability set 加 project `minWriterVersion` 双门控制,不新增可被旧 CLI 忽略的 manifest capability 字段;local reframe 与 git-ref hard reject 必须使用不同 capability 结果。 -这四项仍须与第 10.2 节的共同 release gate 一起通过,才允许发布 0.4.0。git-ref reframe 不在支持范围内。 +这四项是已发布的兼容基线;0.4.2 不改变其语义。任何后续变更仍须重新通过对应 +contract 与 release gate。git-ref reframe 继续不在支持范围内。 ## 14. 远程分支与 npm 发布顺序 -0.4.0 只允许按以下顺序发布: +0.4.2 及后续补丁统一使用“最终 main 提交发布”模型: + +1. 所有实现、修复和文档先在 `develop` 完成窄测试、完整自动化和评审。 +2. 将最终变更合并并推送到 `main`。该合并提交是唯一 release candidate;develop SHA、PR head SHA 和 main 的父提交都不能代替它。 +3. 等待该 main SHA 的 GitHub Quality 与 Windows required checks 成功。 +4. 在本地检出同一提交,运行 `npm run release:check -- --candidate <完整 SHA>`。脚本要求本地 HEAD 和 `origin/main` 都等于 candidate,从 main 创建干净 checkout,并确认检查期间 main 未变化。 +5. 使用 release-check 保留的 tarball 完成五平台真实宿主、跨宿主恢复和最终 Beta gate;所有证据必须绑定同一个 main SHA 与 package version。 +6. 全部门禁成功后才允许执行一次正式 npm 发布。随后核对 registry version、integrity 与 `gitHead`,确保仍指向 candidate。 +7. npm 核对成功后,为同一提交创建并推送版本 tag,发布 GitHub Release,并记录候选 SHA 与 tarball SHA-256。 -`2c9d697` 是上一已验证开发候选,其 [Quality gate](https://github.com/whitelonng/mancode/actions/runs/29930349142) 和 [Windows gate](https://github.com/whitelonng/mancode/actions/runs/29930353690) 均成功。候选后的任何实现、测试或发布文档修改都会使这些证据不再适用于新候选;新的唯一候选必须重新完成第 1–3 步并推送到 `origin/develop`,第 4–6 步必须在任何正式 npm 发布前补齐。 +任何代码、依赖、构建配置、版本号或发布文档变化都会产生新的 main candidate,并使旧证据失效。检查期间禁止并发更新 main;但“合并到 main”本身是建立候选的必要步骤,不再把 main 永久冻结在旧版本。 -1. 所有实现、修复和文档进入本地 `develop`,形成唯一 release candidate commit。 -2. 在该提交上完成第 10.2 节的全部自动化、恢复、跨平台和真实宿主验收。任何失败都必须修复并从头重跑受影响的 release gate。 -3. [ ] 对本轮形成的新候选只执行 `git push origin develop`。禁止直接或间接更新远程 `main`,包括 push、merge、rebase、以 `main` 为目标的 PR 或自动化发布工作流。 -4. 从远程 `develop` 的同一提交运行 `npm run release:check -- --candidate <完整 SHA>`;使用其保留的 tarball 完成真实宿主证据,再运行最终 Beta gate。 -5. 确认 release candidate commit、远程 `develop` commit、测试证据和待发布 package version 完全一致。 -6. 前五步全部成功后才允许执行 `npm publish`。不发布 `0.4.0-beta`、`0.4.0-rc` 或其他中间 npm 版本。 +### 14.1 0.4.1 偏差与 0.4.2 处置 -若 `npm publish` 前发生任何代码、依赖、构建配置或发布文档变化,候选提交立即失效,必须重新执行步骤 2–5。npm 发布成功不授权更新远程 `main`。 +- 0.4.1 的 npm `gitHead` 是 `8cc8b24` main 合并提交,旧 release-check 却要求 candidate 等于 `origin/develop` 的 `aaa8d6c`;因此已发布提交无法通过当时脚本的身份断言。 +- 0.4.1 的最终 Quality/Windows checks 已成功,但仓库验收文档仍把这些和其他 gate 列为未完成,且没有 0.4.1 tag/GitHub Release。CI 成功不能代替候选绑定与证据收口。 +- 0.4.2 不追溯修改 0.4.1 证据。它改用 main-candidate 模型、补齐 code-head rebind 回归,并要求 npm、tag 和 GitHub Release 全部绑定最终 main SHA。 diff --git a/docs/release-acceptance.md b/docs/release-acceptance.md index 7838dcf..544938f 100644 --- a/docs/release-acceptance.md +++ b/docs/release-acceptance.md @@ -1,49 +1,52 @@ -# 0.4.1 Continuity 发布验收 +# 0.4.2 Continuity 发布验收 -自动化 contract 必须覆盖 Continuity runtime/schema、条件式需求澄清、Policy 2、project upgrade、local reframe、operation recovery、团队协调、git-ref hard reject、五个平台生成结果和 Windows smoke path。条件式需求澄清必须证明清晰请求不被机械提问阻塞,决策性歧义会在 requirements finalize 或实施前停下、提问并等待用户回答。以下证据完成前,不得发布 mancode 0.4.1 或执行 `npm publish`。 +自动化 contract 必须覆盖 Continuity runtime/schema、条件式需求澄清、Policy 2、project upgrade、local reframe、operation recovery、团队协调、git-ref publication/rebind、五个平台生成结果和 Windows smoke path。条件式需求澄清必须证明清晰请求不被机械提问阻塞,决策性歧义会在 requirements finalize 或实施前停下、提问并等待用户回答。以下证据完成前,不得发布 mancode 0.4.2 或执行 `npm publish`。 + +## 唯一候选身份 + +- `develop` 只用于开发集成;最终 release candidate 是已经合并并推送到 `origin/main` 的单个提交。 +- 本地 `HEAD`、`origin/main`、Quality/Windows checks、release-check、真实宿主证据、Beta gate、待发布 package version 和 npm `gitHead` 必须指向同一完整 SHA。 +- 候选建立后,release-check 会记录检查前后的 `origin/main`。检查期间发生任何 main 更新都会使候选失效;后续修复必须形成新的 main 提交并重新执行受影响的全部门禁。 ## 发布条件 -- 在最终发布候选运行 `npm run release:check -- --candidate <完整提交 SHA>`;该命令必须从 `origin/develop` 创建干净 checkout,运行 `npm ci`、`npm run prepublishOnly`、跨 clone、legacy、audit、pack 和安装 smoke,并输出绑定提交与 tarball SHA-256 的本地 JSON 证据。 +- 在最终 main 候选运行 `npm run release:check -- --candidate <完整提交 SHA>`;该命令必须从 `origin/main` 创建干净 checkout,运行 `npm ci`、`npm run prepublishOnly`、跨 clone、legacy、audit、pack 和安装 smoke,并输出绑定提交与 tarball SHA-256 的本地 JSON 证据。 - release-check 先运行 `npm pack --dry-run`,再执行实际 `npm pack`,保留生成的 tarball 并完成 CLI/module smoke;npm beta/rc 不能替代该字节级验证。 -- Windows required check 在 CMD、PowerShell 和 Git Bash 上通过。 +- GitHub Quality gate 与 Windows required check 必须在同一个 main 候选成功;Windows 覆盖 CMD、PowerShell 和 Git Bash。 - Claude Code、Codex、Cursor、GitHub Copilot 和 ZCode 都完成真实双窗口 session 验证。每个平台可证明受信宿主 session,或证明两个真实显式 session 隔离;显式证据只满足发布验收,不授权运行时信任宿主 key。 - 每个平台证明子命令传播;支持子 agent 的平台还需证明继承,或记录合法的 `not_applicable` 原因。缺失、伪造、错误 client、关闭或碰撞的显式 session 证据必须拒绝。 - 完成跨真实宿主 resume、claim、handoff 和恢复路径。 -- release-check 中两个真实独立 clone 完成 git-ref pull、并发 CAS、handoff、receipt recovery 和代码基线交接;不再重复要求同一流程的人工双 clone。 +- release-check 中两个真实独立 clone 完成 git-ref pull、并发 CAS、handoff、receipt recovery、代码基线交接,以及原子 mutation 投影提交后的同 revision code-head rebind 和第二 clone resume。 - release-check 中的真实 0.3.18 legacy fixture 完成 stage、activation、每个中断点恢复和严格条件下的 rollback;人工 smoke 不能替代 crash matrix。 - 最终执行 `mancode context beta --release-candidate --json` 返回 `ready: true` 和空 blockers。 -- 候选提交已经推送到 `origin/develop`,且本地 `HEAD`、`origin/develop`、全部验收证据和待发布 package version 指向同一提交。 -- 记录验收前后的 `origin/main` commit,并证明它没有变化。禁止 push、merge、rebase 或创建以 `main` 为目标的发布操作。 -- 上述条件全部成功后才允许执行 `npm publish`;npm 发布成功后也不得更新 `main`。 +- 上述条件全部成功后,才允许从该 main checkout 发布 release-check 验证过的候选版本;发布后必须核对 npm version、integrity 与 `gitHead`。 +- npm 验证成功后,在同一个 candidate SHA 创建 `v0.4.2` tag 和 GitHub Release,并记录 tarball SHA-256。tag 或 Release 不得指向另一个提交,也不能替代发布前门禁。 ## 发布顺序 -1. 在本地 `develop` 完成唯一 release candidate。 -2. 完成全部自动化、跨平台、恢复和真实宿主验收。 -3. 只执行 `git push origin develop`。 -4. 从远程 `develop` 的同一提交运行 release-check,使用它保留的 tarball 完成真实宿主 spike,再运行最终 Beta gate。 -5. 所有证据一致且 `origin/main` 未变化后,执行唯一一次正式 `npm publish`。 +1. 在 `develop` 完成实现、文档和本地验证,通过评审后合并到 `main`。 +2. 推送最终 main 合并提交,记录完整 candidate SHA,并等待该提交的 Quality 与 Windows checks 成功。 +3. 在本地检出同一 main 提交,从 `origin/main` 运行 release-check。 +4. 使用 release-check 保留的候选 tarball 完成真实宿主 spike、跨宿主恢复和最终 Beta gate。 +5. 确认所有证据仍绑定同一个 main SHA 后执行唯一一次正式 npm 发布,并核对 registry metadata。 +6. 为同一 SHA 创建并推送 `v0.4.2` tag,发布 GitHub Release 并附上候选与 tarball digest。 -任何测试失败或候选提交变化都会使已有验收失效。修复后必须重新验证;不得先发布 npm 再补证据。 +任何测试失败、main 提交变化、package version 变化或发布文档变化都会使已有验收失效。修复后必须形成新候选并重新验证;不得先发布 npm 再补证据。 ## 证据规则 -所有证据必须绑定同一个 `origin/develop` commit、mancode version、操作系统和宿主版本。历史祖先提交、未推送提交或替代宿主结果只能用于调试,不能用于最终 Beta gate。 +所有证据必须绑定同一个 `origin/main` commit、mancode version、操作系统和宿主版本。`develop` 提交、历史祖先提交、未推送提交或替代宿主结果只能用于调试,不能用于最终 Beta gate。 session evidence 不保存原始 key、token、绝对业务路径或任务正文。屏幕截图和日志应脱敏,并保存在发布流程约定的本地证据目录,而不是长期开发文档中。 ## 当前未完成项 -- 本轮发布门禁修复形成的新候选上的 Quality gate,以及 Windows CMD、PowerShell、Git Bash required gate。 -- 五个平台在最终候选上的完整 session spike。 -- 跨真实宿主协作与恢复验收。 -- 最终候选上的 release-check,包括自动双 clone git-ref 和 legacy 验收。 +- 将 0.4.2 实现、测试和文档合并为最终 `origin/main` candidate。 +- 在最终 main 候选上完成 Quality gate 与 Windows CMD、PowerShell、Git Bash required gate。 +- 在最终 main 候选上完成 release-check,包括自动双 clone git-ref、code-head rebind、legacy、tarball SHA-256、安装和 CLI/module smoke。 +- 五个平台在最终候选上的完整 session spike,以及跨真实宿主协作与恢复验收。 - ZCode 项目级 skill 发现和 workspace command 路径确认。 -- release-check 输出的候选 tarball、SHA-256、安装与 CLI/module smoke 证据。 -- 验收前后 `origin/main` 未变化的记录。 - 汇总全部证据后的最终 Beta gate。 - -上一开发候选 `2c9d697` 的 [Quality gate](https://github.com/whitelonng/mancode/actions/runs/29930349142) 和 [Windows compatibility gate](https://github.com/whitelonng/mancode/actions/runs/29930353690) 均已通过,后者覆盖 Windows CMD、PowerShell 和 Git Bash。该证据是历史基线;本轮门禁修复形成新候选后必须重新执行。当前候选 SHA 和运行链接保存在外部发布证据中,避免把自引用 SHA 写进候选提交。 +- npm registry version/integrity/`gitHead` 核对,以及绑定同一提交的 `v0.4.2` tag 和 GitHub Release。 完成一项时更新本文件的未完成列表;不要创建新的平行验收计划。 diff --git a/docs/workflows.md b/docs/workflows.md index 67dc19d..b81a78b 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -129,4 +129,10 @@ handoff 必须经过 `draft → offered → accepted|rejected|cancelled`。accep 在 git-ref transport 下,workflow create、requirements、plan、review 和 verification 采用延后发布:先不带 `--sync` 写入本地 shared authority,把它与匹配的代码一起提交,再执行 `mancode team sync push shared: --expected-task-revision N`。命令直接带 `--sync` 时必须返回 `MANCODE_GIT_REF_DEFERRED_SYNC_REQUIRED`,不能把未获得 receipt 的变更当作已同步。 +`workflow update` 等明确要求 `--sync` 的原子 mutation 先取得远端 receipt,再 materialize +本地 `.mancode/shared` 投影。对于仍需跨 clone resume 的 `in_progress` 或 `blocked` +任务,如果提交这些 tracked 投影使 Git HEAD 前进,owner 必须在 clean worktree 上使用 +不变的 task revision 再执行一次 `team sync push`。该操作只允许同 revision、同 +aggregate 的 code-head fast-forward rebind;完成后另一个 clone 才能 pull 并 resume。 + 只有经过明确确认且通过隐私筛查的决策才能进入 shared memory。任务文本、绝对路径、凭据和宿主 session key 不应写入共享 transport。 diff --git a/package-lock.json b/package-lock.json index f8c60eb..62a69a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mancode", - "version": "0.4.1", + "version": "0.4.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mancode", - "version": "0.4.1", + "version": "0.4.2", "license": "AGPL-3.0-only", "dependencies": { "commander": "^12.1.0", @@ -266,9 +266,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -283,9 +283,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -300,9 +300,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -317,9 +317,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -334,9 +334,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -351,9 +351,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -368,9 +368,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -402,9 +402,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -419,9 +419,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -436,9 +436,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -453,9 +453,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -470,9 +470,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -487,9 +487,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -504,9 +504,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -521,9 +521,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -538,9 +538,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -555,9 +555,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -572,9 +572,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -589,9 +589,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -606,9 +606,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -623,9 +623,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -640,9 +640,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -657,9 +657,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -674,9 +674,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -691,9 +691,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -1610,9 +1610,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1623,32 +1623,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/estree-walker": { diff --git a/package.json b/package.json index 2508a7c..8a9d685 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mancode", - "version": "0.4.1", + "version": "0.4.2", "description": "AI coding agent workflow harness with mancode Continuity for cross-conversation tasks, decisions, verification, and team coordination.", "type": "module", "license": "AGPL-3.0-only", @@ -80,5 +80,8 @@ "tsup": "^8.3.5", "typescript": "^5.7.2", "vitest": "^3.2.6" + }, + "overrides": { + "esbuild": "0.27.2" } } diff --git a/scripts/release-check.mjs b/scripts/release-check.mjs index f7b8283..076ec8d 100644 --- a/scripts/release-check.mjs +++ b/scripts/release-check.mjs @@ -39,8 +39,8 @@ const remote = runCaptured('git', ['remote', 'get-url', 'origin'], sourceRoot); const originDevelop = remoteRef(remote, 'refs/heads/develop'); const originMainBefore = remoteRef(remote, 'refs/heads/main'); assert( - originDevelop === candidate, - 'release candidate must equal origin/develop', + originMainBefore === candidate, + 'release candidate must equal origin/main', ); const outputPath = path.resolve( @@ -65,7 +65,7 @@ try { runCheck(checks, 'clean_clone', 'git', [ 'clone', '--branch', - 'develop', + 'main', '--single-branch', remote, checkout, @@ -206,7 +206,7 @@ try { packageVersion: packageMetadata.version, generatedAt: new Date().toISOString(), source: { - branch: 'develop', + branch: 'main', originDevelop, originMainBefore, originMainAfter, diff --git a/src/installers/adapter-upgrade.ts b/src/installers/adapter-upgrade.ts index 89b2aa3..0c23652 100644 --- a/src/installers/adapter-upgrade.ts +++ b/src/installers/adapter-upgrade.ts @@ -283,6 +283,7 @@ export async function upgradeV3Adapters( [platform, await inspectV3Adapter(root, platform)] as const, ), ); + await removeAdapterUpgradePreview(root, operationId); return { ...resultBase, state: 'committed', @@ -697,6 +698,26 @@ function adapterUpgradePreviewPath(root: string, operationId: Ulid): string { ); } +async function removeAdapterUpgradePreview( + root: string, + operationId: Ulid, +): Promise { + const upgradeRoot = path.join( + path.resolve(root), + '.mancode', + 'staging', + 'adapters', + 'upgrade', + ); + const operationRoot = path.dirname( + adapterUpgradePreviewPath(root, operationId), + ); + if (path.dirname(operationRoot) !== upgradeRoot) { + throw new Error('MANCODE_ADAPTER_UPGRADE_STAGING_INVALID'); + } + await rm(operationRoot, { recursive: true, force: true }); +} + async function readAdapterUpgradePreview( root: string, operationId: Ulid, diff --git a/src/installers/v3-adapter.ts b/src/installers/v3-adapter.ts index 68434ed..d65e504 100644 --- a/src/installers/v3-adapter.ts +++ b/src/installers/v3-adapter.ts @@ -1055,7 +1055,7 @@ const V3_MODE_DEFINITIONS: Record< '- Apply the same decision-readiness gate as `man` before finalizing requirements: validate both clarity and soundness against project facts and team authority. If the goal, scope, acceptance, owner/source of truth, and constraints are clear and consistent, continue without ceremonial questions; if a decision-changing ambiguity, ownership conflict, or hard-risk direction remains, give evidence and a recommendation, ask focused questions, and wait before writing confirmed requirements.', '- Persist unresolved team clarification through the same `workflow requirements draft --file ` command as `man`; do not leave ownership questions or partial answers only in chat history.', '- Use claims, checkpoints, sync, and handoffs through `mancode team`; never infer ownership from an adapter prompt.', - '- With git-ref transport, workflow creation plus requirements, plan, review, and verification mutations use an explicit deferred publication boundary: run the workflow command without `--sync`, commit the resulting `.mancode/shared` authority changes together with the matching code head, then run `mancode team sync push --expected-task-revision `. Never report cross-clone synchronization before the push returns a receipt. Use `--sync` only for a command whose contract performs an atomic git-ref mutation.', + '- With git-ref transport, workflow creation plus requirements, plan, review, and verification mutations use an explicit deferred publication boundary: run the workflow command without `--sync`, commit the resulting `.mancode/shared` authority changes together with the matching code head, then run `mancode team sync push --expected-task-revision `. Never report cross-clone synchronization before the push returns a receipt. Use `--sync` only for a command whose contract performs an atomic git-ref mutation. If that atomic mutation leaves tracked `.mancode/shared` projection changes for a resumable in-progress or blocked task, commit them, then run the same `team sync push` with the unchanged task revision to rebind the remote code head before another clone resumes the task.', ], }, manps: { diff --git a/src/team/git-ref-coordination.ts b/src/team/git-ref-coordination.ts index f59e5a1..c93d38d 100644 --- a/src/team/git-ref-coordination.ts +++ b/src/team/git-ref-coordination.ts @@ -332,7 +332,7 @@ function prepareOwnershipFence( expectedPredecessorBundleDigest: string | null, ): PreparedGitRefCoordinationMutation { const metadata = metadataFromBundle(taskBundle); - assertRemoteTaskEligible(metadata); + assertRemoteTaskCoordination(metadata); assertTaskBundleIdentity(taskBundle, context.taskRef); if (metadata.ownerActorId === null) { throw new Error('MANCODE_TASK_OWNER_REQUIRED'); @@ -344,6 +344,7 @@ function prepareOwnershipFence( throw new Error('MANCODE_TASK_BUNDLE_DIVERGED'); } if (context.fence === null) { + assertRemoteTaskEligible(metadata); if ( metadata.ownerActorId !== context.input.actorId || metadata.ownershipEpoch !== 0 || @@ -363,6 +364,7 @@ function prepareOwnershipFence( throw new Error('MANCODE_TASK_REVISION_CONFLICT'); } if (taskBundle.taskRevision === context.fence.taskRevision) { + assertRemoteTaskRebindEligible(metadata); if (taskBundle.aggregateDigest !== context.fence.aggregateDigest) { throw new Error('MANCODE_SPLIT_BRAIN'); } @@ -380,6 +382,7 @@ function prepareOwnershipFence( taskBundle, ); } + assertRemoteTaskEligible(metadata); } const codeHeadChanged = context.taskBundle !== null && @@ -1259,11 +1262,21 @@ function metadataFromBundle( } function assertRemoteTaskEligible(metadata: WorkflowMetadataV3): void { - if ( - metadata.workflowMode !== 'manteam' || - metadata.coordination !== 'team' || - metadata.status !== 'in_progress' - ) { + assertRemoteTaskCoordination(metadata); + if (metadata.status !== 'in_progress') { + throw new Error('MANCODE_REMOTE_COORDINATION_TASK_INVALID'); + } +} + +function assertRemoteTaskRebindEligible(metadata: WorkflowMetadataV3): void { + assertRemoteTaskCoordination(metadata); + if (metadata.status !== 'in_progress' && metadata.status !== 'blocked') { + throw new Error('MANCODE_REMOTE_COORDINATION_TASK_INVALID'); + } +} + +function assertRemoteTaskCoordination(metadata: WorkflowMetadataV3): void { + if (metadata.workflowMode !== 'manteam' || metadata.coordination !== 'team') { throw new Error('MANCODE_REMOTE_COORDINATION_TASK_INVALID'); } } diff --git a/tests/adapter-upgrade-contracts.test.ts b/tests/adapter-upgrade-contracts.test.ts index 35c9c7c..f35f2d3 100644 --- a/tests/adapter-upgrade-contracts.test.ts +++ b/tests/adapter-upgrade-contracts.test.ts @@ -197,6 +197,23 @@ describe('adapter managed-content digest and upgrade', () => { await expect(readFile(live, 'utf8')).resolves.toContain( '# mancode bootstrap', ); + await expect( + readFile( + path.join( + root, + '.mancode', + 'staging', + 'adapters', + 'upgrade', + preview.operationId, + 'preview.json', + ), + 'utf8', + ), + ).rejects.toThrow(); + await expect( + readFile(path.join(root, preview.stagedTargets[0] ?? ''), 'utf8'), + ).rejects.toThrow(); }); it('does not create staging or live targets without dry-run or confirmation', async () => { diff --git a/tests/git-ref-coordination-contracts.test.ts b/tests/git-ref-coordination-contracts.test.ts index 7081880..58f4137 100644 --- a/tests/git-ref-coordination-contracts.test.ts +++ b/tests/git-ref-coordination-contracts.test.ts @@ -183,6 +183,26 @@ describe('git-ref coordination domain contracts', () => { revision: 2, lastValidatedCodeRef: nextBundle.codeRef, }); + + const completedBundle = bundle(metadata({ status: 'completed' })); + const completed = { + ...baseManifest(), + ownershipFences: [fence(completedBundle)], + taskBundles: [completedBundle], + }; + expect(() => + prepareGitRefCoordinationMutation(completed, { + kind: 'ownership_fence', + operationId: id(28), + actorId: OWNER_ID, + taskRef: TASK_REF, + expectedRemoteRevision: 1, + expectedOwnershipEpoch: 1, + expectedPredecessorBundleDigest: completedBundle.bundleDigest, + taskBundle: bundleWithCodeHead(completedBundle, 'def5678'), + now: NOW, + }), + ).toThrow('MANCODE_REMOTE_COORDINATION_TASK_INVALID'); }); it('materializes remote handoffs as fetched without changing business state', () => { diff --git a/tests/git-ref-cross-clone-e2e.test.ts b/tests/git-ref-cross-clone-e2e.test.ts index 8a16ed5..9bbf62e 100644 --- a/tests/git-ref-cross-clone-e2e.test.ts +++ b/tests/git-ref-cross-clone-e2e.test.ts @@ -1040,6 +1040,124 @@ describe('git-ref coordination across independent clones', () => { ).rejects.toThrow('MANCODE_REPAIR_AUTHORIZATION_MISMATCH'); }, 20_000); + it('rebinds an atomically blocked task to a committed projection before another clone resumes it', async () => { + const fixture = await createFixture(); + const created = await createRemoteTask(fixture.cloneA, fixture.codeHead); + const storeA = await strictStore(fixture.cloneA); + const initialBundle = await taskBundle(fixture.cloneA); + const establishOperationId = id(110); + await storeA.establishCoordinationAuthority({ + operationId: establishOperationId, + actorId: ACTOR_A, + expectedRemoteRevision: 0, + expectedPriorTransportEpoch: null, + targetTransportEpoch: 2, + actorProfiles: fixture.profiles, + ownershipFences: [ + ownershipFence(initialBundle, ACTOR_A, 1, establishOperationId), + ], + claims: [], + handoffs: [], + taskBundles: [initialBundle], + }); + + const blocked = await updateGitRefWorkflow({ + projectRoot: fixture.cloneA, + taskRef: created.taskRef, + sessionId: SESSION_A, + expectedTaskRevision: created.metadata.revision, + status: 'blocked', + blockingReason: 'Awaiting an external dependency.', + operationId: id(111), + now: at(4), + }); + expect(blocked).toMatchObject({ + metadata: { status: 'blocked' }, + remoteRevision: 2, + }); + + const taskRoot = path.join( + '.mancode', + 'shared', + 'workflows', + created.taskRef.taskId, + ); + await git(fixture.cloneA, ['add', '--force', taskRoot]); + await git(fixture.cloneA, [ + 'commit', + '-m', + 'commit atomically materialized blocked task', + ]); + const committedHead = await gitOutput(fixture.cloneA, [ + 'rev-parse', + 'HEAD', + ]); + + const rebound = await captureJson(() => + teamSyncPush(fixture.cloneA, { + task: formatTaskRef(created.taskRef), + expectedTaskRevision: String(blocked.metadata.revision), + session: SESSION_A, + client: 'vitest-a', + json: true, + }), + ); + expect(rebound).toMatchObject({ + exitCode: 0, + value: { + changed: true, + taskRevision: blocked.metadata.revision, + remoteRevision: 3, + }, + }); + await expect(storeA.pull()).resolves.toMatchObject({ + manifest: { + ownershipFences: [ + { + taskRevision: blocked.metadata.revision, + }, + ], + taskBundles: [ + { + taskRevision: blocked.metadata.revision, + codeRef: { head: committedHead }, + }, + ], + }, + }); + + await git(fixture.cloneA, ['push', 'origin', 'main']); + await git(fixture.cloneB, ['fetch', 'origin']); + await git(fixture.cloneB, ['merge', '--ff-only', 'origin/main']); + const pulled = await captureJson(() => + teamSyncPull(fixture.cloneB, { + task: formatTaskRef(created.taskRef), + json: true, + }), + ); + expect(pulled).toMatchObject({ + exitCode: 0, + value: { + remoteRevision: 3, + materializedBundles: [{ status: 'unchanged', codeReachable: true }], + }, + }); + const resumed = await captureJson(() => + contextResume(fixture.cloneB, formatTaskRef(created.taskRef), { + session: SESSION_B, + client: 'vitest-b', + json: true, + }), + ); + expect(resumed).toMatchObject({ + exitCode: 0, + value: { + taskRef: created.taskRef, + taskRevision: blocked.metadata.revision, + }, + }); + }, 20_000); + it('completes a ready shared task and releases its remote claim in one CAS', async () => { const fixture = await createFixture(); const created = await createRemoteTask(fixture.cloneA, fixture.codeHead, { diff --git a/tests/release-check-contracts.test.ts b/tests/release-check-contracts.test.ts index 781d93c..4e50917 100644 --- a/tests/release-check-contracts.test.ts +++ b/tests/release-check-contracts.test.ts @@ -22,6 +22,10 @@ describe('release candidate check', () => { expect(script).toContain("'legacy_migration'"); expect(script).toContain("'tarball_install'"); expect(script).toContain("'origin_main_unchanged'"); + expect(script).toContain('release candidate must equal origin/main'); + expect(script).not.toContain('release candidate must equal origin/develop'); + expect(script).toMatch(/'clone',[\s\S]*'--branch',\s*'main'/); + expect(script).toContain("branch: 'main'"); expect(script).toContain("createHash('sha256')"); expect(script).not.toMatch(/['"]publish['"]/); expect(script).not.toContain('dist-tag'); diff --git a/tests/v3-adapter-contracts.test.ts b/tests/v3-adapter-contracts.test.ts index 10bff9e..5d384bb 100644 --- a/tests/v3-adapter-contracts.test.ts +++ b/tests/v3-adapter-contracts.test.ts @@ -363,6 +363,9 @@ describe('V3 adapter bootstrap integration', () => { expect(entry).toContain( '`mancode team sync push --expected-task-revision `', ); + expect(entry).toContain( + 'with the unchanged task revision to rebind the remote code head', + ); expect(entry).toContain( 'ownership conflict, or hard-risk direction remains', ); diff --git a/website/docs.html b/website/docs.html index 8239e0d..1a9234d 100644 --- a/website/docs.html +++ b/website/docs.html @@ -24,7 +24,7 @@
mancode - Documentation / v0.4.1 + Documentation / v0.4.2