diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/SKILL.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/SKILL.md index 204ab66b..63ec2fea 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/SKILL.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/SKILL.md @@ -81,16 +81,18 @@ If no Terraform is found (even when app code or billing files exist — they can This is the execution controller. After completing each phase, consult this table to determine the next action. -| Current State | Condition | Next Action | -| ------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `discover` | `phases.discover != "completed"` | Load `references/phases/discover/discover.md` | -| `clarify` | `phases.discover == "completed"` AND `phases.clarify != "completed"` | Load `references/phases/clarify/clarify.md` | -| `design` | `phases.clarify == "completed"` AND `phases.design != "completed"` | Load `references/phases/design/design.md` | -| `estimate` | `phases.design == "completed"` AND `phases.estimate != "completed"` | Load `references/phases/estimate/estimate.md` | -| `workshop` | `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop` is `"pending"` or `"in_progress"` | **Do not recompute Estimate.** If `workshop` is `"pending"`, present the post-Estimate workshop offer from `estimate.md`. If `"in_progress"`, load `references/phases/workshop/workshop.md`. | -| `generate` | `phases.estimate == "completed"` AND `phases.workshop == "completed"` AND `phases.generate != "completed"` | Load `references/phases/generate/generate.md` (workshop resolved — entered+exited or declined) | -| `complete` | `phases.generate == "completed"` AND `phases.feedback == "pending"` | Set `phases.feedback` to `"completed"` (user had two chances), then migration complete | -| `complete` | `phases.generate == "completed"` AND `phases.feedback == "completed"` | Migration planning complete | +| Current State | Condition | Next Action | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `discover` | `phases.discover != "completed"` | Load `references/phases/discover/discover.md` | +| `clarify` | `phases.discover == "completed"` AND `phases.clarify != "completed"` | Load `references/phases/clarify/clarify.md` | +| `design` | `phases.clarify == "completed"` AND `phases.design != "completed"` | Load `references/phases/design/design.md` | +| `estimate` | `phases.design == "completed"` AND `phases.estimate != "completed"` | Load `references/phases/estimate/estimate.md` | +| `workshop` | `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop` is `"pending"` or `"in_progress"` | **Do not recompute Estimate.** If `workshop` is `"pending"`, present the **Decision gate** from `estimate.md` (done for now / what-ifs / generate). If `"in_progress"`, load `references/phases/workshop/workshop.md`. | +| `generate` | `phases.estimate == "completed"` AND `phases.workshop == "completed"` AND `phases.generate != "completed"` AND (`run_mode == "decide_and_execute"` OR the user's current-turn message is an explicit request to produce Terraform/migration scripts) | Load `references/phases/generate/generate.md` (workshop resolved — entered+exited or declined; see **Generate is opt-in** below) | +| decide-complete | `current_phase == "complete"` AND `run_mode == "decide"` AND `phases.generate == "pending"` | Decision pack done; Generate available on request. On resume: "Your decision pack is complete. Generate Terraform and migration scripts now? [Yes] [Stay decision-only]" — Yes sets `run_mode: "decide_and_execute"`, `current_phase: "generate"`, loads `generate.md`. Never re-run Estimate. | +| legacy-generate | `current_phase == "generate"` AND `run_mode` is absent AND `phases.generate != "completed"` | **Back-compat** for runs started before Generate was opt-in (or interrupted after an old auto-advance set `current_phase: generate` with no `run_mode`). Do **not** auto-load `generate.md` and do **not** hang with no matching row — present the same resume offer as decide-complete. Yes → set `run_mode: "decide_and_execute"` and continue Generate; No → set `run_mode: "decide"`, `current_phase: "complete"`, leave `generate` pending. | +| `complete` | `phases.generate == "completed"` AND `phases.feedback == "pending"` | Set `phases.feedback` to `"completed"` (user had two chances), then migration complete | +| `complete` | `phases.generate == "completed"` AND `phases.feedback == "completed"` | Migration planning complete | **How to determine current state (deterministic):** @@ -100,12 +102,15 @@ This is the execution controller. After completing each phase, consult this tabl `"in_progress"`, follow the `workshop` row above — **never** re-run Estimate on a plain "continue my migration" / resume. Explicit "what if" / "reprice" / "workshop mode" phrases also load `workshop.md` when Estimate artifacts exist. -3. If `current_phase` exists (and step 2 did not apply), use it (must match one of: discover, clarify, design, estimate, generate, complete) -4. Otherwise use ordered phase evaluation: `discover` → `clarify` → `design` → `estimate` → `generate` -5. Pick the **first** phase in that order where `phases. != "completed"`; if none, state is `complete`. When evaluating `generate`, require `phases.workshop == "completed"` (seed `"pending"` on Discover so a missing key is not treated as resolved). +3. **Legacy Generate resume (mandatory):** If `current_phase == "generate"` AND `run_mode` is absent AND `phases.generate != "completed"`, follow the `legacy-generate` row — present the resume offer; do not auto-load `generate.md` and do not leave the state machine with no matching row. +4. If `current_phase` exists (and steps 2–3 did not apply), use it (must match one of: discover, clarify, design, estimate, generate, complete) +5. Otherwise use ordered phase evaluation: `discover` → `clarify` → `design` → `estimate` → `generate` +6. Pick the **first** phase in that order where `phases. != "completed"`; if none, state is `complete`. When evaluating `generate`, require `phases.workshop == "completed"` (seed `"pending"` on Discover so a missing key is not treated as resolved) **and** Generate opt-in consent (`run_mode == "decide_and_execute"` or an explicit request — see the hard rule above); without consent, treat the state as decide-complete and present the resume offer instead of loading `generate.md`. **Phase gate checks**: If prior phase incomplete, do not advance (e.g., cannot enter estimate without completed design). +**Generate is opt-in (HARD RULE):** Do not load `references/phases/generate/generate.md` unless the user chose option **C** at the post-Estimate Decision gate (`estimate.md`), accepted the decide-complete resume offer, or the user's current-turn message is an explicit request to produce Terraform / migration scripts (not merely mentioning Terraform). Never auto-chain into Generate after Estimate, the workshop, or feedback "to be helpful" — the decision is the product; execution artifacts are a second, explicit product. **On every Execute path (gate C, resume Yes, or an explicit ask), set `run_mode: "decide_and_execute"` in `.phase-status.json` BEFORE loading `generate.md`** — so a session that dies mid-Generate resumes as an Execute run, not a decide run. `run_mode: "decide"` or an absent `run_mode` is not consent. + **Clarify is mandatory:** Do not load `references/phases/design/design.md`, `references/phases/estimate/estimate.md`, or `references/phases/generate/generate.md` unless `$MIGRATION_DIR/.phase-status.json` exists and `phases.clarify` is exactly `"completed"`. A `preferences.json` file alone is **not** sufficient proof that Clarify ran. If the user asks to skip Clarify or jump straight to Design, cost estimate, or artifact generation, refuse briefly, then load `references/phases/clarify/clarify.md` and run Phase 2. There is no exception for "quick" or "obvious" migrations. **Feedback sidebars**: Feedback is not a sequential phase — it is offered at two interleaved sidebars (after Discover and after Estimate). See the **Feedback Sidebars** section below for details. @@ -175,7 +180,7 @@ Use **read-merge-write** updates for `.phase-status.json`: 1. Read the current file before every update. 2. Change only the phase keys being advanced and `last_updated`. 3. Keep prior completed phases unchanged. -4. Set `current_phase` to the next deterministic phase (or `complete` after generate). +4. Set `current_phase` to the next deterministic phase — or `complete` after Generate, **or** after Estimate when the user chose Decision-gate **A** (`run_mode: "decide"`; Generate stays pending). 5. Write the full file in the same turn as your final phase work message. Example — after completing the Clarify phase, write `$MIGRATION_DIR/.phase-status.json` with: @@ -359,15 +364,21 @@ When invoked, the agent **MUST follow this exact sequence**: - If user picks **A** → Load `references/phases/feedback/feedback.md`, execute it, then continue to Clarify. - If user picks **B** → Continue to Clarify (feedback stays `"pending"`). - - **After Estimate**: First offer the what-if workshop per `estimate.md` - (Enter workshop / Proceed toward Generate) when the infra route is active. - Outer Estimate keeps `current_phase: estimate` until workshop is resolved. - Then, if `phases.feedback` is `"pending"`: - "Would you like to share quick feedback now? (5 optional questions + anonymized usage data) - [A] Yes, share feedback - [B] No thanks, continue to Generate" - - If user picks **A** → Load `references/phases/feedback/feedback.md`, execute it, then continue to Generate. - - If user picks **B** → Use the Phase Status Update Protocol to set `phases.feedback` to `"completed"`. Continue to Generate. + - **After Estimate**: First present the post-Estimate **Decision gate** per + `estimate.md` (done for now / what-if workshop / generate). The gate owns + the post-Estimate sequence — do not interleave the feedback offer with it, + and do not stack it with other prompts in one message. Outer Estimate + keeps `current_phase: estimate` until the gate resolves (workshop exits + return to the gate). Then, **after the gate resolves to A or C**, if + `phases.feedback` is `"pending"`: + - **After gate C** (continuing to Generate), use the standard form: + "Would you like to share quick feedback now? (5 optional questions + anonymized usage data) + [A] Yes, share feedback + [B] No thanks" + - **After gate A** (user said they're done), fold a one-line short form into the closing message instead of a separate prompt: "…everything is saved and I'll pick up from here. Quick feedback before you go? [Yes] [No]" — the user just said they're done; don't make feedback feel like another phase. + - Yes/A → Load `references/phases/feedback/feedback.md`, execute it, then continue per the gate choice (Generate for C; done for A). + - No/B → Use the Phase Status Update Protocol to set `phases.feedback` to `"completed"`. Continue per the gate choice. + This placement means the feedback decision-check questions land immediately after the user actually made their migrate/stay decision. - **Warm start / explicit what-if**: If the user says "what if", "reprice", "workshop mode", or "compare scenarios" and infra Estimate artifacts exist, load `references/phases/workshop/workshop.md` (respect Generate re-entry). diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/estimate/estimate.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/estimate/estimate.md index 816eea32..088ebb29 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/estimate/estimate.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/estimate/estimate.md @@ -138,32 +138,44 @@ estimate artifact(s), present a brief summary, then **return to the workshop loop**. Do **not** emit `HANDOFF_OK`, do **not** update `.phase-status.json`, do **not** offer the what-if workshop below. -### Outer Estimate — deferred Generate advance +### Outer Estimate — Decision gate After outer-run `HANDOFF_OK`, use the Phase Status Update Protocol (read-merge-write) — **in the same turn** as the summary: 1. Set `phases.estimate` to `"completed"` 2. Ensure `phases.workshop` exists (seed `"pending"` if missing) -3. **Do not** set `current_phase` to `"generate"` yet — leave `current_phase` at - `"estimate"` until the workshop sidebar is resolved (entered then exited, - or declined) -4. Offer the what-if workshop below (infra route only) +3. **Do not** set `current_phase` to `"generate"` — Generate is opt-in from + here on. Leave `current_phase` at `"estimate"` and present the Decision + gate below. -### Post-Estimate: What-If Workshop Offer +### Post-Estimate: Decision Gate -When `gcp-resource-inventory.json` + `aws-design.json` + `estimation-infra.json` -exist, offer: +**The decision is the product; execution artifacts are opt-in.** The verdict +(`recommendation.outcome` / `path`) already exists in the estimate artifacts — +present it and let the user choose what happens next. Never advance to +Generate without an explicit choice of option C (or an explicit later request +for Terraform/scripts). + +Present (values from the active estimate artifacts; one line each): ``` -Estimate complete. Before Generate, want to see how the numbers move if you -change something? I can reprice scenarios side by side in about a minute each, -without re-running discovery — for example: a different AWS region, cheaper -single-AZ database for staging, Kubernetes (EKS) instead of Fargate, or -ARM-based (Graviton) compute. - -[A] Enter what-if workshop -[B] Proceed toward Generate +Estimate complete. + +### Decision pack ready + +- Verdict: [outcome_label when recommendation.outcome exists; else path_label] +- AWS estimate (Balanced): $[X]/mo · Your GCP baseline: [figure with its + baseline-quality label from estimate-infra.md Part 1 — apply the + not-comparable rule when the sources measure different things] +- Timeline if you execute: ~[N–M] weeks ([complexity tier], from + shared/migration-complexity.md — omit this line when no tier signal exists) +- Deferred to specialists: [BigQuery / other deferred rows, or omit line] + +[A] Done for now — I have what I need to decide +[B] Explore what-ifs — reprice scenarios side by side (~1 min each): region, + single-AZ database, EKS vs Fargate, Graviton +[C] Generate Terraform and migration scripts ``` **Data-justified scenario hint (add one line when applicable):** if a material @@ -172,13 +184,27 @@ assumption was defaulted rather than confirmed — most commonly `availability` comparing a [alternative] scenario would bound that assumption before you commit." Suggest at most one. -- **A** → Load `references/phases/workshop/workshop.md`. Keep - `current_phase: estimate`; set `phases.workshop` → `"in_progress"`. -- **B** → Mark `phases.workshop` → `"completed"`. Set `current_phase` → - `"generate"`. Continue with Feedback/Generate sidebars in `SKILL.md`. - -For AI-only / billing-only runs (no infra inventory), skip the workshop offer and -set `phases.workshop` → `"completed"`, `current_phase` → `"generate"`. +**Choice handling:** + +- **A** → Mark `phases.workshop` → `"completed"` (declined). Set + `run_mode: "decide"` and `current_phase: "complete"` in `.phase-status.json` + (`phases.generate` **stays** `"pending"` — this combination means "decision + complete, execution available on request"; see `schema-phase-status.md`). + Then run the post-gate feedback checkpoint per `SKILL.md`. Close with: + "Your decision pack is complete. If you decide to migrate, say 'generate the + Terraform and migration scripts' — everything is saved and I'll pick up from + here." +- **B** → Load `references/phases/workshop/workshop.md`. Keep + `current_phase: estimate`; set `phases.workshop` → `"in_progress"`. On + workshop exit, **return to this gate** (options A and C; the workshop's + active scenario carries into either) — do not advance to Generate directly. +- **C** → Mark `phases.workshop` → `"completed"` (declined). Set + `run_mode: "decide_and_execute"` and `current_phase` → `"generate"`. Then + run the post-gate feedback checkpoint per `SKILL.md` and continue to + Generate. + +For AI-only / billing-only runs (no infra inventory), present the gate without +option B and set `phases.workshop` → `"completed"`. ## Reference Files @@ -193,7 +219,7 @@ set `phases.workshop` → `"completed"`, `current_phase` → `"generate"`. FORBIDDEN — Do NOT include ANY of: - Changes to architecture mappings from the Design phase -- Execution timelines or migration schedules +- Execution timelines or migration schedules — **exception:** the Decision gate's one-line timeline band (`~N–M weeks`, tier from `shared/migration-complexity.md`) is allowed; full schedules, week-by-week plans, and runbooks remain Generate-only - Terraform or IaC code generation - Detailed migration procedures or runbooks - Team staffing or resource allocation diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/generate/generate.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/generate/generate.md index 060e80aa..8ee07978 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/generate/generate.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/generate/generate.md @@ -1,5 +1,13 @@ # Phase 5: Generate Migration Artifacts (Orchestrator) +> **CONSENT GUARD (check before Step 1):** This phase runs only by explicit +> opt-in. If `.phase-status.json` → `run_mode` is not `"decide_and_execute"`: +> when this turn's user message is an explicit Execute request ("generate the +> Terraform", "create the migration scripts", gate choice C), set +> `run_mode: "decide_and_execute"` (read-merge-write) and proceed; otherwise +> STOP — do not generate anything — and re-present the Decision gate (or the +> decide-complete resume offer) from `estimate.md` / `SKILL.md`. + **Execute ALL steps in order. Do not skip or optimize.** ## Overview diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md index 6682e833..4afaab44 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md @@ -3,23 +3,31 @@ > Marks the workshop sidebar resolved and returns control to the backbone. > Does **not** set `current_phase` to `workshop`. -## When exiting to Generate +## When exiting the workshop + +Workshop exit returns to the **Decision gate** in `estimate.md` — never +directly to Generate. The user chooses A (done for now) or C (generate) there; +the active scenario carries into either choice. 1. Set `preferences.workshop.active` to `false` (keep `active_scenario_id`). 2. Ensure `scenarios/index.json` exists (baseline-only is enough). 3. Update `.phase-status.json` (read-merge-write): - `phases.workshop` → `"completed"` - - `current_phase` → `"generate"` + - `current_phase` **stays** `"estimate"` (the Decision gate sets the next + state based on the user's choice) - `last_updated` → now 4. Emit: ``` - HANDOFF_OK | phase=workshop | artifacts=scenarios/index.json | return_to=generate + HANDOFF_OK | phase=workshop | artifacts=scenarios/index.json | return_to=decision_gate ``` -5. Output: "Workshop paused. Active scenario: `{id}`. Proceeding toward Generate." +5. Output: "Workshop done. Active scenario: `{id}`." Then re-present the + Decision gate from `estimate.md` (options A and C — the workshop was just + explored, so omit B), with the gate's verdict/cost lines refreshed from the + **active scenario's** estimate. ## Soft postcondition If scenarios are missing after an empty entry, warn and still mark workshop -`"completed"` + advance to generate — do not block Generate. +`"completed"` + return to the Decision gate — do not block the gate. diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md index 99d7acf4..98c108f9 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md @@ -55,7 +55,7 @@ Actions (exactly one): - **[A] Apply & reprice** - **[B] Compare scenarios** -- **[C] Exit to Generate** +- **[C] Done — back to the decision gate** (choose "done for now" or "generate scripts" there) - **[D] Exit to full Clarify** (danger — confirm first) ## Step 3: Validate (Apply only) diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop.md index c0ec99f5..810257bc 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/phases/workshop/workshop.md @@ -33,7 +33,7 @@ 3. Branch: - **Apply & reprice** → `workshop-refresh.md` → `workshop-compare.md` - **Compare scenarios** → `workshop-compare.md` - - **Exit to Generate** → `workshop-assemble.md` → return + - **Done / exit** → `workshop-assemble.md` → returns to the Decision gate in `estimate.md` - **Exit to full Clarify** → danger; Clarify re-entry only on explicit confirm ## Hard rules @@ -55,6 +55,7 @@ file wins — fix this table. ## Decline without entering -When Estimate offer **[B] Proceed toward Generate** is chosen, mark -`phases.workshop` `"completed"` (resolved/declined), set `current_phase` to -`"generate"`, then continue Feedback/Generate sidebars in `SKILL.md`. +When the user chooses Decision-gate option **A** (done for now) or **C** +(generate) without entering the workshop, mark `phases.workshop` `"completed"` +(resolved/declined); the gate's choice handling in `estimate.md` sets +`run_mode` and `current_phase`. diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/handoff-gates.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/handoff-gates.md index 67214ef2..6ca9cf06 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/handoff-gates.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/handoff-gates.md @@ -52,6 +52,10 @@ Patching artifacts to satisfy a gate defeats fail-closed validation and produces --- +## Decide-complete is terminal, not a failure + +`current_phase: "complete"` + `run_mode: "decide"` + `phases.generate: "pending"` is a **valid terminal state** (the user stopped at the decision — see `schema-phase-status.md`). It is Estimate's `HANDOFF_OK` outcome, not a `GATE_FAIL`, not an inconsistent ordering, and not an incomplete run to repair. Do not "fix" it by advancing to Generate; the only valid transition out is the decide-complete resume offer (SKILL.md state machine). + ## Phase re-entry (idempotent runs) | Situation | Rule | diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/schema-phase-status.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/schema-phase-status.md index dff4d298..e0570163 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/schema-phase-status.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/shared/schema-phase-status.md @@ -26,6 +26,16 @@ Lightweight phase tracking. This is the SINGLE source of truth for the `.phase-s | `last_updated` | ISO 8601 | After each phase update | | `phases.` | string | Phase transitions: `"pending"` → `"in_progress"` → `"completed"` | +**Optional field — `run_mode`:** + +| Value | Meaning | Set by | +| ---------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| `"decide"` | User stopped at the decision — Generate available on request, never auto-loaded | Decision gate choice A (`estimate.md`) | +| `"decide_and_execute"` | User opted into execution artifacts — Generate may load | Decision gate choice C, or the decide-complete resume offer | +| _(absent)_ | Gate not yet reached — no Generate consent exists | — | + +**Decide-complete state:** `current_phase: "complete"` + `run_mode: "decide"` + `phases.generate: "pending"` means the decision pack is done and execution was not requested. This is a **terminal-unless-asked** state, not a failure and not an incomplete run: resume offers Generate but never auto-runs it, and never re-runs Estimate. No `"skipped"` status exists — `generate` simply stays `"pending"`. + **Rules:** - Phase status progresses: `"pending"` → `"in_progress"` → `"completed"`. Never goes backward. @@ -33,3 +43,4 @@ Lightweight phase tracking. This is the SINGLE source of truth for the `.phase-s - `workshop` is an optional **sidebar** (like feedback): never appears as `current_phase`; `"completed"` means resolved (entered or declined). - `migration_id` matches the `$MIGRATION_DIR` folder name (e.g., `0226-1430`). +- `run_mode` is optional; when present it must be `"decide"` or `"decide_and_execute"`. It is flow state (Generate consent), not a design constraint — it never appears in `preferences.json`. diff --git a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md +++ b/advisor/plugins/aws-startup-advisor/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate. diff --git a/advisor/plugins/aws-startup-advisor/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md b/advisor/plugins/aws-startup-advisor/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/advisor/plugins/aws-startup-advisor/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md +++ b/advisor/plugins/aws-startup-advisor/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate. diff --git a/advisor/plugins/aws-startup-advisor/skills/shared/workshop/workshop-invariants.md b/advisor/plugins/aws-startup-advisor/skills/shared/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/advisor/plugins/aws-startup-advisor/skills/shared/workshop/workshop-invariants.md +++ b/advisor/plugins/aws-startup-advisor/skills/shared/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate. diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/SKILL.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/SKILL.md index 204ab66b..63ec2fea 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/SKILL.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/SKILL.md @@ -81,16 +81,18 @@ If no Terraform is found (even when app code or billing files exist — they can This is the execution controller. After completing each phase, consult this table to determine the next action. -| Current State | Condition | Next Action | -| ------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `discover` | `phases.discover != "completed"` | Load `references/phases/discover/discover.md` | -| `clarify` | `phases.discover == "completed"` AND `phases.clarify != "completed"` | Load `references/phases/clarify/clarify.md` | -| `design` | `phases.clarify == "completed"` AND `phases.design != "completed"` | Load `references/phases/design/design.md` | -| `estimate` | `phases.design == "completed"` AND `phases.estimate != "completed"` | Load `references/phases/estimate/estimate.md` | -| `workshop` | `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop` is `"pending"` or `"in_progress"` | **Do not recompute Estimate.** If `workshop` is `"pending"`, present the post-Estimate workshop offer from `estimate.md`. If `"in_progress"`, load `references/phases/workshop/workshop.md`. | -| `generate` | `phases.estimate == "completed"` AND `phases.workshop == "completed"` AND `phases.generate != "completed"` | Load `references/phases/generate/generate.md` (workshop resolved — entered+exited or declined) | -| `complete` | `phases.generate == "completed"` AND `phases.feedback == "pending"` | Set `phases.feedback` to `"completed"` (user had two chances), then migration complete | -| `complete` | `phases.generate == "completed"` AND `phases.feedback == "completed"` | Migration planning complete | +| Current State | Condition | Next Action | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `discover` | `phases.discover != "completed"` | Load `references/phases/discover/discover.md` | +| `clarify` | `phases.discover == "completed"` AND `phases.clarify != "completed"` | Load `references/phases/clarify/clarify.md` | +| `design` | `phases.clarify == "completed"` AND `phases.design != "completed"` | Load `references/phases/design/design.md` | +| `estimate` | `phases.design == "completed"` AND `phases.estimate != "completed"` | Load `references/phases/estimate/estimate.md` | +| `workshop` | `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop` is `"pending"` or `"in_progress"` | **Do not recompute Estimate.** If `workshop` is `"pending"`, present the **Decision gate** from `estimate.md` (done for now / what-ifs / generate). If `"in_progress"`, load `references/phases/workshop/workshop.md`. | +| `generate` | `phases.estimate == "completed"` AND `phases.workshop == "completed"` AND `phases.generate != "completed"` AND (`run_mode == "decide_and_execute"` OR the user's current-turn message is an explicit request to produce Terraform/migration scripts) | Load `references/phases/generate/generate.md` (workshop resolved — entered+exited or declined; see **Generate is opt-in** below) | +| decide-complete | `current_phase == "complete"` AND `run_mode == "decide"` AND `phases.generate == "pending"` | Decision pack done; Generate available on request. On resume: "Your decision pack is complete. Generate Terraform and migration scripts now? [Yes] [Stay decision-only]" — Yes sets `run_mode: "decide_and_execute"`, `current_phase: "generate"`, loads `generate.md`. Never re-run Estimate. | +| legacy-generate | `current_phase == "generate"` AND `run_mode` is absent AND `phases.generate != "completed"` | **Back-compat** for runs started before Generate was opt-in (or interrupted after an old auto-advance set `current_phase: generate` with no `run_mode`). Do **not** auto-load `generate.md` and do **not** hang with no matching row — present the same resume offer as decide-complete. Yes → set `run_mode: "decide_and_execute"` and continue Generate; No → set `run_mode: "decide"`, `current_phase: "complete"`, leave `generate` pending. | +| `complete` | `phases.generate == "completed"` AND `phases.feedback == "pending"` | Set `phases.feedback` to `"completed"` (user had two chances), then migration complete | +| `complete` | `phases.generate == "completed"` AND `phases.feedback == "completed"` | Migration planning complete | **How to determine current state (deterministic):** @@ -100,12 +102,15 @@ This is the execution controller. After completing each phase, consult this tabl `"in_progress"`, follow the `workshop` row above — **never** re-run Estimate on a plain "continue my migration" / resume. Explicit "what if" / "reprice" / "workshop mode" phrases also load `workshop.md` when Estimate artifacts exist. -3. If `current_phase` exists (and step 2 did not apply), use it (must match one of: discover, clarify, design, estimate, generate, complete) -4. Otherwise use ordered phase evaluation: `discover` → `clarify` → `design` → `estimate` → `generate` -5. Pick the **first** phase in that order where `phases. != "completed"`; if none, state is `complete`. When evaluating `generate`, require `phases.workshop == "completed"` (seed `"pending"` on Discover so a missing key is not treated as resolved). +3. **Legacy Generate resume (mandatory):** If `current_phase == "generate"` AND `run_mode` is absent AND `phases.generate != "completed"`, follow the `legacy-generate` row — present the resume offer; do not auto-load `generate.md` and do not leave the state machine with no matching row. +4. If `current_phase` exists (and steps 2–3 did not apply), use it (must match one of: discover, clarify, design, estimate, generate, complete) +5. Otherwise use ordered phase evaluation: `discover` → `clarify` → `design` → `estimate` → `generate` +6. Pick the **first** phase in that order where `phases. != "completed"`; if none, state is `complete`. When evaluating `generate`, require `phases.workshop == "completed"` (seed `"pending"` on Discover so a missing key is not treated as resolved) **and** Generate opt-in consent (`run_mode == "decide_and_execute"` or an explicit request — see the hard rule above); without consent, treat the state as decide-complete and present the resume offer instead of loading `generate.md`. **Phase gate checks**: If prior phase incomplete, do not advance (e.g., cannot enter estimate without completed design). +**Generate is opt-in (HARD RULE):** Do not load `references/phases/generate/generate.md` unless the user chose option **C** at the post-Estimate Decision gate (`estimate.md`), accepted the decide-complete resume offer, or the user's current-turn message is an explicit request to produce Terraform / migration scripts (not merely mentioning Terraform). Never auto-chain into Generate after Estimate, the workshop, or feedback "to be helpful" — the decision is the product; execution artifacts are a second, explicit product. **On every Execute path (gate C, resume Yes, or an explicit ask), set `run_mode: "decide_and_execute"` in `.phase-status.json` BEFORE loading `generate.md`** — so a session that dies mid-Generate resumes as an Execute run, not a decide run. `run_mode: "decide"` or an absent `run_mode` is not consent. + **Clarify is mandatory:** Do not load `references/phases/design/design.md`, `references/phases/estimate/estimate.md`, or `references/phases/generate/generate.md` unless `$MIGRATION_DIR/.phase-status.json` exists and `phases.clarify` is exactly `"completed"`. A `preferences.json` file alone is **not** sufficient proof that Clarify ran. If the user asks to skip Clarify or jump straight to Design, cost estimate, or artifact generation, refuse briefly, then load `references/phases/clarify/clarify.md` and run Phase 2. There is no exception for "quick" or "obvious" migrations. **Feedback sidebars**: Feedback is not a sequential phase — it is offered at two interleaved sidebars (after Discover and after Estimate). See the **Feedback Sidebars** section below for details. @@ -175,7 +180,7 @@ Use **read-merge-write** updates for `.phase-status.json`: 1. Read the current file before every update. 2. Change only the phase keys being advanced and `last_updated`. 3. Keep prior completed phases unchanged. -4. Set `current_phase` to the next deterministic phase (or `complete` after generate). +4. Set `current_phase` to the next deterministic phase — or `complete` after Generate, **or** after Estimate when the user chose Decision-gate **A** (`run_mode: "decide"`; Generate stays pending). 5. Write the full file in the same turn as your final phase work message. Example — after completing the Clarify phase, write `$MIGRATION_DIR/.phase-status.json` with: @@ -359,15 +364,21 @@ When invoked, the agent **MUST follow this exact sequence**: - If user picks **A** → Load `references/phases/feedback/feedback.md`, execute it, then continue to Clarify. - If user picks **B** → Continue to Clarify (feedback stays `"pending"`). - - **After Estimate**: First offer the what-if workshop per `estimate.md` - (Enter workshop / Proceed toward Generate) when the infra route is active. - Outer Estimate keeps `current_phase: estimate` until workshop is resolved. - Then, if `phases.feedback` is `"pending"`: - "Would you like to share quick feedback now? (5 optional questions + anonymized usage data) - [A] Yes, share feedback - [B] No thanks, continue to Generate" - - If user picks **A** → Load `references/phases/feedback/feedback.md`, execute it, then continue to Generate. - - If user picks **B** → Use the Phase Status Update Protocol to set `phases.feedback` to `"completed"`. Continue to Generate. + - **After Estimate**: First present the post-Estimate **Decision gate** per + `estimate.md` (done for now / what-if workshop / generate). The gate owns + the post-Estimate sequence — do not interleave the feedback offer with it, + and do not stack it with other prompts in one message. Outer Estimate + keeps `current_phase: estimate` until the gate resolves (workshop exits + return to the gate). Then, **after the gate resolves to A or C**, if + `phases.feedback` is `"pending"`: + - **After gate C** (continuing to Generate), use the standard form: + "Would you like to share quick feedback now? (5 optional questions + anonymized usage data) + [A] Yes, share feedback + [B] No thanks" + - **After gate A** (user said they're done), fold a one-line short form into the closing message instead of a separate prompt: "…everything is saved and I'll pick up from here. Quick feedback before you go? [Yes] [No]" — the user just said they're done; don't make feedback feel like another phase. + - Yes/A → Load `references/phases/feedback/feedback.md`, execute it, then continue per the gate choice (Generate for C; done for A). + - No/B → Use the Phase Status Update Protocol to set `phases.feedback` to `"completed"`. Continue per the gate choice. + This placement means the feedback decision-check questions land immediately after the user actually made their migrate/stay decision. - **Warm start / explicit what-if**: If the user says "what if", "reprice", "workshop mode", or "compare scenarios" and infra Estimate artifacts exist, load `references/phases/workshop/workshop.md` (respect Generate re-entry). diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/estimate/estimate.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/estimate/estimate.md index 816eea32..088ebb29 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/estimate/estimate.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/estimate/estimate.md @@ -138,32 +138,44 @@ estimate artifact(s), present a brief summary, then **return to the workshop loop**. Do **not** emit `HANDOFF_OK`, do **not** update `.phase-status.json`, do **not** offer the what-if workshop below. -### Outer Estimate — deferred Generate advance +### Outer Estimate — Decision gate After outer-run `HANDOFF_OK`, use the Phase Status Update Protocol (read-merge-write) — **in the same turn** as the summary: 1. Set `phases.estimate` to `"completed"` 2. Ensure `phases.workshop` exists (seed `"pending"` if missing) -3. **Do not** set `current_phase` to `"generate"` yet — leave `current_phase` at - `"estimate"` until the workshop sidebar is resolved (entered then exited, - or declined) -4. Offer the what-if workshop below (infra route only) +3. **Do not** set `current_phase` to `"generate"` — Generate is opt-in from + here on. Leave `current_phase` at `"estimate"` and present the Decision + gate below. -### Post-Estimate: What-If Workshop Offer +### Post-Estimate: Decision Gate -When `gcp-resource-inventory.json` + `aws-design.json` + `estimation-infra.json` -exist, offer: +**The decision is the product; execution artifacts are opt-in.** The verdict +(`recommendation.outcome` / `path`) already exists in the estimate artifacts — +present it and let the user choose what happens next. Never advance to +Generate without an explicit choice of option C (or an explicit later request +for Terraform/scripts). + +Present (values from the active estimate artifacts; one line each): ``` -Estimate complete. Before Generate, want to see how the numbers move if you -change something? I can reprice scenarios side by side in about a minute each, -without re-running discovery — for example: a different AWS region, cheaper -single-AZ database for staging, Kubernetes (EKS) instead of Fargate, or -ARM-based (Graviton) compute. - -[A] Enter what-if workshop -[B] Proceed toward Generate +Estimate complete. + +### Decision pack ready + +- Verdict: [outcome_label when recommendation.outcome exists; else path_label] +- AWS estimate (Balanced): $[X]/mo · Your GCP baseline: [figure with its + baseline-quality label from estimate-infra.md Part 1 — apply the + not-comparable rule when the sources measure different things] +- Timeline if you execute: ~[N–M] weeks ([complexity tier], from + shared/migration-complexity.md — omit this line when no tier signal exists) +- Deferred to specialists: [BigQuery / other deferred rows, or omit line] + +[A] Done for now — I have what I need to decide +[B] Explore what-ifs — reprice scenarios side by side (~1 min each): region, + single-AZ database, EKS vs Fargate, Graviton +[C] Generate Terraform and migration scripts ``` **Data-justified scenario hint (add one line when applicable):** if a material @@ -172,13 +184,27 @@ assumption was defaulted rather than confirmed — most commonly `availability` comparing a [alternative] scenario would bound that assumption before you commit." Suggest at most one. -- **A** → Load `references/phases/workshop/workshop.md`. Keep - `current_phase: estimate`; set `phases.workshop` → `"in_progress"`. -- **B** → Mark `phases.workshop` → `"completed"`. Set `current_phase` → - `"generate"`. Continue with Feedback/Generate sidebars in `SKILL.md`. - -For AI-only / billing-only runs (no infra inventory), skip the workshop offer and -set `phases.workshop` → `"completed"`, `current_phase` → `"generate"`. +**Choice handling:** + +- **A** → Mark `phases.workshop` → `"completed"` (declined). Set + `run_mode: "decide"` and `current_phase: "complete"` in `.phase-status.json` + (`phases.generate` **stays** `"pending"` — this combination means "decision + complete, execution available on request"; see `schema-phase-status.md`). + Then run the post-gate feedback checkpoint per `SKILL.md`. Close with: + "Your decision pack is complete. If you decide to migrate, say 'generate the + Terraform and migration scripts' — everything is saved and I'll pick up from + here." +- **B** → Load `references/phases/workshop/workshop.md`. Keep + `current_phase: estimate`; set `phases.workshop` → `"in_progress"`. On + workshop exit, **return to this gate** (options A and C; the workshop's + active scenario carries into either) — do not advance to Generate directly. +- **C** → Mark `phases.workshop` → `"completed"` (declined). Set + `run_mode: "decide_and_execute"` and `current_phase` → `"generate"`. Then + run the post-gate feedback checkpoint per `SKILL.md` and continue to + Generate. + +For AI-only / billing-only runs (no infra inventory), present the gate without +option B and set `phases.workshop` → `"completed"`. ## Reference Files @@ -193,7 +219,7 @@ set `phases.workshop` → `"completed"`, `current_phase` → `"generate"`. FORBIDDEN — Do NOT include ANY of: - Changes to architecture mappings from the Design phase -- Execution timelines or migration schedules +- Execution timelines or migration schedules — **exception:** the Decision gate's one-line timeline band (`~N–M weeks`, tier from `shared/migration-complexity.md`) is allowed; full schedules, week-by-week plans, and runbooks remain Generate-only - Terraform or IaC code generation - Detailed migration procedures or runbooks - Team staffing or resource allocation diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/generate/generate.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/generate/generate.md index 060e80aa..8ee07978 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/generate/generate.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/generate/generate.md @@ -1,5 +1,13 @@ # Phase 5: Generate Migration Artifacts (Orchestrator) +> **CONSENT GUARD (check before Step 1):** This phase runs only by explicit +> opt-in. If `.phase-status.json` → `run_mode` is not `"decide_and_execute"`: +> when this turn's user message is an explicit Execute request ("generate the +> Terraform", "create the migration scripts", gate choice C), set +> `run_mode: "decide_and_execute"` (read-merge-write) and proceed; otherwise +> STOP — do not generate anything — and re-present the Decision gate (or the +> decide-complete resume offer) from `estimate.md` / `SKILL.md`. + **Execute ALL steps in order. Do not skip or optimize.** ## Overview diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md index 6682e833..4afaab44 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-assemble.md @@ -3,23 +3,31 @@ > Marks the workshop sidebar resolved and returns control to the backbone. > Does **not** set `current_phase` to `workshop`. -## When exiting to Generate +## When exiting the workshop + +Workshop exit returns to the **Decision gate** in `estimate.md` — never +directly to Generate. The user chooses A (done for now) or C (generate) there; +the active scenario carries into either choice. 1. Set `preferences.workshop.active` to `false` (keep `active_scenario_id`). 2. Ensure `scenarios/index.json` exists (baseline-only is enough). 3. Update `.phase-status.json` (read-merge-write): - `phases.workshop` → `"completed"` - - `current_phase` → `"generate"` + - `current_phase` **stays** `"estimate"` (the Decision gate sets the next + state based on the user's choice) - `last_updated` → now 4. Emit: ``` - HANDOFF_OK | phase=workshop | artifacts=scenarios/index.json | return_to=generate + HANDOFF_OK | phase=workshop | artifacts=scenarios/index.json | return_to=decision_gate ``` -5. Output: "Workshop paused. Active scenario: `{id}`. Proceeding toward Generate." +5. Output: "Workshop done. Active scenario: `{id}`." Then re-present the + Decision gate from `estimate.md` (options A and C — the workshop was just + explored, so omit B), with the gate's verdict/cost lines refreshed from the + **active scenario's** estimate. ## Soft postcondition If scenarios are missing after an empty entry, warn and still mark workshop -`"completed"` + advance to generate — do not block Generate. +`"completed"` + return to the Decision gate — do not block the gate. diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md index 99d7acf4..98c108f9 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop-sheet.md @@ -55,7 +55,7 @@ Actions (exactly one): - **[A] Apply & reprice** - **[B] Compare scenarios** -- **[C] Exit to Generate** +- **[C] Done — back to the decision gate** (choose "done for now" or "generate scripts" there) - **[D] Exit to full Clarify** (danger — confirm first) ## Step 3: Validate (Apply only) diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop.md index c0ec99f5..810257bc 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/phases/workshop/workshop.md @@ -33,7 +33,7 @@ 3. Branch: - **Apply & reprice** → `workshop-refresh.md` → `workshop-compare.md` - **Compare scenarios** → `workshop-compare.md` - - **Exit to Generate** → `workshop-assemble.md` → return + - **Done / exit** → `workshop-assemble.md` → returns to the Decision gate in `estimate.md` - **Exit to full Clarify** → danger; Clarify re-entry only on explicit confirm ## Hard rules @@ -55,6 +55,7 @@ file wins — fix this table. ## Decline without entering -When Estimate offer **[B] Proceed toward Generate** is chosen, mark -`phases.workshop` `"completed"` (resolved/declined), set `current_phase` to -`"generate"`, then continue Feedback/Generate sidebars in `SKILL.md`. +When the user chooses Decision-gate option **A** (done for now) or **C** +(generate) without entering the workshop, mark `phases.workshop` `"completed"` +(resolved/declined); the gate's choice handling in `estimate.md` sets +`run_mode` and `current_phase`. diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/handoff-gates.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/handoff-gates.md index 67214ef2..6ca9cf06 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/handoff-gates.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/handoff-gates.md @@ -52,6 +52,10 @@ Patching artifacts to satisfy a gate defeats fail-closed validation and produces --- +## Decide-complete is terminal, not a failure + +`current_phase: "complete"` + `run_mode: "decide"` + `phases.generate: "pending"` is a **valid terminal state** (the user stopped at the decision — see `schema-phase-status.md`). It is Estimate's `HANDOFF_OK` outcome, not a `GATE_FAIL`, not an inconsistent ordering, and not an incomplete run to repair. Do not "fix" it by advancing to Generate; the only valid transition out is the decide-complete resume offer (SKILL.md state machine). + ## Phase re-entry (idempotent runs) | Situation | Rule | diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/schema-phase-status.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/schema-phase-status.md index dff4d298..e0570163 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/schema-phase-status.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/shared/schema-phase-status.md @@ -26,6 +26,16 @@ Lightweight phase tracking. This is the SINGLE source of truth for the `.phase-s | `last_updated` | ISO 8601 | After each phase update | | `phases.` | string | Phase transitions: `"pending"` → `"in_progress"` → `"completed"` | +**Optional field — `run_mode`:** + +| Value | Meaning | Set by | +| ---------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| `"decide"` | User stopped at the decision — Generate available on request, never auto-loaded | Decision gate choice A (`estimate.md`) | +| `"decide_and_execute"` | User opted into execution artifacts — Generate may load | Decision gate choice C, or the decide-complete resume offer | +| _(absent)_ | Gate not yet reached — no Generate consent exists | — | + +**Decide-complete state:** `current_phase: "complete"` + `run_mode: "decide"` + `phases.generate: "pending"` means the decision pack is done and execution was not requested. This is a **terminal-unless-asked** state, not a failure and not an incomplete run: resume offers Generate but never auto-runs it, and never re-runs Estimate. No `"skipped"` status exists — `generate` simply stays `"pending"`. + **Rules:** - Phase status progresses: `"pending"` → `"in_progress"` → `"completed"`. Never goes backward. @@ -33,3 +43,4 @@ Lightweight phase tracking. This is the SINGLE source of truth for the `.phase-s - `workshop` is an optional **sidebar** (like feedback): never appears as `current_phase`; `"completed"` means resolved (entered or declined). - `migration_id` matches the `$MIGRATION_DIR` folder name (e.g., `0226-1430`). +- `run_mode` is optional; when present it must be `"decide"` or `"decide_and_execute"`. It is flow state (Generate consent), not a design constraint — it never appears in `preferences.json`. diff --git a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md +++ b/migrate/plugins/migration-to-aws/skills/gcp-to-aws/references/vendored/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate. diff --git a/migrate/plugins/migration-to-aws/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md b/migrate/plugins/migration-to-aws/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/migrate/plugins/migration-to-aws/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md +++ b/migrate/plugins/migration-to-aws/skills/heroku-to-aws/references/vendored/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate. diff --git a/migrate/plugins/migration-to-aws/skills/shared/workshop/workshop-invariants.md b/migrate/plugins/migration-to-aws/skills/shared/workshop/workshop-invariants.md index eebbd8ee..7b46789a 100644 --- a/migrate/plugins/migration-to-aws/skills/shared/workshop/workshop-invariants.md +++ b/migrate/plugins/migration-to-aws/skills/shared/workshop/workshop-invariants.md @@ -28,9 +28,11 @@ - The workshop is a sidebar: it NEVER becomes `current_phase`. Entry sets `phases.workshop: "in_progress"`; `current_phase` stays at `"estimate"` until exit/decline. -- Exit to Generate (assembler): `phases.workshop: "completed"`, - `current_phase: "generate"`. Decline at the Estimate offer: same, without - requiring `scenarios/`. +- Exit (assembler): `phases.workshop: "completed"`. Skills WITHOUT a + post-Estimate decision gate advance `current_phase` to `"generate"`. Skills + that DEFINE a decision gate re-present that gate — **never** auto-advance to + Generate (the gate sets the next state from the user's choice). Decline at + the offer: same, without requiring `scenarios/`. - Warm-start rule: `current_phase == "estimate"` AND `phases.estimate == "completed"` AND `phases.workshop == "pending"` → present the workshop offer; NEVER recompute Estimate.