docs(agents): add a tenant-migration skill for moving meshTenants between platforms - #260
Open
grubmeshi wants to merge 3 commits into
Open
docs(agents): add a tenant-migration skill for moving meshTenants between platforms#260grubmeshi wants to merge 3 commits into
grubmeshi wants to merge 3 commits into
Conversation
…m migration Raw capture of a platform engineering session that moved nine meshTenants off a hand-built custom STACKIT platform onto one deployed by the landing zone reference architecture, without destroying the projects behind them. This is the unrefined material, written down while it is still fresh: - skills/tenant-migration/SKILL.md — first draft of the reusable skill - references/tenant-migration-runbook.md — the per-tenant procedure - references/building-block-state-doctoring.md — reaching and rewriting a running block's Terraform state - references/meshstack-api-cookbook.md — endpoints, media types, validation rules and the traps that read as empty results - references/tenant-migration-case-study.md — the worked migration, including both failures and what they taught The next commit turns this into a skill that reads like an instruction rather than a session log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The raw capture read as a session log: the SKILL.md restated the runbook, the method was buried below the narrative, and the tool-like material was hard to reach from the place an agent starts. Restructure it as a decision layer over the references: - SKILL.md now opens with the reason adoption is the only path, the two rules that prevent an unrecoverable mistake, a six-step workflow, the tenant class table, and a per-tenant loop that gives the actual purge, lookup and state-push commands instead of describing them. Detail that belongs to one step moved into the reference it belongs to. - The risk method — throwaway plus snapshot, assert on the plan, prefer in-place over replacement, weigh the blast radius — is a named section with an executable plan gate, so it cannot be skipped by an operator who is tired. - The runbook leads with the procedure and closes with the three guards that rule out an import, since the reader arriving from SKILL.md already knows why. - State doctoring leads with the adopt harness, the recommended path, and spells out both harness setups as commands. - The cookbook states the `application/vnd.meshcloud.api.` prefix the media type table only implied, and shows one complete request. - The case study stays as evidence and is labelled as such. - AGENTS.md points at the skill, matching how it indexes `module` and `e2e-test`. Every technical claim is unchanged; the description field now names the concrete situation (`CustomPlatformImportUnsupportedException`, `RequiresReplace` on `spec.platform_ref`) so only an agent facing this problem loads the skill. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Scorecard CheckNo module changes detected relative to |
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
The cookbook told readers to look at `spec.source.terraform.*` on a building block definition version. The field is `spec.implementation.terraform.*`, and the difference is not benign: `spec.source` returns null, which reads as "this definition has no source" rather than as a wrong query. Found by re-running the audit against a different set of definitions, where every source came back empty until the field name was corrected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
tenant-migrationskill and its reference material, capturing how to move meshTenants between meshPlatforms without destroying the cloud resources behind them.Why
Moving a meshTenant to a different meshPlatform looks like an import and is not one. On a custom platform whose landing zone carries a mandatory building block definition, both routes are closed:
spec.localIdwithCustomPlatformImportUnsupportedException, because the building block that is supposed to create the tenant would have to run the equivalent of aterraform importto construct its initial state.spec.platform_refisRequiresReplace, replacing a meshTenant destroys its building block, and that block's teardown destroys the live cloud resource.The way through is adoption — create the tenant plainly, then write the link to the existing resource into the new block's Terraform state before its runner starts. That is not obvious, it is easy to get wrong in ways that cost live resources, and nothing in this repo wrote it down.
What this is based on
A migration of nine meshTenants off a hand-built custom STACKIT platform onto one deployed by the STACKIT landing zone reference architecture, on a demo meshStack instance. Seven tenants migrated keeping their original project ids, two were deleted as never replicated, all seven building blocks ended
SUCCEEDED, and no duplicate project was created at any point.Every claim in these files was verified against the live instance and the STACKIT API during that work. The failures are included, because they are more instructive than the procedure:
labels = nullplans a label removal the cloud provider ignores, and the provider then fails the apply withProvider produced inconsistent result after apply. A protected label cannot be removed through the labels endpoint at all. Lying about labels in the seed does not help, because the runner refreshes before it plans.platform_tenant_id, which breaks every downstream consumer of that attribute.Contents
.agents/skills/tenant-migration/SKILL.md.agents/references/tenant-migration-runbook.md.agents/references/building-block-state-doctoring.md.agents/references/meshstack-api-cookbook.md.agents/references/tenant-migration-case-study.mdTwo findings worth reading even if you never migrate a tenant
UNPUBLISHEDis unreachable for a platform that has ever been published. Three API guards combine so that unpublishing requiresrestriction = PRIVATE, andPRIVATEis permanently forbidden oncewasOncePublishedis true. Deactivating a platform's landing zones is the effective retirement, since a meshTenant cannot exist without one. Deleting the platform burns its identifier permanently even though the delete is soft.Grepping a repository cannot tell you whether a
kit/-style module is dead. A building block definition reaches code by Git repository path, so the answer lives on the instance. Read sources per version, not per definition — one definition observed here pointed at three different paths across v1–v37 — and check which versions active blocks are actually pinned to.Commits
Deliberately two, so the raw capture stays reviewable separately from the editing:
Review notes
Documentation only — no module, provider or Terraform changes, so nothing here affects any deployment.
.claude/is a symlink to.agents/, so both tool families pick these up.🤖 Generated with Claude Code