SuperAPI AI Directory

cheat-migrate

Office & productivity

View repository

Updated 10-16 08:54

About this skill

/cheat-migrate — Schema version migration

Upgrade the user's .cheat-state.json from the old schema_version to the LATEST_SCHEMA。


Overview

[用户:迁移 / 或 SessionStart 提示后用户跑]
  ↓
[Phase 0: 读 .cheat-state.json + migrations/registry.md → 确定迁移链]
  ↓
[Phase 1: dry-run(默认)展示迁移计划,等用户确认]
  ↓
[Phase 2: 备份 .cheat-state.json → .cheat-state.json.backup-<timestamp>]
  ↓
[Phase 3: 按顺序对每个 step 应用对应迁移文件的 HOW 段]
  ↓
[Phase 4: 验证升级后 state 文件能被解析 + schema_version 已更新]
  ↓
[Phase 5: 报告 + 提示如有备份需要清理]

Constants

  • REGISTRY_PATH = ${SKILL_DIR}/../../migrations/registry.md currently expected by cheat-on-content — single source of truth for the version chain
  • MIGRATIONS_DIR = ${SKILL_DIR}/../../migrations/ — migration file directory
  • DRY_RUN_BY_DEFAULT = true — on the first run, show the plan without directly modifying files
  • BACKUP_BEFORE_WRITE = true — a backup is required before writing; backup files are kept until the next successful init / manual cleanup by the user
  • STOP_ON_STEP_FAILURE = true — if any step fails → stop at the intermediate version, do not advance, do not roll back

💡 Override at invocation:/cheat-migrate — dry-run: false execute directly / /cheat-migrate — to: 1.2 upgrade only to the specified version


Inputs

Required Source
.cheat-state.json User project root
migrations/registry.md LATEST_SCHEMA + version chain table
migrations/<from>-to-<to>.md Specific migration instructions for each step

Workflow

