Skip to content

Generators: one signature identity for every hand-written-member check, the generated members derived from the aspects and marked by an attribute #239

Closed

Description

@CaffeinatedCoder

Why

Seven 2.3.1 bugs (#191, #195, #196, #197, #205, #226, #230) are one question answered differently in several places: is this member the user wrote the one a generator introduces? ValueObjectDeclaration.MethodsWithSignature, ClosedSetTypes.SameParameters, MembersNamed and the base-type walks each decide arity, ref kind, nullability and accessibility by their own rules. The generated members' names are hand-kept lists (ValueObjectDeclaration.cs:182, ClosedSetTypes.cs:35), and AGENTS.md notes that a new generated member left off them is "kept silently".

Proposal

  • One signature identity used by every check, following C#'s overloading rules: name, arity, each parameter's type without its nullability, and its ref kind (out/ref/in against by-value differ, ref against out clash), plus whether the member is visible from the value object (a private base member is not its own).
  • Derive the generated members from what the aspects introduce, so that the check and the generation cannot disagree, instead of name lists kept in step by hand.
  • Mark every generated member with a TypeKit-owned attribute in the base package (Metalama-free), naming the contract member it implements. The signature identity still decides the check before generation, where nothing carries the attribute yet; the attribute answers what that check can only infer after it: whether a base record's member from another assembly was generated or written by hand (the A base record's explicit Create from another project leaves two rule sets #195/A base record's public implementation of a generated member is kept as the value object's, or crashes the aspect #197 family), and, for the analyzers and the run-time satellites, which members are generated, without name lists (discovery by attribute, as GeneratedValueObjectAttribute<TValueObject, T> does for types). Not [GeneratedCode]: Roslyn analyzers skip code marked with it by default, which would silence the CMTK rules and the consumer's own analyzers on those members.

Done when

Every hand-written-member check goes through the one identity; the name lists are gone or generated from the aspects' introductions; every generated member carries the attribute (GeneratedSurface.verified.txt), and a base record's generated member from another assembly is told from a hand-written one by it; the attribute has a claim or a surface waiver; the regression rows of #191 to #197, #205, #226 and #230 pass unchanged; no build outcome changes beyond those fixes.

Outcome (2026-10-31, #279)

  • Separable, so they land as two commits in One signature identity for every hand-written-member check, and [GeneratedMember] on every generated member #279, the identity (fix:) before the attribute (feat:), after the design in decision 128.
  • The identity is C#'s, and it moves some outcomes, each measured against af3f95e: a property or field of a generated method's name (own or a base's), a set's own Name() and a set base's nested converter type now fail with CMTK1011 instead of LAMA0506/LAMA0531/LAMA0611. A base record's TryFrom(int?) over an int, a set's Parse(string, bool?), a base record's MinValue()/Value()/_value() and an entry point's overload now build where they were CMTK1011. No build that built fails.
  • Every generated member carries the attribute, with one exception: Metalama 2026.1 applies no attribute to an override it writes over a record's implicit ToString() (and Equals/GetHashCode() over a base record), and refuses IntroduceAttribute there.
  • "A base record's generated member from another assembly is told from a hand-written one by it": no base type can carry a generated member today (value objects and closed sets are sealed, and an abstract one is not generated), so this can't be exercised with a real base. IsHandWritten reads the attribute, and GeneratedMemberAttributeTests shows that in another assembly (the probes) every generated member carries it and no hand-written one does.

Activity

  1. added this to the 2.4.0 milestone on Oct 31, 2026
  2. added
    choreBuild, CI, tooling, packaging, refactoring with no behaviour change
    package/generatorsAffects CodoMetis.TypeKit.Generators
    on Oct 31, 2026
  3. changed the title [-]Generators: one signature identity for every hand-written-member check, and the generated members derived from the aspects[/-] [+]Generators: one signature identity for every hand-written-member check, the generated members derived from the aspects and marked by an attribute[/+] on Oct 31, 2026
  4. CaffeinatedCoder commented on Oct 31, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Landed on release/2.4.0 by #279 (merge commit 020e48c), with decision 128: one signature identity for the hand-written-member checks, and [GeneratedMember] on every generated member.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/value-objectsValue-object contracts and what the aspects generate for themchoreBuild, CI, tooling, packaging, refactoring with no behaviour changepackage/generatorsAffects CodoMetis.TypeKit.Generators

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions