When creating or modifying lutaml-model classes, attributes MUST be declared BEFORE xml mappings. This is the single most important rule for contributors.

1. The Rule

# CORRECT - Attributes FIRST
class MyClass < Lutaml::Model::Serializable
  attribute :my_attr, MyType  # Declare attribute first

  xml do
    element 'myElem'
    namespace Namespaces::WordProcessingML
    map_element 'elem', to: :my_attr  # Map after
  end
end

# WRONG - Will NOT serialize
class MyClass < Lutaml::Model::Serializable
  xml do
    map_element 'elem', to: :my_attr  # Mapping before attribute
  end

  attribute :my_attr, MyType  # Too late! Framework doesn't know it exists
end

2. Why This Matters

Lutaml-model builds its internal schema by reading attribute declarations sequentially:

  1. When the class body is evaluated, Ruby executes statements top to bottom

  2. The xml do block registers mappings with the framework

  3. If xml do comes first, the framework processes mappings before knowing attributes exist

  4. The framework cannot resolve to: :my_attr because the attribute has not been declared yet

  5. Result: Serialization produces empty XML, deserialization fails silently

This was the root cause of complete document serialization failure during v1.1.0 development.

3. Additional Rules

Use mixed_content for elements with nested content

Elements that contain a mix of text and child elements need mixed_content enabled.

Only one namespace declaration per element level

Do not declare multiple namespaces at the same element level.

Use render_default: true for required optional elements

Optional elements that must always appear in output should use render_default: true.

Use ||= in initialize, not =

In initialize after super, use ||= to preserve lutaml-model parsed values:

def initialize(**attrs)
  super
  @items ||= []  # Preserves parsed values
  # NOT: @items = []  # Overwrites parsed values!
end

4. Generated Classes Are Safe

Schema-generated classes automatically enforce Pattern 0. The model generator always emits attributes before the xml do block. Manual model classes require careful attention.

5. Verification

After modifying any lutaml-model class:

  1. Run the full test suite: bundle exec rspec

  2. Test serialization round-trip for the affected class

  3. Verify XML output is not empty