Phase 0: Determine the migration chain

  1. Read .cheat-state.json → parse current_version = state.schema_version
  2. Read migrations/registry.md → parse LATEST_SCHEMA field (line:LATEST_SCHEMA = "X.Y")
  3. Parse the args.to override (if any); otherwise target = LATEST_SCHEMA
  4. Parse the args.from override (rare scenario: the user's state file schema field is broken, forcing the starting point to be specified)
  5. Status determination:
    • current_version == target → output "✅ state is already {target}, no migration needed" → exit
    • current_version > target(for example, the user ran a dev version and then switched back to release) → error "cannot downgrade, please adjust manually or re-init"
    • current_version < target → continue, look up the migration chain from the registry
  6. Compute chain = [(from, to, file), ...]from the registry's "version chain" table, linking current → target in order

If a step is missing from the registry (for example, current_version is not in the table) → error and show "currently known versions: [1.0, 1.1, ...]" so the user can check.

Phase 1: dry-run

Output the migration plan:

📋 迁移计划

当前版本: 1.0
目标版本: 1.2
将按顺序跑 2 步:

  [1/2] 1.0 → 1.1(MINOR)
       新增字段:typical_duration_seconds, target_publish_cadence_days, ...(共 12 字段)
       删除字段:mode, prediction_complexity, bucket_scheme
       详见: migrations/1.0-to-1.1.md

  [2/2] 1.1 → 1.2(MINOR)
       新增字段:[...]
       详见: migrations/1.1-to-1.2.md

⚠️ 备份位置: .cheat-state.json.backup-<timestamp>

继续吗?回 yes 执行 / no 退出 / dry-run-detail 看每步具体改什么。

If args["dry-run"] == false or the user replies yes → proceed to Phase 2.

Phase 2: Backup

cp .cheat-state.json .cheat-state.json.backup-$(date +%s)

Output: "📦 Backed up to .cheat-state.json.backup-1714838400"

Phase 3: Apply each step in order

For each (from, to, file) in the chain:

  1. Output "→ [N/M] applying {file}..."
  2. Read migrations/<file> → find the ## HOW (Claude steps for /cheat-migrate) section
  3. Execute the natural-language steps in the section one by one— this is the key: the migration is run by Claude reading markdown, not by a python script
  4. After each step completes:
    • Update state.schema_version = to in memory
    • Atomic writeto disk (write .tmp → rename)
  5. If a step fails:
    • Output "❌ {file} step N failed: {error}"
    • Do not advance, do not roll back (state has stopped at the intermediate version of the last successful step)
    • Prompt: "Stopped at schema_version: {last_success_version}. After fixing, rerunning /cheat-migrate will continue from here"
    • Exit

Phase 4: Verification

After upgrading:

  1. Read .cheat-state.json → parse → should succeed
  2. Check schema_version == target
  3. Check that all "required fields" are non-missing (refer to shared-references/state-management.md complete schema)
  4. Failure → error "Migration completed but validation failed: {detail}. The state file may be inconsistent—check the backup for recovery"

Phase 5: Report

✅ 迁移完成

  从: 1.0
  到: 1.2
  应用步骤: 2

state 文件现在含 X 字段,全部通过验证。

📦 备份保留:.cheat-state.json.backup-1714838400
   (确认一切正常后可手动 rm;下次成功 /cheat-init 也会清理过期备份)

下一步建议:
  - 跑 /cheat-status 确认看板正常
  - 如有 hooks 重装需求,跑 bash <skill_repo>/install.sh --reinstall-hooks

Key Rules

  1. Idempotent: re-running on an already-upgraded state should exit immediately with "no migration needed",withoutre-applying steps. Achieved by comparing current_version == target implementation
  2. No version skipping: 1.0 → 1.3 must follow the order 1.0→1.1→1.2→1.3, with each step independently recoverable. A "combined migration that directly upgrades 1.0 → 1.3" is not allowed
  3. No silent compatibility: if the state file's schema_version is unrecognized → explicitly error "unknown version X, most recent known version Y", do not pretend it can continue
  4. Failure stops in place: when step N fails, schema_version stays at the last successfully completed version N-1, and does not roll back to before the migration. Re-running can continue from the breakpoint
  5. Backup is a hard constraint: a backup must exist before writing. Even if the user runs --dry-run: false, the backup action is still performed
  6. Do not touch predictions / rubric / videos: only modify .cheat-state.json. Other user data is the responsibility of their respective skills; the migration skill does not touch them
  7. MAJOR vs MINOR transparent: dry-run output must mark (MAJOR) / (MINOR). For MAJOR, additionally warn "old skills reading with old fields will have problems; after migration you cannot roll back to the old skill version"

Refusals

  • "Skip dry-run, overwrite my state immediately" → allowed(--dry-run: false), but the backup is still enforced
  • "My state is corrupted / the schema_version field is gone, can you guess a version to run" → allowed to specify --from: 1.0, but warn "a guess-based migration may cause field misalignment"
  • "Downgrade to an old version (current > target)" → rejected. Schema evolution is one-way. To downgrade, manually cp a historical git snapshot
  • "Merge multiple migration steps into one atomic" → rejected. Each step being independently recoverable is the core of the design
  • "Call migrate midway through running cheat-bump / cheat-predict" → rejected. Wait for the other skill to finish before running, to avoid corrupting the in_progress_session state

Integration

  • Upstream: SessionStart hook detects state.schema_version != LATEST_SCHEMA → outputs a red warning + suggests running /cheat-migrate
  • Upstream (manual): after the user does git pull to get a new version and sees BREAKING marked in the CHANGELOG → proactively run
  • Downstream: after it finishes, all other skills reading state can get the latest fields
  • With cheat-init: when init writes a new state it directly uses LATEST_SCHEMA and does not need to go through migrate
  • With install.sh --reinstall-hooks: migrationdoes notreinstall the hook script (the hook script belongs to the skill package code, not the user state). These two things are decoupled

State field read/write

This skill writes:

  • schema_version(updated after each step succeeds)

This skill reads:

  • all existing fields (depending on the HOW steps of the specific migration file)

This skill neverwrites:

  • calibration_samples / pending_retros / shoots and other business state (these are the responsibility of other skills)
  • Exception: the migration file explicitly says "when deriving new field values, you need to scan predictions/ to compute baseline_plays"; that is initializing a new field, not modifying an old field

Examples

Example 1: A user upgrades from v0.1.0 to v0.2.0 (assuming 0.2 introduces schema 1.2)

用户:迁移
Claude: [跑 cheat-migrate]
  Phase 0: current=1.1, target=1.2, chain=[(1.1, 1.2)]
  Phase 1: dry-run 输出计划
  用户: yes
  Phase 2: 备份
  Phase 3: 应用 1.1-to-1.2.md(MINOR:新增 platform_metrics_url 等字段)
  Phase 4: 验证 OK
  Phase 5: 报告 ✅

Example 2: The user skipped multiple versions

用户:我从 v0.1.0 升到 v0.5.0,state 还是 1.0
Claude: [跑 cheat-migrate]
  Phase 0: current=1.0, target=1.4 (LATEST), chain=[(1.0, 1.1), (1.1, 1.2), (1.2, 1.3), (1.3, 1.4)]
  Phase 1: dry-run 输出 4 步计划
  ...

Example 3: The migration fails midway

Phase 3:
  → [1/4] 应用 1.0-to-1.1.md ✓
  → [2/4] 应用 1.1-to-1.2.md ✓
  → [3/4] 应用 1.2-to-1.3.md... ❌ 失败:用户 baseline_plays 字段含非数字值,无法转 int
  
state 已停在 schema_version: 1.2。
修复 .cheat-state.json 后重跑 /cheat-migrate 会从 1.2 → 1.3 继续。