diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,7 @@
 # Changelog for `proto-lens`
 
+## v0.7.1.7
+- Relax upper bounds for ghc-9.10.
 
 ## v0.7.1.2
 - Support GHC 9.4
diff --git a/proto-lens-imports/google/protobuf/compiler/plugin.proto b/proto-lens-imports/google/protobuf/compiler/plugin.proto
--- a/proto-lens-imports/google/protobuf/compiler/plugin.proto
+++ b/proto-lens-imports/google/protobuf/compiler/plugin.proto
@@ -1,38 +1,12 @@
 // Protocol Buffers - Google's data interchange format
 // Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
 //
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
 
 // Author: kenton@google.com (Kenton Varda)
 //
-// WARNING:  The plugin interface is currently EXPERIMENTAL and is subject to
-//   change.
-//
 // protoc (aka the Protocol Compiler) can be extended via plugins.  A plugin is
 // just a program that reads a CodeGeneratorRequest from stdin and writes a
 // CodeGeneratorResponse to stdout.
@@ -50,6 +24,7 @@
 option java_package = "com.google.protobuf.compiler";
 option java_outer_classname = "PluginProtos";
 
+option csharp_namespace = "Google.Protobuf.Compiler";
 option go_package = "google.golang.org/protobuf/types/pluginpb";
 
 import "google/protobuf/descriptor.proto";
@@ -78,6 +53,11 @@
   // they import.  The files will appear in topological order, so each file
   // appears before any file that imports it.
   //
+  // Note: the files listed in files_to_generate will include runtime-retention
+  // options only, but all other files will include source-retention options.
+  // The source_file_descriptors field below is available in case you need
+  // source-retention options for files_to_generate.
+  //
   // protoc guarantees that all proto_files will be written after
   // the fields above, even though this is not technically guaranteed by the
   // protobuf wire format.  This theoretically could allow a plugin to stream
@@ -90,9 +70,13 @@
   // fully qualified.
   repeated FileDescriptorProto proto_file = 15;
 
+  // File descriptors with all options, including source-retention options.
+  // These descriptors are only provided for the files listed in
+  // files_to_generate.
+  repeated FileDescriptorProto source_file_descriptors = 17;
+
   // The version number of protocol compiler.
   optional Version compiler_version = 3;
-
 }
 
 // The plugin writes an encoded CodeGeneratorResponse to stdout.
@@ -115,7 +99,20 @@
   enum Feature {
     FEATURE_NONE = 0;
     FEATURE_PROTO3_OPTIONAL = 1;
+    FEATURE_SUPPORTS_EDITIONS = 2;
   }
+
+  // The minimum edition this plugin supports.  This will be treated as an
+  // Edition enum, but we want to allow unknown values.  It should be specified
+  // according the edition enum value, *not* the edition number.  Only takes
+  // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  optional int32 minimum_edition = 3;
+
+  // The maximum edition this plugin supports.  This will be treated as an
+  // Edition enum, but we want to allow unknown values.  It should be specified
+  // according the edition enum value, *not* the edition number.  Only takes
+  // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  optional int32 maximum_edition = 4;
 
   // Represents a single generated file.
   message File {
diff --git a/proto-lens-imports/google/protobuf/descriptor.proto b/proto-lens-imports/google/protobuf/descriptor.proto
--- a/proto-lens-imports/google/protobuf/descriptor.proto
+++ b/proto-lens-imports/google/protobuf/descriptor.proto
@@ -36,7 +36,6 @@
 // A valid .proto file can be translated directly to a FileDescriptorProto
 // without any other information (e.g. without reading its imports).
 
-
 syntax = "proto2";
 
 package google.protobuf;
@@ -58,6 +57,42 @@
   repeated FileDescriptorProto file = 1;
 }
 
