kata-migrate-phases

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<objective> Detect and fix duplicate phase numeric prefixes caused by per-milestone numbering. Migrates all phase directories to globally sequential numbering.
Projects with multiple milestones may have colliding prefixes (e.g.,
01-foundation
from v0.1.0 and
01-setup
from v0.2.0 both in
completed/
). This causes
find ... -name "01-*" | head -1
to return the wrong directory. </objective>
<context> @.planning/STATE.md @.planning/ROADMAP.md </context> <process> <step name="detect_collisions">
Scan all phase directories for duplicate numeric prefixes:
bash
DUPES=$(for state in active pending completed; do
  ls .planning/phases/${state}/ 2>/dev/null
done | grep -oE '^[0-9]+' | sort -n | uniq -d)
<objective> 检测并修复因按里程碑单独编号导致的重复阶段数字前缀问题。将所有阶段目录迁移为全局连续编号。
拥有多个里程碑的项目可能会出现前缀冲突(例如,v0.1.0的
01-foundation
和v0.2.0的
01-setup
都位于
completed/
目录下)。这会导致
find ... -name "01-*" | head -1
返回错误的目录。 </objective>
<context> @.planning/STATE.md @.planning/ROADMAP.md </context> <process> <step name="detect_collisions">
扫描所有阶段目录,查找重复的数字前缀:
bash
DUPES=$(for state in active pending completed; do
  ls .planning/phases/${state}/ 2>/dev/null
done | grep -oE '^[0-9]+' | sort -n | uniq -d)

Also check flat directories (unmigrated projects)

Also check flat directories (unmigrated projects)

FLAT_DUPES=$(ls .planning/phases/ 2>/dev/null | grep -E '^[0-9]' | grep -oE '^[0-9]+' | sort -n | uniq -d)
ALL_DUPES=$(echo -e "${DUPES}\n${FLAT_DUPES}" | sort -nu | grep -v '^$') echo "Duplicate prefixes: ${ALL_DUPES:-none}"

If no duplicates found:
No phase prefix collisions detected. All phase directories have unique numeric prefixes.

Exit.
</step>

<step name="validate_environment">

Read ROADMAP.md and STATE.md. Confirm project is active:

```bash
[ -f .planning/ROADMAP.md ] || { echo "ERROR: No ROADMAP.md found. Not a Kata project."; exit 1; }
[ -f .planning/STATE.md ] || { echo "ERROR: No STATE.md found. Not a Kata project."; exit 1; }
Display:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Kata ► PHASE MIGRATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

◆ Duplicate prefixes detected: [list]
◆ Building chronology from ROADMAP.md...
</step> <step name="build_milestone_chronology">
Parse ROADMAP.md to build globally sequential phase numbering. Milestones appear in chronological order.
Completed milestones: Each
<details>
block contains phase lists. Parse phases in document order.
Current milestone: Parse
#### Phase N:
headings from the active section.
Build a chronology array. Each entry:
{global_seq} {phase_name}
where
phase_name
is the slug from the phase heading (e.g., "foundation", "api-endpoints").
bash
GLOBAL_SEQ=0
CHRONOLOGY=""
FLAT_DUPES=$(ls .planning/phases/ 2>/dev/null | grep -E '^[0-9]' | grep -oE '^[0-9]+' | sort -n | uniq -d)
ALL_DUPES=$(echo -e "${DUPES}\n${FLAT_DUPES}" | sort -nu | grep -v '^$') echo "Duplicate prefixes: ${ALL_DUPES:-none}"

如果未找到重复项:
No phase prefix collisions detected. All phase directories have unique numeric prefixes.

退出。
</step>

<step name="validate_environment">

读取ROADMAP.md和STATE.md,确认项目处于活跃状态:

```bash
[ -f .planning/ROADMAP.md ] || { echo "ERROR: No ROADMAP.md found. Not a Kata project."; exit 1; }
[ -f .planning/STATE.md ] || { echo "ERROR: No STATE.md found. Not a Kata project."; exit 1; }
显示:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Kata ► PHASE MIGRATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

◆ Duplicate prefixes detected: [list]
◆ Building chronology from ROADMAP.md...
</step> <step name="build_milestone_chronology">
解析ROADMAP.md以构建全局连续的阶段编号。里程碑按时间顺序排列。
**已完成的里程碑:**每个
<details>
块包含阶段列表。按文档顺序解析阶段。
**当前里程碑:**从活跃区域解析
#### Phase N:
标题。
构建时间线数组。每个条目格式为:
{global_seq} {phase_name}
,其中
phase_name
是阶段标题对应的短名称(例如“foundation”、“api-endpoints”)。
bash
GLOBAL_SEQ=0
CHRONOLOGY=""

