private void createErrors(
            Differences differences,
            ChangedShape<MemberShape> change,
            boolean wasNullable,
            Collection<ValidationEvent> events
    ) {
        MemberShape oldMember = change.getOldShape();
        MemberShape newMember = change.getNewShape();
        String message = String.format("Member `%s` changed from %s to %s: ",
                oldMember.getMemberName(),
                wasNullable ? "nullable" : "non-nullable",
                wasNullable ? "non-nullable" : "nullable");
        boolean oldHasInput = hasInputTrait(differences.getOldModel(), oldMember);
        boolean newHasInput = hasInputTrait(differences.getNewModel(), newMember);
        ShapeId shape = change.getShapeId();
        SourceLocation oldMemberSourceLocation = oldMember.getSourceLocation();
        Shape newTarget = differences.getNewModel().expectShape(newMember.getTarget());
        List<ValidationEvent> eventsToAdd = new ArrayList<>();
        SourceLocation newMemberContainerSource = differences.getNewModel()
                .expectShape(newMember.getContainer())
                .getSourceLocation();

        if (oldHasInput && !newHasInput) {
            // If there was an input trait before, but not now, then the nullability must have
            // changed from nullable to non-nullable.
            eventsToAdd.add(emit(Severity.ERROR,
                    "RemovedInputTrait",
                    shape,
                    newMemberContainerSource,
                    message,
                    "The @input trait was removed from " + newMember.getContainer()));
        } else if (!oldHasInput && newHasInput) {
            // If there was no input trait before, but there is now, then the nullability must have
            // changed from non-nullable to nullable.
            eventsToAdd.add(emit(Severity.DANGER,
                    "AddedInputTrait",
                    shape,
                    newMemberContainerSource,
                    message,
                    "The @input trait was added to " + newMember.getContainer()));
        } else if (!newHasInput) {
            // Can't add clientOptional to a preexisting required member.
            if (change.isTraitAdded(ClientOptionalTrait.ID) && change.isTraitInBoth(RequiredTrait.ID)) {
                eventsToAdd.add(emit(Severity.ERROR,
                        "AddedClientOptionalTrait",
                        shape,
                        oldMemberSourceLocation,
                        message,
                        "The @clientOptional trait was added to a @required member."));
            }
            // Can't add required to a member unless the member is marked as @clientOptional or part of @input.
            if (change.isTraitAdded(RequiredTrait.ID) && !newMember.hasTrait(ClientOptionalTrait.ID)) {
                eventsToAdd.add(emit(Severity.ERROR,
                        "AddedRequiredTrait",
                        shape,
                        oldMemberSourceLocation,
                        message,
                        "The @required trait was added to a member."));
            }
            // Can't add the default trait to a member unless the member was previously required.
            if (change.isTraitAdded(DefaultTrait.ID) && !change.isTraitRemoved(RequiredTrait.ID)) {
                eventsToAdd.add(emit(Severity.ERROR,
                        "AddedDefaultTrait",
                        shape,
                        oldMemberSourceLocation,
                        message,
                        "The @default trait was added to a member that was not previously @required."));
            }
            // Can only remove the required trait if the member was nullable or replaced by the default trait.
            if (change.isTraitRemoved(RequiredTrait.ID)
                    && !newMember.hasTrait(DefaultTrait.ID)
                    && !oldMember.hasTrait(ClientOptionalTrait.ID)) {
                if (newTarget.isStructureShape() || newTarget.isUnionShape()) {
                    eventsToAdd.add(emit(Severity.WARNING,
                            "RemovedRequiredTrait.StructureOrUnion",
                            shape,
                            oldMemberSourceLocation,
                            message,
                            "The @required trait was removed from a member "
                                    + "that targets a " + newTarget.getType() + ". This is backward compatible in "
                                    + "generators that always treat structures and unions as optional "
                                    + "(e.g., AWS generators)"));
                } else {
                    eventsToAdd.add(emit(Severity.ERROR,
                            "RemovedRequiredTrait",
                            shape,
                            oldMemberSourceLocation,
                            message,
                            "The @required trait was removed and not replaced with the @default "
                                    + "trait and @addedDefault trait."));
                }
            }
        }

        // If not specific event was emitted, emit a generic event.
        if (eventsToAdd.isEmpty()) {
            eventsToAdd.add(emit(Severity.ERROR, null, shape, oldMemberSourceLocation, null, message));
        }

        events.addAll(eventsToAdd);
    }
Validates that only backward compatible changes are made to
structure member nullability to ensure that if something was
previously nullable to clients then it continue to be nullable
and vice versa.
smithy-diff/src/main/java/software/amazon/smithy/diff/evaluators/ChangedNullability.java