microsoft / microsoft/Dataverse-skills
dv-metadata: document column-constraint setting + Web API metadata contract (PUT not PATCH, @odata.type)
- Dominant language
- No language data
- Stars
- 226
- Forks
- 61
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 7
Description
## Summary
`dv-metadata` teaches column creation as `client.tables.create(name, {"Col": "type"})` (type strings only). It does not tell the agent that the SDK cannot set column **constraints** (`MaxLength`, `MinValue`/`MaxValue`, `Format`, `RequiredLevel`, custom `DisplayName`), nor does it document the raw Web API metadata contract needed to set them. So when a user asks for a bounded column (e.g. "Rating 1-5", "Comment = 2000 chars"), the agent has no documented path, improvises the raw Web API, and loops through several metadata-endpoint quirks.
## Evidence (from a live ChatGPT-web run)
Creating a Customer Feedback table with Rating 1-5 and a 2000-char Comment, the agent:
1. Created columns with SDK defaults (no constraints -- the SDK cannot express them; see microsoft/PowerPlatform-DataverseClient-Python#194).
2. Tried to read `MaxLength`/`MinValue` off the **generic** AttributeMetadata collection -> Dataverse does not project type-specific fields -> had to read the **typed** attribute.
3. Tried `PATCH` to update attribute metadata -> rejected; the metadata endpoint uses `PUT`.
4. Sent the `PUT` without the `@odata.type` derived-type discriminator -> Dataverse treated it as generic and rejected `Format`/`MaxLength` -> had to add the discriminator.
5. Ended up searching learn.microsoft.com for the contract mid-task.
Each step cost a retry (~minutes). All are well-known, documentable rules.
## Proposed skill additions (dv-metadata)
Add a "Column constraints" section:
- The high-level SDK create (`client.tables.create` / `add_columns`) only sets the column **type + default size** -- it cannot set `MaxLength`, `MinValue`/`MaxValue`, `Format`, `Precision`, `RequiredLevel`, or a custom `DisplayName`. (Once microsoft/PowerPlatform-DataverseClient-Python#194 lands, prefer the rich column spec; until then, use the Web API for constrained columns.)
- To set constraints, POST/PUT to `EntityDefinitions({metadataId})/Attributes` with the **derived-type `@odata.type`** (e.g. `Microsoft.Dynamics.CRM.StringAttributeMetadata`, `MemoAttributeMetadata`, `IntegerAttributeMetadata`).
- **Anti-hallucination note** (mirroring the PAC wrong/correct tables): attribute metadata **updates are `PUT`, not `PATCH`**, and the payload **must** carry `@odata.type` or Dataverse treats it as generic and rejects type-specific properties.
- **Verify** type-specific fields by reading the **typed** attribute (`.../Attributes()/Microsoft.Dynamics.CRM.StringAttributeMetadata`), not by projecting across the generic collection.
## Sequencing -- prefer the SDK path as it lands, keep the raw Web API contract as the documented fallback
The raw Web API contract above (`PUT` not `PATCH`, derived `@odata.type`, read typed props via the derived-type cast) is correct and worth documenting **now** -- it is the current reality and the fallback for older SDK versions. But the end state is to route agents through the SDK so they stop hand-rolling metadata calls. These are Web-API-surface warts; the .NET modern client never hits them because it uses the Organization Service message contracts (typed `UpdateAttributeRequest`, no HTTP verb; `RetrieveEntity` returns typed objects in one call). The Python SDK is Web-API-bound, so the fixes belong in the SDK + this skill -- not in a platform change.
- **Create with constraints** -> SDK rich column spec: microsoft/PowerPlatform-DataverseClient-Python#194 (in progress).
- **Update an existing column** -> new SDK `update_column`: microsoft/PowerPlatform-DataverseClient-Python#202 -- hides the `PUT`/`@odata.type` entirely.
- **Typed reads** -> new SDK `RetrieveMetadataChanges`-backed typed read: microsoft/PowerPlatform-DataverseClient-Python#203 -- one request, no cast; property projection means it does not need any platform "omit null fields" change.
Proposed dv-metadata structure: document the raw Web API contract as the **fallback**, and add a "prefer the SDK" callout that becomes the primary path once the three SDK issues ship. This keeps the skill accurate today and removes the improvised-Web-API loop tomorrow -- no platform change required.
## Links
- SDK gap that forces the Web API path (create-time constraints): microsoft/PowerPlatform-DataverseClient-Python#194
- SDK `update_column` (update existing column, hides PUT/@odata.type): microsoft/PowerPlatform-DataverseClient-Python#202
- SDK typed reads via `RetrieveMetadataChanges` (single request, no cast): microsoft/PowerPlatform-DataverseClient-Python#203
Contributor guide
Research direction
Start in the dv-metadata skill and use the cited SDK gaps (#194, #202, #203) as sequencing context. Document the SDK limitation, the raw Web API fallback (PUT, derived @odata.type, typed reads), and the prefer-the-SDK path; done when these rules and current/future paths are explicit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, documentation
- Issue type
- Documentation
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100