Parse all "Phase N: name" lines from ROADMAP.md in document order.

Parse all "Phase N: name" lines from ROADMAP.md in document order.

Completed milestones appear in <details> blocks; current milestone uses #### headings.

Completed milestones appear in <details> blocks; current milestone uses #### headings.

Both formats contain "Phase N: name" — grep catches all.

Both formats contain "Phase N: name" — grep catches all.

while IFS= read -r line; do name=$(echo "$line" | grep -oE 'Phase [0-9.]+: .+' | sed 's/Phase [0-9.]*: //' | sed 's/**$//' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-') if [ -n "$name" ]; then CHRONOLOGY="${CHRONOLOGY}${GLOBAL_SEQ} ${name}\n" GLOBAL_SEQ=$((GLOBAL_SEQ + 1)) fi done < <(grep -E 'Phase [0-9.]+:' .planning/ROADMAP.md)

Decimal phases (2.1, 2.2) get sequential integer numbers after their parent. Document order determines sequence.

Display: `Chronology ([N] phases): 00 → foundation, 01 → api-endpoints, ...`
</step>

<step name="map_directories_to_phases">

Match each phase name from the chronology to its existing directory. Search across `active/`, `pending/`, `completed/`, and flat fallback.

For each chronology entry `{seq} {name}`:
1. Find directories whose slug matches `{name}` across all states
2. If multiple matches, use the one whose numeric prefix matches the original milestone-local number
3. Build mapping: `STATE/OLD_DIR → STATE/NEW_PREFIX-SLUG`

Strip numeric prefix from each directory name to get slug, compare against chronology name. Build `MAPPING` as newline-delimited entries: `STATE/OLD_DIR → PADDED-SLUG`.

Display the full mapping table.
</step>

<step name="present_migration_plan">

Display the rename table:
Migration Plan: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
completed/01-foundation → completed/00-foundation completed/02-api-endpoints → completed/01-api-endpoints completed/01-setup → completed/02-setup ... active/01-current-work → active/15-current-work
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Total: [N] directories to rename

Use AskUserQuestion:
- header: "Migration"
- question: "Rename [N] directories to globally sequential numbers?"
- options:
  - "Proceed" — Execute all renames
  - "Cancel" — Abort migration

If cancelled, exit with "Migration cancelled."
</step>

<step name="execute_renames">

Two-pass approach to avoid mid-rename collisions (established pattern from `kata-move-phase`):

**Pass 1:** Rename all directories to temporary names: `mv OLD tmp-{seq}-{slug}`

**Pass 2:** Rename from temporary to final: `mv tmp-{seq}-{slug} {padded}-{slug}`

For active/pending phases in Pass 2, also rename internal files (`*-PLAN.md`, `*-RESEARCH.md`, `*-CONTEXT.md`, `*-SUMMARY.md`) by replacing the old phase prefix with the new padded prefix: `sed "s/^[0-9.]*-/${PADDED}-/"`.

Completed phase internal files left unchanged. Wildcard lookup (`*-PLAN.md`) handles them.

Display:
◆ Pass 1: Renamed [N] directories to temporary names ◆ Pass 2: Renamed [N] directories to final names ◆ Active/pending internal files updated: [count]
</step>

<step name="update_documentation">

**Update ROADMAP.md current milestone phase numbers:**

For the current (non-archived) milestone section, update `#### Phase N:` headings to use new global numbers. Match phase names to chronology to determine correct new number.

**Update STATE.md current position:**

Update the current phase reference to use the new global number. Find the line referencing the active phase and update its number.

**Leave historical `<details>` blocks unchanged.** They are archived records. Milestone archive files in `.planning/milestones/` are authoritative.

Display:
◆ Updated ROADMAP.md current milestone phase numbers ◆ Updated STATE.md current position
</step>

<step name="verify">

Re-run collision detection:

```bash
DUPES=$(for state in active pending completed; do
  ls .planning/phases/${state}/ 2>/dev/null
done | grep -oE '^[0-9]+' | sort -n | uniq -d)

FLAT_DUPES=$(ls .planning/phases/ 2>/dev/null | grep -E '^[0-9]' | grep -oE '^[0-9]+' | sort -n | uniq -d)

ALL_DUPES=$(echo -e "${DUPES}\n${FLAT_DUPES}" | sort -nu | grep -v '^$')
If clean:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Kata ► MIGRATION COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✓ [N] directories renamed to globally sequential numbers
✓ No duplicate prefixes remain
✓ ROADMAP.md and STATE.md updated
If duplicates remain: report as error with details. </step>
<step name="commit">
Check planning config:
bash
COMMIT_PLANNING_DOCS=$(cat .planning/config.json 2>/dev/null | grep -o '"commit_docs"[[:space:]]*:[[:space:]]*[^,}]*' | grep -o 'true\|false' || echo "true")
git check-ignore -q .planning 2>/dev/null && COMMIT_PLANNING_DOCS=false
If
COMMIT_PLANNING_DOCS=false
:
Skip git operations.
If
COMMIT_PLANNING_DOCS=true
(default):
bash
git add .planning/phases/ .planning/ROADMAP.md .planning/STATE.md
git commit -m "$(cat <<'EOF'
chore: migrate phase directories to globally sequential numbering
EOF
)"
</step> </process>
<anti_patterns>
  • Don't rename completed phase internal files (wildcard lookup handles them, reduces risk)
  • Don't modify historical
    <details>
    blocks in ROADMAP.md (archived records)
  • Don't rename one directory at a time without temp pass (causes mid-rename collisions)
  • Don't ask per-directory confirmation (impractical for 30+ phases)
  • Don't run migration on projects with no collisions (detect and exit early) </anti_patterns>
<success_criteria>
  • Duplicate phase prefixes detected across all state directories
  • Chronology built from ROADMAP.md in document order
  • Migration plan displayed with full rename table
  • User confirmation obtained before any renames
  • Two-pass rename executed without collisions
  • Active/pending internal files renamed to match new prefix
  • Completed phase internal files left unchanged
  • ROADMAP.md current milestone phase numbers updated
  • STATE.md current position updated
  • Historical
    <details>
    blocks unchanged
  • Verification confirms no remaining collisions
  • Changes committed (if commit_docs enabled)
  • Idempotent: re-run on clean project exits with "no collisions" </success_criteria>
while IFS= read -r line; do name=$(echo "$line" | grep -oE 'Phase [0-9.]+: .+' | sed 's/Phase [0-9.]*: //' | sed 's/**$//' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-') if [ -n "$name" ]; then CHRONOLOGY="${CHRONOLOGY}${GLOBAL_SEQ} ${name}\n" GLOBAL_SEQ=$((GLOBAL_SEQ + 1)) fi done < <(grep -E 'Phase [0-9.]+:' .planning/ROADMAP.md)

小数形式的阶段(2.1、2.2)在其父阶段之后获得连续的整数编号。文档顺序决定编号序列。

显示:`Chronology ([N] phases): 00 → foundation, 01 → api-endpoints, ...`
</step>

<step name="map_directories_to_phases">

将时间线中的每个阶段名称与其现有目录匹配。在`active/`、`pending/`、`completed/`目录及扁平目录(回退)中搜索。

对于每个时间线条目`{seq} {name}`:
1. 在所有状态目录中查找短名称匹配`{name}`的目录
2. 如果存在多个匹配项,使用其数字前缀与原里程碑本地编号一致的目录
3. 构建映射关系:`STATE/OLD_DIR → STATE/NEW_PREFIX-SLUG`

从每个目录名称中去除数字前缀以获取短名称,与时间线中的名称进行比较。构建`MAPPING`为换行分隔的条目:`STATE/OLD_DIR → PADDED-SLUG`。

显示完整的映射表。
</step>

<step name="present_migration_plan">

显示重命名表:
Migration Plan: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
completed/01-foundation → completed/00-foundation completed/02-api-endpoints → completed/01-api-endpoints completed/01-setup → completed/02-setup ... active/01-current-work → active/15-current-work
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Total: [N] directories to rename

使用AskUserQuestion:
- header: "Migration"
- question: "Rename [N] directories to globally sequential numbers?"
- options:
  - "Proceed" — Execute all renames
  - "Cancel" — Abort migration

如果用户选择取消,输出“Migration cancelled.”并退出。
</step>

<step name="execute_renames">

采用两步法重命名,避免重命名过程中出现冲突(此模式源自`kata-move-phase`):

**第一步:**将所有目录重命名为临时名称:`mv OLD tmp-{seq}-{slug}`

**第二步:**将临时名称重命名为最终名称:`mv tmp-{seq}-{slug} {padded}-{slug}`

在第二步中,对于活跃/待处理阶段,还需重命名内部文件(`*-PLAN.md`、`*-RESEARCH.md`、`*-CONTEXT.md`、`*-SUMMARY.md`),将旧的阶段前缀替换为新的补零前缀:`sed "s/^[0-9.]*-/${PADDED}-/"`。

已完成阶段的内部文件保持不变。通配符查找(`*-PLAN.md`)可处理这些文件。

显示:
◆ Pass 1: Renamed [N] directories to temporary names ◆ Pass 2: Renamed [N] directories to final names ◆ Active/pending internal files updated: [count]
</step>

<step name="update_documentation">

**更新ROADMAP.md中当前里程碑的阶段编号:**

对于当前(未归档)的里程碑区域,将`#### Phase N:`标题更新为使用新的全局编号。将阶段名称与时间线匹配以确定正确的新编号。

**更新STATE.md中的当前位置:**

更新当前阶段引用为新的全局编号。查找引用活跃阶段的行并更新其编号。

**请勿修改ROADMAP.md中的历史`<details>`块**,它们是归档记录。`.planning/milestones/`中的里程碑归档文件为权威来源。

显示:
◆ Updated ROADMAP.md current milestone phase numbers ◆ Updated STATE.md current position
</step>

<step name="verify">

重新运行冲突检测:

```bash
DUPES=$(for state in active pending completed; do
  ls .planning/phases/${state}/ 2>/dev/null
done | grep -oE '^[0-9]+' | sort -n | uniq -d)

FLAT_DUPES=$(ls .planning/phases/ 2>/dev/null | grep -E '^[0-9]' | grep -oE '^[0-9]+' | sort -n | uniq -d)

ALL_DUPES=$(echo -e "${DUPES}\n${FLAT_DUPES}" | sort -nu | grep -v '^$')
如果无冲突:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Kata ► MIGRATION COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✓ [N] directories renamed to globally sequential numbers
✓ No duplicate prefixes remain
✓ ROADMAP.md and STATE.md updated
如果仍存在重复项:报告错误及详细信息。 </step>
<step name="commit">
检查规划配置:
bash
COMMIT_PLANNING_DOCS=$(cat .planning/config.json 2>/dev/null | grep -o '"commit_docs"[[:space:]]*:[[:space:]]*[^,}]*' | grep -o 'true\|false' || echo "true")
git check-ignore -q .planning 2>/dev/null && COMMIT_PLANNING_DOCS=false
**如果
COMMIT_PLANNING_DOCS=false
:**跳过git操作。
如果
COMMIT_PLANNING_DOCS=true
(默认设置):
bash
git add .planning/phases/ .planning/ROADMAP.md .planning/STATE.md
git commit -m "$(cat <<'EOF'
chore: migrate phase directories to globally sequential numbering
EOF
)"
</step> </process>
<anti_patterns>
  • 请勿重命名已完成阶段的内部文件(通配符查找可处理这些文件,降低风险)
  • 请勿修改ROADMAP.md中的历史
    <details>
    块(它们是归档记录)
  • 请勿不使用临时步骤就逐个重命名目录(会导致重命名过程中出现冲突)
  • 请勿请求逐个目录的确认(对于30+个阶段来说不切实际)
  • 请勿在无冲突的项目上运行迁移(检测到无冲突后提前退出) </anti_patterns>
<success_criteria>
  • 检测到所有状态目录中的重复阶段前缀
  • 按文档顺序从ROADMAP.md构建时间线
  • 显示包含完整重命名表的迁移计划
  • 在执行任何重命名前获得用户确认
  • 执行两步法重命名,无冲突
  • 活跃/待处理阶段的内部文件已重命名以匹配新前缀
  • 已完成阶段的内部文件保持不变
  • ROADMAP.md中当前里程碑的阶段编号已更新
  • STATE.md中的当前位置已更新
  • 历史
    <details>
    块未被修改
  • 验证确认无剩余冲突
  • 变更已提交(如果commit_docs已启用)
  • 幂等性:在无冲突的项目上重新运行时,输出“no collisions”并退出 </success_criteria>