+// The full set of known editions.
+enum Edition {
+  // A placeholder for an unknown edition value.
+  EDITION_UNKNOWN = 0;
+
+  // A placeholder edition for specifying default behaviors *before* a feature
+  // was first introduced.  This is effectively an "infinite past".
+  EDITION_LEGACY = 900;
+
+  // Legacy syntax "editions".  These pre-date editions, but behave much like
+  // distinct editions.  These can't be used to specify the edition of proto
+  // files, but feature definitions must supply proto2/proto3 defaults for
+  // backwards compatibility.
+  EDITION_PROTO2 = 998;
+  EDITION_PROTO3 = 999;
+
+  // Editions that have been released.  The specific values are arbitrary and
+  // should not be depended on, but they will always be time-ordered for easy
+  // comparison.
+  EDITION_2023 = 1000;
+  EDITION_2024 = 1001;
+
+  // Placeholder editions for testing feature resolution.  These should not be
+  // used or relyed on outside of tests.
+  EDITION_1_TEST_ONLY = 1;
+  EDITION_2_TEST_ONLY = 2;
+  EDITION_99997_TEST_ONLY = 99997;
+  EDITION_99998_TEST_ONLY = 99998;
+  EDITION_99999_TEST_ONLY = 99999;
+
+  // Placeholder for specifying unbounded edition support.  This should only
+  // ever be used by plugins that can expect to never require any changes to
+  // support a new edition.
+  EDITION_MAX = 0x7FFFFFFF;
+}
+
 // Describes a complete .proto file.
 message FileDescriptorProto {
   optional string name = 1;     // file name, relative to root of source tree
@@ -86,8 +121,13 @@
   optional SourceCodeInfo source_code_info = 9;
 
   // The syntax of the proto file.
-  // The supported values are "proto2" and "proto3".
+  // The supported values are "proto2", "proto3", and "editions".
+  //
+  // If `edition` is present, this value must be "editions".
   optional string syntax = 12;
+
+  // The edition of the proto file.
+  optional Edition edition = 14;
 }
 
 // Describes a message type.
@@ -129,7 +169,52 @@
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
+  message Declaration {
+    // The extension number declared within the extension range.
+    optional int32 number = 1;
 
+    // The fully-qualified name of the extension field. There must be a leading
+    // dot in front of the full name.
+    optional string full_name = 2;
+
+    // The fully-qualified type name of the extension field. Unlike
+    // Metadata.type, Declaration.type must have a leading dot for messages
+    // and enums.
+    optional string type = 3;
+
+    // If true, indicates that the number is reserved in the extension range,
+    // and any extension field with the number will fail to compile. Set this
+    // when a declared extension field is deleted.
+    optional bool reserved = 5;
+
+    // If true, indicates that the extension must be defined as repeated.
+    // Otherwise the extension must be defined as optional.
+    optional bool repeated = 6;
+
+    reserved 4;  // removed is_repeated
+  }
+
+  // For external users: DO NOT USE. We are in the process of open sourcing
+  // extension declaration and executing internal cleanups before it can be
+  // used externally.
+  repeated Declaration declaration = 2 [retention = RETENTION_SOURCE];
+
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 50;
+
+  // The verification state of the extension range.
+  enum VerificationState {
+    // All the extensions of the range must be declared.
+    DECLARATION = 0;
+    UNVERIFIED = 1;
+  }
+
+  // The verification state of the range.
+  // TODO: flip the default to DECLARATION once all empty ranges
+  // are marked as UNVERIFIED.
+  optional VerificationState verification = 3
+      [default = UNVERIFIED, retention = RETENTION_SOURCE];
+
   // Clients can define custom options in extensions of this message. See above.
   extensions 1000 to max;
 }
@@ -153,9 +238,10 @@
     TYPE_BOOL = 8;
     TYPE_STRING = 9;
     // Tag-delimited aggregate.
-    // Group type is deprecated and not supported in proto3. However, Proto3
+    // Group type is deprecated and not supported after google.protobuf. However, Proto3
     // implementations should still be able to parse the group wire format and
-    // treat group fields as unknown fields.
+    // treat group fields as unknown fields.  In Editions, the group wire format
+    // can be enabled via the `message_encoding` feature.
     TYPE_GROUP = 10;
     TYPE_MESSAGE = 11;  // Length-delimited aggregate.
 
@@ -172,8 +258,11 @@
   enum Label {
     // 0 is reserved for errors
     LABEL_OPTIONAL = 1;
-    LABEL_REQUIRED = 2;
     LABEL_REPEATED = 3;
+    // The required label is only allowed in google.protobuf.  In proto3 and Editions
+    // it's explicitly prohibited.  In Editions, the `field_presence` feature
+    // can be used to get this behavior.
+    LABEL_REQUIRED = 2;
   }
 
   optional string name = 1;
