Skip to content

Commit 2d6ddad

Browse files
akshay-vizCopilot
andcommitted
docs(model-apps): write down the actual Dataverse-access policy
AGENTS.md asserted "All Dataverse access is via the SDK" inside the build paragraph, where it is true. Read as a global rule it is not: eight scripts call `dataverseRequest()` directly, the file tree already describes `dataverse-request.js` as an "escape hatch", and this PR's `entityPrivileges` reader goes straight to the raw http client. So the rule as written made every legitimate direct call look like a violation, and gave a reviewer no way to tell a sanctioned exception from an accident. Records the policy that was actually being followed: SDK by default for anything the SDK models -- because it persists workspace metadata, resolves artifact identity the same way the build does, and owns retry/pagination, so a read that bypasses it can disagree with the write about which artifact it means -- plus the two sanctioned hatches and what each is for. The maker SDK models the maker surface; `WhoAmI`, `customapis` and `connectionreferences` are simply not in it. Also states the four things a direct call must do, each of which is a bug this plugin has actually hit: say WHY the SDK cannot serve it (so nobody "simplifies" it back), use an absolute URL with the API prefix (the raw client validates with `new URL` and rejects a relative path), leave `Edm.Guid` values unquoted, and test the reader itself rather than only an injected stub -- which is precisely how the `entityPrivileges` URL bug reached review with a green suite. Scopes the build paragraph's claim to the build so the two do not contradict. Documentation only; no behaviour change. 1480 tests still pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 42626da2-b66f-4162-acaa-b1127ef23d89
1 parent 5efd1be commit 2d6ddad

1 file changed

Lines changed: 38 additions & 2 deletions

File tree

plugins/model-apps/AGENTS.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ the pipeline and delegates each script's **behavioral spec** to the entries belo
123123
`@odata.nextLink` pagination (`queryRecords({ paginate:true })`), so it verifies EVERY app in the
124124
environment rather than one 5000-row page; a pagination fault (the SDK's repeated-nextLink guard) still
125125
fails **closed** rather than scanning a partial list. Classic `dashboards[]` are opt-in.
126-
**All Dataverse access is via the SDK**, so metadata is persisted under
126+
**All of the build's Dataverse access is via the SDK** (see "Dataverse Access From Scripts" for the
127+
sanctioned exceptions elsewhere), so metadata is persisted under
127128
`<app-folder>/.maker-workspace/` for reuse/edits. The 14 phases
128129
(`solution·data-model·sample-data·web-resources·views·charts·forms·commands·dashboards·app-shell·pages·ai-features·security·publish`)
129130
are unchanged; independent ops run with bounded parallelism.
@@ -682,7 +683,42 @@ repo-root `shared/telemetry/`; `scripts/lib/telemetry/lib` is a **physical copy*
682683
- **Accessibility** — WCAG AA, ARIA labels, keyboard navigation, semantic HTML
683684
- **Complete code** — no placeholders, TODOs, or ellipses in final output
684685

685-
## Skill Authoring Guidelines
686+
## Dataverse Access From Scripts
687+
688+
**Default: go through the vendored SDK.** Anything the SDK models — tables, columns, relationships,
689+
views, charts, forms, commands, dashboards, app modules, sitemaps, solutions, roles, settings — is
690+
read and written through `createMakerSdk`. That is not style: the SDK persists metadata under
691+
`<app-folder>/.maker-workspace/` for reuse and edits, resolves artifact identity the same way the
692+
build does, and owns retry/pagination behaviour. A read that bypasses it can disagree with the write
693+
about which artifact it is talking about.
694+
695+
Two escape hatches exist, and both are deliberate. The maker SDK models the *maker* surface; parts of
696+
Dataverse simply are not in it.
697+
698+
| Hatch | Use for | Examples in tree |
699+
|---|---|---|
700+
| `dataverseRequest()` in `lib/dataverse-auth.js` (and the `dataverse-request.js` CLI) | Dataverse surfaces the SDK does not model at all | `WhoAmI` (`check-auth.js`), `customapis` (`list-custom-apis.js`), `connectionreferences` (`create-connection-reference.js`), solution-component adds (`add-page-to-solution.js`) |
701+
| The raw `httpClient` from `createAzHttpClient` | A surface the SDK *does* touch but whose response it **projects away** | `entityPrivileges` in `verify-model-app.js``fetchEntityMetadata` returns `{logicalName, displayName, entitySetName, attributes, relationships}` and drops `Privileges` entirely |
702+
703+
**Prefer `dataverseRequest()` over the raw client.** It already handles the API path, auth, headers
704+
and timeouts. Reach for `httpClient` only when you must share the exact client instance the SDK is
705+
using, as the verify reader does.
706+
707+
When you do go direct, all four of these apply:
708+
709+
1. **Comment WHY the SDK cannot serve it** — name the SDK method you would otherwise call and what it
710+
drops or lacks. "Deliberately not `sdk.fetchEntityMetadata`" is the difference between a
711+
documented exception and something a later reader "simplifies" back into a silent bug.
712+
2. **Absolute URL including `/api/data/v9.2`** when using the raw `httpClient`. It is the transport
713+
the SDK drives, so it takes full request URLs and validates them with `new URL(url)` for its
714+
same-origin guard — a relative path throws there rather than resolving against the org.
715+
3. **GUIDs unquoted.** Record ids and `_x_value` lookups are `Edm.Guid`; `id eq '<guid>'` fails with
716+
*"A binary operator with incompatible types was detected"*. See `references/troubleshooting.md`.
717+
4. **Test the reader itself, not only an injected stub.** The `entityPrivileges` URL bug shipped
718+
because every test injected a fake reader into `verifySpec`, so the real one was never executed —
719+
and `verify-spec` catches per-entity read failures, so it would have failed silently on every live
720+
run rather than crashing. Drive at least one test through the real client's request seam.
721+
686722

687723
- Keep SKILL.md under 500 lines
688724
- Use short, descriptive `name` field (e.g., `genpage`)

0 commit comments

Comments
 (0)