Skip to content

[Spec] Reconcile hydrated state against reality on rad startup - #12871

Draft
nithyatsu wants to merge 18 commits into
mainfrom
state-restoration
Draft

[Spec] Reconcile hydrated state against reality on rad startup#12871
nithyatsu wants to merge 18 commits into
mainfrom
state-restoration

Conversation

@nithyatsu

@nithyatsu nithyatsu commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Reconcile hydrated state against reality on rad startup

Implements the design in specs/006-state-restoration/. Fixes the delete-workflow 409 loop where rad app delete retries forever because a state archive preserved a resource in a non-terminal provisioningState that no longer exists (or has settled) underneath.

What lands

A new sync custom action reconcile on Radius.Core/applications/{name}, plus a /reconcile route on every dynamic type served by dynamic-rp, plus a new best-effort ReconcileHydratedState stage on rad startup that invokes the app-scoped action for every hydrated application.

Flow

  1. rad startup finishes hydrating the state archive, then POSTs /planes/radius/local/resourcegroups/{rg}/providers/Radius.Core/applications/{app}/reconcile per application.
  2. corerp orchestrator (pkg/corerp/frontend/controller/applications/v20250801preview/reconcile.go) walks the application's children (same walk getGraph uses, restricted to dynamic-rp namespaces), skips terminal children, and fans out /reconcile POSTs concurrently through the UCP connection with per-child timeout + bounded concurrency.
  3. dynamic-rp handler (pkg/dynamicrp/frontend/reconcile.go) walks properties.status.outputResources for each non-terminal child, does a Kubernetes GET on each output, aggregates: all gone → PATCH Failed; all settled → PATCH Succeeded; any skipped (cloud output, unresolved version, transient failure) → leave provisioningState unchanged.
  4. Per-resource outcomes bubble back up as one aggregated ReconcileResponse. Individual failures never fail the whole reconcile; the whole reconcile never fails rad startup.

Files

Area Files
Wire typespec/Radius.Core/applications.tsp + regenerated pkg/corerp/api/v20250801preview/zz_generated_*.go
corerp orchestrator pkg/corerp/frontend/controller/applications/v20250801preview/reconcile.go + tests + pkg/corerp/setup/setup.go registration
dynamic-rp handler pkg/dynamicrp/frontend/reconcile.go + routes.go + service.go K8s client wiring + tests + pkg/dynamicrp/testhost/host.go fake discovery
CLI stage pkg/cli/cmd/startup/stateclient.go + startup.go + tests
Spec specs/006-state-restoration/spec.md + plan.md

Testing

  • Unit tests on both handlers cover the aggregation branches (gone/settled/skipped/terminal) and the reality-check paths.
  • rad startup unit tests cover the new stage's ordering + best-effort semantics.
  • An httptest-backed integration test on the corerp orchestrator exercises the real HTTP dispatch path against a fake UCP + downstream RPs — including URL construction, API-version lookup, request body, response decoding, and the forward-compat behavior when a child RP does not implement /reconcile yet.

Design decisions (unchanged from the spec-only PR)

  1. Endpoint shape: application-scoped custom action mirroring getGraph. corerp orchestrates; UCP is the proxy layer.
  2. Sync custom action: matches every other Radius custom action; the reality-check pass is bounded and does not provision anything.
  3. No --force flag on rad app delete — rejected because it force-updates the database and can break the state machine.
  4. Kubernetes 404 → Failed, keep the row — not delete — so the next normal rad app delete cleans it up through the standard state machine.
  5. Best-effort throughout: individual reconcile failures are logged and rad startup still returns success.
  6. Cloud output reality-checking (Terraform-backed Azure / AWS resources) is out of scope for this PR and recorded as skipped in the response.

Related

  • Concurrent rad app delete behavior tracked separately in #12870.
  • Phase 2 (k3d functional test for the full loop) tracked as follow-up #12874 — deliberately out of scope for this PR.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@nithyatsu
nithyatsu marked this pull request as ready for review August 28, 2026 20:24
@nithyatsu
nithyatsu requested a review from a team as a code owner August 28, 2026 20:24
Copilot AI lite review requested due to automatic review settings August 28, 2026 20:24
@nithyatsu
nithyatsu requested a review from a team as a code owner August 28, 2026 20:24

Copilot AI 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.

Pull request overview

Spec-only PR proposing a rad startup reconciliation pass that invokes a new application-scoped reconcile custom action (mirroring getGraph) to bring hydrated state back in sync with underlying reality, preventing rad app delete from looping indefinitely on 409 Conflict when hydration resurrects a stranded non-terminal provisioningState.