@@ -199,7 +288,6 @@
   // For booleans, "true" or "false".
   // For strings, contains the default text contents (not escaped in any way).
   // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
-  // TODO(kenton):  Base-64 encode?
   optional string default_value = 7;
 
   // If set, gives the index of a oneof in the containing type's oneof_decl
@@ -217,12 +305,12 @@
   // If true, this is a proto3 "optional". When a proto3 field is optional, it
   // tracks presence regardless of field type.
   //
-  // When proto3_optional is true, this field must be belong to a oneof to
-  // signal to old proto3 clients that presence is tracked for this field. This
-  // oneof is known as a "synthetic" oneof, and this field must be its sole
-  // member (each proto3 optional field gets its own synthetic oneof). Synthetic
-  // oneofs exist in the descriptor only, and do not generate any API. Synthetic
-  // oneofs must be ordered after all "real" oneofs.
+  // When proto3_optional is true, this field must belong to a oneof to signal
+  // to old proto3 clients that presence is tracked for this field. This oneof
+  // is known as a "synthetic" oneof, and this field must be its sole member
+  // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs
+  // exist in the descriptor only, and do not generate any API. Synthetic oneofs
+  // must be ordered after all "real" oneofs.
   //
   // For message fields, proto3_optional doesn't create any semantic change,
   // since non-repeated message fields always track presence. However it still
@@ -306,7 +394,6 @@
   optional bool server_streaming = 6 [default = false];
 }
 
-
 // ===================================================================
 // Options
 
@@ -347,18 +434,17 @@
   // domain names.
   optional string java_package = 1;
 
-
-  // If set, all the classes from the .proto file are wrapped in a single
-  // outer class with the given name.  This applies to both Proto1
-  // (equivalent to the old "--one_java_file" option) and Proto2 (where
-  // a .proto always translates to a single class, but you may want to
-  // explicitly choose the class name).
+  // Controls the name of the wrapper Java class generated for the .proto file.
+  // That class will always contain the .proto file's getDescriptor() method as
+  // well as any top-level extensions defined in the .proto file.
+  // If java_multiple_files is disabled, then all the other classes from the
+  // .proto file will be nested inside the single wrapper outer class.
   optional string java_outer_classname = 8;
 
-  // If set true, then the Java code generator will generate a separate .java
+  // If enabled, then the Java code generator will generate a separate .java
   // file for each top-level message, enum, and service defined in the .proto
-  // file.  Thus, these types will *not* be nested inside the outer class
-  // named by java_outer_classname.  However, the outer class will still be
+  // file.  Thus, these types will *not* be nested inside the wrapper class
+  // named by java_outer_classname.  However, the wrapper class will still be
   // generated to contain the file's getDescriptor() method as well as any
   // top-level extensions defined in the file.
   optional bool java_multiple_files = 10 [default = false];
@@ -366,15 +452,18 @@
   // This option does nothing.
   optional bool java_generate_equals_and_hash = 20 [deprecated=true];
 
-  // If set true, then the Java2 code generator will generate code that
-  // throws an exception whenever an attempt is made to assign a non-UTF-8
-  // byte sequence to a string field.
-  // Message reflection will do the same.
-  // However, an extension field still accepts non-UTF-8 byte sequences.
-  // This option has no effect on when used with the lite runtime.
+  // A proto2 file can set this to true to opt in to UTF-8 checking for Java,
+  // which will throw an exception if invalid UTF-8 is parsed from the wire or
+  // assigned to a string field.
+  //
+  // TODO: clarify exactly what kinds of field types this option
+  // applies to, and update these docs accordingly.
+  //
+  // Proto3 files already perform these checks. Setting the option explicitly to
+  // false has no effect: it cannot be used to opt proto3 files out of UTF-8
+  // checks.
   optional bool java_string_check_utf8 = 27 [default = false];
 
