# @stravica-ai/engineering-pa-runbook

Migration runbook JSON Schema, reference runbooks, and structural validator.

## What the runbook schema is for

A migration runbook is a structured, machine-readable document that describes the sequence of steps needed to migrate a Dave PA instance from v1 (fork layout) to v2 (operator-repo layout). Each step has a declared `intent`, optional `params`, optional `preconditions`, expected outcomes (`expect`), and a `rollback` spec.

Runbooks are designed to be executed by an autonomous agent that reads `inspection.json` (output of `pa migrate-inspect`), substitutes template variables, and dispatches each step to host-specific actuators.

## Intent vocabulary

| Intent | Description |
|---|---|
| `snapshot-v1-fork` | Preserve the v1 fork as a rollback point (git tag or directory copy) before migration begins |
| `run-migrate-to-v2` | Invoke the `migrate-to-v2` CLI to produce the v2 operator-repo layout from the v1 fork |
| `rewrite-crontab` | Rewrite one or more crontab entries to use the new v2 instance working directory |
| `drop-cron-entry` | Remove a specific named cron entry (e.g. `upstream-triage`) that is not carried forward to v2 |
| `update-host-service` | Update a service/daemon entry — launchd plist on macOS, systemd unit on Linux |
| `verify-sync-continuity` | Verify sync jobs run and reach their destinations (e.g. NFS/SMB mount reachable, sync exits 0) |
| `verify-boot-health` | Run `pa status` in the v2 instance and assert exit 0 |
| `define-roster-entry` | Add or update a host entry in the operator roster, recording layout version and daveRoot |

## The inspect → runbook → execute flow

```
1. pa migrate-inspect --out inspection-<host>.json
       Produces a structured snapshot of host state: layout version, runtimes,
       crontab entries, launchd plists, mounts, env vars, extensions.

2. Agent reads inspection-<host>.json and selects the appropriate reference
   runbook from reference/ (or a custom runbook), substituting {{daveRoot}}
   and {{inspectedAt}} template variables.

3. Agent executes each step sequentially:
       - Evaluates preconditions against inspection data or live host state
       - Dispatches the intent to a host-specific actuator
       - Checks expect outcomes
       - On failure: triggers rollback action

4. On completion: define-roster-entry registers the host as v2.
```

## Executing-agent contract

When an agent interprets a runbook step, it maps `intent` to host-specific commands as follows:

| Intent | macOS | Linux |
|---|---|---|
| `snapshot-v1-fork` | `git tag` or `cp -r` | Same |
| `run-migrate-to-v2` | `node migrate-to-v2/cli.mjs` | Same |
| `rewrite-crontab` | `crontab -l` + edit + `crontab -` | Same |
| `drop-cron-entry` | `crontab -l` + filter + `crontab -` | Same |
| `update-host-service` | Edit `~/Library/LaunchAgents/<label>.plist`, `launchctl unload/load` | Edit `/etc/systemd/system/<unit>.service`, `systemctl daemon-reload && restart` |
| `verify-sync-continuity` | Check mount reachable, run sync script | Same |
| `verify-boot-health` | `pa status` in `daveRoot` | Same |
| `define-roster-entry` | Write to `operator/roster.json` | Same |

The agent reads the `host.os` field from `inspection.json` to determine which platform-specific path to take for `update-host-service`. All other intents are platform-neutral.

## Schema reference

- `schema/runbook.schema.json` — JSON Schema 2020-12 for runbook documents
- `schema/inspection.schema.json` — JSON Schema 2020-12 for inspection.json output

## How to validate a runbook

```js
import { validate } from '@stravica-ai/engineering-pa-runbook/src/validator.mjs';
import { readFileSync } from 'node:fs';

const schema = JSON.parse(readFileSync('./schema/runbook.schema.json', 'utf8'));
const runbook = JSON.parse(readFileSync('./reference/hq-dave.runbook.json', 'utf8'));
const result = validate(schema, runbook);
if (!result.valid) {
  console.error(result.errors);
}
```

Or from the CLI:

```bash
node -e "
import('./src/validator.mjs').then(async ({validate}) => {
  const {readFile} = await import('node:fs/promises');
  const schema = JSON.parse(await readFile('./schema/runbook.schema.json','utf8'));
  const rb = JSON.parse(await readFile('./reference/hq-dave.runbook.json','utf8'));
  const r = validate(schema, rb);
  console.log(r.valid ? 'VALID' : 'INVALID: ' + r.errors.join('; '));
});
"
```

## Tests

```bash
pnpm --filter @stravica-ai/engineering-pa-runbook test
# or
node --test 'test/**/*.test.mjs'
```

- `test/validator.test.mjs` — unit tests for the structural validator
- `test/runbooks.test.mjs` — validates all 3 reference runbooks against the schema