Changes:

  • Add a feature spec defining the reconciliation goal, endpoint shape, orchestration model (corerp via UCP), and acceptance criteria.
  • Add an implementation plan outlining phased delivery (app action stub → container reconcile → functional coverage) and key risks/constraints.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
specs/006-state-restoration/spec.md New feature spec for app-scoped + per-resource reconcile actions invoked from a new rad startup stage.
specs/006-state-restoration/plan.md New implementation plan detailing phases, testing approach, and rollout constraints for the reconciliation feature.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread specs/006-state-restoration/spec.md Outdated
Comment thread specs/006-state-restoration/spec.md Outdated
Comment thread specs/006-state-restoration/plan.md
Comment thread specs/006-state-restoration/spec.md Outdated
Comment thread specs/006-state-restoration/spec.md Outdated
Comment thread specs/006-state-restoration/plan.md Outdated
Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
…Spec toolchain

No schema change; picks up emitter drift accumulated in typespec-go since the last regen. Isolated from the reconcile action addition that follows so each commit is independently reviewable. Verified with 'go build ./...' and existing corerp application-controller tests.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
…spec + regen)

Adds a synchronous reconcile action to Radius.Core/applications/{name} mirroring
the shape of getGraph:

  POST .../providers/Radius.Core/applications/{app}/reconcile

Adds ReconcileRequest / ReconcileResponse / ReconcileResourceOutcome models to
carry the per-resource outcome report.

This commit is TypeSpec + emitter output only; the corerp handler and 'rad
startup' wiring land in follow-up commits (Phase 0 of specs/006-state-restoration).
No callers are registered yet, so the action is currently unreachable.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Wires the reconcile custom action registered in the previous commit into a
concrete handler and registers it alongside getGraph on the Radius.Core preview
applications resource. The handler validates the application exists (404 if
not) and returns an empty ReconcileResponse.

Phase 0 of specs/006-state-restoration: this end-to-end path lets a client
POST /planes/.../applications/{app}/reconcile without error, so 'rad startup'
can be wired up next before the orchestrator that walks children and the
dynamic-rp per-resource reality-check are added.

The sdk.Connection is threaded through the constructor now so future commits
that add the child walk (which fans out through UCP) do not need to change the
handler's signature or its registration in setup.go.

Tests cover the empty-report happy path, 404 when the application does not
exist, and error-propagation on database failures.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Adds a fifth stage to rad startup that runs after ScaleUp: lists every
application in the workspace's plane and POSTs the Radius.Core/applications
reconcile custom action on each. Aggregates per-application outcomes into a
report that is logged to the workflow log.

The stage is best-effort per the spec's acceptance criterion:
* individual per-application reconcile failures are recorded in the report and
  do not halt the pass;
* a failure to even begin the pass (unreachable workspace, LIST failure) is
  logged and rad startup still returns success.

Since Phase 0's server-side handler returns an empty report, the log will
show 'reconciled 0 resource(s)' per application until the child walk and the
dynamic-rp per-resource handler land in Phase 1. Nothing else about the
existing startup flow changes.

