Action-taking orchestrator for TCM-to-TCM migrations. Composes the five per-vendor references of tcm-case-management through the canonical field map in test-case-anatomy-reference to guarantee that no field is silently dropped across the transfer.
Distinct from test-case-quality-critic (audits quality; read-only) and tcm-case-management used directly (single-tool CRUD; not a cross-platform concern).
When invoked
Required inputs:
The agent refuses if dry-run is not acknowledged before live write.
Step 1 - Build the field map
Load test-case-anatomy-reference and derive the source-to-destination mapping from its Tracker-schema map section. Every canonical field (identifier, objective, preconditions, inputs, steps, expected results, postconditions, environment, traceability) must have either a mapped destination field or an explicit "no equivalent - discard / notes" entry. Emit the field map as the first output section before touching any API.
Example row for a TestRail-to-Qase migration:
| Canonical field | TestRail source | Qase destination | Notes |
|---|---|---|---|
| Objective | title | title | Direct |
| Preconditions | custom_preconds | preconditions | Direct |
| Steps | custom_steps_separated[].content | steps[].action | Reshape array |
| Expected results | custom_steps_separated[].expected | steps[].expected_result | Reshape array |
| Traceability | refs (free text) | links | Requires issue URL; warn if bare ID |
| Priority | priority_id (1-4 enum) | priority (1-3 enum, inverted) | Map: TR 1=Low/Qase 3=Low; TR 4=Critical/Qase 1=High |
Priority enum inversion is documented in tcm-case-management references/qase-io.md (opens in new window): Qase uses 1=High / 2=Medium / 3=Low, opposite to TestRail's 1=Low / 4=Critical ordering.
Step 2 - Export from source
Call the source TCM's paginated list endpoint with full pagination:
Write the raw export to a local JSON file: export-<source>-<project>-<timestamp>.json.
Step 3 - Transform
Apply the field map from Step 1 to every case. Use jq for reshaping:
jq '[.cases[] | {
title: .title,
preconditions: .custom_preconds,
steps: [.custom_steps_separated[] |
{action: .content, expected_result: .expected, data: ""}],
priority: (if .priority_id == 4 then 1
elif .priority_id == 3 then 2
else 3 end),
automation: 0
}]' export-testrail-AUTH-20260604.json > transform-qase-AUTH-20260604.jsonWrite the transformed payload to transform-<dest>-<project>-<timestamp>.json. Log any field that could not be mapped as a warning row in the migration report.
Step 4 - Dry-run validation
Before writing to the destination, validate each transformed case:
Emit a dry-run report listing: total cases, valid count, warning count, error count. Do not call any destination write endpoint until the QA lead reviews the dry-run report and confirms dry_run=false.
Step 5 - Live import
On confirmed dry_run=false, call the destination's create or bulk import endpoint for each case (or batch where the API supports it). Rate-throttle to 60 req/min across all five platforms to avoid 429s. Log each case: source ID, destination ID, status (created / skipped / error).
Output format
## TCM migration report - <source> -> <destination> - <project> - <date>
**Cases exported:** N
**Field map:** <attached below>
**Dry-run warnings:** N
**Dry-run errors:** N
**Live import verdict:** DRY-RUN ONLY / COMPLETED / PARTIAL
### Field map
| Canonical field | Source field | Destination field | Transform | Notes |
|---|---|---|---|---|
| ... | ... | ... | ... | ... |
### Dry-run findings
| Source ID | Title (truncated) | Issue |
|---|---|---|
| ... | ... | ... |
### Migration log (live only)
| Source ID | Destination ID | Status |
|---|---|---|
| ... | ... | ... |
### Warnings
- <field-level or case-level warnings>