-
   // Generated classes can be optimized for speed or code size.
   enum OptimizeMode {
     SPEED = 1;         // Generate complete code for parsing, serialization,
@@ -391,9 +480,6 @@
   //   - Otherwise, the basename of the .proto file, without extension.
   optional string go_package = 11;
 
-
-
-
   // Should generic services be generated in each language?  "Generic" services
   // are not specific to any particular RPC system.  They are generated by the
   // main code generators in each language (without additional plugins).
@@ -407,7 +493,8 @@
   optional bool cc_generic_services = 16 [default = false];
   optional bool java_generic_services = 17 [default = false];
   optional bool py_generic_services = 18 [default = false];
-  optional bool php_generic_services = 42 [default = false];
+  reserved 42;  // removed php_generic_services
+  reserved "php_generic_services";
 
   // Is this file deprecated?
   // Depending on the target platform, this can emit Deprecated annotations
@@ -419,7 +506,6 @@
   // only to generated classes for C++.
   optional bool cc_enable_arenas = 31 [default = true];
 
-
   // Sets the objective c class prefix which is prepended to all objective c
   // generated classes from this .proto. There is no default.
   optional string objc_class_prefix = 36;
@@ -452,6 +538,8 @@
   // determining the ruby package.
   optional string ruby_package = 45;
 
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 50;
 
   // The parser stores options it doesn't recognize here.
   // See the documentation for the "Options" section above.
@@ -496,6 +584,8 @@
   // this is a formalization for deprecating messages.
   optional bool deprecated = 3 [default = false];
 
+  reserved 4, 5, 6;
+
   // Whether the message is an automatically generated map entry type for the
   // maps field.
   //
@@ -522,7 +612,21 @@
   reserved 8;  // javalite_serializable
   reserved 9;  // javanano_as_lite
 
+  // Enable the legacy handling of JSON field name conflicts.  This lowercases
+  // and strips underscored from the fields before comparison in proto3 only.
+  // The new behavior takes `json_name` into account and applies to proto2 as
+  // well.
+  //
+  // This should only be used as a temporary measure against broken builds due
+  // to the change in behavior for JSON field name conflicts.
+  //
+  // TODO This is legacy behavior we plan to remove once downstream
+  // teams have had time to migrate.
+  optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true];
 
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 12;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -531,15 +635,24 @@
 }
 
 message FieldOptions {
+  // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead.
   // 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!
-  optional CType ctype = 1 [default = STRING];
+  // options below.  This option is only implemented to support use of
+  // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of
+  // type "bytes" in the open source release.
+  // TODO: make ctype actually deprecated.
+  optional CType ctype = 1 [/*deprecated = true,*/ default = STRING];
   enum CType {
     // Default mode.
     STRING = 0;
 
+    // The option [ctype=CORD] may be applied to a non-repeated field of type
+    // "bytes". It indicates that in C++, the data should be stored in a Cord
+    // instead of a string.  For very large strings, this may reduce memory
+    // fragmentation. It may also allow better performance when parsing from a
+    // Cord, or when parsing with aliasing enabled, as the parsed Cord may then
+    // alias the original buffer.
     CORD = 1;
 
     STRING_PIECE = 2;
@@ -548,7 +661,9 @@
   // a more efficient representation on the wire. Rather than repeatedly
   // writing the tag and type for each element, the entire array is encoded as
   // a single length-delimited blob. In proto3, only explicit setting it to
-  // false will avoid using packed encoding.
+  // false will avoid using packed encoding.  This option is prohibited in
+  // Editions, but the `repeated_field_encoding` feature can be used to control
+  // the behavior.
   optional bool packed = 2;
 
   // The jstype option determines the JavaScript type used for values of the
@@ -591,19 +706,18 @@
   // call from multiple threads concurrently, while non-const methods continue
   // to require exclusive access.
   //
-  //
-  // Note that implementations may choose not to check required fields within
-  // a lazy sub-message.  That is, calling IsInitialized() on the outer message
-  // may return true even if the inner message has missing required fields.
-  // This is necessary because otherwise the inner message would have to be
-  // parsed in order to perform the check, defeating the purpose of lazy
-  // parsing.  An implementation which chooses not to check required fields
-  // must be consistent about it.  That is, for any particular sub-message, the
-  // implementation must either *always* check its required fields, or *never*
-  // check its required fields, regardless of whether or not the message has
-  // been parsed.
+  // Note that lazy message fields are still eagerly verified to check
+  // ill-formed wireformat or missing required fields. Calling IsInitialized()
+  // on the outer message would fail if the inner message has missing required
+  // fields. Failed verification would result in parsing failure (except when
+  // uninitialized messages are acceptable).
   optional bool lazy = 5 [default = false];
 
+  // unverified_lazy does no correctness checks on the byte stream. This should
+  // only be used where lazy with verification is prohibitive for performance
+  // reasons.
+  optional bool unverified_lazy = 15 [default = false];
+
   // Is this field deprecated?
   // Depending on the target platform, this can emit Deprecated annotations
   // for accessors, or it will be completely ignored; in the very least, this
@@ -613,17 +727,85 @@
   // For Google-internal migration only. Do not use.
   optional bool weak = 10 [default = false];
 
+  // Indicate that the field value should not be printed out when using debug
+  // formats, e.g. when the field contains sensitive credentials.
+  optional bool debug_redact = 16 [default = false];
 
+  // If set to RETENTION_SOURCE, the option will be omitted from the binary.
+  // Note: as of January 2023, support for this is in progress and does not yet
+  // have an effect (b/264593489).
+  enum OptionRetention {
+    RETENTION_UNKNOWN = 0;
+    RETENTION_RUNTIME = 1;
+    RETENTION_SOURCE = 2;
+  }
+
+  optional OptionRetention retention = 17;
+
+  // This indicates the types of entities that the field may apply to when used
+  // as an option. If it is unset, then the field may be freely used as an
+  // option on any kind of entity. Note: as of January 2023, support for this is
+  // in progress and does not yet have an effect (b/264593489).
+  enum OptionTargetType {
+    TARGET_TYPE_UNKNOWN = 0;
+    TARGET_TYPE_FILE = 1;
+    TARGET_TYPE_EXTENSION_RANGE = 2;
+    TARGET_TYPE_MESSAGE = 3;
+    TARGET_TYPE_FIELD = 4;
+    TARGET_TYPE_ONEOF = 5;
+    TARGET_TYPE_ENUM = 6;
+    TARGET_TYPE_ENUM_ENTRY = 7;
+    TARGET_TYPE_SERVICE = 8;
+    TARGET_TYPE_METHOD = 9;
+  }
+
+  repeated OptionTargetType targets = 19;
+
+  message EditionDefault {
+    optional Edition edition = 3;
+    optional string value = 2;  // Textproto value.
+  }
+  repeated EditionDefault edition_defaults = 20;
+
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 21;
+
+  // Information about the support window of a feature.
+  message FeatureSupport {
+    // The edition that this feature was first available in.  In editions
+    // earlier than this one, the default assigned to EDITION_LEGACY will be
+    // used, and proto files will not be able to override it.
+    optional Edition edition_introduced = 1;
+
+    // The edition this feature becomes deprecated in.  Using this after this
+    // edition may trigger warnings.
+    optional Edition edition_deprecated = 2;
+
+    // The deprecation warning text if this feature is used after the edition it
+    // was marked deprecated in.
+    optional string deprecation_warning = 3;
+
+    // The edition this feature is no longer available in.  In editions after
+    // this one, the last default assigned will be used, and proto files will
+    // not be able to override it.
+    optional Edition edition_removed = 4;
+  }
+  optional FeatureSupport feature_support = 22;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
   // Clients can define custom options in extensions of this message. See above.
   extensions 1000 to max;
 
-  reserved 4;  // removed jtype
+  reserved 4;   // removed jtype
+  reserved 18;  // reserve target, target_obsolete_do_not_use
 }
 
 message OneofOptions {
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 1;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -645,6 +827,17 @@
 
   reserved 5;  // javanano_as_lite
 
+  // Enable the legacy handling of JSON field name conflicts.  This lowercases
+  // and strips underscored from the fields before comparison in proto3 only.
+  // The new behavior takes `json_name` into account and applies to proto2 as
+  // well.
+  // TODO Remove this legacy behavior once downstream teams have
+  // had time to migrate.
+  optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true];
+
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 7;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -659,6 +852,17 @@
   // this is a formalization for deprecating enum values.
   optional bool deprecated = 1 [default = false];
 
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 2;
+
+  // Indicate that fields annotated with this enum value should not be printed
+  // out when using debug formats, e.g. when the field contains sensitive
+  // credentials.
+  optional bool debug_redact = 3 [default = false];
+
+  // Information about the support window of a feature value.
+  optional FieldOptions.FeatureSupport feature_support = 4;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -668,6 +872,9 @@
 
 message ServiceOptions {
 
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 34;
+
   // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
   //   framework.  We apologize for hoarding these numbers to ourselves, but
   //   we were already using them long before we decided to release Protocol
@@ -710,6 +917,9 @@
   optional IdempotencyLevel idempotency_level = 34
       [default = IDEMPOTENCY_UNKNOWN];
 
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 35;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -717,7 +927,6 @@
   extensions 1000 to max;
 }
 
-
 // A message representing a option the parser does not recognize. This only
 // appears in options protos created by the compiler::Parser class.
 // DescriptorPool resolves these when building Descriptor objects. Therefore,
@@ -728,8 +937,8 @@
   // 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".
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents
+  // "foo.(bar.baz).moo".
   message NamePart {
     required string name_part = 1;
     required bool is_extension = 2;
@@ -747,6 +956,172 @@
 }
 
 // ===================================================================
+// Features
+
+// TODO Enums in C++ gencode (and potentially other languages) are
+// not well scoped.  This means that each of the feature enums below can clash
+// with each other.  The short names we've chosen maximize call-site
+// readability, but leave us very open to this scenario.  A future feature will
+// be designed and implemented to handle this, hopefully before we ever hit a
+// conflict here.
+message FeatureSet {
+  enum FieldPresence {
+    FIELD_PRESENCE_UNKNOWN = 0;
+    EXPLICIT = 1;
+    IMPLICIT = 2;
+    LEGACY_REQUIRED = 3;
+  }
+  optional FieldPresence field_presence = 1 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" },
+    edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" }
+  ];
+
+  enum EnumType {
+    ENUM_TYPE_UNKNOWN = 0;
+    OPEN = 1;
+    CLOSED = 2;
+  }
+  optional EnumType enum_type = 2 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" }
+  ];
+
+  enum RepeatedFieldEncoding {
+    REPEATED_FIELD_ENCODING_UNKNOWN = 0;
+    PACKED = 1;
+    EXPANDED = 2;
+  }
+  optional RepeatedFieldEncoding repeated_field_encoding = 3 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" }
+  ];
+
+  enum Utf8Validation {
+    UTF8_VALIDATION_UNKNOWN = 0;
+    VERIFY = 2;
+    NONE = 3;
+    reserved 1;
+  }
+  optional Utf8Validation utf8_validation = 4 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "NONE" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" }
+  ];
+
+  enum MessageEncoding {
+    MESSAGE_ENCODING_UNKNOWN = 0;
+    LENGTH_PREFIXED = 1;
+    DELIMITED = 2;
+  }
+  optional MessageEncoding message_encoding = 5 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" }
+  ];
+
+  enum JsonFormat {
+    JSON_FORMAT_UNKNOWN = 0;
+    ALLOW = 1;
+    LEGACY_BEST_EFFORT = 2;
+  }
+  optional JsonFormat json_format = 6 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_MESSAGE,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" }
+  ];
+
+  reserved 999;
+
+  extensions 1000 to 9994 [
+    declaration = {
+      number: 1000,
+      full_name: ".pb.cpp",
+      type: ".pb.CppFeatures"
+    },
+    declaration = {
+      number: 1001,
+      full_name: ".pb.java",
+      type: ".pb.JavaFeatures"
+    },
+    declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" },
+    declaration = {
+      number: 9990,
+      full_name: ".pb.proto1",
+      type: ".pb.Proto1Features"
+    }
+  ];
+
+  extensions 9995 to 9999;  // For internal testing
+  extensions 10000;         // for https://github.com/bufbuild/protobuf-es
+}
+
+// A compiled specification for the defaults of a set of features.  These
+// messages are generated from FeatureSet extensions and can be used to seed
+// feature resolution. The resolution with this object becomes a simple search
+// for the closest matching edition, followed by proto merges.
+message FeatureSetDefaults {
+  // A map from every known edition with a unique set of defaults to its
+  // defaults. Not all editions may be contained here.  For a given edition,
+  // the defaults at the closest matching edition ordered at or before it should
+  // be used.  This field must be in strict ascending order by edition.
+  message FeatureSetEditionDefault {
+    optional Edition edition = 3;
+
+    // Defaults of features that can be overridden in this edition.
+    optional FeatureSet overridable_features = 4;
+
+    // Defaults of features that can't be overridden in this edition.
+    optional FeatureSet fixed_features = 5;
+
+    reserved 1, 2;
+    reserved "features";
+  }
+  repeated FeatureSetEditionDefault defaults = 1;
+
+  // The minimum supported edition (inclusive) when this was constructed.
+  // Editions before this will not have defaults.
+  optional Edition minimum_edition = 4;
+
+  // The maximum known edition (inclusive) when this was constructed. Editions
+  // after this will not have reliable defaults.
+  optional Edition maximum_edition = 5;
+}
+
+// ===================================================================
 // Optional source code info
 
 // Encapsulates information about the original source file from which a
