docs(adr) promote Cosmos ARM-vs-data-plane split to ADR-0012#65
Merged
Conversation
Promote the locked Cosmos schema-CRUD-via-ARM, item-CRUD-via- data-plane-SDK invariant from CLAUDE.md + session memory to a formal ADR per Phase 2 § Scope item 1. The decision was made and shipped in PR #63 (2026-05-04) after PR #62 attempted a custom Cosmos data-plane RBAC role granting `Microsoft.DocumentDB/databaseAccounts/sqlDatabases/*` and was rejected by Azure runtime validation: data-plane RBAC genuinely does not model schema-mutation actions. ADR-0012 captures: - Why both SDK surfaces matter (data-plane SDK convenience methods make the wrong path tempting; ARM SDK is the correct schema-CRUD path) - The failed PR #62 attempt as documented context, so the same custom- role path is not retried - The locked solution (ICosmosProvisioner abstraction with ArmCosmosProvisioner + DataPlaneCosmosProvisioner selected at DI-resolution time by Cosmos:AccountResourceId presence) - Operational consequences with the load-bearing precision: two role assignments in TWO INDEPENDENT RBAC systems — Cosmos DB Operator in Azure RBAC for ARM ops, plus Cosmos DB Built-in Data Contributor in Cosmos SQL RBAC for item ops. Subscription Owner inheritance covers Azure RBAC but does NOT automatically grant Cosmos SQL RBAC, which must be explicitly assigned at the Cosmos account scope - Four alternatives considered and rejected (data-plane SDK with master keys; the failed PR #62 custom-role attempt; containers in Bicep; no-abstraction-caller-picks) Three cross-reference edits land in the same PR so the documentation is internally consistent at every commit: - CLAUDE.md § Cosmos persistence — inline rationale collapses to a one-line ADR-0012 pointer (the showcase posture aim: CLAUDE.md references ADRs rather than duplicating their content) - CLAUDE.md § Locked invariants item 4 — adds ADR-0012 pointer - docs/guardrails.md § Locked decisions — adds ADR-0012 pointer - docs/adr/README.md index — adds 0011 (pre-existing oversight; the reconciliation ADR landed in PR #35 but the index was never updated) and 0012 ADR-0013 (two-tier Bicep deploy with deployPhase2 gate) is the companion Phase 2 § Scope item 2 promotion; ships in its own PR.
This was referenced May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First Phase 2 PR: promote the locked Cosmos schema-CRUD-via-ARM / item-CRUD-via-data-plane-SDK invariant from
CLAUDE.mdand session memory to formal ADR-0012, perdocs/build-spec.mdPhase 2 § Scope item 1.The underlying decision was made and shipped in PR #63 (2026-05-04) after PR #62 attempted a custom Cosmos data-plane RBAC role granting
Microsoft.DocumentDB/databaseAccounts/sqlDatabases/*and was rejected by Azure runtime validation: data-plane RBAC genuinely does not model schema-mutation actions, regardless of role definition. ADR-0012 captures the lesson permanently so the same path isn't retried.The ADR documents the load-bearing precision that the operational consequences require two role assignments in TWO INDEPENDENT RBAC systems —
Cosmos DB Operatorin Azure RBAC for ARM ops, plusCosmos DB Built-in Data Contributorin Cosmos SQL RBAC (a separate system from Azure RBAC) for item ops. Subscription Owner inheritance covers Azure RBAC but does NOT automatically grant Cosmos SQL RBAC. Verified viaaz role definition list --name "Cosmos DB Operator"(returns the role); the data-plane role's well-known ID00000000-0000-0000-0000-000000000002is documented inline.Three cross-reference edits land in the same PR so the documentation is internally consistent at every commit:
CLAUDE.md§ Cosmos persistence: inline rationale collapses to a one-line ADR-0012 pointer (the showcase posture aim — CLAUDE.md references ADRs rather than duplicating content)CLAUDE.md§ Locked invariants item 4: adds ADR-0012 pointerdocs/guardrails.md§ Locked decisions: adds ADR-0012 pointerdocs/adr/README.mdindex: adds 0011 (pre-existing oversight — the reconciliation ADR landed in PR feat(sync) scraper-to-Machine reconciliation service + ADR 0011 #35 but the index was never updated) and 0012Test Plan
dotnet build PinballWizard.slnx --nologoanddotnet test PinballWizard.slnxare expected to remain green (507 / 507).Out of Scope
deployPhase2gate) — companion Phase 2 § Scope item 2; ships in its own PR.ingestion_sourcesseed, OPDB sync against deployed Cosmos, OTel groundwork, Playwright bump, Dependabot triage, Stern Playwright asymmetry resolution, work-email proactive denylist all remain Phase 2 § Scope items in their own PRs.Checklist
README.mdand/ordocs/are updated — yes, three docs updated alongside the ADR for cross-reference coherenceTODO/FIXME/ commented-out code committed<NoWarn>without justification — N/A; no codePre-push self-audit (additive PRs)
N/A for this PR — docs-only, no scraper / options class / extension / additive code surface. Per
docs/guardrails.md§ "Per-PR gate" andCLAUDE.md§ "PR self-audit", "Doc-only PRs and pure dependency bumps may skip" the audit. Identity check still verified:git log -1 --format='%an <%ae>'→Jim Keeley <94459922+jkeeley2073@users.noreply.github.com>✅🤖 Generated with Claude Code