Skip to content

feat(aws-startup-advisor): add credits and Azure plans - #459

Open
herosjourney wants to merge 7 commits into
aws:mainfrom
herosjourney:fix/upfront-credits-azure-plan-json
Open

herosjourney wants to merge 7 commits into
aws:mainfrom
herosjourney:fix/upfront-credits-azure-plan-json

Conversation

@herosjourney

@herosjourney herosjourney commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Migration-credit eligibility was surfaced only after a supported assessment completed, so users did not learn at the start of a migration that creating an assessment could qualify them for AWS Promotional Credits. The gap also applied to standalone LLM migrations, which received no upfront offer at all.

Azure had staged Estimate and Generate handoff scaffolding from #435, but the shared plan.json producer did not map AZURE_TO_AWS. Eligible Azure assessments therefore ended in PLAN_SKIP and could not produce the file required by the AWS Startups Migrate upload flow.

The first implementation also exposed lifecycle contradictions: delegated LLM runs could see both the infrastructure and LLM notices before initiated_by was durable, interrupted agent-advisor delegations could leave schema-invalid state that Resume could not route, and Azure's loaded skill disagreed with Discover about unsupported billing-export, RDfA, Bicep, and ARM inputs.

Fix

Surface a one-time offer at the beginning of a Fresh Azure, GCP, or Heroku infrastructure/mixed assessment and at the beginning of a Fresh standalone full llm-to-bedrock migration. The approved product copy is:

Get $1,500 in AWS Promotional Credits for your migration when you create an assessment. Migrating a larger workload? You may be eligible for more. Talk to your AWS representative. Final eligibility determined by AWS.

  • Provider migrations explain that an eligible completed assessment produces plan.json and link to AWS Startups Migrate for upload.
  • The standalone LLM notice links to the same offer but truthfully states that this flow does not currently create an uploadable plan.json.
  • Resume/re-entry, access-only LLM, advisor-delegated, and provider phases delegated by LLM_TO_BEDROCK suppress the offer. The LLM Fresh path uses a once-only marker so an interrupted pre-initialization retry does not render it twice.
  • Both byte-identical plan writers now map AZURE_TO_AWS to sourcePlatform: "AZURE"; the existing Estimate option A and Generate completion handoffs reveal the file and upload CTA only after PLAN_OK.
  • Provider and advisor initialization now write durable, schema-valid ownership state before notice decisions, preserving initiated_by across delegation and making interrupted runs resumable.
  • Azure's active skill guidance now matches Discover: Terraform, consent-gated live az, application code, direct consent-gated AI usage APIs, and user-stated Azure spend are supported inputs; billing exports and RDfA are not ingested, Bicep/ARM workspaces halt rather than price a partial estate, and an RDfA archive as the only source also halts.

Scope

Fresh eligible Azure, GCP, and Heroku assessments show the offer before scanning or consent-gated source capture. Fresh standalone full LLM migrations show the LLM-specific no-plan version before delegated Discover. Existing runs and ineligible/delegated routes do not receive duplicate or misleading notices.

Azure activation intentionally keeps the existing producer contract narrow:

  • Infrastructure assessments emit scope: "INFRA_ONLY" with awsMonthlyBasis: "BALANCED".
  • Mixed infrastructure+AI assessments emit scope: "FULL" only when both estimates have usable overall accuracy bands.
  • Azure AI-only assessments remain unsupported by the importer contract and return PLAN_SKIP.
  • Missing or malformed state/estimate artifacts, unsupported platform/scope combinations, and out-of-contract totals remain fail-open: the writer exits successfully with PLAN_SKIP, does not create plan.json, and does not block migration completion.
  • Existing GCP and Heroku mappings and success-gated completion CTAs are unchanged.
Implementation details for reviewers
  • Canonical infrastructure/mixed and standalone-LLM notice files are vendored and parity-checked for standalone skill packaging.
  • GCP evaluates the notice only after its normal state write; Azure records LLM_TO_BEDROCK during early initialization when entered by the LLM wrapper. Both can therefore suppress the provider notice before rendering.
  • Agent-advisor creates a normal phase-state envelope, including migration_id, last_updated, phases, and initiated_by: "AGENT_ADVISOR", instead of relying on a marker-only JSON object. Discover recognizes and expands the delegated Fresh case without routing it through Resume.
  • llm-to-bedrock remains absent from SKILL_TO_PLATFORM; no LLM plan producer or final upload CTA was added.
  • Azure Estimate option A invokes the writer only after HANDOFF_OK, and Azure Generate invokes it only after its own HANDOFF_OK. Both preserve PLAN_OK/PLAN_SKIP gating and fail-open completion behavior.
  • Contract tests cover notice copy and ordering, one-time rendering, delegated/access-only/Resume suppression, schema-valid lifecycle state, Azure unsupported-input behavior, all six provider Estimate/Generate handoffs, writer parity, representative Azure output, and malformed/missing Azure inputs.

External release dependency