@@ -801,8 +1176,8 @@
     // location.
     //
     // Each element is a field number or an index.  They form a path from
-    // the root FileDescriptorProto to the place where the definition.  For
-    // example, this path:
+    // the root FileDescriptorProto to the place where the definition appears.
+    // For example, this path:
     //   [ 4, 3, 2, 7, 1 ]
     // refers to:
     //   file.message_type(3)  // 4, 3
@@ -856,13 +1231,13 @@
     //   // Comment attached to baz.
     //   // Another line attached to baz.
     //
-    //   // Comment attached to qux.
+    //   // Comment attached to moo.
     //   //
-    //   // Another line attached to qux.
-    //   optional double qux = 4;
+    //   // Another line attached to moo.
+    //   optional double moo = 4;
     //
     //   // Detached comment for corge. This is not leading or trailing comments
-    //   // to qux or corge because there are blank lines separating it from
+    //   // to moo or corge because there are blank lines separating it from
     //   // both.
     //
     //   // Detached comment for corge paragraph 2.
@@ -902,8 +1277,20 @@
     optional int32 begin = 3;
 
     // Identifies the ending offset in bytes in the generated code that
-    // relates to the identified offset. The end offset should be one past
+    // relates to the identified object. The end offset should be one past
     // the last relevant byte (so the length of the text = end - begin).
     optional int32 end = 4;
