fix(backup): cover the agentic-teams resources — closes the data-loss gap

The audit found that none of the new resources were in BACKUP_KINDS, so
git-backup never captured them and a restore would lose every epic, roadmap
node, repo and forge registration. Closes 135/165.

Backed up: gitprovider, repo, epic, epictask — configuration and the vision
layer. NOT tasks: a work item carries in-flight state (lifecycle position,
verdicts, PR links) and restoring a stale one from git would resurrect work that
has since moved on. That is the same reasoning that keeps McpInstance out of the
backup, and there is a test asserting it stays out.

Two properties the tests pin, because both are the kind of thing that fails
silently:

- **Credentials serialize as a REFERENCE, never a value.** The backup repo is a
  plaintext git checkout; emitting a resolved token would export every forge
  credential to disk in cleartext. credSecretId/credSecretKey are internal
  fields and become `credRef: {name, key}`; restore re-resolves against whatever
  the secret backend holds now.
- **Relations serialize by name, not foreign key.** A restore into a different
  database has different cuids, so a backed-up projectId would dangle.

Restore ordering follows dependencies: a forge before the repos that reference
it, an epic before its roadmap nodes.

Two deliberate refusals on the restore path: an Epic's `status` is never written
by a restore, so a stale backup cannot silently mark it delivered — that
terminal state is only reachable through setStatus and its rules; and a
GitProvider is not probed on restore, because the forge may legitimately be
unreachable while a backup replays and failing the whole restore for that is
worse than a row that needs a later `probe`.

The pre-existing APPLY_ORDER length guard caught this change, which is exactly
what it is for; updated 9 → 13 and tied it to BACKUP_KINDS.length so the two
cannot drift apart again.

Also marks 153 done — `mcpctl tasks accept/reject` shipped with the CLI work; the
generated graph had it blocked behind the git-provider merge, but the gate itself
does not need it.

Local: build clean, workspace 2463 passed (+6), lint unchanged at 794 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4wNHWf7xSwnZCWpJcyv9p
This commit is contained in:
Michal
2026-08-09 20:44:20 +01:00
parent 300c42b404
commit 5f5efd1144
8 changed files with 299 additions and 14 deletions

View File

@@ -2846,9 +2846,9 @@
"131",
"133"
],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-08T08:55:58.627Z"
"updatedAt": "2026-08-09T19:44:20.519Z"
},
{
"id": "136",
@@ -3104,9 +3104,9 @@
"131",
"149"
],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-08T08:55:58.627Z"
"updatedAt": "2026-08-09T19:44:20.538Z"
},
{
"id": "154",
@@ -3286,9 +3286,9 @@
"dependencies": [
"135"
],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-09T19:36:34.052Z"
"updatedAt": "2026-08-09T19:44:20.531Z"
},
{
"id": "166",
@@ -3405,12 +3405,12 @@
],
"metadata": {
"version": "1.0.0",
"lastModified": "2026-08-09T18:56:11.750Z",
"taskCount": 163,
"completedCount": 124,
"lastModified": "2026-08-09T19:44:20.538Z",
"taskCount": 173,
"completedCount": 127,
"tags": [
"master"
]
}
}
}
}