Azure plan.json production and the Azure upload CTA are intentionally enabled in this PR, but this does not mean live Azure import compatibility is available today. Merge/release of the Azure handoff is dependent on a coordinated external AWS Startups Migrate ImportPlan update that accepts sourcePlatform: "AZURE". The external importer is outside this repository and was not exercised by this PR; repository tests validate producer output only. Do not release the Azure CTA until that importer support is confirmed deployed.

The exact $1,500 AWS Promotional Credits sentence quoted above is approved product copy for this plugin and intentionally remains more specific than the linked page current qualification-only wording. Final eligibility determined by AWS. is required and retained.

Validation

Final copy validation on commit 37b1701c0764d1212de11c72ae3326347d350dc1:

  • Full Python suite: 401 passed.
  • Markdown lint: passed with 0 errors; model-ID and staleness checks passed.
  • Vendored parity: 53 files byte-identical and registered.
  • Skill-reference validation: 1,301 references checked, 0 missing, 7 known baselined references, and 0 stale baseline entries.
  • Artifact validation: 80 artifacts checked, 0 errors.
  • Both Heroku Node source-review suites passed: 13/13 and 44/44.
  • Writer parity and targeted Azure PLAN_OK/fail-open PLAN_SKIP, lifecycle, notice-ordering, and handoff checks passed.
  • git diff --check upstream/main...HEAD passed with no whitespace errors.

The external AWS Startups Migrate importer was not exercised. Repository validation confirms producer output, including the product-approved sourcePlatform: "AZURE" value and supported scope behavior; live importer compatibility remains an external integration boundary.

Type of Change

  • New plugin
  • New skill
  • Bug fix
  • Documentation update
  • Other — migration-offer and Azure assessment enhancement

Startup Advisor review checklist

By submitting this PR, I confirm that:

  • I have reviewed the full diff and understand all changes I am submitting.
  • I have tested my changes and confirmed they work as intended.
  • I have run mise -C plugins/aws-startup-advisor run ci and all checks pass.
  • I have disclosed any known issues, limitations, or untested scenarios.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@herosjourney
herosjourney requested review from a team as code owners October 15, 2026 22:09
@kapurshr

Copy link
Copy Markdown

Reviewed. Good to go.

@shrugninreddy-hash shrugninreddy-hash left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two blocking issues, details inline: Azure plan.json can't be imported yet because ImportPlan doesn't accept AZURE, and the $1,500 figure doesn't match the web page or the plugin's own end-of-run copy.

@leon1418 leon1418 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🤖 AI review 🤖]

Two lifecycle issues remain at 92a22769: an interrupted advisor delegation can overwrite its provider state, and an interrupted LLM assessment can repeat the one-time offer. Details inline.

Validation: original-source state/marker probes, plus reverified passing results for the unchanged head (401 Python tests, 57 Node tests and the plugin lint checks).

Comment thread plugins/aws-startup-advisor/skills/llm-to-bedrock/SKILL.md
Logan Kleier added 2 commits October 19, 2026 15:22
Restore Azure PLAN_SKIP until importer support is confirmed, replace fixed migration-credit amounts with qualification language, and preserve advisor/LLM retry state across interruptions.

Verification:
- uv run --no-project --with pytest python -m pytest tests/test_decision_gate_wiring.py tests/test_emit_plan_json.py -q: PASS (21 passed)
- python3 tools/sync-vendored.py --check: PASS (52 files)
- Azure fixture runtime probe: PASS (exit 0, PLAN_SKIP, no plan.json)
- mise -C plugins/aws-startup-advisor run ci: PASS (401 passed; markdown, artifacts, parity, refs, model and Node checks passed)
- set -o pipefail; mise run build 2>&1 | tail -80: PASS (markdown, manifests, spec, parity, gitleaks)
- git diff --check: PASS
- git diff --check upstream/main...HEAD: PASS
Scope advisor envelope creation to the no-state branch and initialize LLM assessment provider state in the preselected directory for both GCP and Azure.

Verification:
- targeted pytest: initial 1 failed/20 passed; fixed assertion; final 21 passed
- startup-advisor CI: intermediate reference/fixture-anchor failures fixed; final 401 passed, markdown/artifacts/references/parity/Node/model checks passed
- mise run build: passed (final rerun; markdown, manifests, spec, parity, gitleaks)
- git diff --check: passed

@leon1418 leon1418 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[🤖 AI review 🤖]

Rechecked d151214202754308ab9c4cc07bb38c3fd951332c. Both lifecycle concerns are fixed, and no additional verified source findings remain. Azure stays on PLAN_SKIP, its upfront upload notice is removed, and the remaining notices use qualification-based wording.

Validation: 401 Python tests, 57 Node tests, all registered plugin checks, and original-source state/marker probes passed. No live migration or upload was performed.

leon1418
leon1418 previously approved these changes Oct 20, 2026
aws#458 (parse RDfA reports into Discover) merged into main while this branch's
prior 'Azure's active skill guidance now matches Discover' commit still
described RDfA as an unsupported, halting input. Both descriptions can no
longer be true at once.