+
+    // Represents the identified object's effect on the element in the original
+    // .proto file.
+    enum Semantic {
+      // There is no effect or the effect is indescribable.
+      NONE = 0;
+      // The element is set or otherwise mutated.
+      SET = 1;
+      // An alias to the element is returned.
+      ALIAS = 2;
+    }
+    optional Semantic semantic = 5;
   }
 }
diff --git a/proto-lens.cabal b/proto-lens.cabal
--- a/proto-lens.cabal
+++ b/proto-lens.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.12
 
--- This file has been generated from package.yaml by hpack version 0.36.0.
+-- This file has been generated from package.yaml by hpack version 0.37.0.
 --
 -- see: https://github.com/sol/hpack
 
 name:           proto-lens
-version:        0.7.1.5
+version:        0.7.1.6
 synopsis:       A lens-based implementation of protocol buffers in Haskell.
 description:    The proto-lens library provides an API for protocol buffers using modern Haskell language and library patterns.  Specifically, it provides:
                 .
@@ -58,11 +58,11 @@
   hs-source-dirs:
       src
   build-depends:
-      base >=4.10 && <4.20
+      base >=4.10 && <4.21
     , bytestring >=0.10 && <0.13
     , containers >=0.5 && <0.8
     , deepseq >=1.4 && <1.6
-    , ghc-prim >=0.4 && <0.12
+    , ghc-prim >=0.4 && <0.13
     , lens-family >=1.2 && <2.2
     , parsec ==3.1.*
     , pretty ==1.1.*
diff --git a/src/Data/ProtoLens/Encoding/Bytes.hs b/src/Data/ProtoLens/Encoding/Bytes.hs
--- a/src/Data/ProtoLens/Encoding/Bytes.hs
+++ b/src/Data/ProtoLens/Encoding/Bytes.hs
@@ -6,7 +6,6 @@
 
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE LambdaCase #-}
@@ -63,14 +62,14 @@
 import qualified Data.Vector.Generic as V
 import Data.Word (Word8, Word32, Word64)
 import Foreign.Marshal (malloc, free)
-import Foreign.Storable (peek)
 import System.IO (Handle, hGetBuf)
 #if MIN_VERSION_base(4,11,0)
 import qualified GHC.Float as Float
+import Foreign.Storable (peek)
 #else
 import Foreign.Ptr (castPtr)
 import Foreign.Marshal.Alloc (alloca)
-import Foreign.Storable (Storable, poke)
+import Foreign.Storable (Storable, peek, poke)
 import System.IO.Unsafe (unsafePerformIO)
 #endif
 
@@ -96,9 +95,9 @@
 getVarIntH h = do
     buf <- liftIO malloc
     let loopStart !n !s =