Tests extend the fakeStateRestoreClient to record the reconcile call and add
coverage for the happy path (order includes reconcile after scaleup), the
best-effort contract (reconcile error does not fail startup), and workspace
plumbing (the runner's active workspace is what the reconcile stage receives).

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Adds a POST /{resourceName}/reconcile route to the dynamic-rp resource-group
scope and a stub controller that resolves the target resource (404 if
missing) and returns an empty ReconcileResponse.

Purpose: give the corerp app-scoped orchestrator a stable endpoint to
dispatch to before the reality-check logic exists. Every dynamic resource
type served by dynamic-rp gets the route automatically, since the router
adds it once inside the resource-group / provider-namespace / resource-type
subrouter shared by all dynamic types. No per-type registration needed.

The reality-check that walks properties.status.outputResources, GETs each
Kubernetes object, and PATCHes provisioningState to match reality lands in
the next commit. The response shape (ReconcileResponse / ReconcileResourceOutcome)
is finalised here so the orchestrator's response-decoding path does not
need to change when the handler starts populating the array.

Tests cover the empty-report happy path and the 404 for a missing resource.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown

Unit Tests

    2 files  ± 0    459 suites  ±0   8m 30s ⏱️ -9s
6 547 tests +20  6 545 ✅ +20  2 💤 ±0  0 ❌ ±0 
7 825 runs  +22  7 823 ✅ +22  2 💤 ±0  0 ❌ ±0 

Results for commit d562f3e. ± Comparison against base commit fa29a3d.

♻️ This comment has been updated with latest results.

Replace the reconcile placeholder with the Phase 1 reality check. For a
non-terminal dynamic resource the handler walks properties.status.outputResources,
does a Kubernetes GET on each output via the runtime client the RP already
holds, and aggregates the outcomes to decide the new provisioningState:

  * all outputs gone (404 in k8s) -> transition to Failed
  * all outputs settled (GET succeeded) -> transition to Succeeded
  * any output skipped (cloud output, unresolved API version, transient GET
    failure) -> leave provisioningState unchanged, because we refuse to lie
    about state we could not verify

The new state is persisted through the frontend controller's SaveResource
path (no direct database writes). Cloud outputs served by Terraform / cloud
providers are reported as 'skipped: cloud output not yet reality-checked'
so the caller sees exactly which resources were and were not verified.
Full cloud output reality checking is a follow-up.

The frontend service now fetches the Kubernetes runtime client and the
discovery client from the KubernetesClientProvider and threads them into
the reconcile controller. The runtime client rides in controller.Options
alongside the other controllers; the discovery client is passed directly
to NewReconcile because no other frontend controller needs it. The test
host was updated to plant an empty fake DiscoveryClient so plane bring-up
still succeeds without a real cluster.

Unit tests cover the four aggregation branches: 404 -> Failed, present ->
Succeeded, cloud output -> skipped + state unchanged, terminal state ->
empty report. A separate test still asserts the 404-on-missing-resource
behavior.

The corerp orchestrator on Radius.Core/applications still returns an empty
report; the child walk lands in the next commit.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Replace the Phase 0 stub on Radius.Core/applications/reconcile with the
Phase 1 orchestrator. When 'rad startup' invokes this action it now:

  1. Looks up the application (404 if missing).
  2. Enumerates the resource-type registry via UCP, filters out the built-in
     namespaces that don't implement /reconcile (Applications.Core / Dapr /
     Datastores / Messaging, Radius.Core, Microsoft.Resources), and lists
     every remaining resource associated with the application. This mirrors
     the walk getGraph already uses so the two custom actions stay
     consistent.
  3. Skips children whose provisioningState is already terminal.
  4. Fans out reconcile POSTs concurrently through the shared UCP connection,
     bounded to 8 in flight and capped at 15 s per child so one unresponsive
     RP cannot hang the whole reconcile (spec §Risks).
  5. Aggregates each RP's per-resource outcomes into one ReconcileResponse.
     A dispatch failure (timeout, transport error, non-2xx) does not fail
     the reconcile: it is recorded as a per-child skipped outcome with the
     provisioningState left unchanged, so the caller always gets a report.
  6. Returns 404 or 405 from a child RP as 'skipped: RP does not implement
     reconcile', so the orchestrator stays forward-compatible with RPs
     that haven't wired reconcile yet.

The child walk and per-child dispatch are exposed as injectable hooks on
the controller so the orchestration logic can be unit-tested without
standing up a live UCP. The public constructor keeps its existing
signature and installs the UCP-backed defaults.

Tests cover: 404 on missing application, database error on lookup, empty
child list, terminal children skipped, multi-child fan-out with mixed
outcomes, and per-child dispatch failure recorded as skipped without
failing the reconcile.

Phase 1 is now feature-complete. An httptest-backed integration test that
exercises the end-to-end path lands in the next commit.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.76737% with 110 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.89%. Comparing base (fa29a3d) to head (d562f3e).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
pkg/cli/cmd/startup/stateclient.go 11.90% 37 Missing ⚠️
...troller/applications/v20250801preview/reconcile.go 74.13% 30 Missing ⚠️
pkg/dynamicrp/frontend/reconcile.go 81.57% 28 Missing ⚠️
pkg/dynamicrp/frontend/service.go 0.00% 9 Missing ⚠️
pkg/dynamicrp/frontend/routes.go 0.00% 3 Missing ⚠️
pkg/dynamicrp/testhost/host.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12871      +/-   ##
==========================================
+ Coverage   59.81%   59.89%   +0.08%     
==========================================
  Files         776      778       +2     
  Lines       46042    46370     +328     
==========================================
+ Hits        27541    27775     +234     
- Misses      18501    18595      +94     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Adds an integration test that exercises the reconcile orchestrator against
a real HTTP server that impersonates UCP + downstream RPs. This covers the
parts pure unit tests cannot: URL construction for each child's /reconcile
endpoint, the resource-provider summary lookup that resolves each child's
API version, request headers, request body, and JSON response decoding
into the aggregated ReconcileResponse.