Reconcile by keeping this branch's real fixes (billing exports correctly
described as not implemented, Bicep/ARM halt behavior, the tightened Input
Security framing, and the delegated-LLM initiated_by note folded into aws#458's
new shared Step 0) while restoring RDfA as a supported, non-halting Discover
input everywhere this branch had marked it unsupported:

- azure-to-aws/SKILL.md: frontmatter description, build-status note, the
  live-first-discovery and discovery-budget-risk bullets, Input Security
  (RDfA moves back to the untrusted-but-supported input list; drops the
  RDfA-halts-if-only-source and RDfA-plus-other-source sentences), the
  .gitignore note, and the Sizing/Migration mode defaults.
- azure-to-aws/references/phases/discover/discover.md: merge conflict
  resolved by keeping aws#458's refactored 'Shared Step 0' (used by both the
  RDfA and live-az pre-dispatch actions) and relocating this branch's
  initiated_by: LLM_TO_BEDROCK note into it.
- Root plugins/aws-startup-advisor/README.md: two capability rows that
  listed RDfA alongside Bicep/ARM/billing-exports as unsupported.
- tests/test_decision_gate_wiring.py: updated
  test_azure_skill_describes_only_implemented_discovery_sources to assert
  RDfA is present and described as supported, instead of absent/unsupported.

Full suite: 475 passed. lint:vendored-parity (54 files), lint:skill-refs
(1318 checked, 0 missing), lint:artifacts (81 checked, 0 errors),
lint:consent-disclosure, and lint:md (SKILL.md, discover.md, README.md) all
pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
@herosjourney

Copy link
Copy Markdown
Contributor Author

Reconciled with #458 (merged): 19bd2d9 merges main (which now includes #458's RDfA Discover support) and restores RDfA as a supported, non-halting input everywhere this branch had marked it unsupported — while keeping this branch's actual fixes intact.

What changed in the reconciliation commit:

  • azure-to-aws/SKILL.md — frontmatter description, build-status note, the live-first-discovery and discovery-budget-risk bullets, the Input Security section (RDfA moves back to the untrusted-but-supported input list; the "RDfA is the only source → halt" and "RDfA accompanies a supported source → skip it" sentences are removed since RDfA is a real producer now), the .gitignore note, and the Sizing/Migration mode defaults.
  • azure-to-aws/references/phases/discover/discover.md — the merge conflict was between this branch's old pre-_init prose in the live-az pre-dispatch action and feat(aws-startup-advisor): parse RDfA reports into Discover (azure-to-aws) #458's refactor of that into a shared Shared Step 0 (now run once for both the RDfA and live-az pre-dispatch actions). Kept feat(aws-startup-advisor): parse RDfA reports into Discover (azure-to-aws) #458's shared step and relocated this branch's initiated_by: "LLM_TO_BEDROCK" note into it, so the delegated-LLM lifecycle fix this PR introduced is preserved.
  • Root plugins/aws-startup-advisor/README.md — two capability-matrix rows listed RDfA alongside Bicep/ARM/billing-exports as unsupported; updated to match.
  • tests/test_decision_gate_wiring.py::test_azure_skill_describes_only_implemented_discovery_sources — updated to assert RDfA is present and described as supported (previously asserted the opposite, plus the two now-removed halt sentences).

Everything else from this PR (the upfront migration-credit notice, AZURE_TO_AWS → plan.json mapping, the initiated_by durability fix, and the Bicep/ARM/billing-export halt behavior, which is still correct post-#458) is untouched.

Validation after the merge + fix, on 19bd2d9:

  • Full Python suite: 475 passed.
  • lint:vendored-parity: 54 files byte-identical.
  • lint:skill-refs: 1,318 checked, 0 missing.
  • lint:artifacts: 81 checked, 0 errors.
  • lint:consent-disclosure: OK.
  • lint:md on the three edited files: 0 errors.
  • mergeable: MERGEABLE against current main.

@herosjourney

Copy link
Copy Markdown
Contributor Author

@shrugninreddy-hash Thanks for flagging both integration boundaries. Product has confirmed two explicit decisions: we are keeping Azure plan.json production and its CTA, but merge/release of that handoff is dependent on a coordinated external ImportPlan update that accepts sourcePlatform: "AZURE"; the PR description now states that repository tests validate only the producer and that the Azure CTA must not be released before importer support is deployed. Product also reconfirmed the exact $1,500 AWS Promotional Credits wording, including “Final eligibility determined by AWS.”, so that approved copy remains unchanged despite the linked page currently using qualification-only wording.

Logan Kleier added 2 commits October 21, 2026 17:42
Resolve README conflicts by retaining main's customer-supplied RDfA wording while preserving the PR's user-stated Azure spend baseline. Resolve Azure skill conflicts by retaining main's expanded discovery description and reapplying the PR's unsupported billing/Bicep/ARM and baseline guidance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants