{
  "$schema": "https://stravica.ai/schemas/runbook/1.0",
  "id": "smarthome01-v1-to-v2",
  "target": "smarthome01",
  "description": "Migrate smarthome01 from v1 fork to v2. upstream-triage cron entry is deliberately dropped (operator decision 2026-05-17).",
  "version": "1.0.0",
  "inspectionRef": "inspection-smarthome01.json",
  "steps": [
    {
      "id": "step-1",
      "intent": "snapshot-v1-fork",
      "description": "Preserve v1 fork.",
      "params": { "snapshotSuffix": "pre-v2-{{inspectedAt|date}}" },
      "preconditions": [
        { "assert": "workingTreeClean" },
        { "assert": "onBranch", "value": "main" }
      ],
      "expect": { "produces": ["{{daveRoot}}-pre-v2-{{inspectedAt|date}}/"] },
      "rollback": { "trigger": "v2 instance fails 24h soak", "action": "restore-from-snapshot" }
    },
    {
      "id": "step-2",
      "intent": "drop-cron-entry",
      "description": "Remove upstream-triage cron entry (operator decision: not carried forward to v2).",
      "params": { "matchCommand": "upstream-triage" },
      "preconditions": [
        { "assert": "cronEntryExists", "value": "upstream-triage" }
      ],
      "expect": { "cronEntryAbsent": "upstream-triage" },
      "rollback": { "trigger": "upstream-triage still required", "action": "restore-cron-entry" },
      "notes": "Operator confirmed drop on 2026-05-17. upstream-triage is superseded by Dex-side processing."
    },
    {
      "id": "step-3",
      "intent": "run-migrate-to-v2",
      "description": "Run migrate-to-v2 CLI.",
      "params": {
        "source": "{{daveRoot}}",
        "target": "{{daveRoot}}-v2",
        "dryRun": false
      },
      "preconditions": [
        { "assert": "snapshotExists" },
        { "assert": "nodeVersion", "value": ">=24" },
        { "assert": "pnpmOnPath" }
      ],
      "expect": { "produces": ["{{daveRoot}}-v2/package.json", "{{daveRoot}}-v2/operator/"] },
      "rollback": { "trigger": "migrate-to-v2 exits non-zero", "action": "restore-from-snapshot" }
    },
    {
      "id": "step-4",
      "intent": "rewrite-crontab",
      "description": "Update the 3 remaining cron entries (distill, wsd-ingest, sync) to use the v2 instance path.",
      "params": {
        "entries": [
          { "matchCommand": "distill", "newWorkingDirectory": "{{daveRoot}}-v2" },
          { "matchCommand": "wsd-ingest", "newWorkingDirectory": "{{daveRoot}}-v2" },
          { "matchCommand": "sync", "newWorkingDirectory": "{{daveRoot}}-v2" }
        ]
      },
      "preconditions": [
        { "assert": "cronEntryExists", "value": "distill" },
        { "assert": "cronEntryExists", "value": "wsd-ingest" },
        { "assert": "cronEntryExists", "value": "sync" }
      ],
      "expect": { "cronEntriesUpdated": 3 }
    },
    {
      "id": "step-5",
      "intent": "verify-sync-continuity",
      "description": "Verify sync reaches the dropbox share from the v2 instance.",
      "params": { "daveRoot": "{{daveRoot}}-v2" },
      "preconditions": [
        { "assert": "mountExists", "value": "/mnt/share/dropbox" }
      ],
      "expect": { "syncExitCode": 0 }
    },
    {
      "id": "step-6",
      "intent": "verify-boot-health",
      "description": "Verify pa status exits 0.",
      "params": { "daveRoot": "{{daveRoot}}-v2" },
      "expect": { "exitCode": 0 }
    },
    {
      "id": "step-7",
      "intent": "define-roster-entry",
      "description": "Register smarthome01 in operator roster.",
      "params": { "hostId": "smarthome01", "layoutVersion": "v2", "daveRoot": "{{daveRoot}}-v2" }
    }
  ]
}
