encoding/protobuf: move to new-style definitions

Change-Id: Ic5ce67f8e8258eab16d48b96cec63e424f24007f
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5943
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/testdata/script/def_proto.txt b/cmd/cue/cmd/testdata/script/def_proto.txt
index bbb8ec0..684aded 100644
--- a/cmd/cue/cmd/testdata/script/def_proto.txt
+++ b/cmd/cue/cmd/testdata/script/def_proto.txt
@@ -8,14 +8,14 @@
 import "time"
 
 // Attributes defines attributes.
-Attributes :: {
+#Attributes: {
 	// A map of attribute name to its value.
 	attributes?: {
-		[string]: AttributeValue
+		[string]: #AttributeValue
 	} @protobuf(1,type=map<string,AttributeValue>)
 
 	// Specifies one attribute value with different type.
-	AttributeValue :: {
+	#AttributeValue: {
 		// The attribute value.
 		close({}) | close({
 			stringValue: string @protobuf(2,name=string_value)
@@ -31,12 +31,12 @@
 			timestampValue: time.Time @protobuf(7,type=google.protobuf.Timestamp,name=timestamp_value)
 		}) | close({
 			// Used for values of type STRING_MAP
-			stringMapValue: StringMap @protobuf(9,name=string_map_value)
+			stringMapValue: #StringMap @protobuf(9,name=string_map_value)
 		})
 	}
 
 	// Defines a string map.
-	StringMap :: {
+	#StringMap: {
 		// Holds a set of name/value pairs.
 		entries?: {
 			[string]: string
diff --git a/cmd/cue/cmd/testdata/script/import_proto.txt b/cmd/cue/cmd/testdata/script/import_proto.txt
index 7ea596f..6ab00a8 100644
--- a/cmd/cue/cmd/testdata/script/import_proto.txt
+++ b/cmd/cue/cmd/testdata/script/import_proto.txt
@@ -21,7 +21,7 @@
 -- root/cue.mod/gen/googleapis.com/acme/test/test/test_proto_gen.cue --
 package test_test
 
-AnotherTest: {
+#AnotherTest: {
 	test?: int32 @protobuf(1)
 }
 -- root/mixer/v1/attributes.proto --
@@ -170,14 +170,14 @@
 )
 
 // Attributes defines attributes.
-Attributes :: {
+#Attributes: {
 	// A map of attribute name to its value.
 	attributes?: {
-		[string]: AttributeValue
+		[string]: #AttributeValue
 	} @protobuf(1,type=map<string,AttributeValue>)
 
 	// Specifies one attribute value with different type.
-	AttributeValue :: {
+	#AttributeValue: {
 		// The attribute value.
 		close({}) | close({
 			stringValue: string @protobuf(2,name=string_value)
@@ -193,16 +193,16 @@
 			timestampValue: time.Time @protobuf(7,type=google.protobuf.Timestamp,name=timestamp_value)
 		}) | close({
 			// Used for values of type STRING_MAP
-			stringMapValue: StringMap @protobuf(9,name=string_map_value)
+			stringMapValue: #StringMap @protobuf(9,name=string_map_value)
 		}) | close({
-			testValue: test.Test @protobuf(10,type=acme.test.Test,name=test_value)
+			testValue: test.#Test @protobuf(10,type=acme.test.Test,name=test_value)
 		}) | close({
-			testValue: test_test.AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
+			testValue: test_test.#AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
 		})
 	}
 
 	// Defines a string map.
-	StringMap :: {
+	#StringMap: {
 		// Holds a set of name/value pairs.
 		entries?: {
 			[string]: string
@@ -216,14 +216,14 @@
 import "acme.com/api/mixer/v1"
 
 // Defines the per-service client configuration.
-ServiceConfig :: {
-	disableCheckCalls?:  bool          @protobuf(1,name=disable_check_calls)
-	disableReportCalls?: bool          @protobuf(2,name=disable_report_calls)
-	mixerAttributes?:    v1.Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
+#ServiceConfig: {
+	disableCheckCalls?:  bool           @protobuf(1,name=disable_check_calls)
+	disableReportCalls?: bool           @protobuf(2,name=disable_report_calls)
+	mixerAttributes?:    v1.#Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
 }
 -- expect-test_proto_gen.cue --
 package test
 
-Test :: {
+#Test: {
 	test?: int32 @protobuf(1)
 }
diff --git a/encoding/protobuf/examples_test.go b/encoding/protobuf/examples_test.go
index 43cf758..a0a7f5d 100644
--- a/encoding/protobuf/examples_test.go
+++ b/encoding/protobuf/examples_test.go
@@ -46,7 +46,7 @@
 	// package basic
 	//
 	// // This is my type.
-	// MyType :: {
+	// #MyType: {
 	// 	stringValue?: string @protobuf(1,name=string_value) // just any 'ole string
 	//
 	// 	// A method must start with a capital letter.
diff --git a/encoding/protobuf/parse.go b/encoding/protobuf/parse.go
index 7274b00..833b731 100644
--- a/encoding/protobuf/parse.go
+++ b/encoding/protobuf/parse.go
@@ -195,9 +195,10 @@
 }
 
 type mapping struct {
-	ref   string
-	alias string // alias for the type, if exists.
-	pkg   *protoConverter
+	ref     string
+	cueName string
+	alias   string // alias for the type, if exists.
+	pkg     *protoConverter
 }
 
 func (p *protoConverter) importPath() string {
@@ -223,12 +224,12 @@
 	return p.tfile.Pos(pos.Offset, 0)
 }
 
-func (p *protoConverter) addRef(pos scanner.Position, name string) {
+func (p *protoConverter) addRef(pos scanner.Position, name, cuename string) {
 	top := p.scope[len(p.scope)-1]
 	if _, ok := top[name]; ok {
 		failf(pos, "entity %q already defined", name)
 	}
-	top[name] = mapping{ref: name}
+	top[name] = mapping{ref: name, cueName: cuename}
 }
 
 func (p *protoConverter) addNames(elems []proto.Visitee) {
@@ -260,7 +261,7 @@
 		}
 		sym := strings.Join(append(p.path, name), ".")
 		p.symbols[sym] = true
-		p.addRef(pos, name)
+		p.addRef(pos, name, "#"+name)
 	}
 }
 
@@ -268,7 +269,7 @@
 	p.scope = p.scope[:len(p.scope)-1]
 }
 
-func (p *protoConverter) uniqueTop(name string) string {
+func (p *protoConverter) uniqueTop(name string, asIs bool) string {
 	a := strings.SplitN(name, ".", 2)
 	for i := len(p.scope) - 1; i > 0; i-- {
 		if _, ok := p.scope[i][a[0]]; ok {
@@ -283,19 +284,32 @@
 				})
 				p.aliases[first] = alias
 			}
-			if len(a) > 1 {
-				alias += "." + a[1]
+			a[0] = alias
+			if len(a) > 1 && !asIs {
+				a[1] = "#" + a[1]
 			}
-			return alias
+			return strings.Join(a, ".")
 		}
 	}
-	return name
+
+	if e, ok := p.scope[0][name]; ok {
+		return e.cueName
+	}
+	// TODO: do something more principled.
+	switch name {
+	case "time.Time", "time.Duration":
+		return name
+	}
+	if !asIs {
+		a[len(a)-1] = "#" + a[len(a)-1]
+	}
+	return strings.Join(a, ".")
 }
 
 func (p *protoConverter) toExpr(pos scanner.Position, name string) (expr ast.Expr) {
 	expr, err := parser.ParseExpr("", name, parser.ParseComments)
 	if err != nil {
-		panic(err)
+		panic(fmt.Sprintf("error parsing name %q: %v", name, err))
 	}
 	ast.SetPos(expr, p.toCUEPos(pos))
 	return expr
@@ -303,14 +317,14 @@
 
 func (p *protoConverter) resolve(pos scanner.Position, name string, options []*proto.Option) string {
 	if s, ok := protoToCUE(name, options); ok {
-		return p.uniqueTop(s)
+		return p.uniqueTop(s, true)
 	}
 	if strings.HasPrefix(name, ".") {
 		return p.resolveTopScope(pos, name[1:], options)
 	}
 	for i := len(p.scope) - 1; i > 0; i-- {
 		if m, ok := p.scope[i][name]; ok {
-			return m.ref
+			return m.cueName
 		}
 	}
 	return p.resolveTopScope(pos, name, options)
@@ -324,12 +338,14 @@
 			i = len(name)
 		}
 		if m, ok := p.scope[0][name[:i]]; ok {
+			isPkg := false
 			if m.pkg != nil {
 				p.imported[m.pkg.importPath()] = true
 				// TODO: do something more principled.
+				isPkg = true
 			}
 			cueName := name[i:]
-			return p.uniqueTop(m.ref + cueName)
+			return p.uniqueTop(m.ref+cueName, !isPkg || m.ref == m.cueName)
 		}
 	}
 	failf(pos, "name %q not found", name)
@@ -385,7 +401,7 @@
 				if imp.importPath() == p.importPath() {
 					pkg = nil
 				}
-				p.scope[0][ref] = mapping{prefix + k, "", pkg}
+				p.scope[0][ref] = mapping{prefix + k, prefix + toCue(k), "", pkg}
 			}
 		}
 		if len(pkgNamespace) == 0 {
@@ -400,6 +416,15 @@
 	return nil
 }
 
