merge
fun <TData> merge(a: TableOptionsResolved<TData>, b: TableOptionsResolved<TData>?): TableOptionsResolved<TData>
Returns the field-by-field merge { ...a, ...b } — b wins.
Nullable members fall back to a when b leaves them null (matching the "present key" rule). The non-null core members and renderFallbackValue are always taken from b; the final merge(defaults, userOptions) is the only call that carries their real values, so feature-fragment merges only see placeholders on both sides anyway.
Passing null for b returns a unchanged — a feature whose getDefaultOptions is absent contributes no overlay.