Devin API sandbox
Point your Devin v3 API calls at https://devin.sandboxapis.dev (curl or a client generated from the official v3-openapi.yaml). Auth is a Bearer token (Devin's cog_ service-user keys; any value is accepted here). The enterprise scope serves the sandbox's tier-1 slice: sessions, members/users, ACU consumption (PST day buckets, as documented), and usage metrics. Session PRs link to real pulls on the git hosts, with matching identities.
Coverage badge
Deep120/122 · 98%
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.
devin.sandboxapis.devServed & verified
70 / 57%
Answering with real universe data, each response checked against Devin's published spec by the conformance suite on this build.
The full read API
122
Every read surface Devin publishes, deferred long tail included, minus the rows excluded by policy. Writes are out of scope: this universe is read-only.
Not served yet
52
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 -H 'Authorization: Bearer any-key' "https://devin.sandboxapis.dev/v3/enterprise/sessions?first=5"Verified drop-in clients
No client library is version-pinned against Devin yet, so this page claims none. What is asserted is the wire: every response above is validated against Devin'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 122 rows the coverage manifest carries for Devin, 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.
122 read surfaces in 28 families
CORRECTED 2026-09-12 (hello-18 serving wave W-c): the reason this row carried said canon carries no attachment entity AT ALL, and hello-15 made that FALSE - canon.Attachment landed with the support-desk domain (packages/canon/src/support-desk.ts:962), the artifact holds 35 attachment rows with real bodies, and renderer-zendesk resolves them by id today. The empty answer still stands on the NARROWER fact, which is this row's own: every attachment in this universe hangs off a record some OTHER product owns, and NO generation attaches one to an AGENT SESSION - a session here starts from repository work rather than from a file somebody dragged in, so nobody ever uploaded one, and Devin's own answer for a session with none is the empty list this renderer's sessionAttachments() has returned since the host opened. THE ASK is an attachment whose PARENT is an agent session
SERVED 2026-09-14 (hello-20 `providerTails`, founder ruling F6): SessionInsightsResponse requires twelve fields; ten were already SessionResponse's, `session_size` has been derived on this host since the metrics family shipped, and the two that were missing are num_user_messages and num_devin_messages. DECISIONS 2026-08-20 [devin] refused all four rows on exactly those two - 'serving zeroes would be a lie (every session begins with a user prompt), and manufacturing counts or transcripts from content_seed would be invention' - and founder ruling F6 (decisions/2026-09-14-0202) mints `agent_session_turn`: an ordinal, an author and an instant, and NO BODY COLUMN. The counts are now a MEASUREMENT of rows the artifact really holds (reader.agentSessionTurnCounts(), counted in SQL so a long conversation costs one row out of the artifact rather than all of them) and not a word of prose is invented. THE TWO `/messages` ROWS ARE UNTOUCHED AND STILL REFUSED, which is the shape of the ruling rather than an oversight: a transcript of turns WITHOUT TEXT is not a transcript, and there is no column a SessionMessage could be built out of - conformance asserts the turn table's columns are exactly session/ord/author/at_epoch. `analysis` is null, which is the document's own value for an analysis that has not completed and the same class of authored prose the knowledge-note rows are refused on. `session_size` reads the SAME sessionSize(centi) the fleet histogram /metrics/sessions has bucketed by on every frozen pin since Phase 30, so an insight and the histogram beside it can never disagree - which is why F6's new counts deliberately do NOT enter the banding. Built on shapeSession rather than beside it, so the insight view and the session object agree field for field (asserted). Gated on reader.hasProviderTails(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED session-turn generation gap, because a page of sessions each reporting zero messages IS the lie the 2026-08-20 ruling refused. This row is the ENTERPRISE SINGLE READ; a session id this universe does not have is Devin's own 404.
`tags` has been [] on every SessionResponse this renderer serves — this org never adopted session tagging, and the sub-resource returns the same empty list the session object reports (DECISIONS 2026-08-20 [devin])
SERVED 2026-09-14 (hello-20 `providerTails`, founder ruling F6): SessionInsightsResponse requires twelve fields; ten were already SessionResponse's, `session_size` has been derived on this host since the metrics family shipped, and the two that were missing are num_user_messages and num_devin_messages. DECISIONS 2026-08-20 [devin] refused all four rows on exactly those two - 'serving zeroes would be a lie (every session begins with a user prompt), and manufacturing counts or transcripts from content_seed would be invention' - and founder ruling F6 (decisions/2026-09-14-0202) mints `agent_session_turn`: an ordinal, an author and an instant, and NO BODY COLUMN. The counts are now a MEASUREMENT of rows the artifact really holds (reader.agentSessionTurnCounts(), counted in SQL so a long conversation costs one row out of the artifact rather than all of them) and not a word of prose is invented. THE TWO `/messages` ROWS ARE UNTOUCHED AND STILL REFUSED, which is the shape of the ruling rather than an oversight: a transcript of turns WITHOUT TEXT is not a transcript, and there is no column a SessionMessage could be built out of - conformance asserts the turn table's columns are exactly session/ord/author/at_epoch. `analysis` is null, which is the document's own value for an analysis that has not completed and the same class of authored prose the knowledge-note rows are refused on. `session_size` reads the SAME sessionSize(centi) the fleet histogram /metrics/sessions has bucketed by on every frozen pin since Phase 30, so an insight and the histogram beside it can never disagree - which is why F6's new counts deliberately do NOT enter the banding. Built on shapeSession rather than beside it, so the insight view and the session object agree field for field (asserted). Gated on reader.hasProviderTails(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED session-turn generation gap, because a page of sessions each reporting zero messages IS the lie the 2026-08-20 ruling refused. This row is the ENTERPRISE LIST, which the vendored document gives the same filter surface as /v3/enterprise/sessions (and no devin_id, so the narrowing is ignored here rather than invented).
the org-scoped twin of the enterprise attachments row, held to the same answer by test. CORRECTED 2026-09-12 (hello-18 serving wave W-c): the reason this row carried said canon carries no attachment entity AT ALL, and hello-15 made that FALSE - canon.Attachment landed with the support-desk domain (packages/canon/src/support-desk.ts:962), the artifact holds 35 attachment rows with real bodies, and renderer-zendesk resolves them by id today. The empty answer still stands on the NARROWER fact, which is this row's own: every attachment in this universe hangs off a record some OTHER product owns, and NO generation attaches one to an AGENT SESSION - a session here starts from repository work rather than from a file somebody dragged in, so nobody ever uploaded one, and Devin's own answer for a session with none is the empty list this renderer's sessionAttachments() has returned since the host opened. THE ASK is an attachment whose PARENT is an agent session
SERVED 2026-09-14 (hello-20 `providerTails`, founder ruling F6): SessionInsightsResponse requires twelve fields; ten were already SessionResponse's, `session_size` has been derived on this host since the metrics family shipped, and the two that were missing are num_user_messages and num_devin_messages. DECISIONS 2026-08-20 [devin] refused all four rows on exactly those two - 'serving zeroes would be a lie (every session begins with a user prompt), and manufacturing counts or transcripts from content_seed would be invention' - and founder ruling F6 (decisions/2026-09-14-0202) mints `agent_session_turn`: an ordinal, an author and an instant, and NO BODY COLUMN. The counts are now a MEASUREMENT of rows the artifact really holds (reader.agentSessionTurnCounts(), counted in SQL so a long conversation costs one row out of the artifact rather than all of them) and not a word of prose is invented. THE TWO `/messages` ROWS ARE UNTOUCHED AND STILL REFUSED, which is the shape of the ruling rather than an oversight: a transcript of turns WITHOUT TEXT is not a transcript, and there is no column a SessionMessage could be built out of - conformance asserts the turn table's columns are exactly session/ord/author/at_epoch. `analysis` is null, which is the document's own value for an analysis that has not completed and the same class of authored prose the knowledge-note rows are refused on. `session_size` reads the SAME sessionSize(centi) the fleet histogram /metrics/sessions has bucketed by on every frozen pin since Phase 30, so an insight and the histogram beside it can never disagree - which is why F6's new counts deliberately do NOT enter the banding. Built on shapeSession rather than beside it, so the insight view and the session object agree field for field (asserted). Gated on reader.hasProviderTails(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED session-turn generation gap, because a page of sessions each reporting zero messages IS the lie the 2026-08-20 ruling refused. This row is the ORG-SCOPED SINGLE READ; {org_id} resolves through the shared org wrapper first, so an id this universe does not have is Devin's own 404 before the generation is consulted.
the org-scoped twin of the enterprise tags row, held to the same answer by test: this org never adopted session tagging (DECISIONS 2026-08-20 [devin])
SERVED 2026-09-14 (hello-20 `providerTails`, founder ruling F6): SessionInsightsResponse requires twelve fields; ten were already SessionResponse's, `session_size` has been derived on this host since the metrics family shipped, and the two that were missing are num_user_messages and num_devin_messages. DECISIONS 2026-08-20 [devin] refused all four rows on exactly those two - 'serving zeroes would be a lie (every session begins with a user prompt), and manufacturing counts or transcripts from content_seed would be invention' - and founder ruling F6 (decisions/2026-09-14-0202) mints `agent_session_turn`: an ordinal, an author and an instant, and NO BODY COLUMN. The counts are now a MEASUREMENT of rows the artifact really holds (reader.agentSessionTurnCounts(), counted in SQL so a long conversation costs one row out of the artifact rather than all of them) and not a word of prose is invented. THE TWO `/messages` ROWS ARE UNTOUCHED AND STILL REFUSED, which is the shape of the ruling rather than an oversight: a transcript of turns WITHOUT TEXT is not a transcript, and there is no column a SessionMessage could be built out of - conformance asserts the turn table's columns are exactly session/ord/author/at_epoch. `analysis` is null, which is the document's own value for an analysis that has not completed and the same class of authored prose the knowledge-note rows are refused on. `session_size` reads the SAME sessionSize(centi) the fleet histogram /metrics/sessions has bucketed by on every frozen pin since Phase 30, so an insight and the histogram beside it can never disagree - which is why F6's new counts deliberately do NOT enter the banding. Built on shapeSession rather than beside it, so the insight view and the session object agree field for field (asserted). Gated on reader.hasProviderTails(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED session-turn generation gap, because a page of sessions each reporting zero messages IS the lie the 2026-08-20 ruling refused. This row is the ORG-SCOPED LIST, which additionally honours `devin_id` - the one query param the org-scoped operation declares and the enterprise one does not.
refuse — conversational content: the session transcript is what Devin and the engineer said to each other, and this universe does not invent it (the standing founder-adopted default; revisit if a client asks)
refuse — conversational content: the session transcript is what Devin and the engineer said to each other, and this universe does not invent it (the standing founder-adopted default; revisit if a client asks)
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — a snapshot blueprint and its builds exist only because a write created them, and this universe accepts no writes (invariant #3) — the async-artifact shape ruled in coverage/reviews/2026-09-01-jira-modes.md
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — Devin's code-scanning add-on is not enabled for this enterprise, and Devin answers 403 to every code-scan read for an enterprise without it — no scan, finding, metric or profile can exist here
refuse — the id half of the service-user pair: this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
refuse — the id half of the service-user pair: this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
CORRECTED 2026-09-12 (hello-18 serving wave W-c). The 2026-09-10 correction already replaced this row's original reason - "this universe has no identity provider" - because hello-15's canon.IdentityProviderConfig and canon.IdentityGroup (packages/canon/src/ci-config.ts:359, :401) made it false: a SAML provider with SCIM enabled, the administrator who switched it on, the date it was switched on, and four groups derived from ACCESS facts, which renderer-circleci serves today (/organizations/{org_id}/groups, ruled 2026-09-07). Two of the three supporting clauses that correction left have since gone false in their turn, and this is the second correction this row has needed for the same reason: a ruling resting on an absence canon later filled. canon DOES attach a role to an identity group (hello-17's grants - a membership row with scope_kind 'group', reader.groupRole(), which renderer-circleci serves), and canon DOES bind a person to an external uid (hello-18's externalUid - person.external_uid, which GitLab's saml/{uid} and scim/{uid} resolve). The empty answer still stands, and it now stands on the FIRST clause alone - which is the one the vendored document actually asks about: `IdpGroupUser` is "a user whose membership is derived from IDP group assignments", and NO Devin membership here is derived that way. Every Devin seat is assigned DIRECTLY to a person by the organization, which is the same absence every member detail already reports as idp_role_assignments: []. THE ASK is now one fact rather than two: a Devin SEAT a person holds BECAUSE an identity group confers it. A directory identity on a person is not that, and a role on a group is not that either. NOTE for the next wave: the five idp-GROUPS rows in this fence still carry the falsified "canon attaches no role to an identity group" clause, and they are deliberately untouched here because on those rows the correction may be a re-SERVE rather than a re-word - `IdpGroup.role_assignments` is RoleAssignment[] and hello-17's groupRole() may now answer it - which is a ruling this wave cannot make alone
the org-scoped idp-users twin, held to the same answer by test. CORRECTED 2026-09-12 (hello-18 serving wave W-c). The 2026-09-10 correction already replaced this row's original reason - "this universe has no identity provider" - because hello-15's canon.IdentityProviderConfig and canon.IdentityGroup (packages/canon/src/ci-config.ts:359, :401) made it false: a SAML provider with SCIM enabled, the administrator who switched it on, the date it was switched on, and four groups derived from ACCESS facts, which renderer-circleci serves today (/organizations/{org_id}/groups, ruled 2026-09-07). Two of the three supporting clauses that correction left have since gone false in their turn, and this is the second correction this row has needed for the same reason: a ruling resting on an absence canon later filled. canon DOES attach a role to an identity group (hello-17's grants - a membership row with scope_kind 'group', reader.groupRole(), which renderer-circleci serves), and canon DOES bind a person to an external uid (hello-18's externalUid - person.external_uid, which GitLab's saml/{uid} and scim/{uid} resolve). The empty answer still stands, and it now stands on the FIRST clause alone - which is the one the vendored document actually asks about: `IdpGroupUser` is "a user whose membership is derived from IDP group assignments", and NO Devin membership here is derived that way. Every Devin seat is assigned DIRECTLY to a person by the organization, which is the same absence every member detail already reports as idp_role_assignments: []. THE ASK is now one fact rather than two: a Devin SEAT a person holds BECAUSE an identity group confers it. A directory identity on a person is not that, and a role on a group is not that either. NOTE for the next wave: the five idp-GROUPS rows in this fence still carry the falsified "canon attaches no role to an identity group" clause, and they are deliberately untouched here because on those rows the correction may be a re-SERVE rather than a re-word - `IdpGroup.role_assignments` is RoleAssignment[] and hello-17's groupRole() may now answer it - which is a ruling this wave cannot make alone
the v3beta1 idp-users twin, held to the same answer by test. CORRECTED 2026-09-12 (hello-18 serving wave W-c). The 2026-09-10 correction already replaced this row's original reason - "this universe has no identity provider" - because hello-15's canon.IdentityProviderConfig and canon.IdentityGroup (packages/canon/src/ci-config.ts:359, :401) made it false: a SAML provider with SCIM enabled, the administrator who switched it on, the date it was switched on, and four groups derived from ACCESS facts, which renderer-circleci serves today (/organizations/{org_id}/groups, ruled 2026-09-07). Two of the three supporting clauses that correction left have since gone false in their turn, and this is the second correction this row has needed for the same reason: a ruling resting on an absence canon later filled. canon DOES attach a role to an identity group (hello-17's grants - a membership row with scope_kind 'group', reader.groupRole(), which renderer-circleci serves), and canon DOES bind a person to an external uid (hello-18's externalUid - person.external_uid, which GitLab's saml/{uid} and scim/{uid} resolve). The empty answer still stands, and it now stands on the FIRST clause alone - which is the one the vendored document actually asks about: `IdpGroupUser` is "a user whose membership is derived from IDP group assignments", and NO Devin membership here is derived that way. Every Devin seat is assigned DIRECTLY to a person by the organization, which is the same absence every member detail already reports as idp_role_assignments: []. THE ASK is now one fact rather than two: a Devin SEAT a person holds BECAUSE an identity group confers it. A directory identity on a person is not that, and a role on a group is not that either. NOTE for the next wave: the five idp-GROUPS rows in this fence still carry the falsified "canon attaches no role to an identity group" clause, and they are deliberately untouched here because on those rows the correction may be a re-SERVE rather than a re-word - `IdpGroup.role_assignments` is RoleAssignment[] and hello-17's groupRole() may now answer it - which is a ruling this wave cannot make alone
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
refuse — knowledge notes are authored free-text prose a human wrote, the same class of content as session messages, and this universe does not invent authored prose (the standing founder-adopted default; revisit if a client asks)
SERVED 2026-09-12 (post-hello-18 serving pass). The 2026-09-10 correction on this row named its own expiry: the empty stood because "canon attaches no role to an identity group and binds no person to an external uid", and THE ASK was exactly those two facts. Both have landed - hello-17's features.grants writes one membership row per identity group with scope_kind 'group' (reader.groupRole(), decisions/2026-09-11-2304-hello-17-grants.md), and hello-18's features.externalUid puts person.external_uid on every human (which GitLab's saml/{uid} and scim/{uid} resolve) - and the 2026-09-12 wave that re-worded the idp-USERS rows left the note this answers: "on those rows the correction may be a re-SERVE rather than a re-word". A GROUP IS REGISTERED WITH THIS ENTERPRISE WHEN CANON BINDS IT TO A ROLE: that binding is what registering one MEANS, canon records no Devin-side registration object, and gating all five rows on it is what keeps the three lists answering the same set. This is the ACCOUNT-scoped registry and IdpGroupResponse declares ONE field, the name - no role, no member count, no created instant - so it publishes the same groups the two IdpGroup lists do rather than every directory group: three lists that could disagree about which groups exist would be invariant #5 broken across one family. EVERY MEMBER STILL REPORTS idp_role_assignments: [] AND THAT IS NOT A CONTRADICTION - it is the vendored document's own distinction: IdpRoleAssignment is a role "inherited via IDP group membership" and IdpGroupUser is a user whose "membership is derived from IDP group assignments", both facts about a SEAT, and every Devin seat here is assigned DIRECTLY by the organization (canon's ai_seat), which is the fact the idp-USERS rows were re-ruled onto on 2026-09-12. IdpGroup.role_assignments is what the GROUP confers, not what any member has received. Gated on groupRole(), so on every artifact without features.grants - the 127 pins frozen before hello-20 - the lists are Devin's empty envelope and the by-name reads are its 404, byte for byte what these rows served before; conformance asserts that on the hello-7 harness those pins ride.
SERVED 2026-09-12 (post-hello-18 serving pass). The 2026-09-10 correction on this row named its own expiry: the empty stood because "canon attaches no role to an identity group and binds no person to an external uid", and THE ASK was exactly those two facts. Both have landed - hello-17's features.grants writes one membership row per identity group with scope_kind 'group' (reader.groupRole(), decisions/2026-09-11-2304-hello-17-grants.md), and hello-18's features.externalUid puts person.external_uid on every human (which GitLab's saml/{uid} and scim/{uid} resolve) - and the 2026-09-12 wave that re-worded the idp-USERS rows left the note this answers: "on those rows the correction may be a re-SERVE rather than a re-word". A GROUP IS REGISTERED WITH THIS ENTERPRISE WHEN CANON BINDS IT TO A ROLE: that binding is what registering one MEANS, canon records no Devin-side registration object, and gating all five rows on it is what keeps the three lists answering the same set. This row's old reason said "IdpGroup REQUIRES role_assignments, a Devin role the group confers, and canon attaches no role to an identity group at all", and that is the clause hello-17 falsified. ONE ASSIGNMENT PER GROUP, because a group's role is the FLOOR of its members' authority and canon writes exactly one scope_kind 'group' row per group; role_id is the SAME catalog row /v3/enterprise/roles publishes, so the reference resolves beside the answer that produced it; role_type follows canon's permission list (org:admin administers the whole organization, which is what an enterprise-scoped role is) and org_id follows role_type, the rule shapeUser already applies to a member's own assignments. EVERY MEMBER STILL REPORTS idp_role_assignments: [] AND THAT IS NOT A CONTRADICTION - it is the vendored document's own distinction: IdpRoleAssignment is a role "inherited via IDP group membership" and IdpGroupUser is a user whose "membership is derived from IDP group assignments", both facts about a SEAT, and every Devin seat here is assigned DIRECTLY by the organization (canon's ai_seat), which is the fact the idp-USERS rows were re-ruled onto on 2026-09-12. IdpGroup.role_assignments is what the GROUP confers, not what any member has received. Gated on groupRole(), so on every artifact without features.grants - the 127 pins frozen before hello-20 - the lists are Devin's empty envelope and the by-name reads are its 404, byte for byte what these rows served before; conformance asserts that on the hello-7 harness those pins ride.
SERVED 2026-09-12 (post-hello-18 serving pass). The 2026-09-10 correction on this row named its own expiry: the empty stood because "canon attaches no role to an identity group and binds no person to an external uid", and THE ASK was exactly those two facts. Both have landed - hello-17's features.grants writes one membership row per identity group with scope_kind 'group' (reader.groupRole(), decisions/2026-09-11-2304-hello-17-grants.md), and hello-18's features.externalUid puts person.external_uid on every human (which GitLab's saml/{uid} and scim/{uid} resolve) - and the 2026-09-12 wave that re-worded the idp-USERS rows left the note this answers: "on those rows the correction may be a re-SERVE rather than a re-word". A GROUP IS REGISTERED WITH THIS ENTERPRISE WHEN CANON BINDS IT TO A ROLE: that binding is what registering one MEANS, canon records no Devin-side registration object, and gating all five rows on it is what keeps the three lists answering the same set. The by-name half, and its refusal was DISSOLVED rather than overruled: the row was refuse because "the IdpGroup list is empty, no name can resolve, and Devin's own 404 is the only possible answer". The list is not empty now, a name it carries answers 200 with the list's own item, and a name it does not carries Devin's ordinary resource 404 - the same status the ruling wanted, produced by the served route rather than asserted by a table, and WITHOUT x-sandboxapis-refusal, which conformance asserts is absent. EVERY MEMBER STILL REPORTS idp_role_assignments: [] AND THAT IS NOT A CONTRADICTION - it is the vendored document's own distinction: IdpRoleAssignment is a role "inherited via IDP group membership" and IdpGroupUser is a user whose "membership is derived from IDP group assignments", both facts about a SEAT, and every Devin seat here is assigned DIRECTLY by the organization (canon's ai_seat), which is the fact the idp-USERS rows were re-ruled onto on 2026-09-12. IdpGroup.role_assignments is what the GROUP confers, not what any member has received. Gated on groupRole(), so on every artifact without features.grants - the 127 pins frozen before hello-20 - the lists are Devin's empty envelope and the by-name reads are its 404, byte for byte what these rows served before; conformance asserts that on the hello-7 harness those pins ride.
SERVED 2026-09-12 (post-hello-18 serving pass). The 2026-09-10 correction on this row named its own expiry: the empty stood because "canon attaches no role to an identity group and binds no person to an external uid", and THE ASK was exactly those two facts. Both have landed - hello-17's features.grants writes one membership row per identity group with scope_kind 'group' (reader.groupRole(), decisions/2026-09-11-2304-hello-17-grants.md), and hello-18's features.externalUid puts person.external_uid on every human (which GitLab's saml/{uid} and scim/{uid} resolve) - and the 2026-09-12 wave that re-worded the idp-USERS rows left the note this answers: "on those rows the correction may be a re-SERVE rather than a re-word". A GROUP IS REGISTERED WITH THIS ENTERPRISE WHEN CANON BINDS IT TO A ROLE: that binding is what registering one MEANS, canon records no Devin-side registration object, and gating all five rows on it is what keeps the three lists answering the same set. The org-scoped twin, serving the same object as its enterprise twin: which endpoint you ask does not change what a group may do, the reading shapeOrgUser already takes one resource along. The parent still has to resolve - an {org_id} this universe does not have is Devin's 404 through the shared org wrapper. EVERY MEMBER STILL REPORTS idp_role_assignments: [] AND THAT IS NOT A CONTRADICTION - it is the vendored document's own distinction: IdpRoleAssignment is a role "inherited via IDP group membership" and IdpGroupUser is a user whose "membership is derived from IDP group assignments", both facts about a SEAT, and every Devin seat here is assigned DIRECTLY by the organization (canon's ai_seat), which is the fact the idp-USERS rows were re-ruled onto on 2026-09-12. IdpGroup.role_assignments is what the GROUP confers, not what any member has received. Gated on groupRole(), so on every artifact without features.grants - the 127 pins frozen before hello-20 - the lists are Devin's empty envelope and the by-name reads are its 404, byte for byte what these rows served before; conformance asserts that on the hello-7 harness those pins ride.
SERVED 2026-09-12 (post-hello-18 serving pass). The 2026-09-10 correction on this row named its own expiry: the empty stood because "canon attaches no role to an identity group and binds no person to an external uid", and THE ASK was exactly those two facts. Both have landed - hello-17's features.grants writes one membership row per identity group with scope_kind 'group' (reader.groupRole(), decisions/2026-09-11-2304-hello-17-grants.md), and hello-18's features.externalUid puts person.external_uid on every human (which GitLab's saml/{uid} and scim/{uid} resolve) - and the 2026-09-12 wave that re-worded the idp-USERS rows left the note this answers: "on those rows the correction may be a re-SERVE rather than a re-word". A GROUP IS REGISTERED WITH THIS ENTERPRISE WHEN CANON BINDS IT TO A ROLE: that binding is what registering one MEANS, canon records no Devin-side registration object, and gating all five rows on it is what keeps the three lists answering the same set. The org-scoped by-name twin, on the same terms as its enterprise twin: a name the registry carries answers 200 with the list's own item, a name it does not is Devin's ordinary resource 404 with no refusal header, and an {org_id} nobody has is the org wrapper's 404. EVERY MEMBER STILL REPORTS idp_role_assignments: [] AND THAT IS NOT A CONTRADICTION - it is the vendored document's own distinction: IdpRoleAssignment is a role "inherited via IDP group membership" and IdpGroupUser is a user whose "membership is derived from IDP group assignments", both facts about a SEAT, and every Devin seat here is assigned DIRECTLY by the organization (canon's ai_seat), which is the fact the idp-USERS rows were re-ruled onto on 2026-09-12. IdpGroup.role_assignments is what the GROUP confers, not what any member has received. Gated on groupRole(), so on every artifact without features.grants - the 127 pins frozen before hello-20 - the lists are Devin's empty envelope and the by-name reads are its 404, byte for byte what these rows served before; conformance asserts that on the hello-7 harness those pins ride.
refuse — an automation INSTANCE exists only because somebody configured one, and this universe accepts no writes (invariant #3) - nobody here created a Devin automation. RE-WORDED 2026-09-14 (hello-20 wave W-devin): this reason used to end 'the vendor-fixed half of the surface - schemas and templates - is derived instead', and the wave that went to derive those two found that it cannot be done from this repository. Both of them are still backlog and each now carries the finding that stopped it - a PATCH semantics this read-only replica has none of, and condition field paths and a built-in template catalogue that are the VENDOR's identifiers, which the vendored document declares the shape of and never one instance of. The refusal on this row is untouched by that and rests on its own fact.
refuse — an automation INSTANCE exists only because somebody configured one, and this universe accepts no writes (invariant #3) - nobody here created a Devin automation. RE-WORDED 2026-09-14 (hello-20 wave W-devin): this reason used to end 'the vendor-fixed half of the surface - schemas and templates - is derived instead', and the wave that went to derive those two found that it cannot be done from this repository. Both of them are still backlog and each now carries the finding that stopped it - a PATCH semantics this read-only replica has none of, and condition field paths and a built-in template catalogue that are the VENDOR's identifiers, which the vendored document declares the shape of and never one instance of. The refusal on this row is untouched by that and rests on its own fact.
derive — NOT SERVED, and deliberately still backlog rather than `refuse`: REAL DEVIN ANSWERS 200 HERE for every organization, because this is the VENDOR-FIXED catalogue rather than anything olympus-labs configured, so a refusal would be a lie about the provider. The 2026-09-01 classification read `derive` off that same fact - the vendor half of the automations surface - and the hello-20 serving wave that went to derive it found the vendor half is not in this repository to derive FROM. TWO INDEPENDENT BLOCKERS, each a REQUIRED field. FIRST, `update_semantics` is documented as 'PATCH semantics active for this organization' (replace_groups or merge_patch), and this replica accepts no PATCH at all (invariant #3) - it has no such semantics to report, and choosing one would assert a write behaviour for a request this host will always refuse, which is the ruled Conan-authenticate and PagerDuty routing-key precedent: a value this universe cannot hold is not served. SECOND, `sources` maps an event source to an event name to an AutomationEventSchemaResponse, whose required `fields` map is keyed by the CONDITION FIELD PATH a client puts in conditions[].field - an identifier a client USES, which decisions/2026-09-14-0202 puts squarely on the factual side of the catalogue line, and which the vendored document never names. (The 35 `event_type` values ARE declared, on AutomationTriggerRequest, and are the half that IS derivable; `fields: {}` on all 35 would claim no Devin trigger supports a condition, which is false about the vendor.) THE ASK is a CAPTURE of Devin's own schema document, or a client that says which fields it needs - not a canon entity.
derive — NOT SERVED, and deliberately still backlog rather than `refuse`: REAL DEVIN ANSWERS 200 HERE for every organization - the operation lists Devin's BUILT-IN templates, which are the vendor's product catalogue rather than anything this organization created - so a refusal would be a lie about the provider, and `{templates: []}` would claim Devin ships none, which the create endpoint's own description contradicts (template_id values are accepted there). The 2026-09-01 classification read `derive` off 'the vendor-fixed half of the surface'; the hello-20 serving wave that went to derive it found the vendor half is not in this repository to derive FROM. AutomationTemplateResponse requires template_id, name, description, category, required_integrations, required_mcps, triggers and actions, and the vendored document declares the SHAPE of a template and not one instance: no example, no default, no enum of ids, and a nullable docs_url that would point into Devin's own documentation. A template_id is an identifier a client USES at create time, which decisions/2026-09-14-0202 puts on the FACTUAL side of the catalogue line (a name a client asks for is factual; prose that decorates the story is ours to write) - and the ids, the names and the docs_urls are all on that side and all unobserved. THE ASK is a CAPTURE of Devin's template catalogue - not a canon entity.
nobody here ever wrote a playbook, so the playbook list is empty
the org-scoped playbook twin: nobody here ever wrote a playbook, so the playbook list is empty
refuse — the id half of the playbook pair: nobody here ever wrote a playbook, so the playbook list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
refuse — the id half of the playbook pair: nobody here ever wrote a playbook, so the playbook list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty
the org-scoped service-user twin: this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty
refuse — the id half of the service-user pair: this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
refuse — the id half of the service-user pair: this universe's only non-human identity is the CI bot and it holds no Devin seat, so the service-user list is empty, so no id can resolve and Devin's own 404 is the only possible answer (the by-id shape ruled in DECISIONS 2026-09-01 [coverage/A0])
refuse — the git-provider connection is an install-time OAuth object on Devin's side, and this universe's repositories are served by our own GitHub/GitLab mirrors rather than through a Devin-held provider grant
refuse — the git-provider connection is an install-time OAuth object on Devin's side, and this universe's repositories are served by our own GitHub/GitLab mirrors rather than through a Devin-held provider grant
refuse — the git-provider connection is an install-time OAuth object on Devin's side, and this universe's repositories are served by our own GitHub/GitLab mirrors rather than through a Devin-held provider grant
SERVED 2026-09-12: RepositoryResponse over repo/commits/git_tree_entry. provider_repository_id is githubId(repo.id) - the very id the GitHub replica publishes for the same repository - and the connection host is github.com, which every Devin session's own pr_url already names. The connection id is required with no column and is MINTED deterministically from the ORGANIZATION, because this enterprise has exactly one connection and every repository is read through it; a per-repository id would claim as many connections as repositories. indexing_status is nullable and is null: canon carries no Devin index
SERVED 2026-09-14 (hello-20 wave W-devin): RepoIndexingStatusResponse - the by-path half of `.../repositories/indexing`, and a DIFFERENT schema from it (the list publishes RepositoryIndexingResponse - path, enabled, branches - while this operation publishes enabled plus the index jobs), read off the vendored document rather than assumed from the sibling. All four members follow from ONE measurement rather than four choices: canon carries no Devin index, no index JOB and no indexing setting, and this universe accepts no writes, so indexing_enabled is false, latest_indexes is empty and both latest_completed_* are null. Conformance asserts all four, so the day canon grows an index the row reds instead of carrying a stale `false`. {repository_path} is `owner/repo` and therefore SPANS A SLASH, so the route carries Hono's regex path param and resolves the escaped `%2F` spelling to the same repository - verified rather than assumed, and with NO decodeURIComponent, which would be wrong twice and THROWS a bare 500 on a malformed escape where the document declares a 404 (decisions/2026-09-12-2239). Registered after the list route, which keeps answering the list. A path this organization does not have is Devin's own resource 404 rather than a status object for a repository that is not there (invariant #5). NO GENERATION GATE, deliberately: it answers off listRepos(), which every artifact since hello-1 carries, and the fact it reports is as true of a frozen pin as of live - asserted on hello-7 and hello-20 alike.
SERVED 2026-09-12: RepositoryIndexingResponse requires repository_path, indexing_enabled AND branches (the audit's `repository_path alone` read RepositoryIndexingItem, which is the BULK-INDEX REQUEST schema, not this response). indexing_enabled is false and branches is empty as a MEASUREMENT rather than a default - Devin repository indexing is a setting written through the API, canon carries no Devin index, no index job and no indexing setting, and this universe accepts no writes, so nothing ever enabled it and no branch is configured for it. Conformance asserts both, so the day canon grows an index the row reds instead of carrying a stale false
SERVED 2026-09-14 (hello-20 `auditActor`): reader.listPersonAuditEvents() - the PERSON half of `admin_audit_event`, which hello-20 writes (91 rows at 90 days, every instant an existing act's instant and every actor an existing person). NEVER reader.listAuditEvents(): the bare three accessors default to the SUPPORT DESK's register, and a Devin surface publishing a Zendesk instance's account audit under this enterprise's path would be a different organization's register on the wrong host. THIS HOST PUBLISHES 3 OF THE 91, AND THAT IS TWO GATES RATHER THAN A SLICE TAKEN TO BE SAFE. GATE 1, the rule the GitLab twin states for the same table: the audited object must be an object THIS HOST publishes. Devin publishes the ORGANIZATION (/v3/enterprise/organizations, whose created_at IS reader.orgCreatedEpoch(), so a `create_org` row says in a second place what that endpoint says in the first), the enterprise's MEMBERS, the REPOSITORIES, and the caller's own API KEY - /v3/self has rendered a canon `personal-token` credential as api_key_id + api_key_name since hello-17, so `create_pat` and `revoke_pat` are published for a holder of a Devin seat, whose member id /v3/enterprise/members/users/{user_id} resolves (invariant #5). GATE 2, and it is Devin-specific: AuditLogAction is a CLOSED enum of acts performed INSIDE Devin, where GitLab's event_name is free text - an act with no member in that enum cannot be published here without inventing a value the vendored document forbids (invariant #2). So the 44 membership rows are NOT published, because this universe's Devin membership IS THE SEAT (members() is exactly the ai_seat holders and enterprise_joined_at is the seat's own instant, and Devin's enum distinguishes add_enterprise_member from add_member) and canon writes no audit row for a seat assignment; the 4 team rows are not, because Devin has no team (its idp-groups are DIRECTORY groups); the 2 protected-ref rows are not, because this host publishes no ref; the 1 repo row is not, because every repository act in the enum is an act of CONNECTING a repository to Devin, which canon does not record; and 37 credential rows are not, because an SSH key, a GPG key and a deploy or resource token are git-host credentials Devin neither holds nor publishes. Conformance asserts BOTH directions and the exclusions: every published row is a canonical act, every qualifying canonical act is published, and canon really holds rows of each excluded family - an empty family would make the exclusion vacuous. `data` is the EMPTY OBJECT: the document declares it additionalProperties with no properties and names no key inside it, and this repository holds no capture of Devin's own spellings, so a key invented here would be this replica asserting a wire shape nobody verified (the reason the GitLab twin CAN fill its `details` - GitLab documents custom_message, target_details and ip_address by name). Everything the row knows has a declared field of its own and is in it. `order` defaults to desc, which is the document's own default and the reverse of the artifact's order, and anything but asc/desc is the caller's 422; `action`, `time_after` and `time_before` narrow rather than being ignored. Gated on reader.hasAuditActor(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED hello-20 gap rather than `[]`, which would claim this enterprise has never been administered while the same artifact publishes the organization, the members and the API key that administration produced. This row is the ENTERPRISE register.
SERVED 2026-09-14 (hello-20 `auditActor`): reader.listPersonAuditEvents() - the PERSON half of `admin_audit_event`, which hello-20 writes (91 rows at 90 days, every instant an existing act's instant and every actor an existing person). NEVER reader.listAuditEvents(): the bare three accessors default to the SUPPORT DESK's register, and a Devin surface publishing a Zendesk instance's account audit under this enterprise's path would be a different organization's register on the wrong host. THIS HOST PUBLISHES 3 OF THE 91, AND THAT IS TWO GATES RATHER THAN A SLICE TAKEN TO BE SAFE. GATE 1, the rule the GitLab twin states for the same table: the audited object must be an object THIS HOST publishes. Devin publishes the ORGANIZATION (/v3/enterprise/organizations, whose created_at IS reader.orgCreatedEpoch(), so a `create_org` row says in a second place what that endpoint says in the first), the enterprise's MEMBERS, the REPOSITORIES, and the caller's own API KEY - /v3/self has rendered a canon `personal-token` credential as api_key_id + api_key_name since hello-17, so `create_pat` and `revoke_pat` are published for a holder of a Devin seat, whose member id /v3/enterprise/members/users/{user_id} resolves (invariant #5). GATE 2, and it is Devin-specific: AuditLogAction is a CLOSED enum of acts performed INSIDE Devin, where GitLab's event_name is free text - an act with no member in that enum cannot be published here without inventing a value the vendored document forbids (invariant #2). So the 44 membership rows are NOT published, because this universe's Devin membership IS THE SEAT (members() is exactly the ai_seat holders and enterprise_joined_at is the seat's own instant, and Devin's enum distinguishes add_enterprise_member from add_member) and canon writes no audit row for a seat assignment; the 4 team rows are not, because Devin has no team (its idp-groups are DIRECTORY groups); the 2 protected-ref rows are not, because this host publishes no ref; the 1 repo row is not, because every repository act in the enum is an act of CONNECTING a repository to Devin, which canon does not record; and 37 credential rows are not, because an SSH key, a GPG key and a deploy or resource token are git-host credentials Devin neither holds nor publishes. Conformance asserts BOTH directions and the exclusions: every published row is a canonical act, every qualifying canonical act is published, and canon really holds rows of each excluded family - an empty family would make the exclusion vacuous. `data` is the EMPTY OBJECT: the document declares it additionalProperties with no properties and names no key inside it, and this repository holds no capture of Devin's own spellings, so a key invented here would be this replica asserting a wire shape nobody verified (the reason the GitLab twin CAN fill its `details` - GitLab documents custom_message, target_details and ip_address by name). Everything the row knows has a declared field of its own and is in it. `order` defaults to desc, which is the document's own default and the reverse of the artifact's order, and anything but asc/desc is the caller's 422; `action`, `time_after` and `time_before` narrow rather than being ignored. Gated on reader.hasAuditActor(); an older artifact - the 127 pins frozen before hello-20, and live until the hello-20 cutover - answers the NAMED hello-20 gap rather than `[]`, which would claim this enterprise has never been administered while the same artifact publishes the organization, the members and the API key that administration produced. This row is the ORG-SCOPED register, and it answers the SAME rows as the enterprise one, because every act in the register happened in the one organization this enterprise has - the reading /v3/enterprise/consumption/daily/organizations/{org_id} already takes. An {org_id} this universe does not have is Devin's own 404 through the shared org wrapper, before the generation is consulted.
refuse — guardrails are an enterprise-security beta this org never turned on, and Devin answers 403 to guardrail-violation reads for an enterprise with no guardrail policy configured
refuse — guardrails are an enterprise-security beta this org never turned on, and Devin answers 403 to guardrail-violation reads for an enterprise with no guardrail policy configured
SERVED 2026-09-12: OrganizationResponse over the canonical `org` row this host already resolves {org_id} against. created_at is reader.orgCreatedEpoch(), updated_at the newest canonical event in any of the organization's repositories, and BOTH ACU limits are declared integer|null and are null - this enterprise buys ACUs and spends them (the consumption family reports what was spent) and nobody here capped a session or a cycle, which is the same fact /v3/enterprise/consumption/acu-limits/devin already answers empty
SERVED 2026-09-12: the single read of the same OrganizationResponse the list publishes, through the shared {org_id} resolution - so an id this universe does not have is Devin's own 404
refuse — no Devin Review exists in this universe - a review record is created by a trigger through the API and this universe accepts no writes (invariant #3), and canon's ai_pull rows attribute AUTHORSHIP rather than review (the two pulls Devin produced were reviewed by people, person-14 and person-04); Devin's own answer when no review exists for the resolved commit is its 404, which the operation's own description states. RULED by the founder 2026-09-12
refuse — the org-scoped Devin Review twin, and the same fact: no Devin Review exists in this universe - a review record is created by a trigger through the API and this universe accepts no writes (invariant #3), and canon's ai_pull rows attribute AUTHORSHIP rather than review (the two pulls Devin produced were reviewed by people, person-14 and person-04); Devin's own answer when no review exists for the resolved commit is its 404, which the operation's own description states. RULED by the founder 2026-09-12
SERVED 2026-09-10 (hello-16): reader.listMembershipRoles() (packages/artifact/src/reader.ts:3042) in Devin's PaginatedResponse[Role] envelope. `role_type` is REQUIRED with a closed enterprise|org enum canon does not carry, so it is READ OFF the permission list canon does: a role holding `org:admin` administers the whole organization, everything below it acts inside one org — conformance asserts the derivation rather than the current five answers. THIS ROW IS WHAT MAKES THE MEMBERS SURFACES RESOLVE: every RoleAssignment.role they publish carries a role_id this operation must answer, so from hello-16 on both read this one catalog and conformance asserts that every role a member holds is in it
SERVED 2026-09-10 (hello-16): the same row plus canon's permission list — reader.listMembershipRoles() (reader.ts:3042) — which is the whole difference the operation declares ("Get a single role AND ITS PERMISSIONS"). `permissions` is canon's closed `scope:level` vocabulary, which the schema types `array<string>` with no enum, so re-spelling it into Devin permission identifiers would be a table nothing in canon could hold us to. A role id the catalog does not carry is Devin's own problem+json 404, never the coverage miss
refuse — a schedule exists only because somebody created one, and this universe accepts no writes (invariant #3) — nobody here scheduled a recurring Devin run
refuse — a schedule exists only because somebody created one, and this universe accepts no writes (invariant #3) — nobody here scheduled a recurring Devin run
this org never adopted tagging, which is the same fact the already-ruled session `tags` rows carry (DECISIONS 2026-08-20 [devin])
with no organization tag defined there is no default tag set either — the twin of the org-tags row. Devin's DefaultTagResponse is a nullable SCALAR, so this row's empty shape is `default_tag: null` (empty-shape.ts NULL_KEYS), not an empty list
refuse — an enterprise infrastructure/security administration read, and the sandbox token is an enterprise-member token rather than a superadmin one; Devin answers 403 (the ruled instance-admin precedent, coverage/reviews/2026-09-01-jira-modes.md)
refuse — CORRECTED 2026-09-12 (hello-18 serving wave W-c): the reason this row carried said the artifact carries no file data, and hello-15 made that FALSE - attachment.body holds real bytes for 35 rows and renderer-zendesk serves them. The refusal still stands, on two facts that ARE this row's own. FIRST, no uuid this route could resolve is ever advertised: no generation attaches an attachment to an agent session, .../sessions/{devin_id}/attachments answers [] on every session, so this organization has no attachment with that uuid and Devin's own 404 is the whole answer. SECOND, the SUCCESS answer the document declares is a 307 to an IP-enforcing proxy or a presigned S3 URL - a link into storage this replica has no equivalent of - so even with bytes to serve this row could not answer 307, which is the ruled avatar-bytes precedent (coverage/reviews/2026-09-01-jira-modes.md row 6) applied to a redirect rather than to a body
this enterprise configures no per-seat ACU cap; any figure printed here would be a placeholder copied off the spec example, which invariant #4 forbids (the ruled OpenAI rate_limits shape, DECISIONS 2026-08-20 [P31/openai])
refuse — an enterprise infrastructure/security administration read, and the sandbox token is an enterprise-member token rather than a superadmin one; Devin answers 403 (the ruled instance-admin precedent, coverage/reviews/2026-09-01-jira-modes.md)
refuse — an enterprise infrastructure/security administration read, and the sandbox token is an enterprise-member token rather than a superadmin one; Devin answers 403 (the ruled instance-admin precedent, coverage/reviews/2026-09-01-jira-modes.md)
SERVED 2026-09-12: QueueResponse MEASURED off the fleet rather than asserted - queue_size is the sessions this artifact left unfinished, read through the same status map /v3/enterprise/sessions publishes on every session, and it is 0 at `normal` because every Devin session in canon is terminal (hello-17: 65 completed, 2 failed, no running row). It goes non-zero on its own the day the generator leaves a session in flight
SERVED 2026-09-12 (hello-19 `ciBindings`): the org-level secrets this enterprise hands its CODING AGENT, off reader.orgCiBindings(org, 'coding-agent'). The 2026-09-01 reason asked for a new canon entity ActionsSecret, and hello-19's `ci_binding` IS that entity canonically — one named thing handed to something that runs, with one boolean saying whether its value may be published. THE `coding-agent` AUDIENCE AND NOTHING ELSE: Devin IS the coding agent, while `pipeline` is the build system's audience (GitLab's CI/CD variables, GitHub's Actions secrets) and `dependency-bot` is the updater's — every ci_binding accessor names a scope AND an audience precisely so a renderer has no call it could forget to filter, and conformance asserts that no other audience's key appears here. BOTH ROWS ARE SERVED RATHER THAN THE MASKED HALF, because SecretResponse requires `is_sensitive` as a boolean: Devin's store holds the agent's model key and the workspace it operates in alike, so is_sensitive IS the canonical `masked` column and both values appear. No value is published because SecretResponse declares no value field — the same shape canon holds for a masked binding, which is the argument the whole domain rests on. `secret_id` is minted from the canonical row id (the devinApiKeyId rule); `key` is the name the theme wrote; `note` is null because canon records none; `created_by` is the enterprise administrator's Devin user id, which /v3/enterprise/members/users/{user_id} resolves (invariant #5), and the list is empty rather than naming nobody on an artifact with no Devin seat; `created_at` is the binding's own instant; `secret_type` is key-value and `access_type` is org; `updated_at`/`updated_by` are null exactly when `updated_epoch` equals `created_epoch`, which is canon's own record of never rotated. Gated on hasCiBindings(); an older artifact answers the named hello-19 CI-binding gap, because [] there would say this enterprise hands its agent nothing while the same artifact publishes the sessions that agent ran
SERVED 2026-09-12 on hello-17: PatUserSelf for the founding member - the same `athena` GET /user and GitLab's currentUser resolve to. api_key_id and api_key_name read off a REAL person_credential row (kind personal-token, state active), whose title IS the key's name, and user_id is a Devin member id /v3/enterprise/members/users/{user_id} resolves. Both halves need hello-17 (callerCredentials for the token, adminSeat for the owner's Devin seat); an older generation is NAMED rather than answered with a minted key
03 / What's simulated
Every Devin call resolves against the same simulated data set every other provider serves. Counted from the devin-v3-g12 artifact (universe generation 12):
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.
This vendor's user roster is disjoint from the GitHub Copilot cohort and from Anthropic's, Cursor's and OpenAI's, so nobody holds two vendors' seats; and it equals its own slice of the canonical seat table.
Against GitHub, Anthropic, Cursor, OpenAI · parity/m3-parity.test.ts
Every identity this host bills for resolves as a user on the GitHub host with the same name, and the session count here plus Cursor's agents plus GitHub's own agent tasks sum to the whole canonical agent-session table.
No session this host serves is a Google Antigravity run: the two hosts partition the canonical agent-session table, and no pull request is claimed by both.
Against Google Antigravity · parity/agent-run-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.
devin-v3.snap.sandboxapis.devgeneration 5v3serveddevin-v3-g10.snap.sandboxapis.devgeneration 10v3serveddevin-v3-g11.snap.sandboxapis.devgeneration 11v3serveddevin-v3-g12.snap.sandboxapis.devgeneration 12v3serveddevin-v3-g6.snap.sandboxapis.devgeneration 6v3serveddevin-v3-g8.snap.sandboxapis.devgeneration 8v3serveddevin-v3-g9.snap.sandboxapis.devgeneration 9v3servedNeed an endpoint that is not served yet?
Every row Devin'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.