-          (liftIO $ hGetBuf h buf 1) >>=
+          liftIO (hGetBuf h buf 1) >>=
           \case
-            1 -> (liftIO $ peek buf) >>=
+            1 -> liftIO (peek buf) >>=
                  getVarIntLoopFinish loopStart n s
             _ -> throwE "Unexpected end of file"
     res <- loopStart 0 1
diff --git a/src/Data/ProtoLens/Encoding/Parser.hs b/src/Data/ProtoLens/Encoding/Parser.hs
--- a/src/Data/ProtoLens/Encoding/Parser.hs
+++ b/src/Data/ProtoLens/Encoding/Parser.hs
@@ -1,6 +1,4 @@
 -- | A custom parsing monad, optimized for speed.
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Data.ProtoLens.Encoding.Parser
diff --git a/src/Data/ProtoLens/Field.hs b/src/Data/ProtoLens/Field.hs
--- a/src/Data/ProtoLens/Field.hs
+++ b/src/Data/ProtoLens/Field.hs
@@ -17,7 +17,6 @@
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE MagicHash #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 module Data.ProtoLens.Field
diff --git a/src/Data/ProtoLens/Service/Types.hs b/src/Data/ProtoLens/Service/Types.hs
--- a/src/Data/ProtoLens/Service/Types.hs
+++ b/src/Data/ProtoLens/Service/Types.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE FlexibleContexts      #-}
 {-# LANGUAGE FlexibleInstances     #-}
 {-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE KindSignatures        #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE PolyKinds             #-}
 {-# LANGUAGE RankNTypes            #-}
diff --git a/src/Data/ProtoLens/TextFormat/Parser.hs b/src/Data/ProtoLens/TextFormat/Parser.hs
--- a/src/Data/ProtoLens/TextFormat/Parser.hs
+++ b/src/Data/ProtoLens/TextFormat/Parser.hs
@@ -102,7 +102,7 @@
         value <- naturalOrFloat ptp
         return $ makeNumberValue negative value
     parseString = liftM (ByteStringValue . mconcat)
-        $ many1 $ lexeme ptp $ protoStringLiteral
+        $ many1 $ lexeme ptp protoStringLiteral
     parseEnumValue = liftM EnumValue (identifier ptp)
     parseMessageValue =
         braces ptp (parseAny <|>
diff --git a/tests/parser_test.hs b/tests/parser_test.hs
--- a/tests/parser_test.hs
+++ b/tests/parser_test.hs
@@ -73,8 +73,8 @@
 testIsolate :: [TestTree]
 testIsolate =
     [ testProperty "many" $ \bs bs' ->
-        runParser ((,) <$> (isolate (length bs) $ manyTillEnd getWord8) <*>
-                        (manyTillEnd getWord8))
+        runParser ((,) <$> isolate (length bs) (manyTillEnd getWord8) <*>
+                        manyTillEnd getWord8)
             (B.pack (bs ++ bs'))
             == Right (bs, bs')
     , testProperty "negative length" $ \n ws ->
