Dataplatform validation
Overview
Before the Generator sends anything to the generation API it validates the local Dataplatform tree and fails the build on what it finds. The API already validates structure, references, enums, data types and per-field uniqueness on the payload it receives, so the client checks are scoped to what the API cannot do:
- the client filesystem, which the API never sees; and
- cross-object configuration collisions whose only symptom at runtime is a load that quietly does the wrong thing.
Every violation is reported — the build does not stop at the first — and each one names the file, the key, what is wrong and the likely fix.
What gets validated
| Stage | Component | Output |
|---|---|---|
| Build | EasyFabric Generator (EFG) | ValidateDataplatform → violations on the build log, build fails on any ERROR |
The validator reads Objects/, Connections/, the model files and the notebook folder names from the same tree the generator generates from, so the rules see exactly what the build sees.
Rules
Notebook references resolve
Any notebook hook on an Object (PreBronzeNotebook, MidBronzeNotebook, PostSilverNotebook, …) and any Loadsettings.Notebook on a model table must name a folder that exists under Notebooks/<Layer>/. The API only receives the notebook name in JSON; a typo there silently skips the transformation and surfaces only at runtime in Fabric.
ERROR AdvWorks/products.yaml [PreBronzeNotebook]: Notebook 'Pull_Gith' has no matching
folder under Notebooks/. — fix: did you mean 'Pull_Github'?
When no notebook folders are discovered at all, the rule skips rather than flagging every reference — the notebooks may live outside the validated root.
Tracker paths are unique
Two objects that load bronze must not resolve to the same Bronze tracker file. The tracker path follows from configuration alone, exactly as easyfabric.load_data_bronze derives it at runtime:
ConnectionType | Tracker folder |
|---|---|
azblob | <BronzeFolder>/<DataPlatformObjectname> |
fabricfiles | <BronzeFolder>/<SourceTable> |
with the tracker itself at <folder>/_tracking/tracker.json. BronzeFolder and ConnectionType fall back to the Connection when the Object does not set them.
For azblob the object name is part of the path, so two objects can never collide. For fabricfiles the path is the source folder: two objects with the same BronzeFolder and SourceTable share one tracker file. The second object then reads the first one's snapshot, concludes the source is unchanged, and — with SkipIfSourceUnchanged on its default true — skips its own load without an error. Data is missing in bronze and silver while the run is logged as a success.
ERROR AdvWorks/projects_b.yaml [projects_b]: Objects 'projects_a' and 'projects_b' both
load bronze from tracker file 'advworks/Projecten/_tracking/tracker.json', so the second
one reads the first one's snapshot and silently skips its load. — fix: give 'projects_b'
its own BronzeFolder or SourceTable, or set BronzeLoadSkip: true on the object that must
not load bronze.
Objects that never load bronze cannot collide and are left out of the check:
BronzeLoadSkip: trueon the Object or its Connection;- a
Layerslist that contains neitherALLnorBronze; IsActive: false.
A fabricfiles object whose SourceTable names a single file (products.csv) is not tracked at all — the tracker path would fall inside the file's own path — so it is left out as well.
Adding a rule
Implement IValidationRule in apps/Generator/Generator/Validation/Rules.cs and register the class in DataplatformValidator.Rules. Rules must be side-effect free and return every violation they find rather than failing fast.