Repository: pulumi/pulumi-terraform-bridge
Pull request #996 (2023-04-14 21:35:29)

Implemented TfBridge PF Muxing via shim.Provider merging

github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/e83fc47..a211d68) with merge commit 6287992eedf637808f0d775a5000d61e4a69ad77
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/eef5f4e..f5fd12a) with merge commit 6287992eedf637808f0d775a5000d61e4a69ad77
iwahbe: As of https://github.com/pulumi/pulumi-terraform-bridge/pull/996/commits/cfc707909083cc386ce069527ccfffbdbb269c4f, the PR:
- Changes the implementation of `pf/tfgen.MainWithMuxer` to mux `shim.Provider` instead of the generated schema.
- Does not change the API for `pf/tfgen.MainWithMuxer`.
- Generates a full schema correctly when tested against `pulumi-cloudflare`.
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/9f48216c5..d4a262851) with merge commit 6287992eedf637808f0d775a5000d61e4a69ad77
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/8edba017a..04a3d6a47) with merge commit 6287992eedf637808f0d775a5000d61e4a69ad77
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/b37de4c..192be4e) with merge commit 8b2ed616d3845d6d3de9dcd38a42173bf0e63184
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/ccf14de16..342df6454) with merge commit 8b2ed616d3845d6d3de9dcd38a42173bf0e63184
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/2bd4daf..3946f76) with merge commit c4b7da5f96e1bef95c0b44d84c726a62d529dc85
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/d1c4f9a..544adf8) with merge commit c4b7da5f96e1bef95c0b44d84c726a62d529dc85
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/2137eb14a..a8896e64b) with merge commit 8b2ed616d3845d6d3de9dcd38a42173bf0e63184
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/dff55b1a8..15e52f243) with merge commit c4b7da5f96e1bef95c0b44d84c726a62d529dc85
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/e7cd4e801..650ce734e) with merge commit c4b7da5f96e1bef95c0b44d84c726a62d529dc85
t0yv0: Looking good so far! Please signal when things are in "complete enough" state you'd like me to try testing them on pulumi-aws. 
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/9cf61ad..4d6dba1) with merge commit 10a1beab7e541c82ad36d2606bc12fc0cceed0b8
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/b8146cb..11e5468) with merge commit 747efac307c484b141e46b5cffc29b5659a33495
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/69f21c4..37aa8f3) with merge commit 747efac307c484b141e46b5cffc29b5659a33495
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/a950cd776..946b209cc) with merge commit 747efac307c484b141e46b5cffc29b5659a33495
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/9a8097714..4ee468a2d) with merge commit 10a1beab7e541c82ad36d2606bc12fc0cceed0b8
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/a36929c40..ea38bb0b5) with merge commit 747efac307c484b141e46b5cffc29b5659a33495
iwahbe: Since merging in https://github.com/pulumi/pulumi-terraform-bridge/pull/997, we have made a breaking change to the existing API, altering `MainWithMuxer` to accept only a `pkg/tfbridge.ProviderInfo` for `tfgen` and that `ProviderInfo` with schema and context for `tfbridge`.
t0yv0: MainWithMuxer may be unreleased yet.
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/75b98e2..58e36d2) with merge commit a6564d280ee59de33a62a4cd3f65ecaf9570c292
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/0a9aad8..72fbebc) with merge commit a6564d280ee59de33a62a4cd3f65ecaf9570c292
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/1a49f1d46..b8d2fe84f) with merge commit a6564d280ee59de33a62a4cd3f65ecaf9570c292
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/65142f052..cfd8757a6) with merge commit a6564d280ee59de33a62a4cd3f65ecaf9570c292
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/ad51e9e..c13479d) with merge commit 0c7c151fef210e5eb6a2ab7dd232b0647f727d03
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/ce31cc4..4736668) with merge commit 0c7c151fef210e5eb6a2ab7dd232b0647f727d03
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/df6114c0a..3e2c95ca7) with merge commit 0c7c151fef210e5eb6a2ab7dd232b0647f727d03
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/8862f9fec..41915b5b0) with merge commit 0c7c151fef210e5eb6a2ab7dd232b0647f727d03
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/5ebcc6f..5de1dae) with merge commit 905933bec4f209206a4006eca989a05791dd1add
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/907d9d4..34fb9b6) with merge commit 905933bec4f209206a4006eca989a05791dd1add
github-actions[bot]: Diff for [pulumi-azuread](https://github.com/pulumi-bot/pulumi-azuread/compare/2289038..aba540b) with merge commit 44fea7a8f8d6d03a5f1e7dc2ac8f7abef79d3416
github-actions[bot]: Diff for [pulumi-random](https://github.com/pulumi-bot/pulumi-random/compare/f1c06a5..90d77c6) with merge commit 44fea7a8f8d6d03a5f1e7dc2ac8f7abef79d3416
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/6480320a2..110ac7da2) with merge commit 905933bec4f209206a4006eca989a05791dd1add
github-actions[bot]: Diff for [pulumi-gcp](https://github.com/pulumi-bot/pulumi-gcp/compare/c3f1c469f..5de528ec1) with merge commit 44fea7a8f8d6d03a5f1e7dc2ac8f7abef79d3416
github-actions[bot]: Diff for [pulumi-azure](https://github.com/pulumi-bot/pulumi-azure/compare/825c55cea..5b303ebe3) with merge commit 44fea7a8f8d6d03a5f1e7dc2ac8f7abef79d3416

Patch:
diff --git a/pf/internal/muxer/muxer.go b/pf/internal/muxer/muxer.go
new file mode 100644
index 00000000..eb6f2dd7
--- /dev/null
+++ b/pf/internal/muxer/muxer.go
@@ -0,0 +1,217 @@
+// Copyright 2016-2023, Pulumi Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package muxer
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"context"
+
+	"github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/schemashim"
+	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
+	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
+	shimSchema "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
+	"github.com/pulumi/pulumi-terraform-bridge/x/muxer"
+	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
+)
+
+func SchemaOnlyPluginFrameworkProvider(ctx context.Context, provider provider.Provider) shim.Provider {
+	return schemashim.ShimSchemaOnlyProvider(ctx, provider)
+}
+
+// AugmentShimWithPF augments an existing shim with a PF provider.Provider.
+func AugmentShimWithPF(ctx context.Context, shim shim.Provider, pf provider.Provider) *ProviderShim {
+
+	var p ProviderShim
+	if alreadyMerged, ok := shim.(*ProviderShim); ok {
+		p = *alreadyMerged
+	} else {
+		p = newProviderShim(shim)
+	}
+
+	err := p.extend(schemashim.ShimSchemaOnlyProvider(ctx, pf))
+	contract.AssertNoErrorf(err, "shim and pf provider are not disjoint")
+	return &p
+}
+
+// A merged `shim.Provider` that remembers which `shim.Provider`s it is composed of.
+type ProviderShim struct {
+	simpleSchemaProvider
+
+	MuxedProviders []shim.Provider
+}
+
+// Check if a Resource is served via in the Plugin Framework.
+func (m *ProviderShim) ResourceIsPF(token string) bool {
+	// In an augmented shim.Provider, underlying providers are PF providers iff they
+	// are implemented as SchemaOnlyProviders.
+	for _, p := range m.MuxedProviders {
+		if _, ok := p.ResourcesMap().GetOk(token); !ok {
+			continue
+		}
+		_, ok := p.(*schemashim.SchemaOnlyProvider)
+		return ok
+
+	}
+	return false
+}
+
+// Check if a DataSource is served via the Plugin Framework.
+func (m *ProviderShim) DataSourceIsPF(token string) bool {
+	// In an augmented shim.Provider, underlying providers are PF providers iff they
+	// are implemented as SchemaOnlyProviders.
+	for _, p := range m.MuxedProviders {
+		if _, ok := p.DataSourcesMap().GetOk(token); !ok {
+			continue
+		}
+		_, ok := p.(*schemashim.SchemaOnlyProvider)
+		return ok
+
+	}
+	return false
+}
+
+// Extend the `ProviderShim` with another `shim.Provider`.
+//
+// `provider` will be the `len(m.MuxedProviders)` when mappings are computed.
+func (m *ProviderShim) extend(provider shim.Provider) error {
+	res, err := disjointUnion(m.resources, provider.ResourcesMap())
+	if err != nil {
+		return fmt.Errorf("ResourcesMap is not disjoint: %w", err)
+	}
+
+	data, err := disjointUnion(m.dataSources, provider.DataSourcesMap())
+	if err != nil {
+		return fmt.Errorf("DataSourcesMap is not disjoint: %w", err)
+	}
+
+	m.resources = res
+	m.dataSources = data
+	m.MuxedProviders = append(m.MuxedProviders, provider)
+	return nil
+}
+
+func newProviderShim(provider shim.Provider) ProviderShim {
+	return ProviderShim{
+		simpleSchemaProvider: simpleSchemaProvider{
+			schema:      provider.Schema(),
+			resources:   provider.ResourcesMap(),
+			dataSources: provider.DataSourcesMap(),
+		},
+		MuxedProviders: []shim.Provider{provider},
+	}
+}
+
+// Assign each Resource and DataSource mapped in `info` whichever runtime provider defines
+// it.
+func (m *ProviderShim) ResolveDispatch(info *tfbridge.ProviderInfo) muxer.DispatchTable {
+	var dispatch muxer.DispatchTable
+	dispatch.Resources = map[string]int{}
+	dispatch.Functions = map[string]int{}
+
+	for tfToken, res := range info.Resources {
+		for i, p := range m.MuxedProviders {
+			_, ok := p.ResourcesMap().GetOk(tfToken)
+			if ok {
+				dispatch.Resources[string(res.GetTok())] = i
+				break
+			}
+		}
+	}
+	for tfToken, data := range info.DataSources {
+		for i, p := range m.MuxedProviders {
+			_, ok := p.DataSourcesMap().GetOk(tfToken)
+			if ok {
+				dispatch.Functions[string(data.GetTok())] = i
+				break
+			}
+		}
+	}
+
+	return dispatch
+}
+
+type simpleSchemaProvider struct {
+	schemashim.SchemaOnlyProvider
+	schema      shim.SchemaMap
+	resources   shim.ResourceMap
+	dataSources shim.ResourceMap
+}
+
+func (p *simpleSchemaProvider) Schema() shim.SchemaMap {
+	return p.schema
+}
+
+func (p *simpleSchemaProvider) ResourcesMap() shim.ResourceMap {
+	return p.resources
+}
+
+func (p *simpleSchemaProvider) DataSourcesMap() shim.ResourceMap {
+	return p.dataSources
+}
+
+var _ shim.Provider = (*simpleSchemaProvider)(nil)
+
+func disjointUnion(baseline, extension shim.ResourceMap) (shim.ResourceMap, error) {
+	union, err := disjointMapUnion(toResourceMap(baseline), toResourceMap(extension))
+	if err != nil {
+		return nil, err
+	}
+	return shimSchema.ResourceMap(union), nil
+}
+
+func toResourceMap(rmap shim.ResourceMap) shimSchema.ResourceMap {
+	m := map[string]shim.Resource{}
+	rmap.Range(func(key string, value shim.Resource) bool {
+		m[key] = value
+		return true
+	})
+	return m
+}
+
+func disjointMapUnion[T any](baseline, extension map[string]T) (map[string]T, error) {
+	u := copyMap(baseline)
+
+	var conflictingKeys []string
+
+	for k, v := range extension {
+		if _, conflict := baseline[k]; conflict {
+			conflictingKeys = append(conflictingKeys, k)
+			continue
+		}
+		u[k] = v
+	}
+
+	if len(conflictingKeys) > 0 {
+		sort.Strings(conflictingKeys)
+		return nil, fmt.Errorf("conflicting keys: %s", strings.Join(conflictingKeys, ", "))
+	}
+
+	return u, nil
+}
+
+func copyMap[K comparable, V any](m map[K]V) map[K]V {
+	if m == nil {
+		return nil
+	}
+	out := make(map[K]V, len(m))
+	for k, v := range m {
+		out[k] = v
+	}
+	return out
+}
diff --git a/pf/internal/schemashim/provider.go b/pf/internal/schemashim/provider.go
index 18f80371..c1605871 100644
--- a/pf/internal/schemashim/provider.go
+++ b/pf/internal/schemashim/provider.go
@@ -22,14 +22,18 @@ import (
 	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/pfutils"
 )
 
-type schemaOnlyProvider struct {
+type SchemaOnlyProvider struct {
 	ctx context.Context
 	tf  pfprovider.Provider
 }
 
-var _ shim.Provider = (*schemaOnlyProvider)(nil)
+func (p *SchemaOnlyProvider) PfProvider() pfprovider.Provider {
+	return p.tf
+}
+
+var _ shim.Provider = (*SchemaOnlyProvider)(nil)
 
-func (p *schemaOnlyProvider) Schema() shim.SchemaMap {
+func (p *SchemaOnlyProvider) Schema() shim.SchemaMap {
 	ctx := p.ctx
 	schemaResp := &pfprovider.SchemaResponse{}
 	p.tf.Schema(ctx, pfprovider.SchemaRequest{}, schemaResp)
@@ -39,7 +43,7 @@ func (p *schemaOnlyProvider) Schema() shim.SchemaMap {
 	return newSchemaMap(pfutils.FromProviderSchema(schemaResp.Schema))
 }
 
-func (p *schemaOnlyProvider) ResourcesMap() shim.ResourceMap {
+func (p *SchemaOnlyProvider) ResourcesMap() shim.ResourceMap {
 	resources, err := pfutils.GatherResources(context.TODO(), p.tf)
 	if err != nil {
 		panic(err)
@@ -47,7 +51,7 @@ func (p *schemaOnlyProvider) ResourcesMap() shim.ResourceMap {
 	return &schemaOnlyResourceMap{resources}
 }
 
-func (p *schemaOnlyProvider) DataSourcesMap() shim.ResourceMap {
+func (p *SchemaOnlyProvider) DataSourcesMap() shim.ResourceMap {
 	dataSources, err := pfutils.GatherDatasources(context.TODO(), p.tf)
 	if err != nil {
 		panic(err)
@@ -55,67 +59,67 @@ func (p *schemaOnlyProvider) DataSourcesMap() shim.ResourceMap {
 	return &schemaOnlyDataSourceMap{dataSources}
 }
 
-func (p *schemaOnlyProvider) Validate(c shim.ResourceConfig) ([]string, []error) {
+func (p *SchemaOnlyProvider) Validate(c shim.ResourceConfig) ([]string, []error) {
 	panic("schemaOnlyProvider does not implement runtime operation Validate")
 }
 
-func (p *schemaOnlyProvider) ValidateResource(t string, c shim.ResourceConfig) ([]string, []error) {
+func (p *SchemaOnlyProvider) ValidateResource(t string, c shim.ResourceConfig) ([]string, []error) {
 	panic("schemaOnlyProvider does not implement runtime operation ValidateResource")
 }
 
-func (p *schemaOnlyProvider) ValidateDataSource(
+func (p *SchemaOnlyProvider) ValidateDataSource(
 	t string, c shim.ResourceConfig) ([]string, []error) {
 	panic("schemaOnlyProvider does not implement runtime operation ValidateDataSource")
 }
 
-func (p *schemaOnlyProvider) Configure(c shim.ResourceConfig) error {
+func (p *SchemaOnlyProvider) Configure(c shim.ResourceConfig) error {
 	panic("schemaOnlyProvider does not implement runtime operation Configure")
 }
 
-func (p *schemaOnlyProvider) Diff(t string, s shim.InstanceState,
+func (p *SchemaOnlyProvider) Diff(t string, s shim.InstanceState,
 	c shim.ResourceConfig) (shim.InstanceDiff, error) {
 	panic("schemaOnlyProvider does not implement runtime operation Diff")
 }
 
-func (p *schemaOnlyProvider) Apply(t string, s shim.InstanceState,
+func (p *SchemaOnlyProvider) Apply(t string, s shim.InstanceState,
 	d shim.InstanceDiff) (shim.InstanceState, error) {
 	panic("schemaOnlyProvider does not implement runtime operation Apply")
 }
 
-func (p *schemaOnlyProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
+func (p *SchemaOnlyProvider) Refresh(t string, s shim.InstanceState) (shim.InstanceState, error) {
 	panic("schemaOnlyProvider does not implement runtime operation Refresh")
 }
 
-func (p *schemaOnlyProvider) ReadDataDiff(t string,
+func (p *SchemaOnlyProvider) ReadDataDiff(t string,
 	c shim.ResourceConfig) (shim.InstanceDiff, error) {
 	panic("schemaOnlyProvider does not implement runtime operation ReadDataDiff")
 }
 
-func (p *schemaOnlyProvider) ReadDataApply(t string,
+func (p *SchemaOnlyProvider) ReadDataApply(t string,
 	d shim.InstanceDiff) (shim.InstanceState, error) {
 	panic("schemaOnlyProvider does not implement runtime operation ReadDataApply")
 }
 
-func (p *schemaOnlyProvider) Meta() interface{} {
+func (p *SchemaOnlyProvider) Meta() interface{} {
 	panic("schemaOnlyProvider does not implement runtime operation Meta")
 }
 
-func (p *schemaOnlyProvider) Stop() error {
+func (p *SchemaOnlyProvider) Stop() error {
 	panic("schemaOnlyProvider does not implement runtime operation Stop")
 }
 
-func (p *schemaOnlyProvider) InitLogging() {
+func (p *SchemaOnlyProvider) InitLogging() {
 	panic("schemaOnlyProvider does not implement runtime operation InitLogging")
 }
 
-func (p *schemaOnlyProvider) NewDestroyDiff() shim.InstanceDiff {
+func (p *SchemaOnlyProvider) NewDestroyDiff() shim.InstanceDiff {
 	panic("schemaOnlyProvider does not implement runtime operation NewDestroyDiff")
 }
 
-func (p *schemaOnlyProvider) NewResourceConfig(object map[string]interface{}) shim.ResourceConfig {
+func (p *SchemaOnlyProvider) NewResourceConfig(object map[string]interface{}) shim.ResourceConfig {
 	panic("schemaOnlyProvider does not implement runtime operation ReourceConfig")
 }
 
-func (p *schemaOnlyProvider) IsSet(v interface{}) ([]interface{}, bool) {
+func (p *SchemaOnlyProvider) IsSet(v interface{}) ([]interface{}, bool) {
 	panic("schemaOnlyProvider does not implement runtime operation IsSet")
 }
diff --git a/pf/internal/schemashim/schemashim.go b/pf/internal/schemashim/schemashim.go
index dd0c2b96..c3960648 100644
--- a/pf/internal/schemashim/schemashim.go
+++ b/pf/internal/schemashim/schemashim.go
@@ -22,7 +22,7 @@ import (
 )
 
 func ShimSchemaOnlyProvider(ctx context.Context, provider pfprovider.Provider) shim.Provider {
-	return &schemaOnlyProvider{
+	return &SchemaOnlyProvider{
 		ctx: ctx,
 		tf:  provider,
 	}
diff --git a/pf/tfbridge/extend.go b/pf/tfbridge/extend.go
new file mode 100644
index 00000000..b948eeeb
--- /dev/null
+++ b/pf/tfbridge/extend.go
@@ -0,0 +1,35 @@
+// Copyright 2016-2023, Pulumi Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tfbridge
+
+import (
+	"context"
+
+	pfprovider "github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/muxer"
+	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/schemashim"
+	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
+)
+
+func SchemaOnlyPluginFrameworkProvider(ctx context.Context, p pfprovider.Provider) shim.Provider {
+	return schemashim.ShimSchemaOnlyProvider(ctx, p)
+}
+
+// MuxShimWithPF initializes a shim.Provider that will server resources from both shim and p.
+//
+// To create a muxed provider, ProviderInfo.P must be the result of this function.
+func MuxShimWithPF(ctx context.Context, shim shim.Provider, p pfprovider.Provider) shim.Provider {
+	return muxer.AugmentShimWithPF(ctx, shim, p)
+}
diff --git a/pf/tfbridge/main.go b/pf/tfbridge/main.go
index ae17a6c2..0f6f4af7 100644
--- a/pf/tfbridge/main.go
+++ b/pf/tfbridge/main.go
@@ -27,15 +27,23 @@ import (
 	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
 	pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
 
+	pfmuxer "github.com/pulumi/pulumi-terraform-bridge/pf/internal/muxer"
+	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/schemashim"
 	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
-	sdkBridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 	"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/metadata"
 	"github.com/pulumi/pulumi-terraform-bridge/x/muxer"
 )
 
 // Implements main() or a bridged Pulumi plugin, complete with argument parsing.
 func Main(ctx context.Context, pkg string, prov ProviderInfo, meta ProviderMetadata) {
-	handleFlags(ctx, prov, meta, prov.Version)
+	handleFlags(ctx, prov.Version,
+		func() (*tfbridge.MarshallableProviderInfo, error) {
+			pp, err := newProviderWithContext(ctx, prov, meta)
+			if err != nil {
+				return nil, err
+			}
+			return pp.(*provider).marshalProviderInfo(ctx), nil
+		})
 	// TODO[pulumi/pulumi-terraform-bridge#820]
 	// prov.P.InitLogging()
 
@@ -44,7 +52,10 @@ func Main(ctx context.Context, pkg string, prov ProviderInfo, meta ProviderMetad
 	}
 }
 
-func handleFlags(ctx context.Context, prov ProviderInfo, meta ProviderMetadata, version string) {
+func handleFlags(
+	ctx context.Context, version string,
+	getProviderInfo func() (*tfbridge.MarshallableProviderInfo, error),
+) {
 	// Look for a request to dump the provider info to stdout.
 	flags := flag.NewFlagSet("tf-provider-flags", flag.ContinueOnError)
 
@@ -71,11 +82,10 @@ func handleFlags(ctx context.Context, prov ProviderInfo, meta ProviderMetadata,
 	}
 
 	if *dumpInfo {
-		pp, err := newProviderWithContext(ctx, prov, meta)
+		info, err := getProviderInfo()
 		if err != nil {
 			cmdutil.ExitError(err.Error())
 		}
-		info := pp.(*provider).marshalProviderInfo(ctx)
 		if err := json.NewEncoder(os.Stdout).Encode(info); err != nil {
 			cmdutil.ExitError(err.Error())
 		}
@@ -91,10 +101,15 @@ func handleFlags(ctx context.Context, prov ProviderInfo, meta ProviderMetadata,
 // Implements main() or a bridged Pulumi plugin, complete with argument parsing.
 //
 // This is an experimental API.
-func MainWithMuxer(ctx context.Context, pkg string, meta ProviderMetadata, infos ...Muxed) {
-	f := MakeMuxedServer(ctx, pkg, meta, infos...)
+func MainWithMuxer(ctx context.Context, schema []byte, info tfbridge.ProviderInfo) {
+	handleFlags(ctx, info.Version, func() (*tfbridge.MarshallableProviderInfo, error) {
+		info := info
+		return tfbridge.MarshalProviderInfo(&info), nil
+	})
+
+	f := MakeMuxedServer(ctx, schema, info)
 
-	err := rprovider.Main(pkg, f)
+	err := rprovider.Main(info.Name, f)
 	if err != nil {
 		cmdutil.ExitError(err.Error())
 	}
@@ -105,11 +120,13 @@ func MainWithMuxer(ctx context.Context, pkg string, meta ProviderMetadata, infos
 // This function exposes implementation details for testing. It should not be used outside
 // of pulumi-terraform-bridge.  This is an experimental API.
 func MakeMuxedServer(
-	ctx context.Context, pkg string, meta ProviderMetadata, infos ...Muxed,
+	ctx context.Context, schema []byte, info tfbridge.ProviderInfo,
 ) func(host *rprovider.HostClient) (pulumirpc.ResourceProviderServer, error) {
-	version := infos[0].GetInfo().Version
-	schema := string(meta.PackageSchema)
-	dispatchTable, found, err := metadata.Get[muxer.DispatchTable](infos[0].GetInfo().GetMetadata(), "mux")
+
+	shim, ok := info.P.(*pfmuxer.ProviderShim)
+	contract.Assertf(ok, "MainWithMuxer must have a ProviderInfo.P created with AugmentShimWithPF")
+	version := info.Version
+	dispatchTable, found, err := metadata.Get[muxer.DispatchTable](info.GetMetadata(), "mux")
 	if err != nil {
 		cmdutil.ExitError(err.Error())
 	}
@@ -117,114 +134,44 @@ func MakeMuxedServer(
 		fmt.Printf("Missing precomputed mapping. Did you run `make tfgen`?")
 		os.Exit(1)
 	}
+
+	getTFMapping := func(muxer.GetMappingArgs) (muxer.GetMappingResponse, error) {
+		info := info
+		marshalled := tfbridge.MarshalProviderInfo(&info)
+		data, err := json.Marshal(marshalled)
+		return muxer.GetMappingResponse{
+			Provider: info.Name,
+			Data:     data,
+		}, err
+	}
 	m := muxer.Main{
 		DispatchTable: dispatchTable,
-		Schema:        schema,
+		Schema:        string(schema),
 		GetMappingHandler: map[string]muxer.MultiMappingHandler{
-			"tf":        combineTFGetMappingKey,
-			"terraform": combineTFGetMappingKey,
+			"tf":        getTFMapping,
+			"terraform": getTFMapping,
 		},
 	}
 	return func(host *rprovider.HostClient) (pulumirpc.ResourceProviderServer, error) {
-		for _, info := range infos {
-			info := info // https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables
+		for _, prov := range shim.MuxedProviders {
+			prov := prov // https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables
 
-			// Add PF based servers to the runtime.
-			if info.PF != nil {
+			switch prov := prov.(type) {
+			case *schemashim.SchemaOnlyProvider:
 				m.Servers = append(m.Servers, muxer.Endpoint{
 					Server: func(host *rprovider.HostClient) (pulumirpc.ResourceProviderServer, error) {
-						return newProviderServer(ctx, host, *info.PF, meta)
+						return newProviderServer(ctx, host, ProviderInfo{
+							ProviderInfo: info,
+							NewProvider:  prov.PfProvider,
+						}, ProviderMetadata{PackageSchema: schema})
+					}})
+			default:
+				m.Servers = append(m.Servers, muxer.Endpoint{
+					Server: func(host *rprovider.HostClient) (pulumirpc.ResourceProviderServer, error) {
+						return tfbridge.NewProvider(ctx, host, info.Name, version, prov, info, schema), nil
 					}})
-				continue
 			}
-			m.Servers = append(m.Servers, muxer.Endpoint{
-				Server: func(host *rprovider.HostClient) (pulumirpc.ResourceProviderServer, error) {
-					return tfbridge.NewProvider(ctx, host, pkg, version, info.SDK.P, *info.SDK, meta.PackageSchema), nil
-				}})
-		}
-		return m.Server(host, pkg, version)
-	}
-}
-
-func combineTFGetMappingKey(_ string, infos [][]byte) ([]byte, error) {
-	var target *tfbridge.MarshallableProviderInfo
-	for i, info := range infos {
-		var src tfbridge.MarshallableProviderInfo
-		err := json.Unmarshal(info, &src)
-		if err != nil {
-			return nil, fmt.Errorf("failed to marshal info %d: %w", i, err)
 		}
-		if i == 0 {
-			target = &src
-			continue
-		}
-
-		mergeProviderInfo(target, src)
-	}
-	return json.Marshal(target)
-}
-
-// Merge two tfbridge.MarshallableProviderInfo structs into one-another.
-//
-// Fields from src are merged into dst, prioritizing data in dst.
-//
-// The fields Name, Version and TFProviderVersion are not merged.
-func mergeProviderInfo(dst *tfbridge.MarshallableProviderInfo, src tfbridge.MarshallableProviderInfo) {
-	contract.Assertf(dst != nil, "cannot copy into nil pointer")
-	mergeUnder(&dst.Provider, src.Provider, mergeProvider)
-	mergeMapUnder(&dst.Config, src.Config)
-	mergeMapUnder(&dst.Resources, src.Resources)
-	mergeMapUnder(&dst.DataSources, src.DataSources)
-}
-
-// Merge two tfbridge.MarshallableProvider structs into one-another.
-//
-// Fields from src are merged into dst, prioritizing data from dst.
-func mergeProvider(dst *tfbridge.MarshallableProvider, src tfbridge.MarshallableProvider) {
-	mergeMapUnder(&dst.Schema, src.Schema)
-	mergeMapUnder(&dst.Resources, src.Resources)
-	mergeMapUnder(&dst.DataSources, src.DataSources)
-}
-
-// A helper function to merge two structs together, accounting for the structs being nil.
-func mergeUnder[T any](dst **T, src *T, merge func(*T, T)) {
-	if src == nil {
-		return
-	}
-	if *dst == nil {
-		*dst = src
-	}
-	merge(*dst, *src)
-}
-
-// A helper function to merge two maps together, accounting for the maps being nil.
-func mergeMapUnder[K comparable, V any](dst *map[K]V, src map[K]V) {
-	if src == nil {
-		return
-	}
-	if *dst == nil {
-		*dst = src
-	}
-	for k, v := range src {
-		_, skip := (*dst)[k]
-		if !skip {
-			(*dst)[k] = v
-		}
-	}
-}
-
-// A union of pf and sdk based ProviderInfo for use in MainWithMuxer.
-// Exactly 1 field of this struct should hold a value
-//
-// This is an experimental API.
-type Muxed struct {
-	PF  *ProviderInfo
-	SDK *sdkBridge.ProviderInfo
-}
-
-func (m Muxed) GetInfo() sdkBridge.ProviderInfo {
-	if m.PF == nil {
-		return *m.SDK
+		return m.Server(host, info.Name, version)
 	}
-	return m.PF.ProviderInfo
 }
diff --git a/pf/tfgen/main.go b/pf/tfgen/main.go
index 45494490..757dd9bb 100644
--- a/pf/tfgen/main.go
+++ b/pf/tfgen/main.go
@@ -18,16 +18,13 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/hashicorp/go-multierror"
-	"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
-	"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
 	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
 
+	pfmuxer "github.com/pulumi/pulumi-terraform-bridge/pf/internal/muxer"
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tfbridge"
 	sdkBridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfgen"
 	"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/metadata"
-	"github.com/pulumi/pulumi-terraform-bridge/x/muxer"
 )
 
 // Implements main() logic for a provider build-time helper utility. By convention these utilities are named
@@ -76,214 +73,34 @@ func Main(provider string, info tfbridge.ProviderInfo) {
 // This is an experimental API.
 //
 // [Pulumi Package Schema]: https://www.pulumi.com/docs/guides/pulumi-packages/schema/
-func MainWithMuxer(provider string, infos ...tfbridge.Muxed) {
-	ctx := context.Background()
+func MainWithMuxer(info sdkBridge.ProviderInfo) {
+	shim, ok := info.P.(*pfmuxer.ProviderShim)
+	contract.Assertf(ok, "MainWithMuxer must have a ProviderInfo.P created with AugmentShimWithPF")
 
-	// It is safe to pass infos[0].GetInfo() to MainWithCusomGenerate because it is
-	// only used when passed to GenerateOptions.
+	tfgen.MainWithCustomGenerate(info.Name, info.Version, info, func(opts tfgen.GeneratorOptions) error {
 
-	gen := func(opts tfgen.GeneratorOptions) error {
-		if opts.Sink == nil {
-			opts.Sink = cmdutil.Diag()
-		}
-		muxedInfo, mapping, schema, mergedRenames, err :=
-			UnstableMuxProviderInfo(ctx, opts, provider, infos...)
-		if err != nil {
-			return err
+		if info.MetadataInfo == nil {
+			return fmt.Errorf("ProviderInfo.MetadataInfo is required and cannot be nil")
 		}
 
-		// TODO Be more careful when assembling the final metadata
-		// Right now, only the top layer will be persisted.
-		muxedInfo.MetadataInfo = infos[0].GetInfo().MetadataInfo
-		contract.Assertf(muxedInfo.MetadataInfo != nil,
-			"Must provide a metadata store when muxing providers. See ProviderInfo.MetadataInfo")
-		err = metadata.Set(muxedInfo.GetMetadata(), "mux", mapping)
+		err := metadata.Set(info.GetMetadata(), "mux", shim.ResolveDispatch(&info))
 		if err != nil {
-			return fmt.Errorf("[pf/tfgen] Failed to set mux data in MetadataInfo: %w", err)
+			return err
 		}
 
-		// In the muxing case precompute renames by merging them and set them to MetadataInfo, this will avoid
-		// recomputing the renames in GenerateFromSchema, it will write out the mergedRenames as-is.
-		if err := metadata.Set(muxedInfo.GetMetadata(), "renames", mergedRenames); err != nil {
-			return fmt.Errorf("[pf/tfgen]: Failed to set renames data in MetadataInfo: %w", err)
+		if err := notSupported(opts.Sink, info); err != nil {
+			return err
 		}
 
-		// Having computed the schema, we now want to complete the tfgen process,
-		// reusing as much of the standard process as possible.
-		opts.ProviderInfo = muxedInfo
 		g, err := tfgen.NewGenerator(opts)
 		if err != nil {
 			return err
 		}
 
-		return g.UnstableGenerateFromSchema(&tfgen.GenerateSchemaResult{
-			PackageSpec: schema,
-			Renames:     mergedRenames,
-		})
-	}
-
-	tfgen.MainWithCustomGenerate(provider, infos[0].GetInfo().Version, infos[0].GetInfo(), gen)
-}
-
-// Mux multiple infos into a unified representation.
-//
-// This function exposes implementation details for testing. It should not be used outside
-// of pulumi-terraform-bridge.  This is an experimental API.
-func UnstableMuxProviderInfo(
-	ctx context.Context, opts tfgen.GeneratorOptions,
-	provider string, infos ...tfbridge.Muxed,
-) (sdkBridge.ProviderInfo, muxer.DispatchTable, schema.PackageSpec, tfgen.Renames, error) {
-	if opts.Sink == nil {
-		opts.Sink = cmdutil.Diag()
-	}
-	muxedInfo := infos[0].GetInfo()
-	schemas := []schema.PackageSpec{}
-	var errs multierror.Error
-
-	var renames []tfgen.Renames
-
-	for i, union := range infos {
-		i, union := i, union
-
-		anErr := func(err error) bool {
-			if err == nil {
-				return false
-			}
-			errs.Errors = append(errs.Errors, fmt.Errorf("Muxed proider[%d]: %w", i, err))
-			return true
-		}
-
-		info := union.SDK
-		if pfInfo := union.PF; pfInfo != nil {
-			if err := notSupported(opts.Sink, pfInfo.ProviderInfo); anErr(err) {
-				continue
-			}
-
-			shimInfo := shimSchemaOnlyProviderInfo(ctx, *pfInfo)
-			info = &shimInfo
-		}
-
-		// Initially, muxedInfo **is** infos[0]. We don't want to perform
-		// any destructive edits on already defined functions.
-		if i != 0 {
-			// Now we purge already defined items from the next schema,
-			// marking the all remaining items as defined for future schemas.
-
-			muxedInfo.IgnoreMappings = append(muxedInfo.IgnoreMappings,
-				info.IgnoreMappings...)
-
-			// Resources
-			layerUnder(&muxedInfo.Resources, info.Resources, muxedInfo.ExtraResources,
-				func(k string) {
-					delete(info.Resources, k)
-					info.IgnoreMappings = append(info.IgnoreMappings, k)
-				})
-
-			layerUnder(&muxedInfo.ExtraResources, info.ExtraResources, muxedInfo.Resources,
-				func(k string) {
-					delete(info.ExtraResources, k)
-					info.IgnoreMappings = append(info.IgnoreMappings, k)
-				})
-
-			// Datasources/functions
-			layerUnder(&muxedInfo.DataSources, info.DataSources, muxedInfo.ExtraFunctions,
-				func(k string) {
-					delete(info.DataSources, k)
-					info.IgnoreMappings = append(info.IgnoreMappings, k)
-				})
-			layerUnder(&muxedInfo.ExtraFunctions, info.ExtraFunctions, muxedInfo.DataSources,
-				func(k string) {
-					delete(info.ExtraFunctions, k)
-					info.IgnoreMappings = append(info.IgnoreMappings, k)
-				})
-
-			// Config
-			layerUnder(&muxedInfo.Config, info.Config, muxedInfo.ExtraConfig,
-				func(k string) { delete(info.Config, k) })
-			layerUnder(&muxedInfo.ExtraConfig, info.ExtraConfig, muxedInfo.Config,
-				func(k string) { delete(info.Config, k) })
-		}
-
-		genResult, err := tfgen.GenerateSchemaWithOptions(tfgen.GenerateSchemaOptions{
-			ProviderInfo:    *info,
-			DiagnosticsSink: opts.Sink,
-		})
-
-		if anErr(err) {
-			continue
-		}
-
-		renames = append(renames, genResult.Renames)
-		schemas = append(schemas, genResult.PackageSpec)
-	}
-
-	if err := errs.ErrorOrNil(); err != nil {
-		return sdkBridge.ProviderInfo{}, muxer.DispatchTable{},
-			schema.PackageSpec{}, tfgen.Renames{}, err
-	}
-
-	m, s, err := muxer.MergeSchemasAndComputeDispatchTable(schemas)
-	return muxedInfo, m, s, mergeRenames(renames), err
-}
-
-func mergeRenames(renames []tfgen.Renames) tfgen.Renames {
-	main := renames[0]
-	for _, rename := range renames[1:] {
-		for k, v := range rename.Resources {
-			_, exists := main.Resources[k]
-			if !exists {
-				main.Resources[k] = v
-			}
-		}
-
-		for k, v := range rename.Functions {
-			_, exists := main.Functions[k]
-			if !exists {
-				main.Functions[k] = v
-			}
-		}
-		for k, v := range rename.RenamedProperties {
-			_, exists := main.RenamedProperties[k]
-			if !exists {
-				main.RenamedProperties[k] = v
-			}
-		}
-		for k, v := range rename.RenamedConfigProperties {
-			_, exists := main.RenamedConfigProperties[k]
-			if !exists {
-				main.RenamedConfigProperties[k] = v
-			}
-		}
-		for k, v := range rename.Resources {
-			_, exists := main.Resources[k]
-			if !exists {
-				main.Resources[k] = v
-			}
+		if err := g.Generate(); err != nil {
+			return err
 		}
-	}
-	return main
-}
 
-func layerUnder[T any, O any](
-	dst *map[string]T, src map[string]T, alternativeDst map[string]O,
-	afterAdd func(k string),
-) {
-	contract.Assertf(dst != nil, "Cannot assign to a nil destination")
-	if src == nil {
-		return
-	}
-	if *dst == nil {
-		*dst = map[string]T{}
-	}
-	for k, v := range src {
-		_, ok := (*dst)[k]
-		if alternativeDst != nil && !ok {
-			_, ok = alternativeDst[k]
-		}
-		if ok {
-			continue
-		}
-		(*dst)[k] = v
-		afterAdd(k)
-	}
+		return nil
+	})
 }
diff --git a/pf/tfgen/not_supported.go b/pf/tfgen/not_supported.go
index bfb4b497..f2a8a0e5 100644
--- a/pf/tfgen/not_supported.go
+++ b/pf/tfgen/not_supported.go
@@ -17,10 +17,13 @@ package tfgen
 import (
 	"os"
 	"reflect"
+	"sort"
+	"strings"
 
 	"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
 	"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
 
+	"github.com/pulumi/pulumi-terraform-bridge/pf/internal/muxer"
 	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
 )
 
@@ -33,45 +36,80 @@ func notSupported(sink diag.Sink, prov tfbridge.ProviderInfo) error {
 		})
 	}
 
-	u := &notSupportedUtil{sink}
+	u := &notSupportedUtil{sink: sink}
 
-	if prov.P != nil {
+	skipResource := func(tfToken string) bool { return false }
+	skipDataSource := func(tfToken string) bool { return false }
+	muxedProvider := false
+	if mixed, ok := prov.P.(*muxer.ProviderShim); ok {
+		not := func(f func(string) bool) func(string) bool {
+			return func(s string) bool {
+				return !f(s)
+			}
+		}
+
+		skipResource = not(mixed.ResourceIsPF)
+		skipDataSource = not(mixed.DataSourceIsPF)
+		muxedProvider = true
+	} else if prov.P != nil {
 		u.warn("ProviderInfo.P should be nil for Plugin Framework based providers, populate NewProvider instead")
 	}
 
 	if prov.Resources != nil {
 		for path, res := range prov.Resources {
+			if skipResource(path) {
+				continue
+			}
 			u.resource("resource:"+path, res)
 		}
 	}
 
 	if prov.DataSources != nil {
 		for path, ds := range prov.DataSources {
+			if skipDataSource(path) {
+				continue
+			}
 			u.datasource("datasource:"+path, ds)
 		}
 	}
 
-	if prov.Config != nil {
-		for path, ds := range prov.Config {
-			u.schema("config:"+path, ds)
+	// It might be reasonable to set global values that PF will ignore if this is a
+	// muxed provider, and the SDK side will pick it up.
+	if !muxedProvider {
+		if prov.Config != nil {
+			for path, ds := range prov.Config {
+				u.schema("config:"+path, ds)
+			}
 		}
+
+		u.assertIsZero("PreConfigureCallback", prov.PreConfigureCallback)
+		u.assertIsZero("PreConfigureCallbackWithLogger", prov.PreConfigureCallbackWithLogger)
 	}
 
-	u.assertNotZero("PreConfigureCallback", prov.PreConfigureCallback)
-	u.assertNotZero("PreConfigureCallbackWithLogger", prov.PreConfigureCallbackWithLogger)
+	if len(u.autoNamedResources) > 0 {
+		sort.Strings(u.autoNamedResources)
+		u.warn("SetAutonaming call is currently ignored for bridged resources built with the "+
+			"Plugin Framework. Supporting this feature is tracked in pulumi/pulumi-terraform-bridge#917.\n"+
+			"These resources employ autonaming:\n- %s\n"+
+			"To avoid this warning, exclude these resources from auto naming, for example by adding them"+
+			" to ProviderInfo.Resources after the SetAutonaming call.",
+			strings.Join(u.autoNamedResources, "\n- "))
+	}
 
 	return nil
 }
 
 type notSupportedUtil struct {
 	sink diag.Sink
+
+	autoNamedResources []string
 }
 
 func (u *notSupportedUtil) warn(format string, arg ...interface{}) {
 	u.sink.Warningf(&diag.Diag{Message: format}, arg...)
 }
 
-func (u *notSupportedUtil) assertNotZero(path string, shouldBeZero interface{}) {
+func (u *notSupportedUtil) assertIsZero(path string, shouldBeZero interface{}) {
 	va := reflect.ValueOf(shouldBeZero)
 	if va.IsZero() {
 		return
@@ -93,22 +131,28 @@ func (u *notSupportedUtil) datasource(path string, ds *tfbridge.DataSourceInfo)
 
 func (u *notSupportedUtil) resource(path string, res *tfbridge.ResourceInfo) {
 	u.fields(path, res.Fields)
-	u.assertNotZero(path+".UniqueNameFields", res.UniqueNameFields)
-	u.assertNotZero(path+".Docs", res.Docs)
-	u.assertNotZero(path+".Aliases", res.Aliases)
+	u.assertIsZero(path+".UniqueNameFields", res.UniqueNameFields)
+	u.assertIsZero(path+".Docs", res.Docs)
+	u.assertIsZero(path+".Aliases", res.Aliases)
+	for _, v := range res.Fields {
+		if v.Default != nil && v.Default.AutoNamed {
+			// Supporting this feature is tracked in pulumi/pulumi-terraform-bridge#917
+			u.autoNamedResources = append(u.autoNamedResources, path)
+		}
+	}
 }
 
 func (u *notSupportedUtil) schema(path string, schema *tfbridge.SchemaInfo) {
-	u.assertNotZero(path+".Type", schema.Type)
-	u.assertNotZero(path+".AltTypes", schema.AltTypes)
-	u.assertNotZero(path+".NestedType", schema.NestedType)
-	u.assertNotZero(path+".Transform", schema.Transform)
-	u.assertNotZero(path+".Elem", schema.Elem)
+	u.assertIsZero(path+".Type", schema.Type)
+	u.assertIsZero(path+".AltTypes", schema.AltTypes)
+	u.assertIsZero(path+".NestedType", schema.NestedType)
+	u.assertIsZero(path+".Transform", schema.Transform)
+	u.assertIsZero(path+".Elem", schema.Elem)
 	u.fields(path, schema.Fields)
-	u.assertNotZero(path+".Asset", schema.Asset)
-	u.assertNotZero(path+".Default", schema.Default)
-	u.assertNotZero(path+".Stable", schema.Stable)
-	u.assertNotZero(path+".SuppressEmptyMapElements", schema.SuppressEmptyMapElements)
-	u.assertNotZero(path+".ForceNew", schema.ForceNew)
-	u.assertNotZero(path+".Removed", schema.Removed)
+	u.assertIsZero(path+".Asset", schema.Asset)
+	u.assertIsZero(path+".Default", schema.Default)
+	u.assertIsZero(path+".Stable", schema.Stable)
+	u.assertIsZero(path+".SuppressEmptyMapElements", schema.SuppressEmptyMapElements)
+	u.assertIsZero(path+".ForceNew", schema.ForceNew)
+	u.assertIsZero(path+".Removed", schema.Removed)
 }
diff --git a/pkg/tfbridge/provider.go b/pkg/tfbridge/provider.go
index 50bc38b9..0b47bbec 100644
--- a/pkg/tfbridge/provider.go
+++ b/pkg/tfbridge/provider.go
@@ -1346,9 +1346,7 @@ func generateResourceName(packageName tokens.Package, moduleName string, moduleM
 // declaration (e.g., for length).
 func (p *ProviderInfo) SetAutonaming(maxLength int, separator string) {
 	if p.P == nil {
-		// TODO[pulumi/pulumi-terraform-bridge#917]
-		glog.Warningln("SetAutonaming call is currently ignored for bridged providers built with the " +
-			"Plugin Framework. Supporting this feature is tracked in pulumi/pulumi-terraform-bridge#917")
+		glog.Warningln("SetAutonaming found a `ProviderInfo.P` nil. No Autonames were applied.")
 		return
 	}
 
diff --git a/x/muxer/mapping.go b/x/muxer/mapping.go
index 370e5bdb..ae520e66 100644
--- a/x/muxer/mapping.go
+++ b/x/muxer/mapping.go
@@ -68,23 +68,18 @@ type dispatchTable struct {
 	// Resources and functions can only map to a single provider
 	Resources map[string]int `json:"resources"`
 	Functions map[string]int `json:"functions"`
-
-	// Config values can map to multiple providers
-	Config map[string][]int `json:"config"`
 }
 
 func newDispatchTable() dispatchTable {
 	return dispatchTable{
 		Resources: make(map[string]int),
 		Functions: make(map[string]int),
-		Config:    make(map[string][]int),
 	}
 }
 
 func (dispatchTable dispatchTable) isEmpty() bool {
 	return dispatchTable.Resources == nil &&
-		dispatchTable.Functions == nil &&
-		dispatchTable.Config == nil
+		dispatchTable.Functions == nil
 }
 
 // Layer `srcSchema` under `dstSchema`, keeping track of where resources and functions
@@ -108,9 +103,6 @@ func (dispatchTable dispatchTable) layerSchema(dstSchema, srcSchema *schema.Pack
 			srcSchema.Config.Required)
 	}
 
-	for k := range m.srcSchema.Config.Variables {
-		m.dispatchTable.Config[k] = append(m.dispatchTable.Config[k], m.srcIndex)
-	}
 	layerMap(&m.dstSchema.Config.Variables, m.srcSchema.Config.Variables,
 		func(_ string, t schema.PropertySpec) { m.addType(t.TypeSpec) })
 
diff --git a/x/muxer/muxer.go b/x/muxer/muxer.go
index c84ef8ae..b9555bfd 100644
--- a/x/muxer/muxer.go
+++ b/x/muxer/muxer.go
@@ -68,8 +68,17 @@ type muxer struct {
 	getMappingByKey map[string]MultiMappingHandler
 }
 
+type GetMappingArgs interface {
+	Fetch() []GetMappingResponse
+}
+
+type GetMappingResponse struct {
+	Provider string
+	Data     []byte
+}
+
 type getMappingHandler = map[string]MultiMappingHandler
-type MultiMappingHandler = func(provider string, data [][]byte) ([]byte, error)
+type MultiMappingHandler = func(GetMappingArgs) (GetMappingResponse, error)
 
 func (m *muxer) getFunction(token string) server {
 	i, ok := m.dispatchTable.Functions[token]
@@ -95,40 +104,12 @@ func (m *muxer) GetSchema(ctx context.Context, req *rpc.GetSchemaRequest) (*rpc.
 	return &rpc.GetSchemaResponse{Schema: m.schema}, nil
 }
 
-func filterConfig[T any](m *muxer, i int, vars map[string]T) {
-	for v := range vars {
-		var has bool
-		for _, j := range m.dispatchTable.Config[v] {
-			if j == i {
-				has = true
-				break
-			}
-		}
-		if !has {
-			delete(vars, v)
-		}
-	}
-}
-
-// Destructively filter `vars`, removing variables that are not known to apply to server
-// `i`.
-func (m *muxer) filterConfigVariables(i int, vars map[string]string) {
-	filterConfig(m, i, vars)
-}
-
-// Destructively filter `args`, removing values that are not known to apply to server `i`.
-func (m *muxer) filterConfigArgs(i int, args *structpb.Struct) {
-	filterConfig(m, i, args.Fields)
-}
-
 func (m *muxer) CheckConfig(ctx context.Context, req *rpc.CheckRequest) (*rpc.CheckResponse, error) {
 	subs := make([]func() tuple[*rpc.CheckResponse, error], len(m.servers))
 	for i, s := range m.servers {
 		i, s := i, s
 		subs[i] = func() tuple[*rpc.CheckResponse, error] {
 			req := proto.Clone(req).(*rpc.CheckRequest)
-			m.filterConfigArgs(i, req.Olds)
-			m.filterConfigArgs(i, req.News)
 			return newTuple(s.CheckConfig(ctx, req))
 		}
 	}
@@ -209,10 +190,7 @@ func (m *muxer) DiffConfig(ctx context.Context, req *rpc.DiffRequest) (*rpc.Diff
 		i, s := i, s
 		subs[i] = func() tuple[*rpc.DiffResponse, error] {
 			req := proto.Clone(req).(*rpc.DiffRequest)
-			m.filterConfigArgs(i, req.Olds)
-			m.filterConfigArgs(i, req.News)
-			r, err := s.DiffConfig(ctx, req)
-			return newTuple(r, err)
+			return newTuple(s.DiffConfig(ctx, req))
 		}
 	}
 
@@ -284,10 +262,7 @@ func (m *muxer) Configure(ctx context.Context, req *rpc.ConfigureRequest) (*rpc.
 		i, s := i, s
 		subs[i] = func() tuple[*rpc.ConfigureResponse, error] {
 			req := proto.Clone(req).(*rpc.ConfigureRequest)
-			m.filterConfigVariables(i, req.Variables)
-			m.filterConfigArgs(i, req.Args)
-			r, err := s.Configure(ctx, req)
-			return newTuple(r, err)
+			return newTuple(s.Configure(ctx, req))
 		}
 	}
 	response := &rpc.ConfigureResponse{
@@ -430,7 +405,64 @@ func (m *muxer) Attach(ctx context.Context, req *rpc.PluginAttach) (*emptypb.Emp
 	return &emptypb.Empty{}, nil
 }
 
+type getMappingArgs struct {
+	m   *muxer
+	req *rpc.GetMappingRequest
+	ctx context.Context
+
+	err error
+}
+
+func (a *getMappingArgs) Fetch() []GetMappingResponse {
+	resp, err := a.m.getMappingRaw(a.ctx, a.req, false)
+	a.err = err
+	return resp
+}
+
 func (m *muxer) GetMapping(ctx context.Context, req *rpc.GetMappingRequest) (*rpc.GetMappingResponse, error) {
+
+	// We need to merge multiple mappings
+	combineMapping, found := m.getMappingByKey[req.Key]
+	if !found {
+		results, err := m.getMappingRaw(ctx, req, true)
+		if err != nil {
+			return nil, err
+		}
+
+		switch len(results) {
+		case 0:
+			// There are no results and some sub-providers implemented the
+			// method. This means that no provider responded to this key. We return an
+			// empty response.
+			return &rpc.GetMappingResponse{}, nil
+		case 1:
+			// We don't need to worry about merging GetMapping data if there is only one
+			// server with valid data.
+			return &rpc.GetMappingResponse{
+				Provider: results[0].Provider,
+				Data:     results[0].Data,
+			}, nil
+		}
+		return nil, fmt.Errorf("No multi-mapping handler for GetMapping key '%s'", req.Key)
+	}
+
+	args := getMappingArgs{m, req, ctx, nil}
+	result, err := combineMapping(&args)
+	if err != nil {
+		if args.err != nil {
+			return nil, fmt.Errorf("%w (sub-provider GetMapping call failed: %w)", err, args.err)
+		}
+		return nil, err
+	}
+	return &rpc.GetMappingResponse{
+		Provider: result.Provider,
+		Data:     result.Data,
+	}, nil
+}
+
+func (m *muxer) getMappingRaw(
+	ctx context.Context, req *rpc.GetMappingRequest, strict bool,
+) ([]GetMappingResponse, error) {
 	subs := make([]func() tuple[*rpc.GetMappingResponse, error], len(m.servers))
 	for i, s := range m.servers {
 		i, s := i, s
@@ -439,7 +471,7 @@ func (m *muxer) GetMapping(ctx context.Context, req *rpc.GetMappingRequest) (*rp
 		}
 	}
 	errs := new(multierror.Error)
-	results := [][]byte{}
+	results := []GetMappingResponse{}
 	var providerName string
 	for i, v := range asyncJoin(subs) {
 		if err := v.B; err != nil {
@@ -450,56 +482,30 @@ func (m *muxer) GetMapping(ctx context.Context, req *rpc.GetMappingRequest) (*rp
 		if len(response.Data) == 0 {
 			continue
 		}
-		if response.Provider == "" {
+		if response.Provider == "" && strict {
 			errs.Errors = append(errs.Errors,
 				fmt.Errorf("Missing provider name for subprovider %d", i))
 			continue
 		} else if providerName == "" {
 			providerName = response.Provider
-		} else if providerName != response.Provider {
+		} else if providerName != response.Provider && strict {
 			errs = multierror.Append(errs,
 				m.Warnf(ctx, "GetMapping",
 					"Ignoring Mapping data due to provider name mismatch: %s != %s",
 					providerName, response.Provider))
 			continue
 		}
-		results = append(results, response.Data)
+		results = append(results, GetMappingResponse{
+			Provider: response.Provider,
+			Data:     response.Data,
+		})
 	}
 
 	if err := m.muxedErrors(errs); err != nil {
 		return nil, err
 	}
 
-	switch len(results) {
-	case 0:
-		// There are no results and some sub-providers implemented the
-		// method. This means that no provider responded to this key. We return an
-		// empty response.
-		return &rpc.GetMappingResponse{}, nil
-	case 1:
-		// We don't need to worry about merging GetMapping data if there is only one
-		// server with valid data.
-		return &rpc.GetMappingResponse{
-			Provider: providerName,
-			Data:     results[0],
-		}, nil
-	}
-
-	// We need to merge multiple mappings
-	combineMapping, found := m.getMappingByKey[req.Key]
-	if !found {
-		return nil, fmt.Errorf("No multi-mapping handler for GetMapping key '%s'", req.Key)
-	}
-
-	data, err := combineMapping(providerName, results)
-	if err != nil {
-		return nil, fmt.Errorf("Failed to combine '%s' multi-mapping for '%s': %w", req.Key, providerName, err)
-	}
-
-	return &rpc.GetMappingResponse{
-		Provider: providerName,
-		Data:     data,
-	}, nil
+	return results, nil
 }
 
 func (m *muxer) Warnf(ctx context.Context, method, msg string, a ...any) error {


Test patch:
diff --git a/pf/tests/internal/testprovider/cmd/pulumi-resource-muxedrandom/main.go b/pf/tests/internal/testprovider/cmd/pulumi-resource-muxedrandom/main.go
index 7aa15bf0..b1ef8767 100644
--- a/pf/tests/internal/testprovider/cmd/pulumi-resource-muxedrandom/main.go
+++ b/pf/tests/internal/testprovider/cmd/pulumi-resource-muxedrandom/main.go
@@ -27,8 +27,6 @@ import (
 var schema []byte
 
 func main() {
-	meta := tfbridge.ProviderMetadata{PackageSchema: schema}
-	tfbridge.MainWithMuxer(context.Background(), "random", meta,
-		testprovider.MuxedRandomProvider()...,
-	)
+	tfbridge.MainWithMuxer(context.Background(), schema,
+		testprovider.MuxedRandomProvider())
 }
diff --git a/pf/tests/internal/testprovider/cmd/pulumi-tfgen-muxedrandom/main.go b/pf/tests/internal/testprovider/cmd/pulumi-tfgen-muxedrandom/main.go
index fdd09caf..24575c6a 100644
--- a/pf/tests/internal/testprovider/cmd/pulumi-tfgen-muxedrandom/main.go
+++ b/pf/tests/internal/testprovider/cmd/pulumi-tfgen-muxedrandom/main.go
@@ -22,7 +22,5 @@ import (
 )
 
 func main() {
-	tfgen.MainWithMuxer("random",
-		testprovider.MuxedRandomProvider()...,
-	)
+	tfgen.MainWithMuxer(testprovider.MuxedRandomProvider())
 }
diff --git a/pf/tests/internal/testprovider/random.go b/pf/tests/internal/testprovider/random.go
index 03184aef..f87239cf 100644
--- a/pf/tests/internal/testprovider/random.go
+++ b/pf/tests/internal/testprovider/random.go
@@ -15,6 +15,7 @@
 package testprovider
 
 import (
+	"context"
 	_ "embed"
 	"fmt"
 	"path/filepath"
@@ -139,8 +140,14 @@ func RandomSDKProvider() tfbridge.ProviderInfo {
 	}
 
 	info := tfbridge.ProviderInfo{
-		Name: "muxedrandom",
-		P:    sdkv2.NewProvider(sdkv2randomprovider.New()),
+		Name:        "muxedrandom",
+		Description: "A Pulumi package to safely use randomness in Pulumi programs.",
+		Keywords:    []string{"pulumi", "random"},
+		License:     "Apache-2.0",
+		Homepage:    "https://pulumi.io",
+		Repository:  "https://github.com/pulumi/pulumi-random",
+		Version:     "4.8.2",
+		P:           sdkv2.NewProvider(sdkv2randomprovider.New()),
 		Resources: map[string]*tfbridge.ResourceInfo{
 			"random_human_number": {Tok: randomResource(randomMod, "RandomHumanNumber")},
 		},
@@ -150,15 +157,13 @@ func RandomSDKProvider() tfbridge.ProviderInfo {
 	return info
 }
 
-func MuxedRandomProvider() []tfpf.Muxed {
+func MuxedRandomProvider() tfbridge.ProviderInfo {
 	sdk := RandomSDKProvider()
 	pf := RandomProvider()
-	for _, r := range pf.Resources {
+	for tf, r := range pf.Resources {
 		r.Tok = tokens.Type("muxedrandom:" + strings.TrimPrefix(string(r.Tok), "random:"))
+		sdk.Resources[tf] = r
 	}
-	pf.Name = sdk.Name
-	return []tfpf.Muxed{
-		{SDK: &sdk},
-		{PF: &pf},
-	}
+	sdk.P = tfpf.MuxShimWithPF(context.Background(), sdk.P, pf.NewProvider())
+	return sdk
 }
diff --git a/pf/tests/provider_get_mapping_test.go b/pf/tests/provider_get_mapping_test.go
index a6538b56..19b9e510 100644
--- a/pf/tests/provider_get_mapping_test.go
+++ b/pf/tests/provider_get_mapping_test.go
@@ -25,9 +25,7 @@ import (
 
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tests/internal/testprovider"
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tfbridge"
-	"github.com/pulumi/pulumi-terraform-bridge/pf/tfgen"
 	tfbridge0 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
-	tfgen0 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfgen"
 )
 
 func TestGetMapping(t *testing.T) {
@@ -64,17 +62,9 @@ func TestGetMapping(t *testing.T) {
 func TestMuxedGetMapping(t *testing.T) {
 	ctx := context.Background()
 
-	servers := testprovider.MuxedRandomProvider()
+	info := testprovider.MuxedRandomProvider()
 
-	_, _, schema, _, err := tfgen.UnstableMuxProviderInfo(ctx,
-		tfgen0.GeneratorOptions{}, "muxedrandom", servers...)
-	require.NoError(t, err)
-
-	schemaBytes, err := json.Marshal(schema)
-	require.NoError(t, err)
-
-	server, err := tfbridge.MakeMuxedServer(ctx, "random",
-		tfbridge.ProviderMetadata{PackageSchema: schemaBytes}, servers...)(nil)
+	server, err := tfbridge.MakeMuxedServer(ctx, genSDKSchema(t, info), info)(nil)
 	require.NoError(t, err)
 
 	req := func(key string) (context.Context, *pulumirpc.GetMappingRequest) {
diff --git a/pf/tests/schemas.go b/pf/tests/schemas.go
index a8e3d5bc..a40051f2 100644
--- a/pf/tests/schemas.go
+++ b/pf/tests/schemas.go
@@ -17,6 +17,7 @@ package tfbridgetests
 import (
 	"bytes"
 	"context"
+	"encoding/json"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -26,6 +27,8 @@ import (
 
 	tfpf "github.com/pulumi/pulumi-terraform-bridge/pf/tfbridge"
 	"github.com/pulumi/pulumi-terraform-bridge/pf/tfgen"
+	tfbridge0 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
+	tfgen0 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfgen"
 )
 
 func genMetadata(t *testing.T, info tfpf.ProviderInfo) tfpf.ProviderMetadata {
@@ -51,3 +54,11 @@ func testSink(t *testing.T) diag.Sink {
 
 	return testSink
 }
+
+func genSDKSchema(t *testing.T, info tfbridge0.ProviderInfo) []byte {
+	pkg, err := tfgen0.GenerateSchema(info, testSink(t))
+	require.NoError(t, err)
+	bytes, err := json.MarshalIndent(pkg, "", "  ")
+	require.NoError(t, err)
+	return bytes
+}
diff --git a/pf/tfgen/not_supported_test.go b/pf/tfgen/not_supported_test.go
index ad8a07e7..70e22952 100644
--- a/pf/tfgen/not_supported_test.go
+++ b/pf/tfgen/not_supported_test.go
@@ -31,6 +31,6 @@ func TestZeroRecognizer(t *testing.T) {
 		sink: diag.DefaultSink(&stdout, &stderr, diag.FormatOptions{Color: colors.Never}),
 	}
 
-	u.assertNotZero("key", "value")
+	u.assertIsZero("key", "value")
 	require.Contains(t, stderr.String(), "key received a non-zero custom value")
 }
diff --git a/x/muxer/mapping_test.go b/x/muxer/mapping_test.go
index dab3a2af..71383363 100644
--- a/x/muxer/mapping_test.go
+++ b/x/muxer/mapping_test.go
@@ -164,11 +164,5 @@ func TestMergeSchemasAndComputeDispatchTable(t *testing.T) {
 			"pkg:mod:ResB": 1,
 		},
 		Functions: map[string]int{},
-
-		Config: map[string][]int{
-			"var1": {0},
-			"var2": {0, 1},
-			"var3": {1},
-		},
 	}, computedDT.dispatchTable)
 }
diff --git a/x/muxer/tests/muxer_test.go b/x/muxer/tests/muxer_test.go
index eb488877..4b1a607f 100644
--- a/x/muxer/tests/muxer_test.go
+++ b/x/muxer/tests/muxer_test.go
@@ -74,11 +74,6 @@ func TestConfigure(t *testing.T) {
 		"test:mod:A": 0,
 		"test:mod:B": 1,
 	}
-	m.Config = map[string][]int{
-		"a": {0},
-		"b": {0, 1},
-		"c": {1},
-	}
 
 	mux(t, m).replay(
 		exchange("/pulumirpc.ResourceProvider/Configure", `{
@@ -93,7 +88,8 @@ func TestConfigure(t *testing.T) {
 			part(0, `{
   "args": {
     "a": "1",
-    "b": "2"
+    "b": "2",
+    "c": "3"
   }
 }`, `{
   "acceptSecrets": true,
@@ -101,6 +97,7 @@ func TestConfigure(t *testing.T) {
 }`),
 			part(1, `{
   "args": {
+    "a": "1",
     "b": "2",
     "c": "3"
   }
@@ -144,12 +141,16 @@ func TestGetMapping(t *testing.T) {
 			"test:mod:B": 1,
 		}
 
-		combine := func(provider string, data [][]byte) ([]byte, error) {
-			assert.Equal(t, "p1", provider)
-			assert.Len(t, data, 2)
-			assert.Equalf(t, "d1", string(data[0]), "first sub-server")
-			assert.Equalf(t, "d2", string(data[1]), "second sub-server")
-			return []byte("r1"), nil
+		combine := func(args muxer.GetMappingArgs) (muxer.GetMappingResponse, error) {
+			result := args.Fetch()
+			assert.Equal(t, "p1", result[0].Provider)
+			assert.Len(t, result, 2)
+			assert.Equalf(t, "d1", string(result[0].Data), "first sub-server")
+			assert.Equalf(t, "d2", string(result[1].Data), "second sub-server")
+			return muxer.GetMappingResponse{
+				Provider: "p1",
+				Data:     []byte("r1"),
+			}, nil
 		}
 
 		mux(t, m).getMappingHandler("k", combine).replay(