Point azure-devops-node-api at https://ado.sandboxapis.dev/olympus-labs (the serverUrl is the organization URL). Paths mirror dev.azure.com; the discovery contract (connectionData/resourceAreas) is served, so official SDKs route correctly.
Coverage badge
Deep209/232 · 90%
The share of read rows with a final answer — served and verified, a deviation, retired upstream, or a reviewed empty/refusal. Computed in the coverage manifest, copied here.
ado.sandboxapis.devServed & verified
189 / 81%
Answering with real universe data, each response checked against Azure DevOps's published spec by the conformance suite on this build.
The full read API
232
Every read surface Azure DevOps publishes, deferred long tail included, minus the rows excluded by policy. Writes are out of scope: this universe is read-only.
Not served yet
43
Each returns an explicit, provider-shaped coverage error naming the gap — never invented data.
01 / The swap
No SDK of ours, no shim, no recorded fixtures. The same client library you already use, one environment variable different.
curl "https://ado.sandboxapis.dev/olympus-labs/olympus-labs/_apis/git/repositories/parthenon?api-version=7.1"Verified drop-in clients
No client library is version-pinned against Azure DevOps yet, so this page claims none. What is asserted is the wire: every response above is validated against Azure DevOps's own published spec by the conformance suite. Client pins live in coverage/client-pins.yaml and are added as each SDK joins the suite.
02 / Coverage by family
All 232 rows the coverage manifest carries for Azure DevOps, deferred long tail included and nothing capped. Open a family, or filter by path to find the exact endpoint your client calls.
Status — what a conformance test found
Mode — what kind of answer a row gets
A row with no mode shown has not been judged yet. Modes are the manifest's own words, from coverage/MODES.yaml; every empty and refuse carries a written reason and a review date before it counts as final.
Badge — where Deep starts
REST + GraphQL + git rows that are not `excluded`. Write operations are NOT rows (DECISIONS 2026-09-01 decision 9): they are counted in meta.write_operations and never enter this ratio.
232 read surfaces in 31 families
XAML build controllers cannot exist on an Azure DevOps Services organization, but Controllers_List is still published at 7.1 and 7.2 and declares a BuildController[] 200, so the truthful answer is Azure DevOps' empty collection envelope rather than a 404 that would deny the operation exists (founder ruling 2026-09-03, coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
a build badge is a pure function of the most recent build for the definition, and this universe has those builds - Azure DevOps answers 200 with a badge here, deprecated or not. SERVED 2026-09-03: the capture the re-ruling asked for settled the body, and the SVG this route answers is reproduced byte for byte (packages/conformance/specs/ado/captures/build-badge.json, coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
SERVED 2026-09-09: reader.artifactContent, addressed through the timeline record that produced it — {recordId} is the same timeline job id /build/builds/{id}/timeline publishes. FLIPPED from `generate` on 2026-09-09: the ArtifactContent entity has existed since hello-15
SERVED 2026-09-09: reader.jobArtifacts(job) over the build's jobs — a build's attachments ARE the files its jobs uploaded, and {type} is the artifact's own mime_type, the only type canon records for one. FLIPPED from `generate` on 2026-09-09: the ArtifactContent entity has existed since hello-15
no project, build, definition or pull request in this organization carries a property - Azure DevOps entity properties are written by extensions and pipeline tasks through the API and olympus-labs installs none, and this universe accepts no writes; ADO's own answer for an entity with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
no project, build, definition or pull request in this organization carries a property - Azure DevOps entity properties are written by extensions and pipeline tasks through the API and olympus-labs installs none, and this universe accepts no writes; ADO's own answer for an entity with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-12: YamlBuild is {yaml} and the bytes are ci_config_document.source, the document as its author wrote it - byte-identical to the blob at its own path, which conformance asserts against /_apis/git/repositories/{id}/items
the repository build badge is a pure function of the most recent build for the repo and branch, which this universe has. SERVED 2026-09-03 from the badge markup captured on its two SIBLING operations - this one alone needs a token, so it is the badge row whose body is inferred from the family rather than captured directly, and the review doc says so (coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
the one source provider this organization has is TfsGit - a project git repository rather than a connected external service (renderer-ado/src/app.ts:1330) - and a TfsGit provider carries no connected-service webhook; ADO's own answer for a provider with none is {"count": 0, "value": []} at 200 (there is no connected service for a webhook to be registered against). RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed; RE-WORDED 2026-09-12 (hello-18 wave W-b) with the mode unmoved - the clause that stood here read "canon's webhook_subscription rows are PagerDuty subscriptions on incident events", which hello-18's webhookFilters domain made false by widening that table with repository, organization and namespace hooks for the git hosts. The conclusion rests on the clause above it and is untouched: a git host's repository hook is a different object on a different provider, and reader.opsWebhookScope() keeps the two apart at the reader.
refuse — XAML build controllers were removed from Azure DevOps Services; mirroring them would advertise a surface no current client can reach (the ruled GitLab vendor-removed precedent, coverage/reviews/2026-09-01-gitlab-modes.md, certificate-based clusters)
refuse — the sandbox token is a project-member token, not a Project Collection Administrator, and Azure DevOps answers 403 to organization-wide resource-usage reads for such a token (the ruled GitLab/Jira instance-admin precedent, coverage/reviews/2026-09-01-jira-modes.md row 2)
generate — new canon entity ActionsPolicy
generate — new canon entity RetentionLease
generate — new canon entity ActionsPolicy
derive
derive
generate — new canon entity ActionsPolicy
generate — new canon entity ActionsPolicy
generate — new canon entity ActionsPolicy
generate — new canon entity RetentionLease
generate — new canon entity RetentionLease
generate — new canon entity RetentionLease
generate — new canon entity RetentionLease
generate — new canon entity ActionsPolicy
SERVED 2026-09-09: reader.runArtifacts(run) filtered to the name asked for — the SAME artifact /artifacts lists, so the list and the single read cannot describe different files
SERVED 2026-09-09: reader.artifactContent(artifact) — hello-15's features.ciConfig gave the artifact row its bytes and both digests, and compile.ts throws if any CI artifact lacks them, so the file read hands back exactly what canon holds. FLIPPED from `generate` ("new canon entity ArtifactContent") on 2026-09-09: that entity has existed since hello-15. Pre-hello-15 pins answer the named generation gap
SERVED 2026-09-09: reader.commitsOnlyIn(this build's commit, the previous build of the same definition's commit) — a build's changes are the commits it introduced, and the change id IS the commit sha the git surface serves
SERVED 2026-09-09: the fromBuildId..toBuildId range form of the same reader.commitsOnlyIn arithmetic
SERVED 2026-09-09: reader.listRuns(repo) filtered to the workflow and taken newest-first; {definition} accepts the definition id or its name, and branchName resolves against the repository's default branch, which is the branch every canonical run builds
hello-13's JobLog is the build log: the list renders one BuildLog per job of the run, from the same canonical lines Bitbucket's step log serves
the log content itself - reader.jobLogText(job) as text/plain, sliced by the operation's own startLine/endLine
no build and no build definition in olympus-labs is tagged - a build tag is applied by hand or by a pipeline task and this universe accepts no writes; ADO's own answer for a build with none is [] at 200 and for the project-wide list {"count": 0, "value": []} (canon's tag/tag_assignment rows are PagerDuty tags over escalation policies, teams and users). RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-09: reader.pullsForCommit over the build's own commits, then the issues those pulls closed — the SAME closed_by_pull seam GitPullRequest.workItemRefs reads, so the CI side and the git side name one set of work items
SERVED 2026-09-09: canon records a workflow's CURRENT definition and no edits to it, which is why renderDefinition has published revision 1 since Wave D — so the history is the `add` that created it, dated at reader.listRuns' earliest run of that workflow and attributed to that run's actor
no build and no build definition in olympus-labs is tagged - a build tag is applied by hand or by a pipeline task and this universe accepts no writes; ADO's own answer for a build with none is [] at 200 and for the project-wide list {"count": 0, "value": []} (canon's tag/tag_assignment rows are PagerDuty tags over escalation policies, teams and users). RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
the build status badge is a pure function of the most recent build for the definition and branch, which this universe has. SERVED 2026-09-03: the capture the re-ruling asked for settled the body, and all seven status states plus the label parameter are reproduced byte for byte (packages/conformance/specs/ado/captures/build-badge.json, coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
no build and no build definition in olympus-labs is tagged - a build tag is applied by hand or by a pipeline task and this universe accepts no writes; ADO's own answer for a build with none is [] at 200 and for the project-wide list {"count": 0, "value": []} (canon's tag/tag_assignment rows are PagerDuty tags over escalation policies, teams and users). RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-09: the fromBuildId..toBuildId range form of the same reader.pullsForCommit walk
SERVED 2026-09-09: reader.listBranches over the project's repositories. This organization has exactly one source provider — every repository is a project Git repository, which Azure DevOps calls TfsGit — so any other provider name is the ordinary 404
SERVED 2026-09-09: reader.getPull(repo, number) in the thinner shape the build area uses — the same canonical pull request /git/repositories/{id}/pullRequests/{n} serves
generate — new canon entity RetentionLease
refuse — a build report is uploaded by a task or an extension, and no canonical build in this universe uploads one — so there is no report for a build id to name. BuildReportMetadata.content is documented only as "The content of the report" with no format, no enum and no example (build.json carries zero examples blocks), so serving one would mean inventing both content and type (invariant #4). Refuse rather than empty because the operation returns a document, not a collection: there is no empty shape for it to answer with. RULED by the founder 2026-09-09
refuse — nothing in this universe aggregates build metrics, so there is no BuildMetric resource for a definition to name. The COUNTS would derive trivially from reader.listRuns; what cannot be sourced is the vocabulary — BuildMetric.name and scope are provider strings the vendored build.json declares no enum and no example for, and the WORK_ITEM_ICONS precedent is allowed precisely because it cites Microsoft's published sample verbatim. A capture would settle it, on the model of packages/conformance/specs/ado/captures/build-badge.json. RULED by the founder 2026-09-09
refuse — the project-scoped half of the same fact: nothing in this universe aggregates build metrics, and BuildMetric.name/scope are provider vocabulary the vendored description declares no enum and no example for, so no aggregation type can name a metric this universe holds. RULED by the founder 2026-09-09
SERVED 2026-09-09: the single iteration pullIterations() derives from reader.pullCommits(pull) — canon records a pull request's commits, not the pushes that delivered them, so this universe has exactly one iteration and {iterationId} resolves against that list
SERVED 2026-09-09: reader.pullDiffRange(pull) + the tree diff over reader.gitTreeEntries/getGitBlob — the SAME three-dot range (merge base to head) GitHub's /pulls/{n}/files and every review-comment hunk use, so the three cannot describe different diffs
SERVED 2026-09-09: reader.pullCommits(pull) — one iteration per pull request, so the iteration's commits ARE the pull request's commits and conformance asserts the two sets are equal
SERVED 2026-09-09: reader.pullLabels(pull), addressed by either half of {labelIdOrName} — the deterministic label guid or the canonical label name
SERVED 2026-09-09: reader.listReviews + reader.pullRequestedReviewers, addressed by the identity guid the reviewers list publishes in each row's reviewerUrl
SERVED 2026-09-09: the single read off the same reader.checksForCommit list /statuses serves; the status context is a canonical check context, asserted in conformance
SERVED 2026-09-09: the comments of the thread pullThreads() builds from reader.pullReviewComments + reader.listReviews — read off the same thread document /threads serves, so a comment cannot appear on one route and not the other
SERVED 2026-09-09: the single read off that same thread document
SERVED 2026-09-09: reader.checksForCommit over reader.pullCommits(pull), filtered by the iterationId each status already carries, so the pull-request-level list and the iteration-level list cannot disagree
SERVED 2026-09-09: the single read off the same reader.checksForCommit list the iteration's statuses route serves
a GitSuggestion is offered to the CALLER — Azure DevOps' "you pushed branch X, open a pull request?" — and this host's caller is the synthetic connection identity connectionDataPayload mints, not a canonical person, so it has pushed nothing and has nothing suggested to it. The same fact `/_apis/teams?$mine=true` and `isCurrentUserEngaged: false` already state. Suggestions_List declares a GitSuggestion[] 200, so Azure DevOps' empty collection envelope is the truthful answer rather than a 404 that would deny the operation exists (invariant #4). RULED by the founder 2026-09-09
SERVED 2026-09-09: the batch-by-id form of the same classificationRoots() tree the root listing serves, so an id read off one route resolves on the other
SERVED 2026-09-09: the relation types this host emits on a work item (ArtifactLink today), so a work item's `rel` resolves here. `attributes` is omitted rather than guessed — the vendored description declares no values for usage/editable/enabled
SERVED 2026-09-09: the single read off that same table, by reference name or friendly name
SERVED 2026-09-09: the next state after each work item's current one, per the six-state canonical workflow stateOf() already publishes as System.State. A terminal item is reported with `message` and NO errorCode — Azure DevOps sends a code there and the vendored description declares none of its values, so a client cannot be handed one to switch on
SERVED 2026-09-09: reader.issueLabels over the tracker issues — a project's work-item tags ARE the labels those items carry as System.Tags, so the tag list and the field agree by construction
SERVED 2026-09-09: the single read off that same list, by deterministic tag guid or by name
SERVED 2026-09-09: the categories of the four work-item types TYPE_DEFS renders. Microsoft.*Category is Azure DevOps' own reference-name vocabulary, used here on the same footing TYPE_DEFS already uses Microsoft.VSTS.WorkItemTypes.* — and there is no category for a type this host does not return
SERVED 2026-09-09: the single read off that same table
SERVED 2026-09-09: one work-item type's VIEW of the field registry /wit/fields serves — System.State's allowedValues are that type's own states, so the field view and the type document cannot declare different states. A VIEW rather than a copy since 2026-09-10: Microsoft.VSTS.Scheduling.StartDate and .TargetDate are Epic and Feature fields in the Agile process, so they are on those two types' lists and on no other's
SERVED 2026-09-09: the single read off that same view — a field the PROJECT has but this TYPE does not is a 404 here while /wit/fields answers it
SERVED 2026-09-09: the outbound artifact link this host really puts on a work item — the vstfs:///Git/PullRequestId/… link renderWorkItem emits — so the catalogue and the links agree. Azure DevOps organizations carry more; enumerating those would advertise links no work item here carries
SERVED 2026-09-09: the 41-icon catalogue render-boards.ts already carries for the single-icon row, which is what makes the icon URL every work-item type prints resolve
WorkItemIcon is JSON - {id, url} - and application/json is the operation's own default media type; served from the icon catalogue Azure DevOps publishes, which is also what makes the icon URL every work item type prints resolve (re-ruled 2026-09-03, coverage/reviews/2026-09-03-ado-refuse-shapes.md)
SERVED 2026-09-09: reader.listCommits filtered by searchCriteria — author/user, fromDate/toDate, fromCommitId/toCommitId, ids, itemVersion and itemPath (over reader.resolveGitPath, the same trees /items serves). The members that would attach data this host does not hold (includeWorkItems, includeUserImageUrl, compareVersion, the non-default historyMode) answer the coverage error rather than being ignored
SERVED 2026-09-09: the commit's tree against its first parent's, over reader.commitTreeSha/gitTreeEntries/getGitBlob — the same set difference that now produces the changeCounts renderCommitRef publishes, so a commit's counts and its change list cannot drift
SERVED 2026-09-09: reader.commitsOnlyIn (run both ways for ahead/behind) + reader.mergeBase + the tree diff; diffCommonCommit is honoured, so a caller gets the three-dot or the two-dot diff they actually asked for
SERVED 2026-09-09: renderBranchStats over reader.getBranchByName + reader.listPulls/pullCommits — the single-branch form of the stats operation the Swagger describes as its own path entry
SERVED 2026-09-09: reader.mergeBase(a, b) — the nearest common ancestor over the real parent graph. otherCollectionId/otherRepositoryId answer the coverage error: this organization holds one project collection
no repository in this universe is a fork and none has been forked: the project owns every repository and there is no collection outside it to fork into — the same fact /repositories/{id}?includeParent=true already reports by omitting parentRepository
refuse — every tag in this universe is LIGHTWEIGHT — a canonical release carries tag, body, author, created_epoch and tag_commit but no tag OBJECT, and {objectId} is the only way this operation is addressed. packages/renderer-github/src/git/objects.ts already rules the same point for the git transport: "Tags are LIGHTWEIGHT (a ref straight at a commit) … Inventing an annotated tag object here would mint a sha no other endpoint serves." So no objectId can resolve to a GitAnnotatedTag and Azure DevOps' own ResourceNotFoundException is the whole answer. RULED by the founder 2026-09-09
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
SERVED 2026-09-09: the $top/order form of the same renderComments() list over reader.issueComments — its own path entry in the Swagger and therefore its own row
SERVED 2026-09-09: the single read off the same renderComments() document, found by the id that list published
SERVED 2026-09-09: Work Items_Get Work Item Template — a BLANK work item for a type, built from the same TYPE_DEFS and FIELD_DEFS registries /wit/workitemtypes publishes, so its default state is the first state that type declares. It carries no id, because a template is not a stored work item
SERVED 2026-09-09: exactly one version, and that is a fact rather than a truncation — canon records no comment edit, which is why renderComments has published version 1 since Phase 20
SERVED 2026-09-09: the single read off that one-entry history
SERVED 2026-09-09: the column names renderBoard() really puts on this project's boards, as BoardSuggestedValue
SERVED 2026-09-09: the swimlane names renderBoard() really puts on this project's boards
SERVED 2026-09-09: the same four columns renderBoard() embeds in the board document, so the board and this list cannot describe different columns
SERVED 2026-09-09: the same swimlane renderBoard() embeds
SERVED 2026-09-09: the team's tracker issues in that sprint, as the target-only WorkItemLink rows a flat listing uses
SERVED 2026-09-10 (hello-16): ParentChildWIMap over canon's own hierarchy — reader.hasPortfolio() gates it, a tracker issue's parent is the epic row `issue.epic` names via reader.epic(id), and a feature's is `epic.parent` (reader.epicChildren from the other end). The requested ids are filtered by childBacklogContextCategoryRefName, which resolves through the same category table /wit/workitemtypecategories publishes. A pre-hello-16 pin answers the named portfolio generation gap (NO_PORTFOLIO): nothing there has a parent, so an empty array would claim this project's backlog is flat
generate — new canon entity BoardConfig
SERVED 2026-09-09: the reverse half of that round trip — the key /graph/storagekeys handed back returns the descriptor /graph/users published
SERVED 2026-09-09: reader.listTeams() matched on the one-way vssgp. descriptor renderGraphGroup publishes
SERVED 2026-09-09: reader.teamMembers(team) — the edge exists when canon puts that person on that team, and Azure DevOps' own 404 (the one error response in the whole vendored ADO description) answers when it does not
SERVED 2026-09-09: the status-only half of the same reader.teamMembers(team) edge — 200 when the membership exists, Azure DevOps' declared 404 when it does not, and no body either way
SERVED 2026-09-09: every subject reader.listPeople/listTeams holds is active — the same fact renderIdentity has published as isActive since Wave D — and a descriptor naming nobody 404s
SERVED 2026-09-09: reader.listPeople() matched on the one-way aad. descriptor renderGraphUser publishes, so the single read and the list describe one subject
generate — new canon entity BoardConfig
generate — new canon entity BoardConfig
derive — a cumulative-flow chart is a pure function of work item state over time, which this universe already serves at wit/workItems/{id}/updates and revisions; only the image encoding is missing, so the row is derive and deferred rather than a refusal Azure DevOps would never send. STILL DEFERRED after the 2026-09-03 capture wave: the chart-image operations are NOT anonymously reachable - an anonymous request is redirected to the sign-in page, recorded with its 302 in packages/conformance/specs/ado/captures/build-badge.json (`notAnonymouslyReachable`) - so the image format is still unobserved and authoring one would be the invented body the badge rows were held back from (coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
derive
derive — an iteration burndown is a pure function of one sprint and the work item state history this universe already serves; only the image encoding is missing, so the row is derive and deferred rather than a refusal Azure DevOps would never send. STILL DEFERRED after the 2026-09-03 capture wave: the chart-image operations are NOT anonymously reachable - an anonymous request is redirected to the sign-in page, recorded with its 302 in packages/conformance/specs/ado/captures/build-badge.json (`notAnonymouslyReachable`) - so the image format is still unobserved and authoring one would be the invented body the badge rows were held back from (coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
derive — an iterations burndown is a pure function of the team sprints and the work item state history this universe already serves; only the image encoding is missing, so the row is derive and deferred rather than a refusal Azure DevOps would never send. STILL DEFERRED after the 2026-09-03 capture wave: the chart-image operations are NOT anonymously reachable - an anonymous request is redirected to the sign-in page, recorded with its 302 in packages/conformance/specs/ado/captures/build-badge.json (`notAnonymouslyReachable`) - so the image format is still unobserved and authoring one would be the invented body the badge rows were held back from (coverage/reviews/2026-09-03-ado-badges-and-controllers.md)
SERVED 2026-09-09: reader.runArtifacts(run) — the Pipelines API's view of the same canonical artifact the Build API serves, one entity over two surfaces. $expand=signedContent stays the explicit refusal: this universe mints no signed URLs
the pipelines-surface twin of the build log list: a LogCollection over the same canonical job logs
the pipelines-surface Log metadata for one canonical job log; signedContent is refused rather than invented, this universe runs no signed blob store
SERVED 2026-09-09: the project-scoped form of the same reader.listTeams() list, guarded on the project
SERVED 2026-09-09: the single team read, resolved by name, tracker key or team guid exactly as the work surface resolves {team}; $expandIdentity=true adds the group identity with memberIds from reader.teamMembers
SERVED 2026-09-10 (hello-16): the team roster as TeamMember — reader.listMemberships("team", team) filtered to state=active, with isTeamAdmin being the maintainer rung of that membership. It reads `membership` rather than `team_member` because `isTeamAdmin` IS a role and the v1 roster table has none; the two agree row for row, which conformance asserts. A pre-hello-16 pin answers the named access generation gap (NO_MEMBERSHIPS), never an empty roster
SERVED 2026-09-09: reader.listTeams() as WebApiTeam, ids being the adoGuid('team', …) that {team} path segments already resolve against on the work/boards surface. $mine=true answers the empty envelope: this host's connection identity is not a canonical person, so it belongs to no team
no repository in this universe has ever been deleted, so the deleted-repository list is truthfully empty — RULED EMPTY by the founder 2026-09-09 (the 2026-09-01 deletion question, coverage/reviews/2026-09-01-ado-modes.md). The WORK-ITEM recycle bin went the other way and was GENERATED in hello-13: work items were deleted in this story, repositories never were
nobody in olympus-labs has favorited a branch - a favorite is a per-user bookmark written through the API and this universe accepts no writes; ADO's own answer for a caller with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
no repository in this universe has ever been deleted, so the repository recycle bin is truthfully empty — RULED EMPTY by the founder 2026-09-09 (the same deletion question, coverage/reviews/2026-09-01-ado-modes.md). Deliberately unlike wit/recyclebin, whose DeletedWorkItem canon hello-13 generated
refuse — nobody in olympus-labs has favorited a branch, so no favorite id resolves; ADO's own answer is its 404 for the favorite. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
SERVED 2026-09-09: the single-member form of the renderCapacity() list, built from the same 6h/day default so the two cannot report different capacities for one person
SERVED 2026-09-09: reader.teamMembers over the team that owns the iteration, at the same 6h/day default the per-team capacity list serves, so the roll-up and the list cannot disagree
no team in olympus-labs has recorded a day off - canon models no team calendar, and this host already publishes daysOff [] on every member capacity it serves (renderMemberCapacity, renderer-ado/src/render-work.ts); ADO's own answer for an iteration with none is {"daysOff": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
refuse — a fork-sync, an import, a cherry-pick, a revert and a merge operation each exist only because a write started one; this universe accepts no writes, so Azure DevOps answers 404 for the operation that was never queued (the ruled GitHub migrations/source-imports precedent, coverage/reviews/2026-09-01-github-modes.md row 4)
no service principal exists in this organization - olympus-labs registers no Entra application and every graph subject is a person or a group (person 17, identity_group 4, and the "service-accounts" group idgroup-004 holds people rather than applications); ADO's own answer for an organization with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-09: the storage key IS the identity id /_apis/identities publishes for the same person (adoGuid('identity', …)), which is what closes the round trip with /graph/descriptors
PersonAvatar is canon as of hello-13 (features.avatars): one identicon a person, compiled into the person_avatar table and rasterised by identiconPng. The generate ruling of 2026-09-03 is satisfied, and the same row is what GitHub, GitLab and Jira now serve - byte-identical, asserted in conformance/src/parity/avatar-parity.test.ts
SERVED 2026-09-12 (hello-18 wave W-b): the PER-PERSON EXTERNAL UID this row's 2026-09-10 re-scoping named as the one missing fact landed with features.externalUid (decisions/2026-09-12-1120-hello-18-external-uid.md) - person.external_uid, a directory identity for all 16 humans and none for the build robot. originId IS that uid; origin is aad on a person the directory provisioned and vsts on the machine account, which no directory provisioned; descriptor and domain are the ones /graph/users already publishes, and graphOriginId() is now read by BOTH routes so this host cannot hand a caller two directory ids for one person. A pre-hello-18 artifact keeps the minted GraphUser.originId it has always served and this route names the generation instead
refuse — no service principal exists in this organization, so no service-principal descriptor resolves; ADO's own answer is its 404 for the subject. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
hello-13's DeletedWorkItem canon: two work items were filed and then deleted, so the bin lists their shallow references
the by-ids variant of the same bin, serving the fuller WorkItemDeleteReference for each requested id
the single deleted work item, resource and all, from the same canon row; an id nobody deleted is an ordinary 404
no team in this project defines a work item template - a template is a prefilled field set a team administrator saves by hand and this universe accepts no writes; ADO creates none with a project and its own answer for a team with none is {"count": 0, "value": []} at 200 (canon's template_field rows are the support-desk ticket form, not an ADO template). RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
refuse — no team in this project defines a work item template, so no template id resolves; ADO's own answer is its 404 for the template. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-09: the two levels TYPE_DEFS supports plus the field mapping the backlog is ordered and estimated by; workItemTypeMappedStates comes off the SAME TYPE_DEFS table /wit/workitemtypes publishes
SERVED 2026-09-09: the Requirement and Task levels, each naming only work-item types /wit/workitemtypes returns
SERVED 2026-09-09: the team's tracker issues filtered to the level's own work-item types; rel/source are OMITTED rather than nulled, because this host renders no portfolio type and canon carries no work-item-to-work-item parent, so a backlog entry has nothing above it to name
SERVED 2026-09-09: the single read off that same list, by category reference name or level name
no project, build, definition or pull request in this organization carries a property - Azure DevOps entity properties are written by extensions and pipeline tasks through the API and olympus-labs installs none, and this universe accepts no writes; ADO's own answer for an entity with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-09: reader.getGitBlob(sha) — the objectId IS the sha1 the compiler hashed the bytes to, so a blob id read off /items or /trees fetches here and matches the same file's sha on the GitHub and Bitbucket renderings
SERVED 2026-09-09: reader.commitTreeSha + reader.gitTreeEntries walked at the recursionLevel asked for, resolved at the versionDescriptor's commit — every objectId is the artifact's own git object sha
SERVED 2026-09-09: reader.resolveGitPath(rootTree, path) + reader.getGitBlob for includeContent; $format=text/octetstream and download=true serve the blob's own bytes, $format=zip answers the coverage error (this host has no archive encoder on the ADO surface)
SERVED 2026-09-09: reader.gitTreeEntries(sha), recursive on request; sizes are summed from reader.getGitBlob so a tree's size is the bytes it really holds
SERVED 2026-09-12 (hello-18 wave W-b): the Attachment widening landed with features.attachmentParents (decisions/2026-09-12-1148-hello-18-attachment-parents.md) — six ALTERs appending issue/issue_comment/pull/alert/namespace/person to the hello-15 attachment table, so a file now hangs off the engineering records this host publishes. attachmentsForPull() — a BARE ARRAY, which is the git document's own choice here rather than this host's {count, value} envelope. contentHash is a real sha1 over the bytes served (Azure DevOps declares SHA1 where canon measures sha256, so it is computed with the same sha1Raw the git object model uses — a measurement, not a value invented to fill a field), and the url resolves to those same bytes. A pull request that carries no file answers [] rather than a gap
SERVED 2026-09-12 (hello-18 wave W-b): the Attachment widening landed with features.attachmentParents (decisions/2026-09-12-1148-hello-18-attachment-parents.md) — six ALTERs appending issue/issue_comment/pull/alert/namespace/person to the hello-15 attachment table, so a file now hangs off the engineering records this host publishes. The bytes of one of those files, addressed BY FILE NAME — which is how this operation is keyed ("the name of the attachment") and the reason the list's url names the file rather than an id
no project, build, definition or pull request in this organization carries a property - Azure DevOps entity properties are written by extensions and pipeline tasks through the API and olympus-labs installs none, and this universe accepts no writes; ADO's own answer for an entity with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
generate — ContentReaction (hello-15) covers Azure DevOps' WORK-ITEM comment reactions, but not this one, and the blocker is the thread comment rather than the reaction: a PR thread comment here is POSITIONAL (comments[i].id is i+1 inside the thread) and a thread's members come from review comments AND from review BODIES. A review body is not a reaction target in canon, so half the ids this path can name are things content_reaction cannot answer, and an empty like-list on those would assert nobody liked a comment the domain cannot represent. Blocked on a canonical identity for a PR thread comment
no delivery plan exists in this project - a delivery plan is a view an administrator creates by hand and this universe accepts no writes; ADO creates none with a project and its own answer for a project with none is {"count": 0, "value": []} at 200. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
refuse — no delivery plan exists in this project, so no plan id resolves; ADO's own answer is its 404 for the plan, and the delivery timeline never reaches a plan to render. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
refuse — no delivery plan exists in this project, so no plan id resolves; ADO's own answer is its 404 for the plan, and the delivery timeline never reaches a plan to render. RULED by the founder 2026-09-12 (round 19, the hello-17 coverage audit), as proposed.
SERVED 2026-09-12 (hello-18 wave W-b): canon.SavedFilter landed with features.savedFilters (decisions/2026-09-12-1139-hello-18-saved-filters.md) — a query whose CLAUSES are canon's and whose TEXT the compiler bakes per host, so saved_filter.query is already JQL on a `jira` row and WIQL on an `ado` one. The project's query hierarchy: EXACTLY TWO ROOTS, which are Azure DevOps' own — every project is created with My Queries and Shared Queries and no others. The shared root holds this project's saved queries; My Queries is honestly EMPTY, and that is a fact about a PER-USER folder rather than about writes — it is scoped to the calling identity, this replica's caller is a synthetic connection identity with no saved state, and a fresh user's personal folder in real Azure DevOps is empty too. $depth fills children in; $expand=clauses is refused explicitly (the parsed clause tree is a re-parse of a text the COMPILER wrote)
SERVED 2026-09-12 (hello-18 wave W-b): canon.SavedFilter landed with features.savedFilters (decisions/2026-09-12-1139-hello-18-saved-filters.md) — a query whose CLAUSES are canon's and whose TEXT the compiler bakes per host, so saved_filter.query is already JQL on a `jira` row and WIQL on an `ado` one. A DIFFERENT OPERATION from the list, with its own envelope: Queries_Search Queries answers QueryHierarchyItemsResult ({count, hasMore, value}) and matches on the query's NAME, which is what the parameter's own description asks for. It searches QUERIES rather than folders, because a folder is not a query
SERVED 2026-09-12 (hello-18 wave W-b): canon.SavedFilter landed with features.savedFilters (decisions/2026-09-12-1139-hello-18-saved-filters.md) — a query whose CLAUSES are canon's and whose TEXT the compiler bakes per host, so saved_filter.query is already JQL on a `jira` row and WIQL on an `ado` one. One query hierarchy item by ID OR BY PATH — the document takes both ("ID or path of the query") and both roots are addressable as well as the queries under them. $expand=wiql carries the baked text verbatim, and the columns and sortColumns are READ OFF that same text so the hierarchy and /wit/wiql/{id} cannot disagree about what the query selects
SERVED 2026-09-12: the `new canon entity TeamSetting` ask was stale. Every field of TeamSetting already had a source this host publishes - backlogIteration is the project's root iteration node, defaultIteration is the team's active sprint (the same row /teamsettings/iterations?$timeframe=current returns), backlogVisibilities names the levels backlogLevels() serves and bugsBehavior is the shared BUGS_BEHAVIOR constant renderBacklogConfiguration already prints. workingDays is MEASURED off the canonical event log - the weekdays this team's members really act on, in each actor's own local time - and comes out as all seven on hello-17 rather than the Mon-Fri an Azure DevOps team is created with
SERVED 2026-09-09: a team owns its own area path, which is the same System.AreaPath every one of its work items carries
SERVED 2026-09-09: the project-level view of the two backlog levels TYPE_DEFS supports, as work-item categories. portfolioBacklogs is empty because this host renders no portfolio work-item type — the same fact the backlog list states
the route is literally "my work": AccountRecentActivityWorkItemModelBase.identityId is "TeamFoundationId of the user this activity belongs to" and activityDate is "Date of the last Activity by the user". This host's caller is not a canonical person, so it has visited and edited nothing — serving the project's work items here would answer a different question from the one asked. The operation declares a model[] 200, so the empty envelope is the truthful answer. RULED by the founder 2026-09-09
ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it over issueComment targets, which is what a work-item comment IS here. CommentReactionType is a CLOSED SIX - no rocket, no eyes - so this host renders the six Azure DevOps has and its counts are over those six
ContentReaction is canon as of hello-15 (features.contentReactions); reactionsFor() answers it over issueComment targets, which is what a work-item comment IS here. CommentReactionType is a CLOSED SIX - no rocket, no eyes - so this host renders the six Azure DevOps has and its counts are over those six
SERVED 2026-09-09: the Task type's own states, in the order /wit/workitemtypes/Task declares them; isCustomized is false because nobody in this universe edited them
SERVED 2026-09-09: reader.listSprints + the team's Task-kind issues in that sprint — each one's column is a pure function of the state stateOf() gives it
SERVED 2026-09-12 (hello-18 wave W-b): canon.SavedFilter landed with features.savedFilters (decisions/2026-09-12-1139-hello-18-saved-filters.md) — a query whose CLAUSES are canon's and whose TEXT the compiler bakes per host, so saved_filter.query is already JQL on a `jira` row and WIQL on an `ado` one. RUNS the saved query: the stored WIQL goes through runWiql — the same parser and evaluator POST /wit/wiql uses, not a second execution path — so a query this hierarchy publishes and a query a caller pastes take identical code. That is what closes the debt the saved-filter decision entry named: the compiler holds its own copy of the Agile process's state names beside render-workitems.ts's, a compiler cannot import a renderer, and only running the baked text on this host checks both. The conformance entry posts the same text and asserts the two runs return the same work items
SERVED 2026-09-12 (hello-18 wave W-b): canon.SavedFilter landed with features.savedFilters (decisions/2026-09-12-1139-hello-18-saved-filters.md) — a query whose CLAUSES are canon's and whose TEXT the compiler bakes per host, so saved_filter.query is already JQL on a `jira` row and WIQL on an `ado` one. The status-only half of the same run — Azure DevOps publishes Wiql_Get as a HEAD as well as a GET, and a HEAD carries no body, which is the split /graph/memberships/{a}/{b} already serves on this host. A query id nobody saved is the same 404 on both verbs
SERVED 2026-09-12 (hello-18 wave W-b): the Attachment widening landed with features.attachmentParents (decisions/2026-09-12-1148-hello-18-attachment-parents.md) — six ALTERs appending issue/issue_comment/pull/alert/namespace/person to the hello-15 attachment table, so a file now hangs off the engineering records this host publishes. The WORK-ITEM stream: attachmentsForIssue() and attachmentsForIssueComment(), which is the same set the Jira host publishes off the same canonical issue (invariant #5 across providers). The declared fileName override and download switch are both honoured; the bytes are attachment.body, whose size and digest the compiler measured off exactly them. A pull-request file is NOT reachable here and a desk file is reachable from neither
generate — new canon entity BranchRestriction
03 / What's simulated
Every Azure DevOps call resolves against the same simulated data set every other provider serves. Counted from the ado-7-1-g11 artifact (universe generation 11):
Each line below is one assertion in the conformance suite named beside it — run on every build, over one artifact, through the real renderers. Nothing is claimed here that no expect checks.
Every pull request's `sourceRefName` is `refs/heads/` plus the exact branch name GitHub serves as `head.ref`, GitLab as `source_branch` and Bitbucket as `source.branch.name`.
Against GitHub, GitLab, Bitbucket · parity/branch-parity.test.ts
A Boards work item's revision instants are the same instants Jira records in that issue's changelog, its `Microsoft.VSTS.Scheduling.StoryPoints` is the estimate Jira and Linear serve, and its relations name the pull request Linear reports as that issue's closing branch.
A Build here is the same CI run Buildkite serves as a build: the same `buildNumber`, and a `sourceVersion` that is the same 40-character commit SHA Buildkite reports as that build's `commit`.
Against Buildkite · parity/ci-log-parity.test.ts
05 / Pinned snapshots
Each pin regenerates byte-identically on every request, so a test written against one never drifts. Generations are DIFFERENT universes, not versions of one — never swap a suffix expecting the same data.
ado-7-1.snap.sandboxapis.devgeneration 17.1not in this generationado-7-1-g10.snap.sandboxapis.devgeneration 107.1servedado-7-1-g11.snap.sandboxapis.devgeneration 117.1servedado-7-1-g2.snap.sandboxapis.devgeneration 27.1servedado-7-1-g3.snap.sandboxapis.devgeneration 37.1servedado-7-1-g5.snap.sandboxapis.devgeneration 57.1servedado-7-1-g6.snap.sandboxapis.devgeneration 67.1servedado-7-1-g8.snap.sandboxapis.devgeneration 87.1servedado-7-1-g9.snap.sandboxapis.devgeneration 97.1servedNeed an endpoint that is not served yet?
Every row Azure DevOps's manifest carries is on this page, so “not here” is an answer rather than a gap in the rendering. Tell us which path and which client, and it moves up the queue — the order is set by what people ask for.