+// TODO: this doesn't work. Do something more principled.
+func toCue(name string) string {
+	a := strings.Split(name, ".")
+	for i, s := range a {
+		a[i] = "#" + s
+	}
+	return strings.Join(a, ".")
+}
+
 func (p *protoConverter) stringLit(pos scanner.Position, s string) *ast.BasicLit {
 	return &ast.BasicLit{
 		ValuePos: p.toCUEPos(pos),
@@ -412,13 +437,14 @@
 }
 
 func (p *protoConverter) ref(pos scanner.Position) *ast.Ident {
-	return &ast.Ident{NamePos: p.toCUEPos(pos), Name: p.path[len(p.path)-1]}
+	name := "#" + p.path[len(p.path)-1]
+	return &ast.Ident{NamePos: p.toCUEPos(pos), Name: name}
 }
 
 func (p *protoConverter) subref(pos scanner.Position, name string) *ast.Ident {
 	return &ast.Ident{
 		NamePos: p.toCUEPos(pos),
-		Name:    name,
+		Name:    "#" + name,
 	}
 }
 
@@ -485,7 +511,7 @@
 	if v.Comment == nil {
 		ref.NamePos = newSection
 	}
-	f := &ast.Field{Label: ref, Token: token.ISA, Value: s}
+	f := &ast.Field{Label: ref, Value: s}
 	addComments(f, 1, v.Comment, nil)
 
 	p.addDecl(f)
@@ -607,14 +633,14 @@
 	}
 
 	// Top-level enum entry.
-	enum := &ast.Field{Label: name, Token: token.ISA}
+	enum := &ast.Field{Label: name}
 	addComments(enum, 1, x.Comment, nil)
 
 	// Top-level enum values entry.
 	valueName := ast.NewIdent(name.Name + "_value")
 	valueName.NamePos = newSection
 	valueMap := &ast.StructLit{}
