Worked example

A runnable version of everything on the previous pages lives in the repository at examples/custom_build_layer/:

examples/custom_build_layer/
├── data_dictionary/data_structures_extra/
│   └── my_layer.json
└── run.jl
julia --project=scripts examples/custom_build_layer/run.jl

It substitutes a custom chamber layer — IFEdd's own build.layer, extended with a per-volume cost_rate — and reports exactly what the substituted type ended up with.

A substituted type inherits nothing

This is the part worth internalizing. my_layer.json is IFEdd's build.layer schema copied in full, plus one new entry:

"my_layer": {
  "_supertype": "AbstractIFEBuildLayer",
  "data_type": "STRUCT_ARRAY",
  "documentation": "Chamber layer, copied from IFEdd's `build.layer` and extended with `cost_rate`"
},
"my_layer[:].cost_rate": {
  "data_type": "FLT_0D",
  "documentation": "Fabrication cost per unit volume of this layer",
  "type": "static",
  "units": "USD/m^3"
}

Julia has no struct inheritance, and the generator reads only your schema. Your concrete is a sibling of IFEdd's default under the same abstract, not a derivative of it — the two share a dispatch surface, not a layout. Every field you want must be in your JSON:

using IFEdd, GenerateDD

schema_dir = joinpath(pkgdir(IFEdd), "examples", "custom_build_layer",
                      "data_dictionary", "data_structures_extra")

IFEdd.@bake_dd MyDD = (
    schema_dir    = schema_dir,
    slot_bindings = Dict(:AbstractIFEBuildLayer => :my_layer),
)

payload(T) = sort([f for f in fieldnames(T)
                   if !startswith(string(f), "_") && !endswith(string(f), "_σ")])

default_fields = payload(IFEdd.build__layer{Float64})
custom_fields = payload(parentmodule(MyDD).my_layer{Float64})

(kept  = intersect(default_fields, custom_fields),
 added = setdiff(custom_fields, default_fields),
 lost  = setdiff(default_fields, custom_fields))
(kept = [:area, :end_radius, :material, :name, :outline, :start_radius, :thickness, :type, :volume], added = [:cost_rate], lost = Symbol[])

lost is empty only because the schema was copied whole. Drop a line from the JSON and that field moves to lost — silently, since nothing requires a substituted type to resemble the default. Dispatch still succeeds; the failure surfaces later, when some caller reaches for the missing field.

There is no extend directive. Copying is the supported path: open IFEdd's data_dictionary/data_structures_extra/build.json, lift the build.layer entries, rewrite the path prefix to your concrete's name, and add what you need.

What you do not copy

dd = MyDD()
(eltype(dd.build.layer),                                  # your layer
 fieldnames(typeof(dd.build)),                            # parent rebuilt around it
 fieldtype(IFEdd.build{Float64}, :layer))                 # IFEdd's own: untouched
(Main.__bake_MyDD_dfccf24d.my_layer{Float64}, (:code, :ids_properties, :layer, :time, :_name, :_filled, :_frozen, :_threads_lock, :_in_expression, :_parent), IMASdd.IDSvector{IFEdd.build__layer{Float64}})

The parent build was regenerated from IFEdd's schema with only the element type swapped, so time, code and ids_properties came along for free. Housekeeping fields (_name, _filled, _parent, …) and the _σ uncertainty companions are emitted automatically. Slots you did not bind keep their defaults.

The rule of thumb: outward from the substitution point is automatic, inward is yours.

Nested structures come with you

The copied schema carried its nested _supertype marker along, so outline is re-emitted under your own name rather than pointing at IFEdd's:

outline_type = fieldtype(parentmodule(MyDD).my_layer{Float64}, :outline)

(outline_type,
 outline_type <: IFEdd.AbstractIFEBuildLayerOutline,
 outline_type === IFEdd.build__layer___outline{Float64})
(Main.__bake_MyDD_dfccf24d.my_layer___outline{Float64}, true, false)

Same fields, same abstract, different identity. A method written against ::IFEdd.AbstractIFEBuildLayerOutline accepts it; one written against the concrete ::IFEdd.build__layer___outline does not — the concrete-versus-abstract signature question again, one level down.