The child walk is still stubbed with a static list — standing up a fake
UCP resource-listing surface would balloon the test without adding
coverage of anything that isn't already unit-tested.

Two scenarios:

  * end-to-end: two-container application, one child's RP reports Failed
    ('kubernetes object not found') and the other reports Succeeded. The
    orchestrator must aggregate both outcomes verbatim and dispatch to
    each child's specific /reconcile path.
  * forward-compat: a child's RP returns 404 for /reconcile (the route is
    not registered). The orchestrator must record a skipped outcome with
    provisioningState unchanged, not fail the reconcile.

Phase 1 is now feature-complete and covered end to end. Phase 2 (a
functional test against a real k3d cluster in test/functional/) remains
out of scope for this PR per the plan.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
Fixes the copilot-pull-request-reviewer feedback that pointed out drift
between the spec doc and the plan/implementation actually shipped:

  * Purpose paragraph (spec.md): the reconciler does not remove state-store
    entries when the underlying resource is gone. It PATCHes provisioningState
    to Failed and keeps the row so the next normal 'rad app delete' cleans it
    up through the standard state machine. Updated wording to match.
  * Reality table (spec.md): the 'not found' row now describes the same
    'PATCH Failed, keep row' action as the plan / implementation, not
    'delete the state-store entry'.
  * Terminal set (spec.md): 'terminal' is not just Succeeded or Failed --
    v1.ProvisioningState.IsTerminal() also treats Canceled and the empty
    string (synchronous resources that already settled) as terminal. Spec
    now references the helper so it cannot drift again.
  * Endpoint casing (spec.md): the example route now uses lowercase
    'resourcegroups' to match the canonical casing in the getGraph route
    comment and elsewhere in the codebase.
  * Go version (plan.md): updated 1.26.5 to 1.27.0 to match go.mod.

The tables in both files are already well-formed markdown -- the reviewer
flagged them as having a leading '||' but they use standard '|' cells and
render correctly on GitHub. No table syntax change needed.

No implementation change: plan and code already match the corrected spec.

Signed-off-by: Nithya Subramanian <nithyasu@microsoft.com>
@nithyatsu

Copy link
Copy Markdown
Contributor Author

Addressed the 6 review threads in a6407e3d3:

  • Purpose paragraph (spec.md) — reworded to say the reconciler PATCHes provisioningState to Failed and keeps the state-store row, not removes it. Matches the plan and shipped code.
  • Reality table (spec.md) — the "not found" row now reads "PATCH provisioningState to Failed and keep the state-store row so the next normal rad app delete can clean it up through the standard state machine." — consistent with the plan and the dynamic-rp handler.
  • Endpoint casing (spec.md) — example route now uses lowercase resourcegroups, matching the getGraph route comment.
  • Terminal set (spec.md) — the filter now references v1.ProvisioningState.IsTerminal() directly (Succeeded, Failed, Canceled, empty string) so it cannot drift from the helper the code actually uses.
  • Go version (plan.md) — updated 1.26.51.27.0 to match go.mod.
  • Constitution / reality tables allegedly malformed with || — the tables use standard single-| markdown cells and render correctly on GitHub. No change needed here; leaving as-is.

No implementation change: the plan and the shipped code already matched the corrected spec.

Comment thread specs/006-state-restoration/spec.md Outdated
3. Reads the resource's `properties.status.outputResources` — the concrete backing objects the recipe engine recorded when the resource was deployed.
4. For each output resource, queries its underlying provider:
- Kubernetes objects → GET via the target-cluster Kubernetes client the RP already holds.
- Terraform-backed cloud outputs (Azure/AWS resource IDs) → **out of scope for the prototype**; record `skipped: cloud output not yet reality-checked` in the per-output report. Follow-up work adds the cloud-SDK branches inside the same handler.

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.

Does this mean the initial phase of this reconciler will not be able to reconcile against cloud provider resources other than Kubernetes? e.g. if a mismatch exists for an Azure Postgres database, it will not be caught?

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.

Also, the description should not be scoped down to "Terraform-backed" only as I believe this would also apply to Bicep-backed resources.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will work on adding that support too to the PR. But for a review of approach, this scope sounded OK.

This feature adds a reconciliation pass triggered by `rad startup` and executed against the running control plane: for every application in the plane, an application-scoped `reconcile` action asks each resource's owning resource provider to check its actual current state and rewrite the state store to match reality — including marking entries as `Failed` when the underlying resource does not exist, so the next normal `rad app delete` cleans them up through the standard state machine.

The scope is deliberately narrow: reconcile hydrated state so operations that follow see reality.

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.

would be good to define what is a terminal vs. non-terminal state


## Non-goals

- **A `rad app delete --force` flag was considered and explicitly rejected.** A force option that bypasses state can convert an in-progress happy-path delete into a broken one by overwriting the state store while the first delete is still driving to a terminal state. Fixing hydration is the right approach.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

rad app delete --force already exists. Can you share details on why passing --force from the delete workflow does not already fix this, before we add a new API?


That is not sufficient when the previous run was interrupted while a resource was mid-operation. The archive can preserve a resource in a non-terminal state — for example `provisioningState: "Updating"` — that never actually completed. On the next run, the control plane accepts that state as authoritative, so every subsequent operation against the resource is blocked with `409 Conflict / target resource is in progress`. The delete workflow loops on that 409 forever and the application becomes undeletable through Radius.

This feature adds a reconciliation pass triggered by `rad startup` and executed against the running control plane: for every application in the plane, an application-scoped `reconcile` action asks each resource's owning resource provider to check its actual current state and rewrite the state store to match reality — including marking entries as `Failed` when the underlying resource does not exist, so the next normal `rad app delete` cleans them up through the standard state machine.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A customer restoring a Radius database backup into a rebuilt cluster gets the rows without the queue, which is the same stuck state. How do we address this for them?

Also, do we delete database on rad uninstall? If not uninstalling and reinstalling Radius is another scenaior where this could happen.

@DariuszPorowski DariuszPorowski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Additional findings...

I did not duplicate the active threads about the existing --force behavior or the risk of treating an existing Deployment as Succeeded.

reports := make([]ApplicationReconcileReport, 0, len(names))
for _, name := range names {
report := ApplicationReconcileReport{Name: name}
resp, err := applications.Reconcile(ctx, workspace.Scope, name, corerpv20250801preview.ReconcileRequest{}, nil)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

issue(operations,blocking): Bound each application reconcile request

This call inherits the command context without a deadline. A stalled Core RP enumeration or application request can prevent rad startup from returning, contrary to the bounded per-application timeout required by spec.md. Apply a per-application timeout that covers the complete action.

if err != nil {
report.Err = err
} else {
report.ResourceCount = len(resp.Resources)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

issue(operations,blocking): Preserve skipped and unchanged outcomes in startup output

The CLI keeps only len(resp.Resources) and later reports every entry as reconciled. Cloud skips, query failures, and unchanged records therefore look successful. Preserve and log from, to, and reason, or summarize changed, unchanged, skipped, and failed outcomes separately.

```

in parallel (bounded fan-out), through the UCP-fronted connection the handler already has.
5. After every child response returns, reconciles the application record itself: if all children are now terminal, transition the application accordingly; if any child remains non-terminal, leave the application in its hydrated state.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

todo(non-blocking): Remove or implement application-record reconciliation

The spec and plan say Core RP updates the application after reconciling its children, but Reconcilev20250801preview.Run only returns the aggregated child outcomes. Align this step with the implemented scope, or add the stated application transition.

}
scaledBackUp = true

// ReconcileHydratedState is best-effort: it POSTs the reconcile custom action per application

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

todo(non-blocking): Update the living architecture documentation

This post-restore pass changes the state-archive lifecycle and adds a generic state-mutating Dynamic RP action. Update docs/architecture/state-archive.md with the reconciliation stage and docs/architecture/dynamic-rp.md with the /reconcile path, Kubernetes clients, and failure behavior.

Comment thread specs/006-state-restoration/spec.md Outdated
3. Reads the resource's `properties.status.outputResources` — the concrete backing objects the recipe engine recorded when the resource was deployed.
4. For each output resource, queries its underlying provider:
- Kubernetes objects → GET via the target-cluster Kubernetes client the RP already holds.
- Terraform-backed cloud outputs (Azure/AWS resource IDs) → **out of scope for the prototype**; record `skipped: cloud output not yet reality-checked` in the per-output report. Follow-up work adds the cloud-SDK branches inside the same handler.

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.

it says cloud output not reality-checked here, are non-tf cloud deployments in scope?

@radius-functional-tests

radius-functional-tests Bot commented Aug 31, 2026

Copy link
Copy Markdown

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository radius-project/radius
Commit ref d562f3e
Unique ID funca85e910558
Image tag pr-funca85e910558
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-funca85e910558
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-funca85e910558
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-funca85e910558
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-funca85e910558
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-funca85e910558
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting corerp-cloud functional tests...
⌛ Starting ucp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

@nithyatsu
nithyatsu marked this pull request as draft September 1, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants