Subchapter 27.33
references/phases/discover/discover.mdMarkdown18 KBView on GitHub
Lightweight orchestrator that delegates to domain-specific discoverers. Each sub-discovery file is self-contained — it scans for its own input, processes what it finds, and exits cleanly if nothing is relevant. Execute ALL steps in order. Do not skip or deviate.
gcp-resource-inventory.json + gcp-resource-clusters.json (if Terraform found); may also write ai-workload-profile.json when Vertex-strong (see discover-iac.md Step 7d)gcp-resource-inventory.json + gcp-resource-clusters.json from the user’s authenticated gcloud CLI (read-only, consent-gated); merges into the IaC inventory with drift when both runai-workload-profile.json when AI confidence ≥ 70% (may merge with an existing iac_vertex profile)billing-profile.json (if billing data found)openai-usage-profile.json from the OpenAI Admin API (read-only, consent-gated); fills ai-workload-profile.json → current_costs with real spend when that profile existsMultiple artifacts can be produced in a single run — they are not mutually exclusive.
Orientation (fresh runs only): When this is a new migration (no existing .migration/ runs, or the user chooses Fresh below), open your first response with this block — before any scanning output. Skip it entirely when resuming an existing run (the breadcrumb in the resume message covers position).
Here’s how this works. Six phases: I scan your Terraform, app code, or billing data; confirm a few assumptions with you; then design the AWS architecture, price it, and generate everything. Your part is small — most answers come from your own files; you’ll typically confirm one summary sheet and answer 2–7 questions. At the end you get a migrate-or-stay recommendation with costs, Terraform for the in-scope workloads, and step-by-step migration scripts. You can stop at any point — progress is saved and I’ll resume where you left off.
Do not pad it, restate it later, or block on it — continue directly into discovery in the same turn.
Check for existing .migration/ directory at the project root.
[A] Resume: Continue with [latest run][B] Fresh: Create new migration run[C] Cancel$MIGRATION_DIR to the selected run’s directory. Read its .phase-status.json and skip to the appropriate phase per the State Machine in SKILL.md.Create .migration/[MMDD-HHMM]/ directory (e.g., .migration/0226-1430/) using current timestamp (MMDD = month/day, HHMM = hour/minute). Set $MIGRATION_DIR to this new directory.
Create .migration/.gitignore file (if not already present) with exact content:
# Auto-generated migration state (temporary, do not commit)
*
!.gitignoreThis prevents accidental commits of migration artifacts.
Write .phase-status.json with exact schema:
{
"migration_id": "[MMDD-HHMM]",
"run_id": "[fresh random UUID from uuidgen]",
"owning_skill": "GCP_TO_AWS",
"last_updated": "[ISO 8601 timestamp]",
"current_phase": "discover",
"phases": {
"discover": "in_progress",
"clarify": "pending",
"design": "pending",
"estimate":
run_id is minted once here: run uuidgen (or an equivalent random UUID source) and write its output verbatim; never copy a value from an example or a previous run. It is never changed or reused across runs; unlike migration_id it carries no timestamp, so it uniquely identifies this run for telemetry and for the plugin-to-web handoff. owning_skill is always GCP_TO_AWS. If another skill invoked this run (llm-to-bedrock does, for Assess), also set initiated_by to that skill’s identifier, e.g. "initiated_by": "LLM_TO_BEDROCK".
Confirm both .migration/.gitignore and .phase-status.json exist before proceeding to Step 1.
Scan the project directory for each input type. Only load sub-discovery files when their input files are present.
1a. Check for Terraform files:
Glob for: **/*.tf, **/*.tfvars, **/*.tfstate, **/.terraform.lock.hcl
references/phases/discover/discover-iac.md1b. Check for source code / dependency manifests:
Glob for: **/*.py, **/*.js, **/*.ts, **/*.jsx, **/*.tsx, **/*.go, **/*.java, **/*.scala, **/*.kt, **/*.rs, **/requirements.txt, **/setup.py, **/pyproject.toml, **/Pipfile, **/package.json, **/go.mod, **/pom.xml, **/build.gradle
references/phases/discover/discover-app-code.md1c. Check for billing data:
Glob for: **/*billing*.csv, **/*billing*.json, **/*cost*.csv, **/*cost*.json, **/*usage*.csv, **/*usage*.json
Exclude .migration/** from these globs — migration run artifacts (e.g. openai-usage-profile.json, openai-capture/) must never be re-ingested as billing input.
references/phases/discover/discover-billing.md (billing is the primary source — needs full processing for the billing-only design path).discover-billing.md.Lightweight billing extraction (when IaC is the primary source):
When Terraform is present, billing data is supplementary — only service-level costs and AI signal detection are needed. Extract via a script to avoid reading the raw file into context.
Use Bash to read only the first line of the billing file to identify column headers.
Write a script to $MIGRATION_DIR/_extract_billing.py (or .js / shell — use whatever runtime is available) that:
vertex ai, ai platform, bigquery ml, generative ai, gemini, document ai, vision ai, speech-to-text, natural language, dialogflow, translationRun the script: try python3 _extract_billing.py first. If python3 is not found, try python _extract_billing.py. If neither is available, delete the script and fall back to loading references/phases/discover/discover-billing.md.
Write the script’s JSON output to $MIGRATION_DIR/billing-profile.json with this exact schema:
{
"summary": { "total_monthly_spend": 0.00 },
"services": [
{
"gcp_service": "Cloud Run",
"monthly_cost": 450.00,
"top_skus": [
{ "sku_description": "Cloud Run - CPU Allocation Time", "monthly_cost": 300.00 }
]
}
],
"ai_signals": { "detected": false }
}Services sorted descending by monthly_cost. Only include services with cost > 0.
Delete the script file after successful execution.
Critical: Do not Read the billing file with the Read tool. Do not load discover-billing.md or schema-discover-billing.md.
1d. Live discovery (gcloud CLI): Runs AFTER 1a–1c sub-discoveries complete, so its IaC merge sees their output.
$MIGRATION_DIR/live-capture/manifest.json already exists (a prior capture,
e.g. a resumed run) → Load references/phases/discover/discover-live.md and
execute from its Step 3 (parse the existing captures; skip consent/preflight/
capture — they already happened).references/phases/discover/discover-live.md. On no → continue
(do not re-ask this run).references/phases/discover/discover-live.md. On no → continue with whatever
1b/1c produced (billing-only design path remains the fallback).1e. OpenAI usage discovery (Admin API):
Runs AFTER 1a–1d complete, so its merge sees any ai-workload-profile.json.
Load references/phases/discover/discover-openai-api.md when EITHER condition
holds; otherwise skip silently:
ai-workload-profile.json exists with summary.ai_source of openai or
bothThe sub-file’s Step 0 consent gate is the single consent point for this source
— do not pre-ask here (loading the file only presents the gate; declining [B]
exits cleanly and must not be re-asked this run). If
$MIGRATION_DIR/openai-capture/manifest.json already exists (a resumed run),
execute from its Step 3 (parse the existing captures; consent and capture
already happened). This source supplements billing files — both may run in the
same run.
After all loaded sub-discoveries complete, check what artifacts were produced in $MIGRATION_DIR/:
gcp-resource-inventory.json — IaC discovery succeededgcp-resource-clusters.json — IaC discovery produced clustersai-workload-profile.json — App code discovery (confidence ≥ 70%) and/or IaC Vertex-strong inference (discover-iac.md Step 7d)billing-profile.json — Billing data parsedopenai-usage-profile.json — OpenAI Admin API usage captureddiscover-iac.md ran -> require gcp-resource-inventory.json and gcp-resource-clusters.jsondiscover-app-code.md ran:
ai-workload-profile.json exists -> allow completion (app-code route may produce no AI profile).ai-workload-profile.json exists with metadata.profile_source = "iac_vertex" -> allow completion (IaC-inferred profile retained).ai-workload-profile.json.discover-live.md ran AND capture happened ($MIGRATION_DIR/live-capture/manifest.json exists) -> require gcp-resource-inventory.json and gcp-resource-clusters.json, with live_metadata present in the inventory. (If the user declined consent or gcloud was unavailable, the sub-file exited cleanly — no artifact required.)discover-billing.md ran OR lightweight billing extraction ran -> require billing-profile.jsondiscover-openai-api.md ran AND capture happened ($MIGRATION_DIR/openai-capture/manifest.json exists) -> require openai-usage-profile.json; when ai-workload-profile.json also exists, require metadata.sources_analyzed.openai_usage_api = true in it. (If the user declined consent or had no Admin key, the sub-file exited cleanly — no artifact required.)Load and execute references/phases/discover/discover-preview.md to compute the migration preview. This produces migration-preview.json and the preview chat block. Skip only if Step 2 found no artifacts (already STOPped).
Load shared/handoff-gates.md. Re-read from disk every artifact below before checking.
Re-entry guard: If preferences.json exists and phases.clarify is "completed": STOP unless the user explicitly confirms re-running Discover. Emit:
GATE_FAIL | phase=discover | field=preferences.json | reason=stale_downstreamChecks (all must PASS):
gcp-resource-inventory.json, ai-workload-profile.json, or billing-profile.json). openai-usage-profile.json does NOT satisfy this check on its own — it is a supplement (spend and volumes, no integration or capability detail; see SKILL.md Prerequisites) and cannot anchor a run by itself.migration-preview.json exists with complexity_signal set.On any FAIL: Emit GATE_FAIL | phase=discover | field=<path> | reason=<missing|invalid|stale_downstream>. Do NOT modify artifacts to pass the gate. Do NOT update .phase-status.json. Tell the user which sub-discovery to re-run.
On PASS: Emit HANDOFF_OK | phase=discover | artifacts=<comma-separated list of files verified>.
Only after HANDOFF_OK. In the same turn as the output message below, use the Phase Status Update Protocol (read-merge-write) to update .phase-status.json:
phases.discover to "completed"current_phase to "clarify"Output to user — build message from whichever artifacts exist:
gcp-resource-inventory.json exists: “Discovered X total resources across Y clusters.”live_metadata.unmapped_asset_types is non-empty: “Skipped M unmapped asset types (top: X, Y, Z) — full list in live_metadata.”ai-workload-profile.json exists: “Detected AI workloads (source: [ai_source]).”billing-profile.json exists: “Parsed billing data ($Z/month across N services).”openai-usage-profile.json exists: “Captured OpenAI usage via Admin API ($X/month across M models).” Plus, when metadata.capture_warnings is non-empty: “W usage endpoints failed — affected categories are unknown, not zero (see profile metadata).”Append the preview block from Step 3 to the output message below.
Format: “Phase 1 of 6 complete (Discover). [artifact summaries joined by space] [preview block from discover-preview.md Step 6]”
Then: “Remaining: Clarify → Design → Estimate → Generate (+ optional Feedback). Next required step: Phase 2 — Clarify. Load references/phases/clarify/clarify.md now. Do not load Design, Estimate, or Generate until Clarify completes and .phase-status.json marks phases.clarify as completed.”
Breadcrumbs are emitted only after outer-run HANDOFF_OK — never on GATE_FAIL, never from inner workshop reprices.
Discover phase writes files to $MIGRATION_DIR/. Possible outputs (depending on what sub-discoverers find):
gcp-resource-inventory.json — from discover-iac.mdgcp-resource-clusters.json — from discover-iac.mdai-workload-profile.json — from discover-app-code.md (confidence ≥ 70%, optionally merged) and/or discover-iac.md Step 7d (Vertex-strong IaC only)billing-profile.json — from discover-billing.mdopenai-usage-profile.json — from discover-openai-api.md (plus openai-capture/ raw captures inside the gitignored run directory; the transient .openai-admin-env key file is deleted by that sub-file’s Step 4 and is never a phase output)migration-preview.json — from discover-preview.md (always written when any artifact exists)No other files must be created:
All user communication via output messages only.
.migration directory: Create it (Step 0).migration/.gitignore: Create it automatically (Step 0) — prevents accidental commitsThis phase covers Discover & Analysis ONLY.
FORBIDDEN — Do NOT include ANY of:
Your ONLY job: Inventory what exists in GCP. Nothing else.