-	d := &ast.Field{Label: valueName, Token: token.ISA, Value: valueMap}
+	d := &ast.Field{Label: valueName, Value: valueMap}
 	// addComments(valueMap, 1, x.Comment, nil)
 
 	if strings.Contains(name.Name, "google") {
@@ -727,7 +753,7 @@
 
 	// body of @protobuf tag: sequence[,type][,name=<name>][,...]
 	o.tags += fmt.Sprint(x.Sequence)
-	if x.Type != typ {
+	if x.Type != strings.TrimLeft(typ, "#") {
 		o.tags += ",type=" + x.Type
 	}
 	if x.Name != name.Name {
diff --git a/encoding/protobuf/testdata/attributes.proto.out.cue b/encoding/protobuf/testdata/attributes.proto.out.cue
index d0f6618..1c3ff05 100644
--- a/encoding/protobuf/testdata/attributes.proto.out.cue
+++ b/encoding/protobuf/testdata/attributes.proto.out.cue
@@ -19,7 +19,7 @@
 	"time"
 )
 
-StructWrap :: {
+#StructWrap: {
 	struct?: {} @protobuf(1,type=google.protobuf.Struct)
 	any?: _ @protobuf(2,type=google.protobuf.Value)
 	listVal?: [...] @protobuf(3,type=google.protobuf.ListValue)
@@ -45,14 +45,14 @@
 // target.service: example
 // ```
 //
-Attributes :: {
+#Attributes: {
 	// A map of attribute name to its value.
 	attributes?: {
-		[string]: AttributeValue
+		[string]: #AttributeValue
 	} @protobuf(1,type=map<string,AttributeValue>)
 
 	// Specifies one attribute value with different type.
-	AttributeValue :: {
+	#AttributeValue: {
 		// The attribute value.
 		close({}) | close({
 			// Used for values of type STRING, DNS_NAME, EMAIL_ADDRESS, and URI
@@ -77,16 +77,16 @@
 			durationValue: time.Duration @protobuf(8,type=google.protobuf.Duration,name=duration_value)
 		}) | close({
 			// Used for values of type STRING_MAP
-			stringMapValue: StringMap @protobuf(9,name=string_map_value)
+			stringMapValue: #StringMap @protobuf(9,name=string_map_value)
 		}) | close({
-			testValue: test.Test @protobuf(10,type=acme.test.Test,name=test_value)
+			testValue: test.#Test @protobuf(10,type=acme.test.Test,name=test_value)
 		}) | close({
-			testValue: test_test.AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
+			testValue: test_test.#AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
 		})
 	}
 
 	// Defines a string map.
-	StringMap :: {
+	#StringMap: {
 		// Holds a set of name/value pairs.
 		entries?: {
 			[string]: string
@@ -101,7 +101,7 @@
 // dictionary instead. The message-level dictionary is carried by the
 // `words` field of this message, the deployment-wide dictionary is determined via
 // configuration.
-CompressedAttributes :: {
+#CompressedAttributes: {
 	// The message-level dictionary.
 	words?: [...string] @protobuf(1)
 
@@ -142,7 +142,7 @@
 
 	// Holds attributes of type STRING_MAP
 	stringMaps?: {
-		[string]: StringMap
+		[string]: #StringMap
 	} @protobuf(9,type=map<sint32,StringMap>,string_maps,"(gogoproto.nullable)=false")
 }
 let _time_ = time
@@ -150,7 +150,7 @@
 
 // A map of string to string. The keys and values in this map are dictionary
 // indices (see the [Attributes][istio.mixer.v1.CompressedAttributes] message for an explanation)
-StringMap :: {
+#StringMap: {
 	// Holds a set of name/value pairs.
 	entries?: {
 		[string]: int32
diff --git a/encoding/protobuf/testdata/client_config.proto.out.cue b/encoding/protobuf/testdata/client_config.proto.out.cue
index 8e12f61..5bf1119 100644
--- a/encoding/protobuf/testdata/client_config.proto.out.cue
+++ b/encoding/protobuf/testdata/client_config.proto.out.cue
@@ -25,17 +25,17 @@
 )
 
 // Specifies the behavior when the client is unable to connect to Mixer.
-NetworkFailPolicy :: {
+#NetworkFailPolicy: {
 	// Example of single-value enum.
-	FailPolicy ::
+	#FailPolicy:
 		// If network connection fails, request is allowed and delivered to the
 		// service.
 		"FAIL_OPEN"
 
-	FailPolicy_value :: FAIL_OPEN: 0
+	#FailPolicy_value: FAIL_OPEN: 0
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
-	policy?: FailPolicy @protobuf(1)
+	policy?: #FailPolicy @protobuf(1)
 
 	// Max retries on transport error.
 	maxRetry?: uint32 @protobuf(2,name=max_retry)
@@ -49,7 +49,7 @@
 }
 
 // Defines the per-service client configuration.
-ServiceConfig :: {
+#ServiceConfig: {
 	// If true, do not call Mixer Check.
 	disableCheckCalls?: bool @protobuf(1,name=disable_check_calls)
 
@@ -60,19 +60,19 @@
 	// typically includes the "destination.service" attribute.
 	// In case of a per-route override, per-route attributes take precedence
 	// over the attributes supplied in the client configuration.
-	mixerAttributes?: v1.Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
 
 	// HTTP API specifications to generate API attributes.
-	httpApiSpec?: [...HTTPAPISpec] @protobuf(4,name=http_api_spec)
+	httpApiSpec?: [...#HTTPAPISpec] @protobuf(4,name=http_api_spec)
 
 	// Quota specifications to generate quota requirements.
-	quotaSpec?: [...QuotaSpec] @protobuf(5,name=quota_spec)
+	quotaSpec?: [...#QuotaSpec] @protobuf(5,name=quota_spec)
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
 	// This is the service-level policy. It overrides
 	// [mesh-level
 	// policy][istio.mixer.v1.config.client.TransportConfig.network_fail_policy].
-	networkFailPolicy?: NetworkFailPolicy @protobuf(7,name=network_fail_policy)
+	networkFailPolicy?: #NetworkFailPolicy @protobuf(7,name=network_fail_policy)
 
 	// Default attributes to forward to upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes.
@@ -86,11 +86,11 @@
 	// 3. forwarded attributes from the source filter config (if any);
 	// 4. forwarded attributes from the source route config (if any);
 	// 5. derived attributes from the request metadata.
-	forwardAttributes?: v1.Attributes @protobuf(8,type=Attributes,name=forward_attributes)
+	forwardAttributes?: v1.#Attributes @protobuf(8,type=Attributes,name=forward_attributes)
 }
 
 // Defines the transport config on how to call Mixer.
-TransportConfig :: {
+#TransportConfig: {
 	// The flag to disable check cache.
 	disableCheckCache?: bool @protobuf(1,name=disable_check_cache)
 
@@ -102,7 +102,7 @@
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
 	// This is the mesh level policy. The default value for policy is FAIL_OPEN.
-	networkFailPolicy?: NetworkFailPolicy @protobuf(4,name=network_fail_policy)
+	networkFailPolicy?: #NetworkFailPolicy @protobuf(4,name=network_fail_policy)
 
 	// Specify refresh interval to write Mixer client statistics to Envoy share
 	// memory. If not specified, the interval is 10 seconds.
@@ -131,19 +131,19 @@
 	// Default attributes to forward to Mixer upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes. These
 	// attributes are consumed by the proxy in front of mixer.
-	attributesForMixerProxy?: v1.Attributes @protobuf(8,type=Attributes,name=attributes_for_mixer_proxy)
+	attributesForMixerProxy?: v1.#Attributes @protobuf(8,type=Attributes,name=attributes_for_mixer_proxy)
 }
 
 // Defines the client config for HTTP.
-HttpClientConfig :: {
+#HttpClientConfig: {
 	// The transport config.
-	transport?: TransportConfig @protobuf(1)
+	transport?: #TransportConfig @protobuf(1)
 
 	// Map of control configuration indexed by destination.service. This
 	// is used to support per-service configuration for cases where a
 	// mixerclient serves multiple services.
 	serviceConfigs?: {
-		[string]: ServiceConfig
+		[string]: #ServiceConfig
 	} @protobuf(2,type=map<string,ServiceConfig>,service_configs)
 
 	// Default destination service name if none was specified in the
@@ -153,22 +153,22 @@
 	// Default attributes to send to Mixer in both Check and
 	// Report. This typically includes "destination.ip" and
 	// "destination.uid" attributes.
-	mixerAttributes?: v1.Attributes @protobuf(4,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(4,type=Attributes,name=mixer_attributes)
 
 	// Default attributes to forward to upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes.
-	forwardAttributes?: v1.Attributes @protobuf(5,type=Attributes,name=forward_attributes)
+	forwardAttributes?: v1.#Attributes @protobuf(5,type=Attributes,name=forward_attributes)
 }
 
 // Defines the client config for TCP.
-TcpClientConfig :: {
+#TcpClientConfig: {
 	// The transport config.
-	transport?: TransportConfig @protobuf(1)
+	transport?: #TransportConfig @protobuf(1)
 
 	// Default attributes to send to Mixer in both Check and
 	// Report. This typically includes "destination.ip" and
 	// "destination.uid" attributes.
-	mixerAttributes?: v1.Attributes @protobuf(2,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(2,type=Attributes,name=mixer_attributes)
 
 	// If set to true, disables Mixer check calls.
 	disableCheckCalls?: bool @protobuf(3,name=disable_check_calls)
@@ -178,7 +178,7 @@
 
 	// Quota specifications to generate quota requirements.
 	// It applies on the new TCP connections.
-	connectionQuotaSpec?: QuotaSpec @protobuf(5,name=connection_quota_spec)
+	connectionQuotaSpec?: #QuotaSpec @protobuf(5,name=connection_quota_spec)
 
 	// Specify report interval to send periodical reports for long TCP
 	// connections. If not specified, the interval is 10 seconds. This interval
diff --git a/encoding/protobuf/testdata/gateway.proto.out.cue b/encoding/protobuf/testdata/gateway.proto.out.cue
index b5e3056..d0d5330 100644
--- a/encoding/protobuf/testdata/gateway.proto.out.cue
+++ b/encoding/protobuf/testdata/gateway.proto.out.cue
@@ -203,9 +203,9 @@
 //
 package v1alpha3
 
-Gateway :: {
+#Gateway: {
 	// REQUIRED: A list of server specifications.
-	servers?: [...Server] @protobuf(1)
+	servers?: [...#Server] @protobuf(1)
 
 	// REQUIRED: One or more labels that indicate a specific set of pods/VMs
 	// on which this gateway configuration should be applied. The scope of
@@ -279,10 +279,10 @@
 //       serverCertificate: /etc/certs/server.pem
 //       privateKey: /etc/certs/privatekey.pem
 // ```
-Server :: {
+#Server: {
 	// REQUIRED: The Port on which the proxy should listen for incoming
 	// connections.
-	port?: Port @protobuf(1)
+	port?: #Port @protobuf(1)
 	port?: >10 & <100
 
 	// $hide_from_docs
@@ -318,13 +318,13 @@
 	// `DestinationRule`, and `ServiceEntry` configurations for details.
 	hosts?: [...string] @protobuf(2)
 
-	TLSOptions :: {
+	#TLSOptions: {
 		// If set to true, the load balancer will send a 301 redirect for all
 		// http connections, asking the clients to use HTTPS.
 		httpsRedirect?: bool @protobuf(1,name=https_redirect)
 
 		// TLS modes enforced by the proxy
-		TLSmode ::
+		#TLSmode:
 			// The SNI string presented by the client will be used as the match
 			// criterion in a VirtualService TLS route to determine the
 			// destination service from the service registry.
@@ -349,7 +349,7 @@
 			// source and the destination are using Istio mTLS to secure traffic.
 			"AUTO_PASSTHROUGH"
 
-		TLSmode_value :: {
+		#TLSmode_value: {
 			PASSTHROUGH:      0
 			SIMPLE:           1
 			MUTUAL:           2
@@ -359,7 +359,7 @@
 		// Optional: Indicates whether connections to this port should be
 		// secured using TLS. The value of this field determines how TLS is
 		// enforced.
-		mode?: TLSmode @protobuf(2)
+		mode?: #TLSmode @protobuf(2)
 
 		// Extra comment.
 
@@ -399,13 +399,13 @@
 		subjectAltNames?: [...string] @protobuf(6,name=subject_alt_names)
 
 		// TLS protocol versions.
-		TLSProtocol :: "TLS_AUTO" | // Automatically choose the optimal TLS version.
+		#TLSProtocol: "TLS_AUTO" | // Automatically choose the optimal TLS version.
 			"TLSV1_0" | // TLS version 1.0
 			"TLSV1_1" | // TLS version 1.1
 			"TLSV1_2" | // TLS version 1.2
 			"TLSV1_3" // TLS version 1.3
 
-		TLSProtocol_value :: {
+		#TLSProtocol_value: {
 			TLS_AUTO: 0
 			TLSV1_0:  1
 			TLSV1_1:  2
@@ -414,10 +414,10 @@
 		}
 
 		// Optional: Minimum TLS protocol version.
-		minProtocolVersion?: TLSProtocol @protobuf(7,name=min_protocol_version)
+		minProtocolVersion?: #TLSProtocol @protobuf(7,name=min_protocol_version)
 
 		// Optional: Maximum TLS protocol version.
-		maxProtocolVersion?: TLSProtocol @protobuf(8,name=max_protocol_version)
+		maxProtocolVersion?: #TLSProtocol @protobuf(8,name=max_protocol_version)
 
 		// Optional: If specified, only support the specified cipher list.
 		// Otherwise default to the default cipher list supported by Envoy.
@@ -427,7 +427,7 @@
 	// Set of TLS related options that govern the server's behavior. Use
 	// these options to control if all http requests should be redirected to
 	// https, and the TLS modes to use.
-	tls?: TLSOptions @protobuf(3)
+	tls?: #TLSOptions @protobuf(3)
 
 	// The loopback IP endpoint or Unix domain socket to which traffic should
 	// be forwarded to by default. Format should be `127.0.0.1:PORT` or
@@ -436,7 +436,7 @@
 }
 
 // Port describes the properties of a specific port of a service.
-Port :: {
+#Port: {
 	// REQUIRED: A valid non-negative integer port number.
 	number?: uint32 @protobuf(1)
 
diff --git a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue
index 9d0254f..ae8f090 100644
--- a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor_proto_gen.cue
@@ -74,12 +74,12 @@
 
 // The protocol compiler can output a FileDescriptorSet containing the .proto
 // files it parses.
-FileDescriptorSet :: {
-	file?: [...FileDescriptorProto] @protobuf(1)
+#FileDescriptorSet: {
+	file?: [...#FileDescriptorProto] @protobuf(1)
 }
 
 // Describes a complete .proto file.
-FileDescriptorProto :: {
+#FileDescriptorProto: {
 	name?:    string @protobuf(1) // file name, relative to root of source tree
 	package?: string @protobuf(2) // e.g. "foo", "foo.bar", etc.
 
@@ -94,17 +94,17 @@
 	weakDependency?: [...int32] @protobuf(11,name=weak_dependency)
 
 	// All top-level definitions in this file.
-	messageType?: [...DescriptorProto] @protobuf(4,name=message_type)
-	enumType?: [...EnumDescriptorProto] @protobuf(5,name=enum_type)
-	service?: [...ServiceDescriptorProto] @protobuf(6)
-	extension?: [...FieldDescriptorProto] @protobuf(7)
-	options?: FileOptions @protobuf(8)
+	messageType?: [...#DescriptorProto] @protobuf(4,name=message_type)
+	enumType?: [...#EnumDescriptorProto] @protobuf(5,name=enum_type)
+	service?: [...#ServiceDescriptorProto] @protobuf(6)
+	extension?: [...#FieldDescriptorProto] @protobuf(7)
+	options?: #FileOptions @protobuf(8)
 
 	// This field contains optional information about the original source code.
 	// You may safely remove this entire field without harming runtime
 	// functionality of the descriptors -- the information is needed only by
 	// development tools.
-	sourceCodeInfo?: SourceCodeInfo @protobuf(9,name=source_code_info)
+	sourceCodeInfo?: #SourceCodeInfo @protobuf(9,name=source_code_info)
 
 	// The syntax of the proto file.
 	// The supported values are "proto2" and "proto3".
@@ -112,44 +112,44 @@
 }
 
 // Describes a message type.
-DescriptorProto :: {
+#DescriptorProto: {
 	name?: string @protobuf(1)
-	field?: [...FieldDescriptorProto] @protobuf(2)
-	extension?: [...FieldDescriptorProto] @protobuf(6)
-	nestedType?: [...DescriptorProto] @protobuf(3,name=nested_type)
-	enumType?: [...EnumDescriptorProto] @protobuf(4,name=enum_type)
+	field?: [...#FieldDescriptorProto] @protobuf(2)
+	extension?: [...#FieldDescriptorProto] @protobuf(6)
+	nestedType?: [...#DescriptorProto] @protobuf(3,name=nested_type)
+	enumType?: [...#EnumDescriptorProto] @protobuf(4,name=enum_type)
 
-	ExtensionRange :: {
-		start?:   int32                 @protobuf(1) // Inclusive.
-		end?:     int32                 @protobuf(2) // Exclusive.
-		options?: ExtensionRangeOptions @protobuf(3)
+	#ExtensionRange: {
+		start?:   int32                  @protobuf(1) // Inclusive.
+		end?:     int32                  @protobuf(2) // Exclusive.
+		options?: #ExtensionRangeOptions @protobuf(3)
 	}
-	extensionRange?: [...ExtensionRange] @protobuf(5,name=extension_range)
-	oneofDecl?: [...OneofDescriptorProto] @protobuf(8,name=oneof_decl)
-	options?: MessageOptions @protobuf(7)
+	extensionRange?: [...#ExtensionRange] @protobuf(5,name=extension_range)
+	oneofDecl?: [...#OneofDescriptorProto] @protobuf(8,name=oneof_decl)
+	options?: #MessageOptions @protobuf(7)
 
 	// Range of reserved tag numbers. Reserved tag numbers may not be used by
 	// fields or extension ranges in the same message. Reserved ranges may
 	// not overlap.
-	ReservedRange :: {
+	#ReservedRange: {
 		start?: int32 @protobuf(1) // Inclusive.
 		end?:   int32 @protobuf(2) // Exclusive.
 	}
-	reservedRange?: [...ReservedRange] @protobuf(9,name=reserved_range)
+	reservedRange?: [...#ReservedRange] @protobuf(9,name=reserved_range)
 
 	// Reserved field names, which may not be used by fields in the same message.
 	// A given name may only be reserved once.
 	reservedName?: [...string] @protobuf(10,name=reserved_name)
 }
 
-ExtensionRangeOptions :: {
+#ExtensionRangeOptions: {
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
 // Describes a field within a message.
-FieldDescriptorProto :: {
-	Type ::
+#FieldDescriptorProto: {
+	#Type:
 		"TYPE_DOUBLE" |
 		"TYPE_FLOAT" |
 
@@ -185,7 +185,7 @@
 		// Order is weird for historical reasons.
 		"TYPE_SINT64" // Uses ZigZag encoding.
 
-	Type_value :: {
+	#Type_value: {
 		"TYPE_DOUBLE":   1
 		"TYPE_FLOAT":    2
 		"TYPE_INT64":    3
@@ -205,24 +205,24 @@
 		"TYPE_SINT32":   17
 		"TYPE_SINT64":   18
 	}
-	Label ::
+	#Label:
 		// 0 is reserved for errors
 		"LABEL_OPTIONAL" |
 		"LABEL_REQUIRED" |
 		"LABEL_REPEATED"
 
-	Label_value :: {
+	#Label_value: {
 		"LABEL_OPTIONAL": 1
 		"LABEL_REQUIRED": 2
 		"LABEL_REPEATED": 3
 	}
 	name?:   string @protobuf(1)
 	number?: int32  @protobuf(3)
-	label?:  Label  @protobuf(4)
+	label?:  #Label @protobuf(4)
 
 	// If type_name is set, this need not be set.  If both this and type_name
 	// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
-	type?: Type @protobuf(5)
+	type?: #Type @protobuf(5)
 
 	// For message and enum types, this is the name of the type.  If the name
 	// starts with a '.', it is fully-qualified.  Otherwise, C++-like scoping
@@ -250,21 +250,21 @@
 	// user has set a "json_name" option on this field, that option's value
 	// will be used. Otherwise, it's deduced from the field's name by converting
 	// it to camelCase.
-	jsonName?: string       @protobuf(10,name=json_name)
-	options?:  FieldOptions @protobuf(8)
+	jsonName?: string        @protobuf(10,name=json_name)
+	options?:  #FieldOptions @protobuf(8)
 }
 
 // Describes a oneof.
-OneofDescriptorProto :: {
-	name?:    string       @protobuf(1)
-	options?: OneofOptions @protobuf(2)
+#OneofDescriptorProto: {
+	name?:    string        @protobuf(1)
+	options?: #OneofOptions @protobuf(2)
 }
 
 // Describes an enum type.
-EnumDescriptorProto :: {
+#EnumDescriptorProto: {
 	name?: string @protobuf(1)
-	value?: [...EnumValueDescriptorProto] @protobuf(2)
-	options?: EnumOptions @protobuf(3)
+	value?: [...#EnumValueDescriptorProto] @protobuf(2)
+	options?: #EnumOptions @protobuf(3)
 
 	// Range of reserved numeric values. Reserved values may not be used by
 	// entries in the same enum. Reserved ranges may not overlap.
@@ -272,7 +272,7 @@
 	// Note that this is distinct from DescriptorProto.ReservedRange in that it
 	// is inclusive such that it can appropriately represent the entire int32
 	// domain.
-	EnumReservedRange :: {
+	#EnumReservedRange: {
 		start?: int32 @protobuf(1) // Inclusive.
 		end?:   int32 @protobuf(2) // Inclusive.
 	}
@@ -280,7 +280,7 @@
 	// Range of reserved numeric values. Reserved numeric values may not be used
 	// by enum values in the same enum declaration. Reserved ranges may not
 	// overlap.
-	reservedRange?: [...EnumReservedRange] @protobuf(4,name=reserved_range)
+	reservedRange?: [...#EnumReservedRange] @protobuf(4,name=reserved_range)
 
 	// Reserved enum value names, which may not be reused. A given name may only
 	// be reserved once.
@@ -288,28 +288,28 @@
 }
 
 // Describes a value within an enum.
-EnumValueDescriptorProto :: {
-	name?:    string           @protobuf(1)
-	number?:  int32            @protobuf(2)
-	options?: EnumValueOptions @protobuf(3)
+#EnumValueDescriptorProto: {
+	name?:    string            @protobuf(1)
+	number?:  int32             @protobuf(2)
+	options?: #EnumValueOptions @protobuf(3)
 }
 
 // Describes a service.
-ServiceDescriptorProto :: {
+#ServiceDescriptorProto: {
 	name?: string @protobuf(1)
-	method?: [...MethodDescriptorProto] @protobuf(2)
-	options?: ServiceOptions @protobuf(3)
+	method?: [...#MethodDescriptorProto] @protobuf(2)
+	options?: #ServiceOptions @protobuf(3)
 }
 
 // Describes a method of a service.
-MethodDescriptorProto :: {
+#MethodDescriptorProto: {
 	name?: string @protobuf(1)
 
 	// Input and output type names.  These are resolved in the same way as
 	// FieldDescriptorProto.type_name, but must refer to a message type.
-	inputType?:  string        @protobuf(2,name=input_type)
-	outputType?: string        @protobuf(3,name=output_type)
-	options?:    MethodOptions @protobuf(4)
+	inputType?:  string         @protobuf(2,name=input_type)
+	outputType?: string         @protobuf(3,name=output_type)
+	options?:    #MethodOptions @protobuf(4)
 
 	// Identifies if client streams multiple client messages
 	clientStreaming?: bool @protobuf(5,name=client_streaming,"default=false")
@@ -318,7 +318,7 @@
 	serverStreaming?: bool @protobuf(6,name=server_streaming,"default=false")
 }
 
-FileOptions :: {
+#FileOptions: {
 	// Sets the Java package where classes generated from this .proto will be
 	// placed.  By default, the proto package is used, but this is often
 	// inappropriate because proto packages do not normally start with backwards
@@ -352,18 +352,18 @@
 	javaStringCheckUtf8?: bool @protobuf(27,name=java_string_check_utf8,"default=false")
 
 	// Generated classes can be optimized for speed or code size.
-	OptimizeMode :: "SPEED" | // Generate complete code for parsing, serialization,
+	#OptimizeMode: "SPEED" | // Generate complete code for parsing, serialization,
 
 		// etc.
 		"CODE_SIZE" |
 		"LITE_RUNTIME" // Generate code using MessageLite and the lite runtime.
 
-	OptimizeMode_value :: {
+	#OptimizeMode_value: {
 		"SPEED":        1
 		"CODE_SIZE":    2 // Use ReflectionOps to implement these methods.
 		"LITE_RUNTIME": 3
 	}
-	optimizeFor?: OptimizeMode @protobuf(9,name=optimize_for,"default=SPEED")
+	optimizeFor?: #OptimizeMode @protobuf(9,name=optimize_for,"default=SPEED")
 
 	// Sets the Go package where structs generated from this .proto will be
 	// placed. If omitted, the Go package will be derived from the following:
@@ -431,10 +431,10 @@
 
 	// The parser stores options it doesn't recognize here.
 	// See the documentation for the "Options" section above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-MessageOptions :: {
+#MessageOptions: {
 	// Set true to use the old proto1 MessageSet wire format for extensions.
 	// This is provided for backwards-compatibility with the MessageSet wire
 	// format.  You should not use this for any other reason:  It's less
@@ -490,22 +490,22 @@
 	mapEntry?: bool @protobuf(7,name=map_entry)
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-FieldOptions :: {
+#FieldOptions: {
 	// The ctype option instructs the C++ code generator to use a different
 	// representation of the field than it normally would.  See the specific
 	// options below.  This option is not yet implemented in the open source
 	// release -- sorry, we'll try to include it in a future version!
-	ctype?: CType @protobuf(1,"default=STRING")
-	CType ::
+	ctype?: #CType @protobuf(1,"default=STRING")
+	#CType:
 		// Default mode.
 		"STRING" |
 		"CORD" |
 		"STRING_PIECE"
 
-	CType_value :: {
+	#CType_value: {
 		"STRING":       0
 		"CORD":         1
 		"STRING_PIECE": 2
@@ -529,8 +529,8 @@
 	//
 	// This option is an enum to permit additional types to be added, e.g.
 	// goog.math.Integer.
-	jstype?: JSType @protobuf(6,"default=JS_NORMAL")
-	JSType ::
+	jstype?: #JSType @protobuf(6,"default=JS_NORMAL")
+	#JSType:
 		// Use the default type.
 		"JS_NORMAL" |
 
@@ -540,7 +540,7 @@
 		// Use JavaScript numbers.
 		"JS_NUMBER"
 
-	JSType_value :: {
+	#JSType_value: {
 		"JS_NORMAL": 0
 		"JS_STRING": 1
 		"JS_NUMBER": 2
@@ -586,15 +586,15 @@
 	weak?: bool @protobuf(10,"default=false")
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-OneofOptions :: {
+#OneofOptions: {
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-EnumOptions :: {
+#EnumOptions: {
 	// Set this option to true to allow mapping different tag names to the same
 	// value.
 	allowAlias?: bool @protobuf(2,name=allow_alias)
@@ -606,10 +606,10 @@
 	deprecated?: bool @protobuf(3,"default=false")
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-EnumValueOptions :: {
+#EnumValueOptions: {
 	// Is this enum value deprecated?
 	// Depending on the target platform, this can emit Deprecated annotations
 	// for the enum value, or it will be completely ignored; in the very least,
@@ -617,10 +617,10 @@
 	deprecated?: bool @protobuf(1,"default=false")
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-ServiceOptions :: {
+#ServiceOptions: {
 
 	// Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
 	//   framework.  We apologize for hoarding these numbers to ourselves, but
@@ -634,10 +634,10 @@
 	deprecated?: bool @protobuf(33,"default=false")
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
-MethodOptions :: {
+#MethodOptions: {
 
 	// Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
 	//   framework.  We apologize for hoarding these numbers to ourselves, but
@@ -653,19 +653,19 @@
 	// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
 	// or neither? HTTP based RPC implementation may choose GET verb for safe
 	// methods, and PUT verb for idempotent methods instead of the default POST.
-	IdempotencyLevel :: "IDEMPOTENCY_UNKNOWN" |
+	#IdempotencyLevel: "IDEMPOTENCY_UNKNOWN" |
 		"NO_SIDE_EFFECTS" | // implies idempotent
 		"IDEMPOTENT" // idempotent, but may have side effects
 
-	IdempotencyLevel_value :: {
+	#IdempotencyLevel_value: {
 		"IDEMPOTENCY_UNKNOWN": 0
 		"NO_SIDE_EFFECTS":     1
 		"IDEMPOTENT":          2
 	}
-	idempotencyLevel?: IdempotencyLevel @protobuf(34,name=idempotency_level,"default=IDEMPOTENCY_UNKNOWN")
+	idempotencyLevel?: #IdempotencyLevel @protobuf(34,name=idempotency_level,"default=IDEMPOTENCY_UNKNOWN")
 
 	// The parser stores options it doesn't recognize here. See above.
-	uninterpretedOption?: [...UninterpretedOption] @protobuf(999,name=uninterpreted_option)
+	uninterpretedOption?: [...#UninterpretedOption] @protobuf(999,name=uninterpreted_option)
 }
 
 // A message representing a option the parser does not recognize. This only
@@ -674,17 +674,17 @@
 // options protos in descriptor objects (e.g. returned by Descriptor::options(),
 // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
 // in them.
-UninterpretedOption :: {
+#UninterpretedOption: {
 	// The name of the uninterpreted option.  Each string represents a segment in
 	// a dot-separated name.  is_extension is true iff a segment represents an
 	// extension (denoted with parentheses in options specs in .proto files).
 	// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
 	// "foo.(bar.baz).qux".
-	NamePart :: {
+	#NamePart: {
 		namePart?:    string @protobuf(1,name=name_part)
 		isExtension?: bool   @protobuf(2,name=is_extension)
 	}
-	name?: [...NamePart] @protobuf(2)
+	name?: [...#NamePart] @protobuf(2)
 
 	// The value of the uninterpreted option, in whatever type the tokenizer
 	// identified it as during parsing. Exactly one of these should be set.
@@ -698,7 +698,7 @@
 
 // Encapsulates information about the original source file from which a
 // FileDescriptorProto was generated.
-SourceCodeInfo :: {
+#SourceCodeInfo: {
 	// A Location identifies a piece of source code in a .proto file which
 	// corresponds to a particular definition.  This information is intended
 	// to be useful to IDEs, code indexers, documentation generators, and similar
@@ -742,9 +742,9 @@
 	// - Code which tries to interpret locations should probably be designed to
 	//   ignore those that it doesn't understand, as more types of locations could
 	//   be recorded in the future.
-	location?: [...Location] @protobuf(1)
+	location?: [...#Location] @protobuf(1)
 
-	Location :: {
+	#Location: {
 		// Identifies which part of the FileDescriptorProto was defined at this
 		// location.
 		//
@@ -833,12 +833,12 @@
 // Describes the relationship between generated code and its original source
 // file. A GeneratedCodeInfo message is associated with only one generated
 // source file, but may contain references to different source .proto files.
-GeneratedCodeInfo :: {
+#GeneratedCodeInfo: {
 	// An Annotation connects some span of text in generated code to an element
 	// of its generating .proto file.
-	annotation?: [...Annotation] @protobuf(1)
+	annotation?: [...#Annotation] @protobuf(1)
 
-	Annotation :: {
+	#Annotation: {
 		// Identifies the element in the original source .proto file. This field
 		// is formatted the same as SourceCodeInfo.Location.path.
 		path?: [...int32] @protobuf(1,packed)
diff --git a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/google.golang.org/genproto/googleapis/rpc/status/status_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/google.golang.org/genproto/googleapis/rpc/status/status_proto_gen.cue
index 2a660eb..2bfc322 100644
--- a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/google.golang.org/genproto/googleapis/rpc/status/status_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/google.golang.org/genproto/googleapis/rpc/status/status_proto_gen.cue
@@ -66,7 +66,7 @@
 //
 // - Logging. If some API errors are stored in logs, the message `Status` could
 //     be used directly after any stripping needed for security/privacy reasons.
-Status :: {
+#Status: {
 	// The status code, which should be an enum value of
 	// [google.rpc.Code][google.rpc.Code].
 	code?: int32 @protobuf(1)
diff --git a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test/test_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test/test_proto_gen.cue
index 531a95c..7946c97 100644
--- a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test/test_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test/test_proto_gen.cue
@@ -1,5 +1,5 @@
 package test_test
 
-AnotherTest :: {
+#AnotherTest: {
 	test?: int32 @protobuf(1)
 }
diff --git a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test_proto_gen.cue
index 834c4dd..10b74a6 100644
--- a/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/cue.mod/gen/googleapis.com/acme/test/test_proto_gen.cue
@@ -1,5 +1,5 @@
 package test
 
-Test :: {
+#Test: {
 	test?: int32 @protobuf(1)
 }
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
index d0f6618..1c3ff05 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/attributes_proto_gen.cue
@@ -19,7 +19,7 @@
 	"time"
 )
 
-StructWrap :: {
+#StructWrap: {
 	struct?: {} @protobuf(1,type=google.protobuf.Struct)
 	any?: _ @protobuf(2,type=google.protobuf.Value)
 	listVal?: [...] @protobuf(3,type=google.protobuf.ListValue)
@@ -45,14 +45,14 @@
 // target.service: example
 // ```
 //
-Attributes :: {
+#Attributes: {
 	// A map of attribute name to its value.
 	attributes?: {
-		[string]: AttributeValue
+		[string]: #AttributeValue
 	} @protobuf(1,type=map<string,AttributeValue>)
 
 	// Specifies one attribute value with different type.
-	AttributeValue :: {
+	#AttributeValue: {
 		// The attribute value.
 		close({}) | close({
 			// Used for values of type STRING, DNS_NAME, EMAIL_ADDRESS, and URI
@@ -77,16 +77,16 @@
 			durationValue: time.Duration @protobuf(8,type=google.protobuf.Duration,name=duration_value)
 		}) | close({
 			// Used for values of type STRING_MAP
-			stringMapValue: StringMap @protobuf(9,name=string_map_value)
+			stringMapValue: #StringMap @protobuf(9,name=string_map_value)
 		}) | close({
-			testValue: test.Test @protobuf(10,type=acme.test.Test,name=test_value)
+			testValue: test.#Test @protobuf(10,type=acme.test.Test,name=test_value)
 		}) | close({
-			testValue: test_test.AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
+			testValue: test_test.#AnotherTest @protobuf(11,type=acme.test.test.AnotherTest,name=test_value)
 		})
 	}
 
 	// Defines a string map.
-	StringMap :: {
+	#StringMap: {
 		// Holds a set of name/value pairs.
 		entries?: {
 			[string]: string
@@ -101,7 +101,7 @@
 // dictionary instead. The message-level dictionary is carried by the
 // `words` field of this message, the deployment-wide dictionary is determined via
 // configuration.
-CompressedAttributes :: {
+#CompressedAttributes: {
 	// The message-level dictionary.
 	words?: [...string] @protobuf(1)
 
@@ -142,7 +142,7 @@
 
 	// Holds attributes of type STRING_MAP
 	stringMaps?: {
-		[string]: StringMap
+		[string]: #StringMap
 	} @protobuf(9,type=map<sint32,StringMap>,string_maps,"(gogoproto.nullable)=false")
 }
 let _time_ = time
@@ -150,7 +150,7 @@
 
 // A map of string to string. The keys and values in this map are dictionary
 // indices (see the [Attributes][istio.mixer.v1.CompressedAttributes] message for an explanation)
-StringMap :: {
+#StringMap: {
 	// Holds a set of name/value pairs.
 	entries?: {
 		[string]: int32
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/api_spec_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/api_spec_proto_gen.cue
index b3aadd3..33ff9d5 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/api_spec_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/api_spec_proto_gen.cue
@@ -70,14 +70,14 @@
 //   api_keys:
 //   - query: api-key
 // ```
-HTTPAPISpec :: {
+#HTTPAPISpec: {
 	// List of attributes that are generated when *any* of the HTTP
 	// patterns match. This list typically includes the "api.service"
 	// and "api.version" attributes.
-	attributes?: v1.Attributes @protobuf(1,type=Attributes)
+	attributes?: v1.#Attributes @protobuf(1,type=Attributes)
 
 	// List of HTTP patterns to match.
-	patterns?: [...HTTPAPISpecPattern] @protobuf(2)
+	patterns?: [...#HTTPAPISpecPattern] @protobuf(2)
 
 	// List of APIKey that describes how to extract an API-KEY from an
 	// HTTP request. The first API-Key match found in the list is used,
@@ -88,7 +88,7 @@
 	//
 	//     `query: key, `query: api_key`, and then `header: x-api-key`
 	//
-	apiKeys?: [...APIKey] @protobuf(3,name=api_keys)
+	apiKeys?: [...#APIKey] @protobuf(3,name=api_keys)
 }
 
 // HTTPAPISpecPattern defines a single pattern to match against
@@ -104,11 +104,11 @@
 //   httpMethod: GET
 //   uriTemplate: /foo/bar
 // ```
-HTTPAPISpecPattern :: {
+#HTTPAPISpecPattern: {
 	// List of attributes that are generated if the HTTP request matches
 	// the specified http_method and uri_template. This typically
 	// includes the "api.operation" attribute.
-	attributes?: v1.Attributes @protobuf(1,type=Attributes)
+	attributes?: v1.#Attributes @protobuf(1,type=Attributes)
 
 	// HTTP request method to match against as defined by
 	// [rfc7231](https://tools.ietf.org/html/rfc7231#page-21). For
@@ -143,7 +143,7 @@
 //
 // See [API Keys](https://swagger.io/docs/specification/authentication/api-keys)
 // for a general overview of API keys as defined by OpenAPI.
-APIKey :: {
+#APIKey: {
 	close({}) | close({
 		// API Key is sent as a query parameter. `query` represents the
 		// query string parameter name.
@@ -188,7 +188,7 @@
 // - name: foo
 //   namespace: bar
 // ```
-HTTPAPISpecReference :: {
+#HTTPAPISpecReference: {
 	// REQUIRED. The short name of the HTTPAPISpec. This is the resource
 	// name defined by the metadata name field.
 	name?: string @protobuf(1)
@@ -216,12 +216,12 @@
 //   - name: petstore
 //     namespace: default
 // ```
-HTTPAPISpecBinding :: {
+#HTTPAPISpecBinding: {
 	// REQUIRED. One or more services to map the listed HTTPAPISpec onto.
-	services?: [...IstioService] @protobuf(1)
+	services?: [...#IstioService] @protobuf(1)
 
 	// REQUIRED. One or more HTTPAPISpec references that should be mapped to
 	// the specified service(s). The aggregate collection of match
 	// conditions defined in the HTTPAPISpecs should not overlap.
-	apiSpecs?: [...HTTPAPISpecReference] @protobuf(2,name=api_specs)
+	apiSpecs?: [...#HTTPAPISpecReference] @protobuf(2,name=api_specs)
 }
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
index e50b8e0..f032d06 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/client_config_proto_gen.cue
@@ -25,17 +25,17 @@
 )
 
 // Specifies the behavior when the client is unable to connect to Mixer.
-NetworkFailPolicy :: {
+#NetworkFailPolicy: {
 	// Example of single-value enum.
-	FailPolicy ::
+	#FailPolicy:
 		// If network connection fails, request is allowed and delivered to the
 		// service.
 		"FAIL_OPEN"
 
-	FailPolicy_value :: "FAIL_OPEN": 0
+	#FailPolicy_value: "FAIL_OPEN": 0
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
-	policy?: FailPolicy @protobuf(1)
+	policy?: #FailPolicy @protobuf(1)
 
 	// Max retries on transport error.
 	maxRetry?: uint32 @protobuf(2,name=max_retry)
@@ -49,7 +49,7 @@
 }
 
 // Defines the per-service client configuration.
-ServiceConfig :: {
+#ServiceConfig: {
 	// If true, do not call Mixer Check.
 	disableCheckCalls?: bool @protobuf(1,name=disable_check_calls)
 
@@ -60,19 +60,19 @@
 	// typically includes the "destination.service" attribute.
 	// In case of a per-route override, per-route attributes take precedence
 	// over the attributes supplied in the client configuration.
-	mixerAttributes?: v1.Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(3,type=Attributes,name=mixer_attributes)
 
 	// HTTP API specifications to generate API attributes.
-	httpApiSpec?: [...HTTPAPISpec] @protobuf(4,name=http_api_spec)
+	httpApiSpec?: [...#HTTPAPISpec] @protobuf(4,name=http_api_spec)
 
 	// Quota specifications to generate quota requirements.
-	quotaSpec?: [...QuotaSpec] @protobuf(5,name=quota_spec)
+	quotaSpec?: [...#QuotaSpec] @protobuf(5,name=quota_spec)
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
 	// This is the service-level policy. It overrides
 	// [mesh-level
 	// policy][istio.mixer.v1.config.client.TransportConfig.network_fail_policy].
-	networkFailPolicy?: NetworkFailPolicy @protobuf(7,name=network_fail_policy)
+	networkFailPolicy?: #NetworkFailPolicy @protobuf(7,name=network_fail_policy)
 
 	// Default attributes to forward to upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes.
@@ -86,11 +86,11 @@
 	// 3. forwarded attributes from the source filter config (if any);
 	// 4. forwarded attributes from the source route config (if any);
 	// 5. derived attributes from the request metadata.
-	forwardAttributes?: v1.Attributes @protobuf(8,type=Attributes,name=forward_attributes)
+	forwardAttributes?: v1.#Attributes @protobuf(8,type=Attributes,name=forward_attributes)
 }
 
 // Defines the transport config on how to call Mixer.
-TransportConfig :: {
+#TransportConfig: {
 	// The flag to disable check cache.
 	disableCheckCache?: bool @protobuf(1,name=disable_check_cache)
 
@@ -102,7 +102,7 @@
 
 	// Specifies the behavior when the client is unable to connect to Mixer.
 	// This is the mesh level policy. The default value for policy is FAIL_OPEN.
-	networkFailPolicy?: NetworkFailPolicy @protobuf(4,name=network_fail_policy)
+	networkFailPolicy?: #NetworkFailPolicy @protobuf(4,name=network_fail_policy)
 
 	// Specify refresh interval to write Mixer client statistics to Envoy share
 	// memory. If not specified, the interval is 10 seconds.
@@ -131,19 +131,19 @@
 	// Default attributes to forward to Mixer upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes. These
 	// attributes are consumed by the proxy in front of mixer.
-	attributesForMixerProxy?: v1.Attributes @protobuf(8,type=Attributes,name=attributes_for_mixer_proxy)
+	attributesForMixerProxy?: v1.#Attributes @protobuf(8,type=Attributes,name=attributes_for_mixer_proxy)
 }
 
 // Defines the client config for HTTP.
-HttpClientConfig :: {
+#HttpClientConfig: {
 	// The transport config.
-	transport?: TransportConfig @protobuf(1)
+	transport?: #TransportConfig @protobuf(1)
 
 	// Map of control configuration indexed by destination.service. This
 	// is used to support per-service configuration for cases where a
 	// mixerclient serves multiple services.
 	serviceConfigs?: {
-		[string]: ServiceConfig
+		[string]: #ServiceConfig
 	} @protobuf(2,type=map<string,ServiceConfig>,service_configs)
 
 	// Default destination service name if none was specified in the
@@ -153,22 +153,22 @@
 	// Default attributes to send to Mixer in both Check and
 	// Report. This typically includes "destination.ip" and
 	// "destination.uid" attributes.
-	mixerAttributes?: v1.Attributes @protobuf(4,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(4,type=Attributes,name=mixer_attributes)
 
 	// Default attributes to forward to upstream. This typically
 	// includes the "source.ip" and "source.uid" attributes.
-	forwardAttributes?: v1.Attributes @protobuf(5,type=Attributes,name=forward_attributes)
+	forwardAttributes?: v1.#Attributes @protobuf(5,type=Attributes,name=forward_attributes)
 }
 
 // Defines the client config for TCP.
-TcpClientConfig :: {
+#TcpClientConfig: {
 	// The transport config.
-	transport?: TransportConfig @protobuf(1)
+	transport?: #TransportConfig @protobuf(1)
 
 	// Default attributes to send to Mixer in both Check and
 	// Report. This typically includes "destination.ip" and
 	// "destination.uid" attributes.
-	mixerAttributes?: v1.Attributes @protobuf(2,type=Attributes,name=mixer_attributes)
+	mixerAttributes?: v1.#Attributes @protobuf(2,type=Attributes,name=mixer_attributes)
 
 	// If set to true, disables Mixer check calls.
 	disableCheckCalls?: bool @protobuf(3,name=disable_check_calls)
@@ -178,7 +178,7 @@
 
 	// Quota specifications to generate quota requirements.
 	// It applies on the new TCP connections.
-	connectionQuotaSpec?: QuotaSpec @protobuf(5,name=connection_quota_spec)
+	connectionQuotaSpec?: #QuotaSpec @protobuf(5,name=connection_quota_spec)
 
 	// Specify report interval to send periodical reports for long TCP
 	// connections. If not specified, the interval is 10 seconds. This interval
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/quota_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/quota_proto_gen.cue
index c7d0e4c..12ecef7 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/quota_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/quota_proto_gen.cue
@@ -54,25 +54,25 @@
 package client
 
 // Determines the quotas used for individual requests.
-QuotaSpec :: {
+#QuotaSpec: {
 	// A list of Quota rules.
-	rules?: [...QuotaRule] @protobuf(1)
+	rules?: [...#QuotaRule] @protobuf(1)
 }
 
 // Specifies a rule with list of matches and list of quotas.
 // If any clause matched, the list of quotas will be used.
-QuotaRule :: {
+#QuotaRule: {
 	// If empty, match all request.
 	// If any of match is true, it is matched.
-	match?: [...AttributeMatch] @protobuf(1)
+	match?: [...#AttributeMatch] @protobuf(1)
 
 	// The list of quotas to charge.
-	quotas?: [...Quota] @protobuf(2)
+	quotas?: [...#Quota] @protobuf(2)
 }
 
 // Describes how to match a given string in HTTP headers. Match is
 // case-sensitive.
-StringMatch :: {
+#StringMatch: {
 	close({}) | close({
 		// exact string match
 		exact: string @protobuf(1)
@@ -86,7 +86,7 @@
 }
 
 // Specifies a match clause to match Istio attributes
-AttributeMatch :: {
+#AttributeMatch: {
 	// Map of attribute names to StringMatch type.
 	// Each map element specifies one condition to match.
 	//
@@ -98,12 +98,12 @@
 	//     request.http_method:
 	//       exact: POST
 	clause?: {
-		[string]: StringMatch
+		[string]: #StringMatch
 	} @protobuf(1,type=map<string,StringMatch>)
 }
 
 // Specifies a quota to use with quota name and amount.
-Quota :: {
+#Quota: {
 	// The quota name to charge
 	quota?: string @protobuf(1)
 
@@ -113,13 +113,13 @@
 
 // QuotaSpecBinding defines the binding between QuotaSpecs and one or more
 // IstioService.
-QuotaSpecBinding :: {
+#QuotaSpecBinding: {
 	// REQUIRED. One or more services to map the listed QuotaSpec onto.
-	services?: [...IstioService] @protobuf(1)
+	services?: [...#IstioService] @protobuf(1)
 
 	// QuotaSpecReference uniquely identifies the QuotaSpec used in the
 	// Binding.
-	QuotaSpecReference :: {
+	#QuotaSpecReference: {
 		// REQUIRED. The short name of the QuotaSpec. This is the resource
 		// name defined by the metadata name field.
 		name?: string @protobuf(1)
@@ -132,5 +132,5 @@
 	// REQUIRED. One or more QuotaSpec references that should be mapped to
 	// the specified service(s). The aggregate collection of match
 	// conditions defined in the QuotaSpecs should not overlap.
-	quotaSpecs?: [...QuotaSpecReference] @protobuf(2,name=quota_specs)
+	quotaSpecs?: [...#QuotaSpecReference] @protobuf(2,name=quota_specs)
 }
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/service_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/service_proto_gen.cue
index f218dda..726c181 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/service_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/config/client/service_proto_gen.cue
@@ -25,7 +25,7 @@
 // IstioService identifies a service and optionally service version.
 // The FQDN of the service is composed from the name, namespace, and implementation-specific domain suffix
 // (e.g. on Kubernetes, "reviews" + "default" + "svc.cluster.local" -> "reviews.default.svc.cluster.local").
-IstioService :: {
+#IstioService: {
 	// The short name of the service such as "foo".
 	name?: string @protobuf(1)
 
diff --git a/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue
index 1da46a3..59535a4 100644
--- a/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/mixer/v1/mixer_proto_gen.cue
@@ -22,9 +22,9 @@
 )
 
 // Used to get a thumbs-up/thumbs-down before performing an action.
-CheckRequest :: {
+#CheckRequest: {
 	// parameters for a quota allocation
-	QuotaParams :: {
+	#QuotaParams: {
 		// Amount of quota to allocate
 		amount?: int64 @protobuf(1)
 
@@ -36,7 +36,7 @@
 	//
 	// Mixer's configuration determines how these attributes are used to
 	// establish the result returned in the response.
-	attributes?: CompressedAttributes @protobuf(1,"(gogoproto.nullable)=false")
+	attributes?: #CompressedAttributes @protobuf(1,"(gogoproto.nullable)=false")
 
 	// The number of words in the global dictionary, used with to populate the attributes.
 	// This value is used as a quick way to determine whether the client is using a dictionary that
@@ -49,17 +49,17 @@
 
 	// The individual quotas to allocate
 	quotas?: {
-		[string]: QuotaParams
+		[string]: #QuotaParams
 	} @protobuf(4,type=map<string,QuotaParams>,"(gogoproto.nullable)=false")
 }
 
 // The response generated by the Check method.
-CheckResponse :: {
+#CheckResponse: {
 	// Expresses the result of a precondition check.
-	PreconditionResult :: {
+	#PreconditionResult: {
 		// A status code of OK indicates all preconditions were satisfied. Any other code indicates not
 		// all preconditions were satisfied and details describe why.
-		status?: _status_.Status @protobuf(1,type=google.rpc.Status,"(gogoproto.nullable)=false")
+		status?: _status_.#Status @protobuf(1,type=google.rpc.Status,"(gogoproto.nullable)=false")
 
 		// The amount of time for which this result can be considered valid.
 		validDuration?: time.Duration @protobuf(2,type=google.protobuf.Duration,name=valid_duration,"(gogoproto.nullable)=false","(gogoproto.stdduration)")
@@ -69,15 +69,15 @@
 
 		// The total set of attributes that were used in producing the result
 		// along with matching conditions.
-		referencedAttributes?: ReferencedAttributes @protobuf(5,name=referenced_attributes)
+		referencedAttributes?: #ReferencedAttributes @protobuf(5,name=referenced_attributes)
 
 		// An optional routing directive, used to manipulate the traffic metadata
 		// whenever all preconditions are satisfied.
-		routeDirective?: RouteDirective @protobuf(6,name=route_directive)
+		routeDirective?: #RouteDirective @protobuf(6,name=route_directive)
 	}
 
 	// Expresses the result of a quota allocation.
-	QuotaResult :: {
+	#QuotaResult: {
 		// The amount of time for which this result can be considered valid.
 		validDuration?: time.Duration @protobuf(1,type=google.protobuf.Duration,name=valid_duration,"(gogoproto.nullable)=false","(gogoproto.stdduration)")
 
@@ -87,29 +87,29 @@
 
 		// The total set of attributes that were used in producing the result
 		// along with matching conditions.
-		referencedAttributes?: ReferencedAttributes @protobuf(5,name=referenced_attributes,"(gogoproto.nullable)=false")
+		referencedAttributes?: #ReferencedAttributes @protobuf(5,name=referenced_attributes,"(gogoproto.nullable)=false")
 	}
 
 	// The precondition check results.
-	precondition?: PreconditionResult @protobuf(2,"(gogoproto.nullable)=false")
+	precondition?: #PreconditionResult @protobuf(2,"(gogoproto.nullable)=false")
 
 	// The resulting quota, one entry per requested quota.
 	quotas?: {
-		[string]: QuotaResult
+		[string]: #QuotaResult
 	} @protobuf(3,type=map<string,QuotaResult>,"(gogoproto.nullable)=false")
 }
 let _status_ = status
 
 // Describes the attributes that were used to determine the response.
 // This can be used to construct a response cache.
-ReferencedAttributes :: {
+#ReferencedAttributes: {
 	// How an attribute's value was matched
-	Condition :: "CONDITION_UNSPECIFIED" | // should not occur
+	#Condition: "CONDITION_UNSPECIFIED" | // should not occur
 		"ABSENCE" | // match when attribute doesn't exist
 		"EXACT" | // match when attribute value is an exact byte-for-byte match
 		"REGEX" // match when attribute value matches the included regex
 
-	Condition_value :: {
+	#Condition_value: {
 		"CONDITION_UNSPECIFIED": 0
 		"ABSENCE":               1
 		"EXACT":                 2
@@ -117,13 +117,13 @@
 	}
 
 	// Describes a single attribute match.
-	AttributeMatch :: {
+	#AttributeMatch: {
 		// The name of the attribute. This is a dictionary index encoded in a manner identical
 		// to all strings in the [CompressedAttributes][istio.mixer.v1.CompressedAttributes] message.
 		name?: int32 @protobuf(1,type=sint32)
 
 		// The kind of match against the attribute value.
-		condition?: Condition @protobuf(2)
+		condition?: #Condition @protobuf(2)
 
 		// If a REGEX condition is provided for a STRING_MAP attribute,
 		// clients should use the regex value to match against map keys.
@@ -147,20 +147,20 @@
 	words?: [...string] @protobuf(1)
 
 	// Describes a set of attributes.
-	attributeMatches?: [...AttributeMatch] @protobuf(2,name=attribute_matches,"(gogoproto.nullable)=false")
+	attributeMatches?: [...#AttributeMatch] @protobuf(2,name=attribute_matches,"(gogoproto.nullable)=false")
 }
 
 // Operation on HTTP headers to replace, append, or remove a header. Header
 // names are normalized to lower-case with dashes, e.g.  "x-request-id".
 // Pseudo-headers ":path", ":authority", and ":method" are supported to modify
 // the request headers.
-HeaderOperation :: {
+#HeaderOperation: {
 	// Operation type.
-	Operation :: "REPLACE" | // replaces the header with the given name
+	#Operation: "REPLACE" | // replaces the header with the given name
 		"REMOVE" | // removes the header with the given name (the value is ignored)
 		"APPEND" // appends the value to the header value, or sets it if not present
 
-	Operation_value :: {
+	#Operation_value: {
 		"REPLACE": 0
 		"REMOVE":  1
 		"APPEND":  2
@@ -173,17 +173,17 @@
 	value?: string @protobuf(2)
 
 	// Header operation.
-	operation?: Operation @protobuf(3)
+	operation?: #Operation @protobuf(3)
 }
 
 // Expresses the routing manipulation actions to be performed on behalf of
 // Mixer in response to a precondition check.
-RouteDirective :: {
+#RouteDirective: {
 	// Operations on the request headers.
-	requestHeaderOperations?: [...HeaderOperation] @protobuf(1,name=request_header_operations,"(gogoproto.nullable)=false")
+	requestHeaderOperations?: [...#HeaderOperation] @protobuf(1,name=request_header_operations,"(gogoproto.nullable)=false")
 
 	// Operations on the response headers.
-	responseHeaderOperations?: [...HeaderOperation] @protobuf(2,name=response_header_operations,"(gogoproto.nullable)=false")
+	responseHeaderOperations?: [...#HeaderOperation] @protobuf(2,name=response_header_operations,"(gogoproto.nullable)=false")
 
 	// If set, enables a direct response without proxying the request to the routing
 	// destination. Required to be a value in the 2xx or 3xx range.
@@ -195,12 +195,12 @@
 }
 
 // Used to report telemetry after performing one or more actions.
-ReportRequest :: {
+#ReportRequest: {
 
 	// next value: 5
 
 	// Used to signal how the sets of compressed attributes should be reconstitued server-side.
-	RepeatedAttributesSemantics ::
+	#RepeatedAttributesSemantics:
 		// Use delta encoding between sets of compressed attributes to reduce the overall on-wire
 		// request size. Each individual set of attributes is used to modify the previous set.
 		// NOTE: There is no way with this encoding to specify attribute value deletion. This
@@ -212,7 +212,7 @@
 		// will allow for proper accounting of absent values in overall encoding.
 		"INDEPENDENT_ENCODING"
 
-	RepeatedAttributesSemantics_value :: {
+	#RepeatedAttributesSemantics_value: {
 		"DELTA_ENCODING":       0
 		"INDEPENDENT_ENCODING": 1
 	}
@@ -222,10 +222,10 @@
 	// Each `Attributes` element represents the state of a single action. Multiple actions
 	// can be provided in a single message in order to improve communication efficiency. The
 	// client can accumulate a set of actions and send them all in one single message.
-	attributes?: [...CompressedAttributes] @protobuf(1,"(gogoproto.nullable)=false")
+	attributes?: [...#CompressedAttributes] @protobuf(1,"(gogoproto.nullable)=false")
 
 	// Indicates how to decode the attributes sets in this request.
-	repeatedAttributesSemantics?: RepeatedAttributesSemantics @protobuf(4,name=repeated_attributes_semantics)
+	repeatedAttributesSemantics?: #RepeatedAttributesSemantics @protobuf(4,name=repeated_attributes_semantics)
 
 	// The default message-level dictionary for all the attributes.
 	// Individual attribute messages can have their own dictionaries, but if they don't
@@ -241,5 +241,5 @@
 }
 
 // Used to carry responses to telemetry reports
-ReportResponse :: {
+#ReportResponse: {
 }
diff --git a/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue b/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue
index e9136a6..5d26865 100644
--- a/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue
+++ b/encoding/protobuf/testdata/istio.io/api/networking/v1alpha3/gateway_proto_gen.cue
@@ -203,9 +203,9 @@
 //
 package v1alpha3
 
-Gateway :: {
+#Gateway: {
 	// REQUIRED: A list of server specifications.
-	servers?: [...Server] @protobuf(1)
+	servers?: [...#Server] @protobuf(1)
 
 	// REQUIRED: One or more labels that indicate a specific set of pods/VMs
 	// on which this gateway configuration should be applied. The scope of
@@ -279,10 +279,10 @@
 //       serverCertificate: /etc/certs/server.pem
 //       privateKey: /etc/certs/privatekey.pem
 // ```
-Server :: {
+#Server: {
 	// REQUIRED: The Port on which the proxy should listen for incoming
 	// connections.
-	port?: Port @protobuf(1)
+	port?: #Port @protobuf(1)
 	port?: >10 & <100
 
 	// $hide_from_docs
@@ -318,13 +318,13 @@
 	// `DestinationRule`, and `ServiceEntry` configurations for details.
 	hosts?: [...string] @protobuf(2)
 
-	TLSOptions :: {
+	#TLSOptions: {
 		// If set to true, the load balancer will send a 301 redirect for all
 		// http connections, asking the clients to use HTTPS.
 		httpsRedirect?: bool @protobuf(1,name=https_redirect)
 
 		// TLS modes enforced by the proxy
-		TLSmode ::
+		#TLSmode:
 			// The SNI string presented by the client will be used as the match
 			// criterion in a VirtualService TLS route to determine the
 			// destination service from the service registry.
@@ -349,7 +349,7 @@
 			// source and the destination are using Istio mTLS to secure traffic.
 			"AUTO_PASSTHROUGH"
 
-		TLSmode_value :: {
+		#TLSmode_value: {
 			"PASSTHROUGH":      0
 			"SIMPLE":           1
 			"MUTUAL":           2
@@ -359,7 +359,7 @@
 		// Optional: Indicates whether connections to this port should be
 		// secured using TLS. The value of this field determines how TLS is
 		// enforced.
-		mode?: TLSmode @protobuf(2)
+		mode?: #TLSmode @protobuf(2)
 
 		// Extra comment.
 
@@ -399,13 +399,13 @@
 		subjectAltNames?: [...string] @protobuf(6,name=subject_alt_names)
 
 		// TLS protocol versions.
-		TLSProtocol :: "TLS_AUTO" | // Automatically choose the optimal TLS version.
+		#TLSProtocol: "TLS_AUTO" | // Automatically choose the optimal TLS version.
 			"TLSV1_0" | // TLS version 1.0
 			"TLSV1_1" | // TLS version 1.1
 			"TLSV1_2" | // TLS version 1.2
 			"TLSV1_3" // TLS version 1.3
 
-		TLSProtocol_value :: {
+		#TLSProtocol_value: {
 			"TLS_AUTO": 0
 			"TLSV1_0":  1
 			"TLSV1_1":  2
@@ -414,10 +414,10 @@
 		}
 
 		// Optional: Minimum TLS protocol version.
-		minProtocolVersion?: TLSProtocol @protobuf(7,name=min_protocol_version)
+		minProtocolVersion?: #TLSProtocol @protobuf(7,name=min_protocol_version)
 
 		// Optional: Maximum TLS protocol version.
-		maxProtocolVersion?: TLSProtocol @protobuf(8,name=max_protocol_version)
+		maxProtocolVersion?: #TLSProtocol @protobuf(8,name=max_protocol_version)
 
 		// Optional: If specified, only support the specified cipher list.
 		// Otherwise default to the default cipher list supported by Envoy.
@@ -427,7 +427,7 @@
 	// Set of TLS related options that govern the server's behavior. Use
 	// these options to control if all http requests should be redirected to
 	// https, and the TLS modes to use.
-	tls?: TLSOptions @protobuf(3)
+	tls?: #TLSOptions @protobuf(3)
 
 	// The loopback IP endpoint or Unix domain socket to which traffic should
 	// be forwarded to by default. Format should be `127.0.0.1:PORT` or
@@ -436,7 +436,7 @@
 }
 
 // Port describes the properties of a specific port of a service.
-Port :: {
+#Port: {
 	// REQUIRED: A valid non-negative integer port number.
 	number?: uint32 @protobuf(1)
 
diff --git a/encoding/protobuf/types.go b/encoding/protobuf/types.go
index 687819b..5628660 100644
--- a/encoding/protobuf/types.go
+++ b/encoding/protobuf/types.go
@@ -49,7 +49,7 @@
 }
 
 func (p *protoConverter) setBuiltin(from, to string, pkg *protoConverter) {
-	p.scope[0][from] = mapping{to, "", pkg}
+	p.scope[0][from] = mapping{to, to, "", pkg}
 }
 
 var (