Grid Validator
Audit a single Datex Studio grid file (*-grid.json) against grid-specific authoring rules — the mandatory final gate after grid-creator has authored or modified a grid, and before the change is upserted to the branch. This skill is grid-only: it carries gotchas the generic component-validator does not catch (envelope-vs-body shape, text-display coercion, five-location dynamic-filter sync, imperative cell API mismatches, tailored vs custom provenance). For non-grid component files, route to component-validator instead.
This validator reads; it does not edit. It returns a structured punch-list (Blockers / Warnings / Nits) — never a rewrite. The parent (typically grid-creator, or the user directly) owns the fix.
See also:
component-validator— generic dispatcher for non-grid component files (actions, functions, forms, editors, hubs, storage, selectors, customTypes, backendTests, datasources). Falls back togrid-creator/references/grids.mdfor grids ifgrid-validatoris unavailable, but the generic dispatcher does not carry the grid-specific gotchas listed below.See also:
component-wiring-check— cross-component reference contracts (one component pointing at another). This validator only audits a single grid file in isolation; it flags obvious wiring drift it can see in that one file (e.g. aconfigParametersblock that does not mirror the file's owninParams) but does not chase external references.
References
- ../grid-creator/references/grids.md — authoritative grid reference (envelope shape, columns, datasources, queryOptions, dynamic filters, imperative cell API)
- ../tailoring-overlay/references/tailoring.md — overlay shadow-marker rules when the grid is a tailored variant (
tailored_*-grid.json) - ../datasource-creator/references/odata-datasources.md — OData envelope rules for backing datasources embedded in
datasources[0] - ../datasource-creator/references/flow-datasources.md — flow-backed datasource envelope rules (when the grid is backed by a function rather than OData)
- ../component-wiring-check/references/component-wiring.md —
configParameters↔inParamsmirror rules andmoduleIdconformance - ../datex-studio-conventions/file-format.md —
configurationTypeIdtable, single-line minified JSON rule, TypeScript-expression encoding ('literal'quoting, backtick-wrapping) - ../datex-studio-conventions/naming-conventions.md — Suffix table,
referenceName↔ file-stem rule,tailored_/custom_prefix conformance - ../datex-studio-runtime/runtime-globals.md —
$grid.*,$row.*,$col.*runtime globals available inside grid TS expressions
Dependencies
grid-creator— the creator skill whosereferences/grids.mdis the authoritative rulebook this validator audits against. Update that document and this validator picks up the new rules automatically.tailoring-overlay— overlay-specific shadow-marker rules invoked when the grid is a tailored variant rather than a base grid.datasource-creator— backing-datasource rules (OData and flow) applied to the embeddeddatasources[0]block.component-wiring-check— cross-component audit invoked when the punch-list surfaces wiring drift the parent wants to chase further.datex-studio-conventions— generic cross-cutting rules (file format, naming, defaults) that apply on top of the grid-specific checklist.datex-studio-shared/datex-studio-runtime— branch-setup primitives and platform-runtime globals referenced by the grid rule doc.component-validator— sibling generic dispatcher for non-grid component files. Mutually exclusive: a grid file isgrid-validator's territory; any other suffix routes tocomponent-validator.
Workflow
This skill is typically invoked by grid-creator at the end of its authoring loop, or by the user directly with "audit this grid before merge". The invocation pattern is a Task-tool sub-agent dispatch — give the prompt template in the ## Sub-agent section below to the sub-agent along with the target file path.
Invocation (orchestrator side)
- Confirm the target is a grid body — the grid the parent has just authored or modified. The branch is the source of truth, so the target is either the staged scratch
body.jsonabout to bedxs configuration upsert-ed, or a fresh fetch (dxs source explore config <referenceName> --branch <id>, ordxs configuration get grid <id> -b <id> -O envelope.json && jq .json envelope.json > body.json). ItsreferenceNamemust end in-grid(ortailored_*-grid/custom_*-gridfor overlay variants). If it's any other component type, stop and route tocomponent-validatorinstead. Never audit a persistent localsrc/copy as authoritative. - Dispatch the sub-agent — use the Task tool with the prompt template from the
## Sub-agentsection. The sub-agent hasRead,Grep,Globaccess; it does not edit. - Apply the punch-list — the sub-agent returns a markdown punch-list grouped by severity. Treat each finding as follows:
- Blockers — must be fixed before upserting. Route the fix back to
grid-creator. - Warnings — review and decide. May be deliberate; the sub-agent never assumes intent.
- Nits — optional cleanup. Defer unless the parent is already touching that area.
- Blockers — must be fixed before upserting. Route the fix back to
- Re-validate after fixes — if Blockers were fixed, run the validator again. The validator is cheap (one Read + one Grep through the rule doc) and should be the last step before the push.
Scope discipline (validator's contract)
- The validator reads; it does not edit. The parent owns the fix.
- The validator returns a punch-list; it does not return a rewrite.
- The validator audits one grid file; it does not chase cross-component references (that is
component-wiring-check's territory). - The validator does not load raw OData schema documents. If the embedded backing datasource needs entity / property validation against the live schema, the validator recommends the parent invoke
schema-explorerseparately. - The validator does not speculate about intent. If a rule violation could be deliberate, it is flagged as a Warning with a note, not as a Blocker.
Sub-agent
The prompt template below is what the orchestrator passes to the Task-tool sub-agent dispatch. The sub-agent is read-only (Read, Grep, Glob).
You validate a single Datex Studio grid component file (*-grid.json) against the platform's grid authoring rules. You do not edit files. You return a punch list.
Workflow
Load the target grid body. The parent gives you the path to a single JSON file — the scratch
body.jsonstaged for upsert, or a config just fetched from the branch (itsreferenceNameis<name>-grid,tailored_<name>-grid, orcustom_<name>-grid). This is a throwaway temp file, not a persistent source-of-truth copy. Read it in full. The minified JSON envelope is the surface you will audit against the checklist.Load the grid rulebook. Read
../grid-creator/references/grids.md— its checklist sections are the rulebook. If the file is a tailored or custom-provenance overlay, also read../tailoring-overlay/references/tailoring.md. The docs explain the why behind each rule; don't re-derive them from memory.Walk the checklist item-by-item. For each issue, record:
- Severity —
blocker(silent runtime failure, import error, or clear rule violation),warning(drift or inconsistency that may or may not bite),nit(style / naming / optional cleanup). - Rule — which checklist item it maps to.
- Location —
<filename>:<line>or JSON path (e.g.datasources[0].queryOptionsObjectTypeDef). - Evidence — short quote or description.
- Severity —
If the grid is OData-backed, verify
queryOptions.selectsincludes every field declared in the entity-shape locations. Consult../datasource-creator/references/odata-datasources.mdfor the OData envelope rules. If the parent authorizes invoking theschema-explorerskill, use it to confirm entity / property / navigation names against the live OData schema; otherwise flag unverified names as warnings.If the grid is flow-backed (the backing datasource resolves to a function rather than an OData entity), consult
../datasource-creator/references/flow-datasources.mdfor the flow-datasource envelope rules.Always probe these grid-specific failure modes explicitly — they are not caught by a casual checklist walk and the generic
component-validatordoes not carry them:a. Embedded datasource component-identity envelope (envelope shape). Confirm
datasources[0]carries all ofreferenceName(must equaldatasourceConfig.configIdverbatim),title,description,hasKey,hasResult,id,linkedDatasources,customColumns,inParams,outParams,vars,events,accessModifier, and the correctconfigurationTypeIdper../datex-studio-conventions/file-format.md. Also confirm thedatasourceConfigsarray andcomponentReference(when present) line up with the grid's own envelope. MissingreferenceNameis a blocker — it producesInvalid contract. Referenced own configuration <name> does not exist or has been renamedand cascades intoCannot find name 'get'/'getList'/'inParams'/'refresh'TS errors at import.b. Text-display string coercion. For every column with
displayControl.type: "text"whosetextConfig.valuedereferences$row.entity.<Field>, look up<Field>'s declaredtypeinqueryOptionsObjectTypeDef. If it's anything other thanstring, the binding must coerce (e.g."$row.entity.Id?.toString()"for numbers, template-literal backtick-wrapping for compositions,$utils.date.format(...)for dates). An uncoerced non-string binding is a blocker — import fails withType '<number|boolean|...>' is not assignable to type 'string'. Apply the TS-expression encoding rules from../datex-studio-conventions/file-format.md: declarative string slots that are literal text need'literal'single-quoting; compositions need backtick-wrapping.c. Entity-shape five-location sync. When an entity field is bound anywhere in the grid, confirm it appears in all five entity-shape locations per grids.md → Datasource Wiring — Five Places Must Stay in Sync: (1)
datasources[0].queryOptionsObjectTypeDef, (2)datasources[0].outParams[result].objectTypeDef, (3)datasources[0].getListFlow.outParams[result].objectTypeDef, (4)datasources[0].getByKeysFlow.outParams[result].objectTypeDef, (5)datasourceConfig.configOutParameters[result].objectTypeDef. For an OData-backed datasource, locations 3 and 4 arenull— skip them, but the field must also appear indatasources[0].queryOptions.selects(the sixth, runtime-only location that actually retrieves it). Drift in any required location is a blocker — the field isundefinedon$row.entityor import fails with a contract error.d. Dynamic-filter / sort registration sync. When a column declares a dynamic filter or sort, confirm both halves of grids.md → Dynamic Filters and Sorting: (1) the field is registered at both top-level sites —
datasources[0].dynamicFilters/dynamicOrderBys(embedded-datasource side) anddatasourceConfig.dynamicFilters/dynamicOrderBys(consumer side) — with identical entries; and (2) the column carries its per-column wiring (dynamicFilter,dynamicOrderBy,dynamicFilterType,dynamicFilterControl), withdynamicFilter/dynamicOrderBymatching a registered entry. Drift between the two registration sites is a blocker — import fails withOutdated contract. Type mismatch for dynamic filtering/sorting. Do not flag a missing$filter/$orderbyin anyinParamslist — those are auto-injected from the registrations and a manual entry is itself the bug.e. Imperative cell API mismatches. A column wired for cell-click fires the flow named in its
onCellClickFlowConfig(typically underrowFlows); confirm that flow exists in the grid'sflows/rowFlowsblock (or a linked flow file). Imperative writes in row/grid flows use the cell surface from grids.md → Imperative Cell API:$row.cells.<col>.displayControl.text/.displayControl.value,$row.cells.<col>.editControl.value, and the read-only$row.cells.<col>.editControl.isChanged. A cell-click flow reference with no matching definition is a blocker; an imperative write to a cell surface or column that doesn't exist is a warning.f. Tailored vs custom provenance conformance. If the file stem starts with
tailored_, the file is an overlay and the shadow-marker rules in../tailoring-overlay/references/tailoring.mdapply on top of the base grid's checklist. If the file stem starts withcustom_, the file is a customer-specific variant and thecustom_provenance rules in../datex-studio-conventions/naming-conventions.mdapply. Mixing the two prefixes (e.g.tailored_custom_foo-grid.json) or omitting the prefix on a tailored variant is a blocker.g.
$grid.*runtime usage. If the grid uses$grid.*/$row.*/$col.*globals inside TS expressions, confirm the globals exist and are used per../datex-studio-runtime/runtime-globals.md. Unknown global identifiers are a blocker (TS error at import); deprecated globals are a warning.Always probe the universal cross-cutting failure modes even if the grid checklist does not restate them. These are enumerated once in
../datex-studio-conventions/universal-checklist.md— walk that list (description ≤ 100 chars,accessModifierset,referenceName↔ stem, single-line minified JSON, correctconfigurationTypeId, snake_case newinParams/outParamsids,id: 0if net-new). Plus one grid-relevant wiring check:configParametersblock, when present, mirrors the file's owninParamsper../component-wiring-check/references/component-wiring.md. A mismatch the validator can see from the grid file alone is a warning (recommend the parent invokecomponent-wiring-checkfor the full cross-component audit).
Report. Return a short markdown punch list grouped by severity, each item one or two lines. No preamble, no rewrites, no code suggestions beyond one-line pointers. If nothing is wrong, say
No issues found.
Scope Discipline
- You read. You do not edit.
- You return a punch list. You do not return a rewritten file.
- You do not chase references into other component files — cross-component wiring is
component-wiring-check's territory. If a wiring issue is obvious from the grid alone, flag it and let the parent decide whether to follow up. - You do not load raw OData schema documents. If entity / property / navigation validation is needed, recommend the parent invoke the
schema-explorerskill separately. - You do not speculate about intent — if a rule violation could be intentional (e.g. an empty
displayControl.valuethat's legitimate imperative population), flag it as a warning with a note, not a blocker. - If the file is not a grid (suffix is not
-grid.jsonand not atailored_*-grid.json/custom_*-grid.jsonoverlay variant), replyCannot validate: file is not a grid. Route to component-validator instead.and stop.
Output Format
## Blockers
- [`datasources[0].queryOptionsObjectTypeDef`] `warehouse_id` missing (present in locations 2, 3, 4, 5). Entity-shape five-location sync drift.
- [`datasourceConfig.dynamicFilters`] `warehouse_id` registered on `datasources[0].dynamicFilters` but missing here. Dynamic-filter registration drift.
- [`columns[2].textConfig.value`] `$row.entity.OrderTotal` is `number`; needs `.toString()` coercion or template-literal wrapping.
## Warnings
- [`columns[3].dynamicFilter`] targets `accounts` (collection) directly; needs a scalar sidecar per array-field caveat.
- [`columns[5].onCellClickFlowConfig`] references flow `confirmDelete`, which is not defined in `flows` / `rowFlows`.
## Nits
- [`description`] 118 chars — exceeds the ≤100-char soft limit.
- [`title`] equals `referenceName`; a human-readable title is more discoverable in Datex Studio listings.
Omit any bucket that is empty. If all three buckets are empty, return No issues found.