Merge pull request 'Guard task-start against merged branch names; harden sync evidence scan' (#211) from feature/task-start-merged-guard into main
ci / test (push) Successful in 2m3s
ci / test (push) Successful in 2m3s
This commit was merged in pull request #211.
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# feature/task-start-merged-guard 任务卡
|
||||
|
||||
任务主记录:<PR 链接,task-finish 时填写>;状态:进行中;owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 43d33aa4921078bc202393b99cba017d7f731b98
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard(worktree);分支:feature/task-start-merged-guard
|
||||
- 授权与交付终点:owner 2026-10-05 授权立项(决策清单 #7);改 scripts/task.sh 加守护 + 测试 + PR 合入为本卡终点;不改 task.sh 其他行为。
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- **目标**:`cmd_start` 在分支名校验后新增守护——本地或远端存在同名分支且已包含于 `origin/main` 时拒绝启动(exit 非零),提示「沿用原分支或换新 slug」。
|
||||
- **背景**:2026-10-05 EXT-1 复核轮实测,合入后再 `task-start` 同名分支会从新 main 长出第二段历史、空卡覆盖已合入任务卡(两轮证据差点丢失,靠 git show 恢复);旧逻辑只校验本地分支能否创建,不查是否刚合入。
|
||||
- **非目标**:不改 precheck/task-sync/finish 等其他子命令;不做「恢复原卡」的自动修复(拒绝即可,恢复留给人工);不引入新依赖。
|
||||
- **范围变更(2026-10-05 12:33)**:本卡功能负例的证据命令含 `||`,暴露 `cmd_sync` 证据扫描按裸 `|` 切行、把转义碎片当 HEAD 传给 `git diff` 致 fatal 128 杀死 sync 的潜在缺陷(task-sync 门禁被卡死,卡内 12:30–12:32 五次中毒复现)——**同 PR 一并修复**(非十六进制单元格跳过,WARN 语义不变)。
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | 43d33aa4921078bc202393b99cba017d7f731b98 | 43d33aa4921078bc202393b99cba017d7f731b98 | 2026-10-05T12:28:26Z |
|
||||
|
||||
## 证据(Evidence)
|
||||
|
||||
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
|
||||
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|
||||
|---|---|---|---|---|---|
|
||||
|
||||
## 结果与验证(完成后填写)
|
||||
|
||||
- 结果:cmd_start 守护 + cmd_sync 证据扫描加固均落地(见范围变更)。守护:已合入同名分支拒绝启动、提示沿用原分支或换新 slug,负例实测无 worktree 副作用;扫描:含 `\|\|` 转义行的卡片上 sync 正常完成、WARN 语义不变。
|
||||
- 验证:bash -n PASS;功能负例 PASS(exit≠0 断言,无副作用);sync 修复验证 PASS(exit 0);make test 全链 PASS(修复前 94f8d47 与最终 HEAD 两轮,exit 0);权威源为 CI 在 PR HEAD 的 make test+make build(GATE)。
|
||||
- 影响与剩余项:仅 scripts/task.sh 两处;下游建仓(Agent-System-RDM)将复制修复后的版本。
|
||||
| 2026-10-05T12:28:53Z | `bash -n scripts/task.sh` | 94f8d4760b | 0 | SELF | e3b0c44298fc1c14 |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:28:53Z -->
|
||||
```
|
||||
$ bash -n scripts/task.sh
|
||||
[exit 0 | HEAD 94f8d4760b | sha256:e3b0c44298fc1c14] 输出尾部 15 行:
|
||||
|
||||
```
|
||||
| 2026-10-05T12:28:53Z | `bash scripts/task.sh start feature/ext-1-inproc-handler && exit 1 \|\| echo 'guard refused merged branch as expected'` | 94f8d4760b | 0 | SELF | 937f2c0a1987b4f7 |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:28:53Z -->
|
||||
```
|
||||
$ bash scripts/task.sh start feature/ext-1-inproc-handler && exit 1 || echo 'guard refused merged branch as expected'
|
||||
[exit 0 | HEAD 94f8d4760b | sha256:937f2c0a1987b4f7] 输出尾部 15 行:
|
||||
ERROR: branch feature/ext-1-inproc-handler already merged into origin/main — reuse the original branch or pick a new slug (task-start must not recreate merged cards)
|
||||
guard refused merged branch as expected
|
||||
```
|
||||
| 2026-10-05T12:29:05Z | `make test` | 94f8d4760b | 0 | SELF | 84092b2ad053ee79 |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:29:05Z -->
|
||||
```
|
||||
$ make test
|
||||
[exit 0 | HEAD 94f8d4760b | sha256:84092b2ad053ee79] 输出尾部 20 行:
|
||||
|
||||
✓ test/ui.test.tsx (6 tests) 66ms
|
||||
✓ test/toolblock.test.tsx (4 tests) 76ms
|
||||
✓ test/overlay-host.test.tsx (6 tests) 68ms
|
||||
✓ test/file-preview.test.tsx (9 tests) 89ms
|
||||
✓ test/inbox.test.tsx (13 tests) 93ms
|
||||
✓ test/card-anchor.test.tsx (4 tests) 96ms
|
||||
✓ test/inline-confirm.test.tsx (7 tests) 107ms
|
||||
✓ test/capability.test.tsx (14 tests) 153ms
|
||||
|
||||
Test Files 14 passed (14)
|
||||
Tests 103 passed (103)
|
||||
Start at 12:29:37
|
||||
Duration 619ms (transform 415ms, setup 0ms, import 1.36s, tests 955ms, environment 3.25s)
|
||||
|
||||
knip unused exports 55 <= 55
|
||||
cd deps/agent-command && go vet ./... && go test -count=1 ./...
|
||||
ok agent-command 0.002s
|
||||
ok agent-command/conformance 0.002s
|
||||
make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
```
|
||||
| 2026-10-05T12:30:24Z | `make task-sync` | 94f8d4760b | 2 | SELF | c59e97420676c4fa |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:30:24Z -->
|
||||
```
|
||||
$ make task-sync
|
||||
[exit 2 | HEAD 94f8d4760b | sha256:c59e97420676c4fa] 输出尾部 15 行:
|
||||
make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
ERROR: dirty tree — 先显式提交;不隐式 stash(collaboration.md:11)
|
||||
make[1]: *** [Makefile:36: task-sync] Error 1
|
||||
make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
```
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | e58035a8e4b60dc291d9245d669c5a3a561fd699 | 2026-10-05T12:30:36Z |
|
||||
| 2026-10-05T12:30:36Z | `make task-sync` | e58035a8e4 | 2 | SELF | 12717b8736ff03bf |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:30:36Z -->
|
||||
```
|
||||
$ make task-sync
|
||||
[exit 2 | HEAD e58035a8e4 | sha256:12717b8736ff03bf] 输出尾部 15 行:
|
||||
make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
Already up to date.
|
||||
make[1]: *** [Makefile:36: task-sync] Error 128
|
||||
make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
```
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 879bf64b94a6f1c3b126ec52a778b1f8c7630266 | 2026-10-05T12:30:49Z |
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 09aa6e59b08ff74ca3e5c78ab1bffc55e386993c | 2026-10-05T12:31:08Z |
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 9e30c5f656ccaf3186c966c7452df2da3d75292f | 2026-10-05T12:31:17Z |
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | b3a5a31d10d03dabe13e03ddbf29c736f892dea2 | 2026-10-05T12:31:59Z |
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 2fec8b4e829bdb27006c924d51d56016331bde44 | 2026-10-05T12:32:00Z |
|
||||
| 2026-10-05T12:32:55Z | `bash -n scripts/task.sh && bash scripts/task.sh sync && echo 'sync survives escaped-pipe evidence row'` | 278bff9a31 | 1 | SELF | afc745546e4eb5ba |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:32:55Z -->
|
||||
```
|
||||
$ bash -n scripts/task.sh && bash scripts/task.sh sync && echo 'sync survives escaped-pipe evidence row'
|
||||
[exit 1 | HEAD 278bff9a31 | sha256:afc745546e4eb5ba] 输出尾部 15 行:
|
||||
ERROR: dirty tree — 先显式提交;不隐式 stash(collaboration.md:11)
|
||||
```
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 1e0508e8a7071bcd92e78089c6c30c41caf1b594 | 2026-10-05T12:33:06Z |
|
||||
| 同步前验收 | 43d33aa4921078bc202393b99cba017d7f731b98 | 9a3ebe6539d97445a7b5705a0a48bd9a1124aa90 | 2026-10-05T12:33:16Z |
|
||||
| 2026-10-05T12:33:16Z | `bash -n scripts/task.sh && bash scripts/task.sh sync >/dev/null 2>&1 && echo 'sync survives escaped-pipe evidence row'` | 9a3ebe6539 | 0 | SELF | 2a3457acb8b31495 |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:33:16Z -->
|
||||
```
|
||||
$ bash -n scripts/task.sh && bash scripts/task.sh sync >/dev/null 2>&1 && echo 'sync survives escaped-pipe evidence row'
|
||||
[exit 0 | HEAD 9a3ebe6539 | sha256:2a3457acb8b31495] 输出尾部 15 行:
|
||||
sync survives escaped-pipe evidence row
|
||||
```
|
||||
| 2026-10-05T12:33:22Z | `make test` | de75f1ede9 | 0 | SELF | 9a4f394d8e0f5c60 |
|
||||
|
||||
<!-- evidence:run 2026-10-05T12:33:22Z -->
|
||||
```
|
||||
$ make test
|
||||
[exit 0 | HEAD de75f1ede9 | sha256:9a4f394d8e0f5c60] 输出尾部 20 行:
|
||||
✓ test/collapsible.test.tsx (5 tests) 79ms
|
||||
✓ test/ui.test.tsx (6 tests) 70ms
|
||||
✓ test/tabstrip.test.tsx (3 tests) 79ms
|
||||
✓ test/file-preview.test.tsx (9 tests) 84ms
|
||||
✓ test/overlay-host.test.tsx (6 tests) 79ms
|
||||
✓ test/inbox.test.tsx (13 tests) 90ms
|
||||
✓ test/inline-confirm.test.tsx (7 tests) 106ms
|
||||
✓ test/card-anchor.test.tsx (4 tests) 107ms
|
||||
✓ test/capability.test.tsx (14 tests) 157ms
|
||||
|
||||
Test Files 14 passed (14)
|
||||
Tests 103 passed (103)
|
||||
Start at 12:33:50
|
||||
Duration 651ms (transform 432ms, setup 0ms, import 1.42s, tests 993ms, environment 3.42s)
|
||||
|
||||
knip unused exports 55 <= 55
|
||||
cd deps/agent-command && go vet ./... && go test -count=1 ./...
|
||||
ok agent-command 0.002s
|
||||
ok agent-command/conformance 0.002s
|
||||
make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-task-start-merged-guard'
|
||||
```
|
||||
+14
-2
@@ -102,9 +102,18 @@ cmd_precheck() {
|
||||
|
||||
cmd_start() {
|
||||
need_repo
|
||||
local name="${1:-}"; [ -n "$name" ] || die "usage: task.sh start <feature|fix|hotfix>/<slug>"
|
||||
local name="${1:-}"; [ -n "$name" ] || die "usage: task.sh start <feature|fix|hotfix|release>/<slug>"
|
||||
echo "$name" | grep -qE '^(feature|fix|hotfix|release)/[A-Za-z0-9._-]+$' || die "branch name must match (feature|fix|hotfix|release)/<slug>"
|
||||
git fetch -q origin "${TARGET_BRANCH}" 2>/dev/null || true
|
||||
# 已合入的同名分支不得重建(2026-10-05 实测:合入后再 task-start 同名会从新 main 长出
|
||||
# 第二段历史,空卡覆盖已合入任务卡,两轮证据差点丢失)。复核/追加沿用原分支或换新 slug。
|
||||
local guard_ref
|
||||
for guard_ref in "refs/heads/${name}" "refs/remotes/origin/${name}"; do
|
||||
if git rev-parse -q --verify "${guard_ref}" >/dev/null \
|
||||
&& git merge-base --is-ancestor "${guard_ref}" "origin/${TARGET_BRANCH}"; then
|
||||
die "branch ${name} already merged into origin/${TARGET_BRANCH} — reuse the original branch or pick a new slug (task-start must not recreate merged cards)"
|
||||
fi
|
||||
done
|
||||
[ "$(git status --porcelain | { grep -v '^.. \.zcode/' || true; } | wc -l)" -eq 0 ] || die "dirty tree — resolve first (precheck verdict BUSY)"
|
||||
[ "$(git submodule status --recursive 2>/dev/null | { grep -cE '^\+|^U' || true; })" -eq 0 ] || die "submodule drift/conflict — resolve first (precheck verdict BUSY)"
|
||||
git merge-base --is-ancestor "origin/${TARGET_BRANCH}" HEAD || die "local ${TARGET_BRANCH} behind origin — pull --ff-only first"
|
||||
@@ -190,11 +199,14 @@ cmd_sync() {
|
||||
git add "$card"
|
||||
git commit -q -m "Record the sync checkpoint" || true
|
||||
# [evidence] 同步改变了被测对象:卡片证据表中旧 HEAD 的行,其后若有非 .task 变更则失效须重跑。
|
||||
# 按 | 切行会撞上 cmd 单元格里被转义的 \|\|(2026-10-05 实测:碎片 '\' 传给 git diff
|
||||
# 触发 fatal 128,set -e 下直接杀死 sync)——非十六进制碎片一律跳过,不作 HEAD 解析。
|
||||
local eh stale_ev="" short_head changed
|
||||
short_head=$(echo "$head" | cut -c1-10)
|
||||
while IFS='|' read -r _ _ _ eh _ _ _; do
|
||||
eh=$(echo "$eh" | tr -d ' `')
|
||||
{ [ -n "$eh" ] && [ "$eh" != "$short_head" ]; } || continue
|
||||
case "$eh" in ''|*[!0-9a-f]*) continue ;; esac
|
||||
[ "$eh" != "$short_head" ] || continue
|
||||
changed=$(git diff --name-only "${eh}" HEAD -- . ':(exclude).task' 2>/dev/null | head -1)
|
||||
[ -n "$changed" ] && stale_ev="$stale_ev ${eh}"
|
||||
done < <(grep -E '^\| [0-9]{4}-[0-9]{2}-[0-9]{2}T[^|]*\|' "$card" 2>/dev/null || true)
|
||||
|
||||
Reference in New Issue
Block a user